REST Management API
Base: /api/v1/projects/{projectSlug}/.... Bearer-authed with a management key or a session JWT.
Resources
| Path | Methods | Purpose |
|---|---|---|
/content-types | GET, POST | List + create content types |
/content-types/{apiName} | GET, PUT, DELETE | Read / update / delete a type |
/content-types/{apiName}/delete-check | GET | Check whether a type can be safely deleted |
/content-types/{apiName}/fields | GET, POST | List + add fields |
/content-types/{apiName}/fields/{fieldApiName} | PUT, DELETE | Update / delete a field |
/entries | GET, POST | List + create entries |
/entries/{id} | GET, PUT, DELETE | Read / update / soft-delete |
/entries/{id}/publish | POST | Publish a locale |
/entries/{id}/unpublish | POST | Unpublish a locale |
/entries/{id}/duplicate | POST | Clone (with options) |
/entries/{id}/copy-locale | POST | Seed a translation from another locale |
/entries/{id}/versions | GET | List version snapshots |
/entries/{id}/versions/{versionNum} | GET | Read one version snapshot |
/entries/{id}/versions/{versionNum}/restore | POST | Restore a specific version |
/entries/{id}/restore | POST | Restore a version (creates a new version) |
/entries/{id}/references | GET | "Where used" — entries referencing this one |
/entries/{id}/workflow | GET, POST | Current state + transition |
/entries/{id}/preview | POST | Generate a signed preview URL |
/entries/bulk | POST | Up to 100 entries: publish / unpublish / delete / move / workflowTransition / assign / duplicate |
/tree/{siteSlug} | GET | Tree for one site |
/tree/global | GET | Global tree |
/tree/nodes | POST | Create a node |
/tree/nodes/{id} | PUT, DELETE | Update / delete a node |
/tree/nodes/{id}/move | POST | Reparent + reorder |
/sites | GET, POST | List + create |
/sites/{slug} | GET, PUT, DELETE | Read / update / delete |
/media | GET | List assets |
/media/{id} | GET, PUT, DELETE | Read / update / delete |
/media/{id}/locales/{locale} | PUT | Upsert the per-locale overlay (altText, title, description, overrideStorageKey) |
/media/upload | POST | Multipart upload |
/media/folders | GET, POST | List + create folders |
/media/folders/{id} | PUT, DELETE | Update / delete a folder |
/redirects | GET, POST | List + create |
/redirects/{id} | PUT, DELETE | Update / delete |
/redirects/import | POST | CSV import |
/redirects/export | GET | CSV export |
/environments | GET, POST | List + create |
/environments/{slug} | PUT, DELETE | Update / delete |
/environments/{slug}/promote | POST | Promote (full or cherry-pick) |
/environments/select | POST | Set the active environment |
/workflows | GET, POST | List + create |
/workflows/{slug} | PUT, DELETE | Update / delete |
/translations | GET | Translation dashboard |
/translations/stats | GET | Translation coverage stats |
/translations/{entryId} | GET | Per-entry translation status across locales |
/translations/{entryId}/{locale} | PUT | Update status / assignee |
/translations/{entryId}/{locale}/mark-stale | POST | Mark a locale's translation stale |
/views | GET, POST | List + create saved views |
/views/{id} | PUT, DELETE | Update / delete (creator only) |
/api-keys | GET, POST | List + create |
/api-keys/{id} | DELETE | Revoke |
/webhooks | GET, POST | List + create |
/webhooks/{id} | PUT, DELETE | Update / delete |
/webhooks/{id}/test | POST | Fire a test payload |
/roles | GET, POST | List + create |
/roles/{id} | PUT, DELETE | Update / delete a role |
/roles/{id}/permissions | GET, POST | List grants + add a grant |
/roles/{id}/permissions/{grantId} | DELETE | Remove a grant |
/users | GET | List members |
/audit-logs | GET | Not yet implemented — currently a stub returning an empty list ({ data: [] }), no params or pagination |
/search | GET | Full-text + facet search |
/search/reindex | POST | Trigger search reindex (no-op on the default Postgres provider; real reindex when SEARCH_PROVIDER=meilisearch) |
/calendar | GET | Scheduled + completed events |
/calendar/reschedule | POST | Move a scheduled job |
/reports/publishing-activity | GET | Time-series + table |
/reports/content-health | GET | Health summary + per-entry issues |
/reports/schema-usage | GET | Per-content-type stats |
/reports/user-activity | GET | Per-user activity |
/reports/agent-activity | GET | Per-API-key activity |
/governance/analyze | GET, POST | Read last analysis (GET) / run governance analyzer (POST) |
/governance/issues | GET | Cached issues |
/governance/issues/{id}/resolve | POST | Mark acknowledged |
/custom-reports | GET, POST | List + create |
/custom-reports/{id} | PUT, DELETE | Update / delete |
/custom-field-types | GET, POST | List + register |
/custom-field-types/{apiName} | PUT, DELETE | Update / delete |
/ip-allowlist | GET, POST, PUT | List rules + add + toggle settings |
/ip-allowlist/{id} | PUT, DELETE | Edit / delete a rule |
Conventions
- All inputs validated via Zod.
422withdetailson shape mismatch. - Optimistic concurrency on entry updates: pass
versionin the body. - Audit logs record every mutation with before / after JSON snapshots.
- Standard response envelope:
{ data }or{ error, message, details? }.
Platform endpoints
For super-admins only — see Multi-tenant:
/api/v1/platform/tenants— list / create tenants/api/v1/platform/tenants/{slug}— read / update / deactivate tenants
Examples
Create an entry
curl -X POST -H "Authorization: Bearer $MK" -H "Content-Type: application/json" \
https://cms.example.com/api/v1/projects/demo/entries \
-d '{
"contentTypeApiName": "blogPost",
"siteId": "site_main",
"locale": "en-US",
"treeParentId": "node_blog",
"slug": "hello-world",
"fields": { "title": "Hello World" }
}'
Bulk publish
curl -X POST -H "Authorization: Bearer $MK" -H "Content-Type: application/json" \
https://cms.example.com/api/v1/projects/demo/entries/bulk \
-d '{
"action": "publish",
"entryIds": ["ckl_a", "ckl_b", "ckl_c"],
"params": { "locale": "en-US" }
}'
Set localized alt text (and title / description) on a media asset
The locale overlay is an upsert — the row is created on first write, so you don't pre-create it.
{locale} is a path segment (e.g. en-US) and must be a registered tenant locale (unknown → 404).
Send only the fields you want to change; omitted fields are left untouched, and an explicit null clears
one. Requires the update permission.
curl -X PUT -H "Authorization: Bearer $MK" -H "Content-Type: application/json" \
https://cms.example.com/api/v1/projects/demo/media/asset_123/locales/en-US \
-d '{ "altText": "Red bicycle leaning against a brick wall" }'
Returns { data: <MediaAssetLocale> }. Limits: altText ≤ 2000, title ≤ 500, description ≤ 5000 chars.
An empty body returns 422 no_update_fields. This is the write side of the alt text that the delivery
GraphQL MediaAsset.altText / REST ?locale= overlay reads back — see Media.