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. Each entry takes the same body as POST /contents.
The endpoint responds immediately with 202 Accepted and a jobId; poll GET /contents/bulk/{jobId} for progress and per-entry results. Each successful result carries the new record's id and its presigned upload URLs, so one poll gives you everything you need to start uploading.
The batch is validated before any job is created, so a malformed request never half-runs. If every entry is invalid you get 422; if only some are, 207. In both cases no job is created — correct the entries and resubmit the whole batch. Failures that only surface once the job is running are reported per entry in results[] and do not stop the rest of the batch.
Every submission must carry an Idempotency-Key header. Replaying the same key returns the existing job rather than starting a second one, which is what makes retrying after a timeout safe. It deduplicates submissions, not content — two different keys create two sets of records.
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 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
- Staging:
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
- Staging:
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.
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.
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"
}
}
]
}
]
}The content records to create.
The content records to create, at most 100 per submission
authorRef and, when present, collaborationId are validated in your organisation before anything is created.
The content language, for example en-gb.
Your organisation's reference for the acting user. The user becomes the recorded actor, and the author unless a collaboration owns the content. The user must be active. A new, suspended, expired or deleted user is rejected.
The collaboration that owns the content. The authorRef user must be a member of it, or the request is rejected with 422.
Publish automatically when the content becomes ready: every item has completed processing and the content has a thumbnail. Send thumbnail to get a thumbnail upload URL in the same response; without a thumbnail the content stays created. The flag is stored so the publish happens as soon as the record is ready.
Skills to associate with the content. Each name must be an existing skill in your organisation, or the request is rejected with 422. Only accepted together with publishWhenReady: true. Stored in the content tags alongside the topics.
Topics to associate with the content. Free names; a topic is not checked against your organisation's tags. Only accepted together with publishWhenReady: true. Stored in the content tags alongside the skills. A name cannot appear in both lists.
The declared category. A default is inferred when it is omitted. The value is case insensitive, but send it in lower case.
How the content is completed. Defaults to auto. auto, confirm and external apply to any content; on_elearning_completion requires an e-learning item. The quiz, assessment and interactive types require item types this API cannot create yet, so they are rejected with a 409.
A custom duration in milliseconds.
Create the content as endorsed by your organisation. Defaults to false.
The CPD category to record this content against. Only accepted together with isOfficial: true (400 otherwise). The category must exist in your organisation (422 otherwise).
Asks for a thumbnail upload URL. The content thumbnail is uploaded like an item file: give the upload a UUID here and PUT the image bytes (JPEG, PNG, GIF or WebP) to the signedPutUrls entry that echoes it. The uploadId is not stored; it only pairs this request with its response entry, so it must differ from every item uploadId in the same request (400 otherwise). A content has one thumbnail, and a later upload replaces it. Processing is asynchronous: the thumbnail counts for readiness once the image has been resized and stored.
A UUID you generate for this upload.
The content items. At most one upload item (elearning, video or image) plus one non-upload item (rich_text or url) per request. Each rank must be unique.
The display position of the item.
A short description of the item.
The rich text body. May contain HTML.
A public HTTP(S) address. The link preview is generated asynchronously.
The package file name, for example course.zip.
A client-generated UUID for the upload. The response echoes it in signedPutUrls.
The package format. Normally detected during processing — supply it only when known.
The file kind. The file extension in meta.name must match it.
The file name, for example intro.mp4 or cover.png.
A client-generated UUID for the upload. The response echoes it in signedPutUrls.
Whether learners can download the file.
Accepted — a bulk create job was created (or an existing job was matched by idempotency key). Poll pollUrl for progress and per-item results.
Job accepted
The batch was accepted. Poll pollUrl for progress and per-entry results.
{
"jobId": "6863f9a2c1d2e3f4a5b6c7d8",
"status": "pending",
"pollUrl": "/rest/v2/contents/bulk/6863f9a2c1d2e3f4a5b6c7d8"
}Returned when a bulk content job has been accepted for processing.
The id of the job processing the batch
The processing status of a bulk job
The path to poll for progress and per-item results
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.
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"
}
]
}
}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.
The entries that passed validation
The number of entries that passed validation
The entries that passed, by position in your request
The entry's position in the submitted array
The entries that failed validation
The number of entries that failed validation
The entries that were rejected, with the reason for each
The entry's position in the submitted array
The reason the entry was rejected
Unauthorized
Unauthorized
Forbidden
Forbidden
Unsupported Media Type — Content-Type must be application/json
The request could not be processed due to a validation error
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.
The request could not be processed due to a validation error
An unexpected error has occurred
When any default error occurs it may be a system failure and persistent errors may require support.
The server is unable to process the request