Reusable content: create, configure, compose, publish and delete.
List contents
GET/contents
Every content in the org, drafts included — filterable and paginated.
Query parameters
hasUnpublishedChangesenum
Filter independently by pending document changes.
truefalse
isPublishedenum
Filter by whether a published document exists.
truefalse
qstring
Substring match on title or route segment (case-insensitive).
tagstring
Only contents carrying this tag (exact name).
Responses
200List contents.
400Validation failed or the request body is malformed.
401Missing, invalid or revoked API key.
429Rate limit exceeded (240 reads/min, 60 writes/min per key).
500Unexpected server error.
curl https://api.cursare.com/v1/contents \
--header 'Authorization: Bearer cr_live_…'
{
"data": {
"contents": [
{
"certificateTheme": "classic",
"createdAt": "2026-01-31T12:00:00.000Z",
"description": "string",
"hasUnpublishedChanges": true,
"id": "string",
"isPublished": true,
"ownerId": "string",
"publishedAt": "2026-01-31T12:00:00.000Z",
"routeSegment": "string",
"tags": [
"string"
],
"teamId": "string",
"theme": "string",
"title": "string",
"updatedAt": "2026-01-31T12:00:00.000Z"
}
],
"page": 0,
"pageSize": 0,
"total": 0
}
}
Create a draft content
POST/contents
Creates one unpublished content with an organization-unique route segment and no offer. Every document may interleave learning blocks and references. Optional tags are applied after creation; a validation failure removes the draft. Create an offer separately when the content should be enrollable or sellable.
Request body
tagsstring[]
Initial tag list (names must exist in the tag registry).
Responses
201Create a draft content.
400Validation failed or the request body is malformed.
401Missing, invalid or revoked API key.
403The key's organization does not own this resource.
404The resource does not exist (or belongs to another org).
429Rate limit exceeded (240 reads/min, 60 writes/min per key).
500Unexpected server error.
curl https://api.cursare.com/v1/contents \
--request POST \
--header 'Authorization: Bearer cr_live_…' \
--header 'Content-Type: application/json' \
--data '{
"slug": "string",
"tags": [
"string"
],
"teamId": "string",
"title": "string"
}'
{
"data": {
"certificateTheme": "classic",
"createdAt": "2026-01-31T12:00:00.000Z",
"description": "string",
"hasUnpublishedChanges": true,
"id": "string",
"isPublished": true,
"ownerId": "string",
"publishedAt": "2026-01-31T12:00:00.000Z",
"routeSegment": "string",
"tags": [
"string"
],
"teamId": "string",
"theme": "string",
"title": "string",
"updatedAt": "2026-01-31T12:00:00.000Z"
}
}
Get a content
GET/contents/{id}
Responses
200Get a content.
401Missing, invalid or revoked API key.
403The key's organization does not own this resource.
404The resource does not exist (or belongs to another org).
429Rate limit exceeded (240 reads/min, 60 writes/min per key).
500Unexpected server error.
curl https://api.cursare.com/v1/contents/{id} \
--header 'Authorization: Bearer cr_live_…'
{
"data": {
"certificateTheme": "classic",
"createdAt": "2026-01-31T12:00:00.000Z",
"description": "string",
"hasUnpublishedChanges": true,
"id": "string",
"isPublished": true,
"ownerId": "string",
"publishedAt": "2026-01-31T12:00:00.000Z",
"routeSegment": "string",
"tags": [
"string"
],
"teamId": "string",
"theme": "string",
"title": "string",
"updatedAt": "2026-01-31T12:00:00.000Z"
}
}
Update content settings
PATCH/contents/{id}
Updates editorial settings only: discovery metadata, tags, content and certificate themes, slug, and ownership. Commercial, entry, capacity, and delivery terms belong to offer resources. Discovery metadata, tags, themes, route segment and ownership apply to every content. Title and description live inside the document header and are edited in the composer and read back via GET /contents/{id}.
Request body
certificateThemeenum
classicmoderneditorialminimal
seoDescriptionstring | null
themeenum | string | any | null
Responses
200Update content settings.
400Validation failed or the request body is malformed.
401Missing, invalid or revoked API key.
403The key's organization does not own this resource.
404The resource does not exist (or belongs to another org).
429Rate limit exceeded (240 reads/min, 60 writes/min per key).
500Unexpected server error.
curl https://api.cursare.com/v1/contents/{id} \
--request PATCH \
--header 'Authorization: Bearer cr_live_…' \
--header 'Content-Type: application/json' \
--data '{
"certificateTheme": "classic",
"featured": true,
"noindex": true,
"owner": {
"teamId": "string"
},
"seoDescription": "string",
"seoTitle": "string",
"slug": "string",
"tags": [
"string"
],
"theme": "ember"
}'
{
"data": {
"certificateTheme": "classic",
"createdAt": "2026-01-31T12:00:00.000Z",
"description": "string",
"hasUnpublishedChanges": true,
"id": "string",
"isPublished": true,
"ownerId": "string",
"publishedAt": "2026-01-31T12:00:00.000Z",
"routeSegment": "string",
"tags": [
"string"
],
"teamId": "string",
"theme": "string",
"title": "string",
"updatedAt": "2026-01-31T12:00:00.000Z"
}
}
Delete a content
DELETE/contents/{id}
Deletion is refused if the content is referenced by another or purchased.
Responses
200Delete a content.
401Missing, invalid or revoked API key.
403The key's organization does not own this resource.
404The resource does not exist (or belongs to another org).
429Rate limit exceeded (240 reads/min, 60 writes/min per key).
500Unexpected server error.
curl https://api.cursare.com/v1/contents/{id} \
--request DELETE \
--header 'Authorization: Bearer cr_live_…'
{
"data": {
"deleted": true,
"id": "string"
}
}
Publish the current draft
POST/contents/{id}/publish
Atomically validates the draft, derives its ordered published manifest, and writes both the learner document and manifest. Every reference must target published content in the same organization; self-references and cycles are refused.
Responses
200Publish the current draft.
401Missing, invalid or revoked API key.
403The key's organization does not own this resource.
404The resource does not exist (or belongs to another org).
429Rate limit exceeded (240 reads/min, 60 writes/min per key).
500Unexpected server error.
curl https://api.cursare.com/v1/contents/{id}/publish \
--request POST \
--header 'Authorization: Bearer cr_live_…'
{
"data": {
"certificateTheme": "classic",
"createdAt": "2026-01-31T12:00:00.000Z",
"description": "string",
"hasUnpublishedChanges": true,
"id": "string",
"isPublished": true,
"ownerId": "string",
"publishedAt": "2026-01-31T12:00:00.000Z",
"routeSegment": "string",
"tags": [
"string"
],
"teamId": "string",
"theme": "string",
"title": "string",
"updatedAt": "2026-01-31T12:00:00.000Z"
}
}
Duplicate a content
POST/contents/{id}/duplicate
Creates a fresh unpublished copy with a collision-safe route segment. It copies the document and editorial settings, but never offers, learners, cohorts, reviews, purchases, sales history, or the published snapshot.
Path parameters
idstring
The content id to copy.
Responses
201Duplicate a content.
401Missing, invalid or revoked API key.
403The key's organization does not own this resource.
404The resource does not exist (or belongs to another org).
429Rate limit exceeded (240 reads/min, 60 writes/min per key).
500Unexpected server error.
curl https://api.cursare.com/v1/contents/{id}/duplicate \
--request POST \
--header 'Authorization: Bearer cr_live_…'
{
"data": {
"certificateTheme": "classic",
"createdAt": "2026-01-31T12:00:00.000Z",
"description": "string",
"hasUnpublishedChanges": true,
"id": "string",
"isPublished": true,
"ownerId": "string",
"publishedAt": "2026-01-31T12:00:00.000Z",
"routeSegment": "string",
"tags": [
"string"
],
"teamId": "string",
"theme": "string",
"title": "string",
"updatedAt": "2026-01-31T12:00:00.000Z"
}
}
Get the document authoring guide
GET/document-schema
The shared JSON schema, stable learner identifiers, composition guidance, limits and complete valid documents. MCP clients must call get_document_schema before replace_content_document.
Responses
200Get the document authoring guide.
400Validation failed or the request body is malformed.
401Missing, invalid or revoked API key.
429Rate limit exceeded (240 reads/min, 60 writes/min per key).
500Unexpected server error.
curl https://api.cursare.com/v1/document-schema \
--header 'Authorization: Bearer cr_live_…'
{
"data": {
"completeDocument": {
"body": [
"string"
],
"header": {
"description": "string",
"image": {
"alt": "string",
"src": "string",
"assetId": "string",
"attribution": {
"creatorName": "string",
"creatorUrl": "string",
"sourceUrl": "string"
},
"focalPoint": {
"x": 0,
"y": 0
},
"height": 0,
"mimeType": "string",
"width": 0
},
"title": "string",
"layout": [
null
]
},
"version": 0
},
"compositionGuidelines": [
"string"
],
"dialect": "string",
"documentRules": {
"canonicalization": [
"string"
],
"ids": "string",
"limits": {},
"structure": "string"
},
"documentSchema": {},
"minimalDocument": {
"body": [
"string"
],
"header": {
"description": "string",
"image": {
"alt": "string",
"src": "string",
"assetId": "string",
"attribution": {
"creatorName": "string",
"creatorUrl": "string",
"sourceUrl": "string"
},
"focalPoint": {
"x": 0,
"y": 0
},
"height": 0,
"mimeType": "string",
"width": 0
},
"title": "string",
"layout": [
null
]
},
"version": 0
},
"overview": "string",
"version": 0
}
}
Get the content document
GET/contents/{id}/document
The editable Cursare JSON draft plus the published document learners currently read. The draft includes grading keys such as quiz correctOptionIds and stable learner state ids for polls, quizzes, headings and references, so treat this payload as org-staff only: never proxy it to learners or embed it in learner-facing pages.
Responses
200Get the content document.
401Missing, invalid or revoked API key.
403The key's organization does not own this resource.
404The resource does not exist (or belongs to another org).
429Rate limit exceeded (240 reads/min, 60 writes/min per key).
500Unexpected server error.
curl https://api.cursare.com/v1/contents/{id}/document \
--header 'Authorization: Bearer cr_live_…'
{
"data": {
"draftDocument": {
"body": [
"string"
],
"header": {
"description": "string",
"image": {
"alt": "string",
"src": "string",
"assetId": "string",
"attribution": {
"creatorName": "string",
"creatorUrl": "string",
"sourceUrl": "string"
},
"focalPoint": {
"x": 0,
"y": 0
},
"height": 0,
"mimeType": "string",
"width": 0
},
"title": "string",
"layout": [
null
]
},
"version": 0
},
"publishedAt": "2026-01-31T12:00:00.000Z",
"publishedDocument": {
"body": [
"string"
],
"header": {
"description": "string",
"image": {
"alt": "string",
"src": "string",
"assetId": "string",
"attribution": {
"creatorName": "string",
"creatorUrl": "string",
"sourceUrl": "string"
},
"focalPoint": {
"x": 0,
"y": 0
},
"height": 0,
"mimeType": "string",
"width": 0
},
"title": "string",
"layout": [
null
]
},
"version": 0
}
}
}
Replace the draft document
PUT/contents/{id}/document
Replaces the ENTIRE draft with a version 2 JSON document (max 2 MB); learners see nothing until publish. MCP clients must call get_document_schema for the shared schema and composition guidance. The header contains cover, title and description; body contains ordered typed blocks and recursive references. PRESERVE STABLE IDS when editing: headings, references, polls and quiz ids key learner answers, progress and study position — changing them can orphan that state. The returned draft includes answer keys and must not be proxied to learners.
Request body
documentobjectrequired
The full replacement Cursare JSON draft.
Responses
200Replace the draft document.
400Validation failed or the request body is malformed.
401Missing, invalid or revoked API key.
403The key's organization does not own this resource.
404The resource does not exist (or belongs to another org).
429Rate limit exceeded (240 reads/min, 60 writes/min per key).
500Unexpected server error.
curl https://api.cursare.com/v1/contents/{id}/document \
--request PUT \
--header 'Authorization: Bearer cr_live_…' \
--header 'Content-Type: application/json' \
--data '{
"document": {
"body": [
"string"
],
"header": {
"description": "string",
"image": {
"alt": "string",
"src": "string",
"assetId": "string",
"attribution": {
"creatorName": "string",
"creatorUrl": "string",
"sourceUrl": "string"
},
"focalPoint": {
"x": 0,
"y": 0
},
"height": 0,
"mimeType": "string",
"width": 0
},
"title": "string",
"layout": [
null
]
},
"version": 0
}
}'
{
"data": {
"draftDocument": {
"body": [
"string"
],
"header": {
"description": "string",
"image": {
"alt": "string",
"src": "string",
"assetId": "string",
"attribution": {
"creatorName": "string",
"creatorUrl": "string",
"sourceUrl": "string"
},
"focalPoint": {
"x": 0,
"y": 0
},
"height": 0,
"mimeType": "string",
"width": 0
},
"title": "string",
"layout": [
null
]
},
"version": 0
},
"publishedAt": "2026-01-31T12:00:00.000Z",
"publishedDocument": {
"body": [
"string"
],
"header": {
"description": "string",
"image": {
"alt": "string",
"src": "string",
"assetId": "string",
"attribution": {
"creatorName": "string",
"creatorUrl": "string",
"sourceUrl": "string"
},
"focalPoint": {
"x": 0,
"y": 0
},
"height": 0,
"mimeType": "string",
"width": 0
},
"title": "string",
"layout": [
null
]
},
"version": 0
}
}
}