Workspaces API
Internal Application API
These are internal SPA routes (cookie/session authenticated, used by the Studio app), not a versioned public contract — they may change between releases. For external integrations, use the Public API.
Workspaces are the top-level billing entity in Studio. Each user has a primary workspace created at signup, and can create or be invited to secondary workspaces.
List Workspaces
List all workspaces the current user belongs to.
GET /api/workspacesResponse
[
{
"id": "uuid",
"name": "My Workspace",
"slug": "my-workspace",
"type": "primary",
"plan": "starter",
"role": "owner",
"github_installation_id": 12345
}
]Create Workspace
Create a new secondary workspace.
POST /api/workspacesRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Workspace display name |
slug | string | Yes | URL slug (lowercase, alphanumeric, hyphens) |
Response
{
"id": "uuid",
"name": "Team Workspace",
"slug": "team-workspace",
"type": "secondary"
}Get Workspace
Get workspace details including billing information.
GET /api/workspaces/:workspaceIdResponse
{
"id": "uuid",
"name": "My Workspace",
"slug": "my-workspace",
"type": "primary",
"plan": "starter",
"github_installation_id": 12345,
"owner_id": "uuid"
}Auth
Requires workspace membership.
Update Workspace
Update workspace name or settings.
PATCH /api/workspaces/:workspaceIdRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | New workspace name |
Auth
Requires workspace owner or admin role.
Delete Workspace
Delete a workspace and all its projects.
DELETE /api/workspaces/:workspaceIdAuth
Requires workspace owner role. Primary workspaces cannot be deleted (delete the user account instead).
Transfer Ownership
Transfer workspace ownership to another member.
POST /api/workspaces/:workspaceId/transfer-ownerRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
newOwnerId | string | Yes | User ID of the new owner |
Auth
Requires current workspace owner role.
Members
List Members
GET /api/workspaces/:workspaceId/membersResponse
[
{
"id": "uuid",
"user_id": "uuid",
"role": "owner",
"invited_email": "[email protected]",
"accepted_at": "2026-01-01T00:00:00Z",
"display_name": "Jane Doe",
"avatar_url": "https://..."
}
]Invite Member
POST /api/workspaces/:workspaceId/members| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Email address to invite |
role | 'admin' | 'member' | Yes | Workspace role |
Auth
Requires workspace owner or admin role.
Update Member Role
PATCH /api/workspaces/:workspaceId/members/:memberId| Field | Type | Required | Description |
|---|---|---|---|
role | 'admin' | 'member' | Yes | New role |
Remove Member
DELETE /api/workspaces/:workspaceId/members/:memberIdResend Invitation
POST /api/workspaces/:workspaceId/members/:memberId/resendAI Keys (BYOA)
Manage Bring Your Own API key credentials per workspace.
List AI Keys
GET /api/workspaces/:workspaceId/ai-keysResponse
[
{
"id": "uuid",
"provider": "anthropic",
"key_hint": "sk-ant-...7x2q",
"created_at": "2026-01-01T00:00:00Z"
}
]Add/Update AI Key
POST /api/workspaces/:workspaceId/ai-keys| Field | Type | Required | Description |
|---|---|---|---|
provider | string | Yes | AI provider name (e.g., anthropic) |
apiKey | string | Yes | API key (encrypted at rest) |
Delete AI Key
DELETE /api/workspaces/:workspaceId/ai-keys/:keyIdEnterprise Feature
AI key management routes through the enterprise bridge. If ee/ is not loaded, these endpoints return 403.
MCP Cloud Keys
Manage MCP Cloud API keys (crn_mcp_ Bearer keys) that grant programmatic access to the remote MCP endpoint. The plaintext key is shown once at creation and never stored -- the server only keeps a SHA-256 hash plus the prefix.
List MCP Cloud Keys
GET /api/workspaces/:workspaceId/mcp-cloud-keysOptionally narrow to one project with ?projectId=.
Response
{
"keys": [
{
"id": "uuid",
"name": "Production key",
"key_prefix": "crn_mcp_ab12",
"project_id": "uuid",
"allowed_tools": ["list_models", "get_content"],
"media_enabled": false,
"rate_limit_per_minute": 60,
"monthly_call_limit": null,
"last_used_at": "2026-01-01T00:00:00Z",
"created_at": "2026-01-01T00:00:00Z",
"calls_this_month": 42
}
]
}Plaintext keys are never returned here. An empty allowed_tools array means all tools are permitted. (The row also carries created_by and revoked_at, though revoked keys are filtered out of this list.)
Auth
Requires workspace membership (owner, admin, or member).
Create MCP Cloud Key
POST /api/workspaces/:workspaceId/mcp-cloud-keysRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
projectId | string | Yes | Project the key is scoped to |
name | string | Yes | Display name |
allowedTools | string[] | No | Whitelist of MCP tool names (empty = all tools). Unknown names are rejected. |
mediaEnabled | boolean | No | Allow media tools (default false) |
rateLimitPerMinute | number | No | 1-600 requests per minute (default 60) |
monthlyCallLimit | number | null | No | Monthly call cap (null = unlimited) |
Response
{
"id": "uuid",
"key": "crn_mcp_ab12...full-plaintext",
"keyPrefix": "crn_mcp_ab12",
"name": "Production key",
"projectId": "uuid",
"allowedTools": [],
"mediaEnabled": false,
"rateLimitPerMinute": 60,
"monthlyCallLimit": null,
"createdAt": "2026-01-01T00:00:00Z"
}WARNING
The plaintext key is returned exactly once. Store it securely -- the server only keeps its hash.
Auth
Requires workspace owner or admin role. Gated by the api.mcp_cloud plan feature and the api.mcp_keys plan limit.
Error Codes
| Status | Condition |
|---|---|
400 | Missing name/projectId, unknown tool in allowedTools, rateLimitPerMinute out of range, or invalid monthlyCallLimit |
403 | Plan does not include api.mcp_cloud, or the api.mcp_keys key limit is reached |
404 | Workspace or project not found |
Revoke MCP Cloud Key
DELETE /api/workspaces/:workspaceId/mcp-cloud-keys/:keyIdSets revoked_at; the key is immediately rejected by the MCP endpoint. The row is retained for audit.
Response
{ "revoked": true }Auth
Requires workspace owner or admin role.
Connected Apps
Active OAuth grants for the remote MCP connector surface -- the client applications (e.g. Claude) a user has connected to this workspace. See the Connected Apps guide for the end-user flow.
Managed deployments only
These endpoints back the remote-MCP OAuth server, which only runs on the managed auth pair. On the self-hosted (Supabase) pair, GET returns { "enabled": false, "endpoint": null, "grants": [] } and DELETE returns 404.
List Connected Apps
GET /api/workspaces/:workspaceId/connected-appsOwners and admins see every grant in the workspace; members see only their own.
Response
{
"enabled": true,
"endpoint": "https://studio.contentrain.io/api/mcp/remote",
"grants": [
{
"grantId": "uuid",
"clientHost": "claude.ai",
"clientName": "Claude",
"logoUri": "https://...",
"projectId": "uuid",
"projectRepo": "org/my-website",
"scopes": ["content:read", "content:write", "project:metadata"],
"createdAt": "2026-01-01T00:00:00Z",
"lastUsedAt": "2026-01-02T00:00:00Z",
"callsThisMonth": 128,
"mine": true
}
]
}mine indicates whether the grant belongs to the requesting user.
Auth
Requires workspace membership (owner, admin, or member).
Revoke Connected App
DELETE /api/workspaces/:workspaceId/connected-apps/:grantIdRevokes the grant, kills the refresh-token family, and deletes live access tokens. The connected client's next refresh fails with invalid_grant and re-runs the auth flow.
Response
{ "revoked": true }Auth
Owners and admins may revoke any grant; members may revoke only their own (otherwise 403). Returns 404 on the non-managed pair or when the grant does not exist.
Usage & Overage
Get Usage
Return metered usage for the current billing period (calendar month).
GET /api/workspaces/:workspaceId/usageResponse
{
"billingPeriod": "2026-07",
"categories": [
{
"key": "ai_messages",
"limitKey": "ai.messages_per_month",
"name": "AI Messages",
"current": 1234,
"limit": 5000,
"overageEnabled": false,
"overageUnits": 0,
"overageUnitPrice": 0,
"overageAmount": 0,
"unit": "messages",
"percentage": 25
}
],
"totalOverageAmount": 0,
"projectedOverageAmount": 0
}Categories are returned in this order: ai_messages, form_submissions, cdn_bandwidth, media_storage, api_messages, mcp_calls. A limit of -1 means unlimited.
Simple Format
The CLI-friendly format keys each category by camelCase name. Each value is a { current, limit, percentage } object:
GET /api/workspaces/:workspaceId/usage?format=simple{
"aiMessages": { "current": 1234, "limit": 5000, "percentage": 25 },
"formSubmissions": { "current": 12, "limit": 1000, "percentage": 1 },
"cdnBandwidthGb": { "current": 0.5, "limit": 50, "percentage": 1 },
"mediaStorageGb": { "current": 0.2, "limit": 10, "percentage": 2 },
"apiMessages": { "current": 0, "limit": 1000, "percentage": 0 },
"mcpCalls": { "current": 8, "limit": 10000, "percentage": 0 }
}Auth
Requires workspace owner or admin role.
Get Overage Settings
Return overage preferences, plan limits, and per-category overage pricing.
GET /api/workspaces/:workspaceId/overage-settingsResponse
{
"overageSettings": { "ai_messages": true },
"categories": [
{
"limitKey": "ai.messages_per_month",
"settingsKey": "ai_messages",
"unit": "per message",
"unitPrice": 0.03,
"planLimit": 1500,
"enabled": true
}
],
"canEnableOverage": true
}canEnableOverage is true only when the workspace has a saved payment method, an active subscription (trialing / active / past_due), and a non-free plan.
Auth
Requires workspace owner or admin role.
Update Overage Settings
Toggle overage billing per category. Submitted keys are merged with existing settings.
PATCH /api/workspaces/:workspaceId/overage-settingsRequest Body
Any subset of the boolean category toggles:
| Field | Type | Description |
|---|---|---|
ai_messages | boolean | Enable overage for AI messages |
api_messages | boolean | Enable overage for API messages |
cdn_bandwidth | boolean | Enable overage for CDN bandwidth |
form_submissions | boolean | Enable overage for form submissions |
media_storage | boolean | Enable overage for media storage |
mcp_calls | boolean | Enable overage for MCP Cloud calls |
Response
{ "overageSettings": { "ai_messages": true, "cdn_bandwidth": false } }Auth
Requires workspace owner or admin role.
Error Codes
| Status | Condition |
|---|---|
400 | Unknown settings key, non-boolean value, or no fields provided |
402 | No active paid subscription (or no saved payment method) |
403 | Free plan cannot enable overages |
See the Billing guide for how overage pricing is applied.
Billing
Billing actions live under /api/billing/ (they are not scoped under /api/workspaces/ in the path) but take workspaceId in the request body. They route to the active payment provider (Polar by default, Stripe as fallback).
Create Checkout Session
Create a hosted checkout session to subscribe a workspace to a paid plan.
POST /api/billing/checkoutRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
workspaceId | string | Yes | Target workspace |
plan | 'starter' | 'pro' | Yes | Plan to subscribe to |
Response
{ "url": "https://checkout.provider.com/..." }Redirect the browser to url. A free trial is granted only if the workspace has never consumed one.
Auth
Requires workspace owner or admin role. Rate limited to 1 request per 30 seconds per workspace.
Error Codes
| Status | Condition |
|---|---|
400 | Missing workspaceId/plan, or invalid plan |
403 | Not a workspace owner/admin |
409 | Workspace already has an active subscription |
429 | Rate limit exceeded |
502 / 503 | Payment provider unavailable |
Create Portal Session
Create a customer portal session so the user can manage their subscription (payment method, cancel, plan change).
POST /api/billing/portalRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
workspaceId | string | Yes | Target workspace |
Response
{ "url": "https://billing.provider.com/..." }Auth
Requires workspace owner or admin role.
Error Codes
| Status | Condition |
|---|---|
400 | Missing workspaceId, or the workspace has no payment customer yet |
403 | Not a workspace owner/admin |
502 / 503 | Payment provider unavailable |
Related Pages
- Roles & Permissions -- workspace role definitions
- Projects API -- project management within workspaces