API Reference
Contentrain Studio exposes a REST API under /api/. All endpoints use JSON for request and response bodies. The API is organized around Studio's resource hierarchy: workspaces, projects, and their sub-resources.
API Surfaces & Stability
Studio's HTTP surface splits into two distinct contracts. Read this before integrating against any endpoint.
Public, versioned APIs live under /api/{forms,media,cdn,conversation,mcp}/v1/.... They are key-gated (API key or Bearer token, never session cookies), explicitly versioned with a /v1/ segment, and form the stable external contract intended for third-party integrations. Breaking changes ship under a new version segment.
| Surface | Base Path | Auth |
|---|---|---|
| Forms | /api/forms/v1/ | Public / project-scoped |
| Media | /api/media/v1/ | API key |
| CDN | /api/cdn/v1/ | API key |
| Conversation API | /api/conversation/v1/ | crn_conv_ Bearer key (EE-only) |
| MCP Cloud | /api/mcp/v1/ | crn_mcp_ Bearer key |
Internal SPA routes are everything else -- /api/workspaces/..., /api/auth/..., and the projects, content, branches, chat, and webhooks management endpoints. These power the Studio dashboard itself. They use cookie/session authentication, are not a versioned public contract, and are subject to change without notice. The pages below document them for self-hosters and contributors, not as a stability guarantee.
WARNING
Build external integrations against the versioned /v1/ surfaces only. The internal SPA routes may change shape between releases.
Base URL
{NUXT_PUBLIC_SITE_URL}/apiFor local development: http://localhost:3000/api
Authentication
Most endpoints require a valid session. Authentication is cookie-based using AES-256 encrypted httpOnly cookies -- there are no Bearer tokens for the Studio UI API.
Session Lifecycle
- Client calls
POST /api/auth/loginto get an OAuth redirect URL - User completes OAuth flow (GitHub or Google)
- Client calls
POST /api/auth/verifywith the authorization code - Server sets an encrypted session cookie
- All subsequent requests include the cookie automatically
- The auth middleware auto-refreshes tokens 5 minutes before expiry
Public Endpoints
These endpoints do not require authentication:
| Endpoint | Purpose |
|---|---|
POST /api/auth/login | Get OAuth redirect URL |
POST /api/auth/verify | Exchange code/token for session |
POST /api/auth/magic-link | Send magic link email |
GET /api/health | Health check |
POST /api/webhooks/github | GitHub webhook receiver |
POST /api/billing/webhook | Stripe webhook receiver |
GET /api/cdn/v1/:projectId/* | CDN content delivery (API key auth) |
GET /api/forms/v1/:projectId/:modelId/config | Form schema (public) |
POST /api/forms/v1/:projectId/:modelId/submit | Form submission (public) |
POST /api/conversation/v1/:projectId/message | Conversation API (API key auth) |
GET /api/conversation/v1/:projectId/history | Conversation history (API key auth) |
Request Format
Headers
Content-Type: application/json
Cookie: <session-cookie>URL Parameters
Path parameters use Nuxt file-based routing convention:
/api/workspaces/:workspaceId/projects/:projectId/content/:modelIdQuery Parameters
List endpoints support pagination:
| Parameter | Type | Default | Description |
|---|---|---|---|
page | number | 1 | Page number |
limit | number | 20 | Items per page |
Response Format
Success Response
{
"workspace": {
"id": "uuid",
"name": "My Workspace",
"slug": "my-workspace"
}
}List endpoints return arrays:
[
{ "id": "uuid", "name": "Project 1" },
{ "id": "uuid", "name": "Project 2" }
]Error Response
{
"statusCode": 403,
"message": "You do not have permission to perform this action"
}Error Codes
| Status Code | Meaning |
|---|---|
400 | Bad Request -- missing or invalid parameters |
401 | Unauthorized -- no valid session |
402 | Payment Required -- billing locked (trial expired, subscription canceled) |
403 | Forbidden -- insufficient permissions or feature not available on plan |
404 | Not Found -- resource does not exist |
409 | Conflict -- duplicate resource (e.g., duplicate project for same repo) |
429 | Too Many Requests -- rate limit exceeded |
500 | Internal Server Error |
Rate Limiting
Rate limits are applied per-IP for public endpoints and per-session for authenticated endpoints:
| Endpoint Group | Limit | Window |
|---|---|---|
| Auth (login/verify) | 10 requests | 1 minute |
| Form submission | 10 requests per model | 1 minute |
| Form config | 30 requests | 1 minute |
| General API | Varies | Per-endpoint |
INFO
In production with Redis, rate limiting is distributed across instances. Without Redis, rate limiting is in-memory and per-instance only.
Server Middleware
Every authenticated API request passes through these middleware layers in order:
- Auth middleware (
01.auth.ts) -- validates session, auto-refreshes tokens - Accept invite middleware (
02.accept-invite.ts) -- processes pending workspace invitations - Billing middleware (
03.billing.ts) -- resolves workspace billing state, blocks locked workspaces - Audit middleware (
04.audit.ts) -- records audit log entries for write operations
API Sections
| Section | Base Path | Description |
|---|---|---|
| Authentication | /api/auth/ | Login, verify, magic link, logout, session |
| Workspaces | /api/workspaces/ | Workspace CRUD, members, AI keys |
| Projects | .../projects/ | Project CRUD, members, configuration |
| Content | .../content/ | Content save, status updates, brain sync |
| Chat | .../chat | SSE chat endpoint with agent tools |
| Branches | .../branches/ | Branch list, diff, merge, reject |
| Media | .../media/ | Media upload, list, update, delete |
| Forms | /api/forms/v1/ | Public form config and submission |
| CDN | .../cdn/ | CDN settings, builds, keys, delivery |
| Webhooks | .../webhooks/ | Webhook CRUD, test, deliveries |
| Conversation API | /api/conversation/v1/ | Public conversation endpoints |
Related Pages
- Architecture -- how the API fits into the system
- Roles & Permissions -- who can access what
- Environment Variables -- API configuration