Skip to main content

API endpoints

Look up any Studio API endpoint, the headers it needs and the parameters it takes. Use it when you call the API from a script and need the exact route or field. To create a composition through the API from start to finish, see What the API is for. For what a failed call returns, see API errors and validation.

The example on this page is a project whose UID is 0123456789abcdef01234567, and its Blog post template, whose entry UID is blt4444444444444444. The template's URL pattern is /blog/{{entry.slug}}.

Base URL for each region​

Every route on this page starts with /v1.

RegionBase URL
AWS NAhttps://composable-studio-api.contentstack.com/v1
AWS EUhttps://eu-composable-studio-api.contentstack.com/v1
AWS AUhttps://au-composable-studio-api.contentstack.com/v1
Azure NAhttps://azure-na-composable-studio-api.contentstack.com/v1
Azure EUhttps://azure-eu-composable-studio-api.contentstack.com/v1
GCP NAhttps://gcp-na-composable-studio-api.contentstack.com/v1
GCP EUhttps://gcp-eu-composable-studio-api.contentstack.com/v1

Use the region your stack is in. Each region keeps its own projects, so you can't reach a project in one region from another region's URL.

Headers every call needs​

HeaderValueRequired
authtokenYour Contentstack session token.One of authtoken or authorization
authorizationBearer <access_token>, an OAuth access token. The Bearer prefix is required.One of authtoken or authorization
organization_uidThe UID of the organization that owns the project.Yes, on every call
Content-Typeapplication/jsonOn POST and PUT only

The API acts as you. On composition and registered component routes, it passes your token on to Contentstack, so you can do what your token can do.

The API passes on only an authtoken session token or an authorization: Bearer OAuth access token. It ignores an authorization value without the Bearer prefix, such as a bare management token.

If you send both authtoken and authorization, the API uses the one that matches the identity Contentstack found for the request.

Access your token needs​

MethodWhat your token needs
GETRead access to the project's connected stack
POST, PUT, DELETEWrite access to the project's connected stack

On composition and registered component routes, a token without that access gets 422 with error code 21, not 403. On project routes, a project you can't read answers 404 with error code 1. The project list never fails for lack of access. It leaves out the projects whose stack you can't read. See API errors and validation.

How the API handles a request​

You sendWhat happens
A top-level body field the route doesn't knowThe API drops it without an error, so it ignores a misspelled field name. Keys inside settings stay, so a misspelled key there is saved.
A trailing slashThe API ignores it. /v1/projects and /v1/projects/ are the same route.
A DELETE with Content-Type: application/json and no bodyThe API answers 400 before the route runs. Send a DELETE without Content-Type.
A call that runs longer than 60 secondsThe API stops waiting and answers 408. The write can still finish, so list before you retry.
A call that succeedsPOST answers 201. Every other method answers 200.

Project routes​

MethodPathWhat it does
GET/v1/projectsLists the projects in the organization whose stack you can read, plus the projects you created.
GET/v1/projects/{uid}Returns one project. If you can't read it, the API answers 404 instead of telling you it exists.
POST/v1/projectsCreates a project. You need write access to the stack you connect.
PUT/v1/projects/{uid}Changes the top-level fields you send and keeps the rest. settings is replaced whole. The API checks your access against the stack the project is connected to now, even when you send a new one.
DELETE/v1/projects/{uid}Removes the project from Studio. Its compositions stay in the stack as entries. There's no way to restore it through the API.

The fields you can send when you create or change a project:

FieldRequired on createWhat it holds
nameYesThe project name. Up to 256 characters.
connectedStackApiKeyYesThe API key of the stack the project uses.
contentTypeUidYesThe content type in that stack that holds compositions.
descriptionNoUp to 1024 characters. Defaults to empty.
canvasUrlNoThe path of your section preview route, such as /studio. Up to 100 characters. Studio opens a Section's canvas at the environment's Base URL plus this path. With no Base URL for the environment and language, Studio uses the Playground canvas. With a Base URL and an empty path, the canvas shows "Canvas URL is not configured".
settingsNo{ "configuration": { "environment": "…", "locale": "…" } }, plus isFreeformEnabled when Freeform is on. environment is an environment UID and locale is a language code. The API keeps any key you send and replaces settings whole. Composition writes always use the locale, and reads use it when you don't pass one.

The API sets every other field, such as uid, organizationUid or createdBy. If you send one, nothing changes.

Composition routes​

Every composition path starts with /v1/projects/{projectUid}/compositions. The project decides which stack, content type and default locale the call uses, so none of them go in the path.

MethodPath after /compositionsWhat it does
POSTnoneCreates a template or a section. place_composition_as in the body decides which.
POST/templatesCreates a template. Leave out place_composition_as and linked_schemas.
POST/sectionsCreates a section. Leave out place_composition_as, url and connected_content_type.
GETnoneLists templates and sections.
GET/templatesLists templates only.
GET/sectionsLists sections only.
GET/{uid}Returns one composition.
GET/{uid}/referencesLists the entries that use this composition, in every language.
PUT/{uid}Changes the fields you send and keeps the rest.
DELETE/{uid}Deletes the composition. Answers 409 if another composition uses it, unless you pass force=true.

For the Blog post template, GET /v1/projects/0123456789abcdef01234567/compositions/blt4444444444444444/references lists what uses it.

Fields you can send for a composition​

These fields apply when you create a composition and when you PUT one. On a PUT, every field is optional.

FieldRequired on createWhat it holds
titleYesUp to 256 characters. Can't be only spaces.
place_composition_asYes, on the plain create routepage for a template, section for a section.
uiYesThe layout tree as a JSON object, not compressed. The API checks it and compresses it. Its root node has the type page, for sections too.
urlNoA template's URL pattern, such as /blog/{{entry.slug}}. See URL variables.
connected_content_typeNoThe content type a connected template uses. Empty for a freeform template and for a section.
composable_uidNoThe composition's stable ID. If you leave it out, the API sets it to the entry UID. If you send it, it can't be blank, and no other composition in the content type can have it, in any language. You can't change it later.
schema_versionNoA string. Defaults to 1.0.0.
data_sourcesNoAn array. Defaults to [].
static_valueNoAn object of fixed values used by the layout.
url_metadataNoAn object.
linked_schemasNoAn array of the schemas a section can match. The /templates route drops it, but the plain create route stores what you send, even on a template. See Linked schema matching rules.
ui_previewNoA preview image asset.

The API works out which sections a composition places from ui, so you never send that list.

A create or PUT answers with the saved composition. In it, ui is a compressed string that starts with zlib:, and data_sources is a JSON string. A PUT that sends no ui returns the stored value, which can be plain JSON text if something else wrote the entry. If the layout has problems that don't block the save, the answer also has a warnings array. See Layout rules the API checks on every write.

Parameters for listing compositions​

The three list routes take these query parameters. The /templates and /sections routes don't take place_composition_as.

ParameterDefaultWhat it does
place_composition_asnonepage or section.
composable_uidnoneReturns the composition with exactly this ID.
titlenoneReturns compositions whose title contains this text, ignoring case.
limit50How many to return, from 1 to 100. A higher number answers 400.
skip0How many to skip.
include_countfalsetrue adds the total number of matches as meta.count.
include_uifalsetrue adds ui and data_sources to each item. Without it, each item leaves both out.
decompressionfalseWith include_ui=true, returns each ui as a JSON object. An item whose ui can't be read stays compressed.
localeThe project's localeThe language to read.

The answer has compositions and meta. meta holds limit, skip, returned, include_ui, and count when you asked for it.

Parameters for getting or deleting one composition​

RouteParameterDefaultWhat it does
GET /{uid}decompressionfalsetrue returns ui as a JSON object and data_sources as an array. meta.compressed says which form you got.
GET /{uid}localeThe project's localeThe language to read.
DELETE /{uid}forcefalsetrue deletes the composition even when another composition uses it.

Registered components route​

MethodPathWhat it does
GET/v1/projects/{projectUid}/registered-componentsLists the components synced to the project with csdx studio:component:sync, with their props. The route is read-only.

This list isn't the palette. If you registered a component in your app's code but never synced it, it doesn't appear here. See CLI commands and Register a component.

The route takes no query parameters. It returns every synced component at once, as registered_components, with meta.count. A project with nothing synced answers 200 with an empty list.

Component fieldWhat it holds
uidThe component's UID.
organization_uidThe organization that owns it.
projectIdThe project UID.
componentNameThe component's name in code, such as HeroBanner. A node's type is the string your app passes to registerComponent, which this list doesn't return.
displayNameThe label in the palette. It's often empty, so fall back to componentName.
description, aiDescriptionDescriptions for people and for AI tools. Either can be empty.
versionThe version recorded at sync.
importPathWhere the component's source file is, such as src/components/HeroBanner.tsx.
createdAt, updatedAtWhen you first synced it, and when it last changed.
propsThe component's props. Each has type and name, and can have displayName, description, placeholder and defaultValue.

Where to go next​

Report a problem with this page