Studio provisioning API reference

View as Markdown
Last updated September 14, 2026

Provisioning a Studio project touches five hosts, and each one is region-specific. One wrong host provisions a content type, tokens and a Studio project in the wrong data center. Nothing errors, because the calls succeed against whichever region that host belongs to. This page is the host map across regions, the non-prod host pattern, and the /v1/projects request shape that registers the project.

Overview

Two API surfaces do the work.

  • Content Management API (CMA) creates the stack, the compositions content type, the environment, the delivery token and the preview token, and enables Live Preview on the stack.
  • Studio API creates the Studio project through /v1/projects. It binds the project to the stack (connectedStackApiKey) and to the compositions content type (contentTypeUid), then configures the environment, the locale and Freeform.

Three more hosts appear at runtime rather than at provisioning time: the Content Delivery API (CDA), the Live Preview preview channel, and the images content delivery network (CDN). They belong in the same map because the SDK derives one host from another, so a mismatch between them fails after provisioning succeeds.

Every host below belongs to a single region. A project created in one region is not reachable from another region's host.

Prerequisites

Before you send any call on this page, have all four of the following:

  • The region your stack lives in. Establish this first, because every host below depends on it. See Check Studio access.
  • A resolved Contentstack Management API credential, either an Open Authorization (OAuth) access token or a session token. See Studio API authentication.
  • The organization uid that owns the Studio project. The Studio interface shows it under organization settings.
  • The stack api_key for the target stack. Read it from Settings > Stack.

Production host map

The table below lists every service Studio provisioning and rendering touch, for the seven production regions.

RegionCMAStudio APICDA (host)Live Preview (live_preview.host)
AWS NA (us)api.contentstack.iocomposable-studio-api.contentstack.com(omit, default)rest-preview.contentstack.com
AWS EU (eu)eu-api.contentstack.comeu-composable-studio-api.contentstack.comeu-cdn.contentstack.comeu-rest-preview.contentstack.com
AWS AU (au)au-api.contentstack.comau-composable-studio-api.contentstack.comau-cdn.contentstack.comau-rest-preview.contentstack.com
Azure NA (azure-na)azure-na-api.contentstack.comazure-na-composable-studio-api.contentstack.comazure-na-cdn.contentstack.comazure-na-rest-preview.contentstack.com
Azure EU (azure-eu)azure-eu-api.contentstack.comazure-eu-composable-studio-api.contentstack.comazure-eu-cdn.contentstack.comazure-eu-rest-preview.contentstack.com
GCP NA (gcp-na)gcp-na-api.contentstack.comgcp-na-composable-studio-api.contentstack.comgcp-na-cdn.contentstack.comgcp-na-rest-preview.contentstack.com
GCP EU (gcp-eu)gcp-eu-api.contentstack.comgcp-eu-composable-studio-api.contentstack.comgcp-eu-cdn.contentstack.comgcp-eu-rest-preview.contentstack.com

AWS NA is the only region whose CMA host ends in .contentstack.io. Every other region uses <region>-api.contentstack.com. For the canonical, always-current list of Contentstack regional endpoints, see API endpoints by region.

Match the pair. Mixing an NA Studio API host with an EU CMA host returns 401 and 404 responses with no clear error. Pick a region and use both region-matched hosts.

Non-production hosts

Internal QA, staging and development stacks live on csnonprod.com. The Delivery SDK has no region shortcut for them, so you set every host explicitly. The pattern is <env>-<service>.csnonprod.com, where <env> is the non-production environment name, for example dev10, dev11, dev15, stag or eu-dev. Treat the environment name as user-supplied: there are many, and the list changes.

ServiceNon-production host patternUsed by
CDA (Delivery)<env>-cdn.csnonprod.comContentstack.stack({ host })
Live Preview<env>-rest-preview.csnonprod.comlive_preview.host
CMA<env>-api.csnonprod.comManagement scripts, provisioning
Studio API<env>-composable-studio-api.csnonprod.comStudio project creation, project listing
Editor (browser)<env>-app.csnonprod.comThe Studio interface. You open this URL
Images CDN<env>-images.csnonprod.comAsset URLs in entry responses

Without an explicit host:, non-production work lands in production. The Studio React SDK derives its Studio API host from the Delivery stack you pass it. Omit host: on Contentstack.stack({...}) and it defaults to the AWS NA production CDA, so the Studio SDK points at the production Studio API too. Set the CDA host explicitly:

const stack = Contentstack.stack({
  apiKey,
  deliveryToken,
  environment,
  host: `${csEnv}-cdn.csnonprod.com`,
  live_preview: {
    enable: true,
    preview_token,
    host: `${csEnv}-rest-preview.csnonprod.com`,
  },
});

Authentication headers

Both surfaces expect a credential and a scope identifier together, but they scope differently.

SurfaceCredential headerScope header
CMAauthorization: Bearer <access_token>, or authtoken: <session_token>api_key: <stack api_key>
Studio APIauthorization: Bearer <access_token>, or authtoken: <session_token>organization_uid: <org uid>

Studio projects are organization-scoped, so /v1/projects takes organization_uid and not a stack api_key. Sending a stack api_key instead returns 422 error_code 21, "Stack not found".

Try OAuth first. authorization: Bearer <oauth-access-token> paired with organization_uid returns 200 and the project list on AWS NA production. Escalate to a session authtoken only after OAuth returns 401 error_code 105 ("authtoken is not valid") or 422 error_code 21 ("Stack not found"). A session authtoken is a full user-session credential that covers every organization, stack and permission the user holds, so scope it to the single call and discard it. Do not write it to .env.

Send the OAuth token in the right header. OAuth goes in authorization: Bearer, and authtoken: carries session tokens only. Sending an OAuth token as authtoken: returns 401 error_code 105. For the full credential ladder, see Studio API authentication.

Register a project: POST /v1/projects

POST creates the project. A separate PUT configures it, because the environment, the locale and Freeform attach after the project exists.

curl -s -X POST "https://<studio-api-host>/v1/projects" \
  -H "authorization: Bearer <ACCESS_TOKEN>" \
  -H "organization_uid: <ORG_UID>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "<PROJECT_NAME>",
    "description": "<DESCRIPTION>",
    "connectedStackApiKey": "<STACK_API_KEY>",
    "contentTypeUid": "<COMPOSITIONS_CT_UID>",
    "canvasUrl": "/canvas"
  }'
FieldTypeRequiredNotes
namestringYesDisplay name in the Studio project list
descriptionstringNoFree text
connectedStackApiKeystringYesThe stack api_key, not a token
contentTypeUidstringYesThe compositions content type created through the CMA
canvasUrlstringYesThe route on your app that mounts <StudioCanvas />, for example /canvas

A successful create returns 201. An empty or missing connectedStackApiKey produces a project the canvas cannot resolve compositions against, so verify the response carries the value you sent.

Configure a project: PUT /v1/projects/{projectUid}

curl -s -X PUT "https://<studio-api-host>/v1/projects/<PROJECT_UID>" \
  -H "authorization: Bearer <ACCESS_TOKEN>" \
  -H "organization_uid: <ORG_UID>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "<PROJECT_NAME>",
    "canvasUrl": "/canvas",
    "connectedStackApiKey": "<STACK_API_KEY>",
    "contentTypeUid": "<COMPOSITIONS_CT_UID>",
    "settings": {
      "configuration": { "environment": "<ENVIRONMENT_UID>", "locale": "en-us" },
      "isFreeformEnabled": true
    }
  }'

settings.configuration.environment takes the environment uid, not the name. The Studio API accepts a name without erroring, and the environment binding then misses, so compositions never resolve. Look the uid up with GET /v3/environments against the CMA before you send the PUT.

Send the full body on every PUT. To re-bind an existing project to a new stack, send the current connectedStackApiKey. A project holding a stale value serves the previous stack's compositions, and the current stack then looks empty in the canvas.

List projects: GET /v1/projects

Run this before creating anything. Creating blind against a stack that already has a project produces a duplicate, nothing errors, and half your tooling then points at each project.

curl -s "https://<studio-api-host>/v1/projects" \
  -H "authorization: Bearer <ACCESS_TOKEN>" \
  -H "organization_uid: <ORG_UID>" | jq -r \
  '.projects[] | "\(.uid)  \(.name)  stack=\(.connectedStackApiKey)  ct=\(.contentTypeUid)"'

A 401 or 422 response is an authentication failure, not evidence that no project exists. Resolve the credential first, then re-check.

The two-call CT create

The compositions content type references itself through linked_sections, and the CMA validates reference targets when it creates a content type. A content type cannot reference itself before it exists, so a single POST carrying linked_sections fails with error_code 115: symbols.reference_to: content type does not exist.

Send the two calls below in order:

  1. POST /v3/content_types with the schema minus linked_sections.
  2. PUT /v3/content_types/<uid> with the full schema, including linked_sections.

linked_sections is a reference field with multiple: true and reference_to set to the content type's own uid. For the complete field list and the cardinality each field requires, see the provision-studio-project skill.

Troubleshooting

SymptomCauseResolution
Content type creation returns 404The CMA host belongs to a different region than the stackUse the region-matched CMA host from the production host map above
401 and 404 responses with no field diagnosticThe CMA host and the Studio API host belong to different regionsPick one region and use both of its hosts
422 error_code 21, "Stack not found", on /v1/projectsThe request carries a stack api_key where organization_uid belongsSend organization_uid. Studio projects are organization-scoped
401 error_code 105, "authtoken is not valid"The request carries an OAuth token in the authtoken headerSend it as authorization: Bearer <access_token>
403 error_code 316, "You don't have the permission to do this operation"The credential is valid but aims at another organization, or the user lacks stack-create rightsSwitch the active organization, or request stack-create rights. Do not re-authenticate
error_code 115, symbols.reference_to: content type does not existThe initial POST carries linked_sectionsCreate the content type in two calls, as the section above describes
error_code 248, "could not find environment"PUT /v3/environments/<uid> puts the uid in the pathThis CMA endpoint keys on the environment name: PUT /v3/environments/preview
The canvas loads, but compositions never resolvesettings.configuration.environment holds the environment nameLook the uid up with GET /v3/environments and send the uid
Non-production work appears in productionContentstack.stack({...}) omits host:Set host to <env>-cdn.csnonprod.com explicitly
The canvas iframe hangs on "Loading composition"The stack has Live Preview turned off, so the preview channel fails its cross-origin preflightPUT /v3/stacks with stack.settings.live_preview.enable set to true

Next steps