Manage projects with the API
Use the Studio API to create, read, change and delete a Studio project from a script. You need it when you set up a project without the editor, or when you need a project UID for the composition routes.
The example is the Blog project, in the AWS NA region. You create it, read it, change it and then delete it.
Prerequisites
- A stack that already has a compositions content type. The API never creates one. The example uses the
compositionscontent type in the stack with the API keyblt1234567890. - Write access to that stack. To create a project, you need it for the stack you connect. To change or delete one, you need it for the stack the project is connected to now.
- Your organization UID. Send it in the
organization_uidheader on every call. The example's isblt2222222222222222. - A credential. Send an
authtokensession token or anauthorization: BearerOAuth access token. The curl commands on this page read an OAuth access token fromCS_ACCESS_TOKEN. See Headers every call needs. - The base URL for your region. The example uses AWS NA,
https://composable-studio-api.contentstack.com/v1. Every path starts with/v1, and a path without it answers404. For the other regions, see Base URL for each region.
What this is and what you get
A project ties one stack, one compositions content type, an environment, a language and a Canvas URL together. The API keeps projects in its own database. Your stack never holds a project record.
The API has five project routes. They change only the project record and never write to your stack.
| Method | Path | What it does |
|---|---|---|
GET | /v1/projects | Lists the projects you can see in your organization. |
GET | /v1/projects/{uid} | Returns one project. |
POST | /v1/projects | Creates a project. |
PUT | /v1/projects/{uid} | Changes a project. A top-level field you leave out keeps its value, and settings is replaced whole. |
DELETE | /v1/projects/{uid} | Deletes a project. Its compositions stay in your stack. |
For every field and parameter, see Project routes.
You get a project UID, such as 0123456789abcdef01234567 for Blog. It's a 24 character hexadecimal string, not a blt UID. Composition routes take it in the path and find your stack, content type and default language through it. For what each setting does, see What a project holds.
A project has no branch. Studio works on the main branch of the stack.
Faster ways to do this
- The Studio editor. Click New Project on the projects page. The dialog asks for Name, Description and Select Stack, and it creates the compositions content type in your stack first. In Settings, the General tab edits Name and Description. The Configuration tab edits Environment, Language, Canvas URL and Enable Freeform Feature. See Create a project.
- The skill
provision-studio-project. It creates the compositions content type, an environment, a delivery token and a preview token, and it turns on Live Preview. It then creates the project and sets the environment, language and Freeform. Before it creates a project, it lists yours and asks whether to reuse one. It has no step that deletes a project. See provision-studio-project.
The CLI can only set or show the active project, with csdx studio:project:set and csdx studio:project:get. It can't create, change or delete a project. See CLI commands.
Create a project
To create a project, send POST /v1/projects. The request for the Blog project is below. Save it as create-project-body.json.
{
"name": "Blog",
"connectedStackApiKey": "blt1234567890",
"contentTypeUid": "compositions",
"canvasUrl": "/canvas",
"settings": {
"configuration": {
"environment": "blt1111111111111111",
"locale": "en-us"
}
}
}
name, connectedStackApiKey and contentTypeUid are required. description and canvasUrl are optional. These rows come from the full table of fields under Project routes.
| Field | Required on create | What it holds |
|---|---|---|
name | Yes | The project name. Up to 256 characters. |
connectedStackApiKey | Yes | The API key of the stack the project uses. |
contentTypeUid | Yes | The content type in that stack that holds compositions. |
settings | No | { "configuration": { "environment": "…", "locale": "…" } }. The locale is the one composition calls use when you don't pass one. |
In settings.configuration, environment holds the environment's UID, not its name. For production, that's blt1111111111111111. locale holds the language code, en-us. Set it to your stack's master language. Studio opens and saves every Template and Section in the master language, and the API writes in the project's locale. If you leave locale empty, the API sends no language to Contentstack. See Fetch content in a locale.
The API doesn't check that the content type, the environment or the language exists in your stack. A wrong value saves without an error.
Send the request.
curl -X POST "https://composable-studio-api.contentstack.com/v1/projects" \
-H "authorization: Bearer $CS_ACCESS_TOKEN" \
-H "organization_uid: blt2222222222222222" \
-H "Content-Type: application/json" \
-d @create-project-body.json
The API answers 201 with a notice and the saved project. The answer below leaves out createdAt and updatedAt, which the API sets.
{
"notice": "Project created successfully",
"project": {
"name": "Blog",
"description": "",
"canvasUrl": "/canvas",
"connectedStackApiKey": "blt1234567890",
"contentTypeUid": "compositions",
"organizationUid": "blt2222222222222222",
"settings": {
"configuration": {
"environment": "blt1111111111111111",
"locale": "en-us"
}
},
"createdBy": "blt3333333333333333",
"updatedBy": "blt3333333333333333",
"deletedAt": false,
"_id": "0123456789abcdef01234567",
"uid": "0123456789abcdef01234567"
}
}
Keep the uid. Every other project route takes it in the path. _id has the same value, and only the create answer includes it.
You don't send organizationUid, createdBy or uid. The API sets them, and it drops any of them you send without an error.
Project names don't have to be unique. One stack can hold several live projects, each with a different content type.
List and read projects
To find a project's UID, or to see which projects you can reach, send GET /v1/projects.
curl "https://composable-studio-api.contentstack.com/v1/projects" \
-H "authorization: Bearer $CS_ACCESS_TOKEN" \
-H "organization_uid: blt2222222222222222"
The API answers 200 with { "projects": [ ... ] }. Blog is one of the items. The answer has no count, no page fields and no default limit. The list holds two groups of projects:
- Live projects in your organization whose stack you can access.
- Live projects you created. A project you created stays in your list after you lose access to its stack.
The list never includes deleted projects or projects from another organization. If you can see none, the API answers 200 with { "projects": [] }, not 404.
To read one project, send GET /v1/projects/0123456789abcdef01234567.
curl "https://composable-studio-api.contentstack.com/v1/projects/0123456789abcdef01234567" \
-H "authorization: Bearer $CS_ACCESS_TOKEN" \
-H "organization_uid: blt2222222222222222"
The API answers 200 with { "project": { ... } } and no notice. The project has the same fields as the create answer, except _id.
Fetch finds a project only when it's live and in your organization. If you can't read a project, the API answers 404 with error code 1, not 422. So the call doesn't confirm that the project exists.
Change a project
To change a project, send PUT to its path with the fields you want to change. The route takes the same six fields as create, and every one is optional. A top-level field you leave out keeps its stored value.
settings works differently. The API replaces it whole, and doesn't merge it. Send the full configuration and any isFreeformEnabled every time.
The example turns on Enable Freeform Feature for Blog. Save this body as change-project-body.json. It repeats configuration, because the API replaces settings whole.
{
"settings": {
"isFreeformEnabled": true,
"configuration": {
"environment": "blt1111111111111111",
"locale": "en-us"
}
}
}
The API keeps every key you send in settings, such as isFreeformEnabled, and checks none of them. isFreeformEnabled set to true turns on Enable Freeform Feature in Studio.
curl -X PUT "https://composable-studio-api.contentstack.com/v1/projects/0123456789abcdef01234567" \
-H "authorization: Bearer $CS_ACCESS_TOKEN" \
-H "organization_uid: blt2222222222222222" \
-H "Content-Type: application/json" \
-d @change-project-body.json
The API answers 200 with the notice Project updated successfully and the saved project, without _id. Every change sets updatedAt and updatedBy, even when the body is empty.
If you send only isFreeformEnabled, the saved settings loses configuration, so the project loses its environment and its locale.
A few more rules apply to a change:
- A
PUTcan't changeuid,organizationUid,createdByordeletedAt. The API drops them. - A
canvasUrlset to an empty string clears it.
You can point a project at another stack or content type with connectedStackApiKey and contentTypeUid. The editor has no field for this. The API checks your write access against the stack the project is connected to now, before it applies the change. It doesn't check your access to the new stack, or that the new stack or content type exists.
Warning: After you point a project at a stack you can't write to, you can't change or delete the project again. Each call checks the stack the project is connected to.
Changing connectedStackApiKey or contentTypeUid moves no compositions. They stay as entries in the old stack and content type. The project's composition routes then read and write the new ones.
Delete a project
To delete a project, send DELETE to its path, without a Content-Type header. A DELETE with Content-Type: application/json and no body answers 400 before the route runs.
curl -X DELETE "https://composable-studio-api.contentstack.com/v1/projects/0123456789abcdef01234567" \
-H "authorization: Bearer $CS_ACCESS_TOKEN" \
-H "organization_uid: blt2222222222222222"
The API answers 200 with { "notice": "Project deleted successfully" }.
Delete is a soft delete. The API sets deletedAt to the time of the call and deletedBy to your user UID, blt3333333333333333 in the example. The project then drops out of list, fetch, change and delete. Each answers 404 with error code 1. No route restores a deleted project.
Delete doesn't check, count or remove the project's compositions or its content type. They stay in your stack. The editor's Delete Project works differently. It also deletes the compositions content type from the stack.
After you delete a project, you can create another with the same stack and content type.
If it doesn't work
422with error code21andStack not found. Your token lacks write access to the stack you named. On a change or delete, that's the stack the project is connected to now. To change or delete a project you pointed at a stack you can't write to, get write access to that stack.404with error code1andProject not found. The UID is wrong, the project is deleted, ororganization_uidis another organization's.errorsis{ "uid": ["is not valid."] }. On a fetch, it also means you can't access the project.422with error code2on a create, or3on a change. Another live project already uses that stack and content type.errorsis{ "contentTypeUid": ["is not unique."] }. Use a different content type, or delete the other project first.400with amessagelist. A field is missing, the wrong type or too long. The list holds the first problem for each field, such asname must be a string.nametakes up to 256 characters,descriptionup to 1024 andcanvasUrlup to 100.500withInternal server erroron a create. An emptynameorcontentTypeUidpasses validation and then fails. Send a value for both.400on aDELETE. You sentContent-Type: application/jsonwith no body. Send theDELETEwithout aContent-Typeheader.408. The call ran past 60 seconds. The body is{ "message": "Request Timeout", "statusCode": 408 }.- The project saved, but Studio doesn't use your environment or language. The API doesn't check that they exist. Check that
environmentholds the environment's UID, not its name. - The environment and language are gone after a change. The API replaced
settingswhole. Send the fullconfigurationwith every change. - A project is missing from the list. The list holds live projects in your organization whose stack you can access, and the ones you created. Check the
organization_uidheader and your access to the stack.
Where to go next:
- Create a composition in the project: Create a section and a template with the API.
- List the components the project has synced: List the components a project has synced.
- Look up every route and field: API endpoints. Look up every error code: API errors and validation.