Documentation Index

Fetch the complete documentation index at: https://docs.thrivelearning.com/llms.txt

Use this file to discover all available pages before exploring further.

Create content records in bulk

Prev Next
Post
/contents/bulk

Coming soon. This endpoint is not available yet, and the details below may change before release.

Submits an asynchronous job that creates up to 100 content records.

The endpoint responds immediately with 202 Accepted and a jobId; the records are created in the background. Poll GET /contents/bulk/{jobId} for progress and per-item results. Each successful result carries the new content's id and its presigned upload URLs, so a single poll gives you everything you need to start uploading.

Validation happens to the whole batch, up front

The batch is validated before any job is created, so a malformed request never half-runs:

  • every entry invalid — 422, no job created; - some entries invalid — 207, no job created, with a breakdown of which entries were rejected and why. Correct them and resubmit the whole batch.

Failures that only show up while the job is running — a bad upload, an unresolvable author — are reported per item in the job's results[] instead, and do not stop the rest of the batch.

Resubmitting is safe, but only with the same key

Every submission must carry an Idempotency-Key header. Replaying a request with the same key returns the job that already exists rather than starting a second one, which is what makes a retry after a timeout safe. Note this deduplicates submissions, not content — two submissions with different keys will create two sets of records.

Each entry takes the same body as POST /contents, so the same rules apply per entry: the item cap, the one-e-learning-item limit, and skills and topics requiring publishWhenReady.

Security
HTTP
Type basic

HTTP Basic authentication using your Tenant ID and API secret.

  • Username is the Tenant ID (i.e. eu-west-2_AbcdEfghI)
  • Password is the API secret you would have received.

You can also authenticate using OAuth 2.0 client credentials (oauth2 security scheme) instead of Basic auth.

OAuth

OAuth 2.0 client credentials authentication.

Use the following token endpoints (replace :tenantId with your Tenant ID):

  • Public API access tokens

    • Staging: https://public.api.learnstaging.link/oauth2/token/:tenantId
    • Production: https://public.api.learn.link/oauth2/token/:tenantId
    • Staging MEA: https://public.api.meastaging.learn.tech/oauth2/token/:tenantId
    • Production MEA: https://public.api.mea.learn.tech/oauth2/token/:tenantId
  • Webhooks access tokens

    • Staging: https://user.api.learnstaging.link/oauth2/token/:tenantId
    • Production: https://user.api.learn.link/oauth2/token/:tenantId
    • Staging MEA: https://user.api.meastaging.learn.tech/oauth2/token/:tenantId
    • Production MEA: https://user.api.mea.learn.tech/oauth2/token/:tenantId

All access tokens must be sent using the Authorization: Bearer <access_token> header.

Scopes

For API access (non-webhooks), the following scopes are available:

  • api/all – Full read and write access to the API.
  • api/read – Read-only access to the API.
  • api/write – Write access to the API.

For webhooks, the following scopes are available:

  • api/webhooks – Access to webhook functionality.
  • api/all – Full read and write access to the API, including webhooks.

Tokens must include appropriate scopes for the endpoints you wish to call.

FlowClient Credentials
Token URLhttps://public.api.learn.link/oauth2/token/:tenantId
Scopes:
api/writeWrite access to the API.
Header parameters
Idempotency-Key
stringRequired

Caller-generated idempotency key for the submission. Generate it once per logical submission and reuse it on retries — replaying the same key returns the existing job instead of creating a duplicate. Requests without the header are rejected with 422.

Body parameters
bulkCreateContent

Create two records in one submission

Each entry is the same body POST /contents takes. Remember the Idempotency-Key header — without it the submission is rejected.

{
  "contents": [
    {
      "title": "Fire safety",
      "primaryCategory": "article",
      "authorRef": "UID30084022",
      "languageCode": "en-gb",
      "items": [
        {
          "type": "rich_text",
          "rank": "0",
          "summary": "Fire safety basics",
          "meta": {
            "body": "

Fire safety basics.

" } } ] }, { "title": "Data protection", "primaryCategory": "elearning", "authorRef": "UID30084022", "languageCode": "en-gb", "items": [ { "type": "elearning", "rank": "0", "meta": { "name": "gdpr.zip", "uploadId": "1a2b3c4d-5e6f-4708-9a0b-1c2d3e4f5a6b" } } ] } ] }
Expand All
object

The content records to create.

contents
Array of object (ContentCreateBody) Required

The content records to create, at most 100 per submission

Min items1
Max items100
object

The content record to create, along with its initial items.

title
string Required

Title of the content

Min length3
Max length150
ExampleOnboarding pack
primaryCategory
string

How the content should be categorised in the catalogue. Taken as you declare it — it is not inferred from the items you send.

Valid values[ "article", "assessment", "elearning", "event", "file", "pathway", "question", "quiz", "standard", "url", "video" ]
Exampleelearning
languageCode
string Required

The language of the content. Normalised before it is stored: en and en-GB both resolve to en-gb, de-at resolves to de. A language the platform does not support is rejected.

Exampleen-gb
publishWhenReady
boolean

Publish the content automatically as soon as it becomes ready. Because readiness waits on item processing and the thumbnail, this normally happens some time after this request returns.

Defaultfalse
Exampletrue
completionType
string

How a learner completes this content. auto, confirm and external apply to any content; on_elearning_completion requires an e-learning item; on_passing_quizzes, on_passing_observer_completed_quizzes and on_passing_assessments apply to quiz and assessment items, which are not yet supported by this API.

Note that on_elearning_completion combined with a web-format e-learning package can never reach ready.

Valid values[ "auto", "confirm", "external", "on_passing_quizzes", "on_passing_observer_completed_quizzes", "on_passing_assessments", "on_elearning_completion" ]
Exampleauto
skills
Array of string

Skills to associate with the content. Only stored when publishWhenReady is also set — sending skills without it is rejected with 422. Otherwise set them on the publish call.

string
Max length255
Exampleleadership
topics
Array of string

Topics to associate with the content. Only stored when publishWhenReady is also set — sending topics without it is rejected with 422. Otherwise set them on the publish call.

string
Max length255
Exampleonboarding
thumbnailUrl
string (uri)

A publicly reachable image we should fetch and use as the content thumbnail. Content cannot reach ready without a thumbnail, so either supply this or upload your own image to the thumbnailUploadUrl returned in the response. Either way the image is processed asynchronously.

Examplehttps://example.com/thumb.png
items
Array of object (ContentItemInput)

The items that make up the content. Optional, but content with no items can never reach ready and so can never be published.

At most one upload item (e-learning, file, video, audio, image) plus one non-upload item (rich text, url) per request. Add further items later with PATCH /contents/{id}.

One item within a content record. The type decides which meta fields apply.

Upload itemselearning, file, video, audio and image — are two-phase: you declare the item here with an uploadId you generate, then PUT the file to the matching URL returned in signedPutUrls. The item stays at processing until the platform has handled the file.

Non-upload itemsrich_text is ready immediately; url is scraped asynchronously for its title, description and image.

OneOf
object
object
rank
integer Required

The item's position within the content, lowest first. Required, and every item in a content record must have a different rank.

Minimum0
Example0
summary
string

A short label for the item, shown to learners. Optional on upload items; required on rich text and link items.

ExampleWelcome
type
string Required
Valid values[ "elearning" ]
Exampleelearning
meta
object Required
name
string Required

The file name, including its extension. The extension must match the item type you declared — a .pdf sent as a video is rejected.

Examplecourse.zip
uploadId
string (uuid) Required

A UUID you generate for this upload. It is echoed back in signedPutUrls so you can tell which URL belongs to which item, and must be unique within the content.

Example4f1c2b7e-9a3d-4c8e-b2f1-6d0a7c5e3b91
canDownload
boolean

Whether learners may download the original file

Defaulttrue
Exampletrue
format
string

The package format. Normally detected while the package is unpacked, so you rarely need to send it. A web package cannot be used with a completionType of on_elearning_completion.

Valid values[ "scorm12", "scorm2004", "cmi5", "tincan", "web" ]
Examplescorm2004
object
object
rank
integer Required

The item's position within the content, lowest first. Required, and every item in a content record must have a different rank.

Minimum0
Example0
summary
string

A short label for the item, shown to learners. Optional on upload items; required on rich text and link items.

ExampleWelcome
type
string Required
Valid values[ "document" ]
Exampledocument
meta
object Required
name
string Required

The file name, including its extension. The extension must match the item type you declared — a .pdf sent as a video is rejected.

Examplecourse.zip
uploadId
string (uuid) Required

A UUID you generate for this upload. It is echoed back in signedPutUrls so you can tell which URL belongs to which item, and must be unique within the content.

Example4f1c2b7e-9a3d-4c8e-b2f1-6d0a7c5e3b91
canDownload
boolean

Whether learners may download the original file

Defaulttrue
Exampletrue
pages
integer Required

The document's page count, used to estimate its duration.

This field is under review. It is currently required, but the page count cannot be known until after the file has been uploaded. Document items are therefore not yet usable end to end, and this requirement is expected to be relaxed before release.

Minimum1
Example12
object
object
rank
integer Required

The item's position within the content, lowest first. Required, and every item in a content record must have a different rank.

Minimum0
Example0
summary
string

A short label for the item, shown to learners. Optional on upload items; required on rich text and link items.

ExampleWelcome
type
string Required
Valid values[ "video" ]
Examplevideo
meta
object Required
name
string Required

The file name, including its extension. The extension must match the item type you declared — a .pdf sent as a video is rejected.

Examplecourse.zip
uploadId
string (uuid) Required

A UUID you generate for this upload. It is echoed back in signedPutUrls so you can tell which URL belongs to which item, and must be unique within the content.

Example4f1c2b7e-9a3d-4c8e-b2f1-6d0a7c5e3b91
canDownload
boolean

Whether learners may download the original file

Defaulttrue
Exampletrue
primaryLanguage
string

The spoken language of the video

Exampleen-gb
object
object
rank
integer Required

The item's position within the content, lowest first. Required, and every item in a content record must have a different rank.

Minimum0
Example0
summary
string

A short label for the item, shown to learners. Optional on upload items; required on rich text and link items.

ExampleWelcome
type
string Required
Valid values[ "audio" ]
Exampleaudio
meta
object Required
name
string Required

The file name, including its extension. The extension must match the item type you declared — a .pdf sent as a video is rejected.

Examplecourse.zip
uploadId
string (uuid) Required

A UUID you generate for this upload. It is echoed back in signedPutUrls so you can tell which URL belongs to which item, and must be unique within the content.

Example4f1c2b7e-9a3d-4c8e-b2f1-6d0a7c5e3b91
canDownload
boolean

Whether learners may download the original file

Defaulttrue
Exampletrue
durationMs
integer Required

The audio duration in milliseconds.

This field is under review. It is currently required, but the duration cannot be known until after the file has been uploaded. Audio items are therefore not yet usable end to end, and this requirement is expected to be relaxed before release.

Minimum0
Example185000
object
object
rank
integer Required

The item's position within the content, lowest first. Required, and every item in a content record must have a different rank.

Minimum0
Example0
summary
string

A short label for the item, shown to learners. Optional on upload items; required on rich text and link items.

ExampleWelcome
type
string Required
Valid values[ "image" ]
Exampleimage
meta
object Required
name
string Required

The file name, including its extension. The extension must match the item type you declared — a .pdf sent as a video is rejected.

Examplecourse.zip
uploadId
string (uuid) Required

A UUID you generate for this upload. It is echoed back in signedPutUrls so you can tell which URL belongs to which item, and must be unique within the content.

Example4f1c2b7e-9a3d-4c8e-b2f1-6d0a7c5e3b91
canDownload
boolean

Whether learners may download the original file

Defaulttrue
Exampletrue
altText
string

Alternative text, used by screen readers

ExampleA diagram of the onboarding journey
caption
string

A caption shown beneath the image

Max length1000
ExampleThe onboarding journey at a glance
ctaUrl
string (uri)

A link to open when the image is selected

Examplehttps://example.com/onboarding
openInNewTab
boolean

Whether ctaUrl opens in a new tab

Exampletrue
object
object
rank
integer Required

The item's position within the content, lowest first. Required, and every item in a content record must have a different rank.

Minimum0
Example0
summary
string

A short label for the item, shown to learners. Optional on upload items; required on rich text and link items.

ExampleWelcome
type
string Required
Valid values[ "rich_text" ]
Examplerich_text
meta
object
body
string

The rich text body as HTML

Max length100000
Example<p>Welcome to the team.</p>
object
object
rank
integer Required

The item's position within the content, lowest first. Required, and every item in a content record must have a different rank.

Minimum0
Example0
summary
string

A short label for the item, shown to learners. Optional on upload items; required on rich text and link items.

ExampleWelcome
type
string Required
Valid values[ "url" ]
Exampleurl
meta
object Required
url
string Required

Either an external link or a reference to other content on the platform. External links must be publicly reachable — those resolving to internal or private addresses are rejected.

Examplehttps://example.com/handbook
AnyOf
Responses
202

Accepted — a bulk create job was created (or an existing job was matched by idempotency key). Poll pollUrl for progress and per-item results.

accepted

Job accepted

The batch was accepted. Poll pollUrl for progress and per-entry results.

{
  "jobId": "6863f9a2c1d2e3f4a5b6c7d8",
  "status": "pending",
  "pollUrl": "/rest/v2/contents/bulk/6863f9a2c1d2e3f4a5b6c7d8"
}
object

Returned when a bulk content job has been accepted for processing.

jobId
string

The id of the job processing the batch

Example6863f9a2c1d2e3f4a5b6c7d8
status
string

The processing status of a bulk job

Valid values[ "pending", "processing", "completed", "failed" ]
Exampleprocessing
pollUrl
string

The path to poll for progress and per-item results

Example/rest/v2/contents/bulk/6863f9a2c1d2e3f4a5b6c7d8
207

Multi-Status — some entries failed validation, so no job was created. The envelope lists the entries that passed and the ones that were rejected, so the batch can be corrected and resubmitted.

partiallyRejected

Some entries rejected, no job created

Entry 2 failed validation, so nothing was submitted. Correct it and resubmit the whole batch.

{
  "success": {
    "count": "2",
    "entities": [
      {
        "reference": "contents[0]"
      },
      {
        "reference": "contents[1]"
      }
    ]
  },
  "failure": {
    "count": "1",
    "entities": [
      {
        "reference": "contents[2]",
        "message": "title is required"
      }
    ]
  }
}
Expand All
object

A multi-status envelope returned when some entries in the batch failed validation. No job is created — correct the failed entries and resubmit the whole batch.

success
object

The entries that passed validation

count
number

The number of entries that passed validation

Example2.0
entities
Array of object
object
reference
string

The entry's position in the submitted array

Examplecontents[0]
failure
object

The entries that failed validation

count
number

The number of entries that failed validation

Example1.0
entities
Array of object
object
reference
string

The entry's position in the submitted array

Examplecontents[2]
message
string

The reason the entry was rejected

ExamplelanguageCode is required
401

Unauthorized

object

Unauthorized

status
number
Example401.0
error
string
ExampleUnauthorized
message
string
403

Forbidden

object

Forbidden

status
number
Example403.0
error
string
ExampleForbidden
message
string #deprecatedtemplate# #additional-property-template#
OneOf
string
string
object
object
415

Unsupported Media Type — Content-Type must be application/json

Expand All
object
id
string
ExampleUNIQUEREFERENCE111000
timestamp
string
Example2020-03-09T22:18:26.625Z
eventType
string
Valid values[ "user_joined", "user_updated", "user_suspended" ]
message
object (UnprocessableEntityError)

The request could not be processed due to a validation error

status
number
Example422.0
error
string
ExampleUnprocessable Entity
message
string
ExampleThe startDate must be in a valid ISO 8601 format
422

Unprocessable Content — the submission was rejected before any job was created. This happens when the batch array is missing or empty, contains more than 100 entries, or no entry in it passed validation; and when the Idempotency-Key header is absent.

A batch in which only some entries fail validation returns 207 instead, so that you can see which ones to correct.

object

The request could not be processed due to a validation error

status
number
Example422.0
error
string
ExampleUnprocessable Entity
message
string
ExampleThe startDate must be in a valid ISO 8601 format
default

An unexpected error has occurred

When any default error occurs it may be a system failure and persistent errors may require support.

Expand All
object
id
string
ExampleUNIQUEREFERENCE111000
timestamp
string
Example2020-03-09T22:18:26.625Z
eventType
string
Valid values[ "user_joined", "user_updated", "user_suspended" ]
message
object (InternalServerError)

The server is unable to process the request

status
number
Example500.0
error
string
ExampleInternal Server Error