# REST API

> The complete HTTP surface for projects, assets, generation, and delivery.

Base URL: https://beta.studio.agentkit.best. Bodies are JSON unless stated otherwise. Use Authorization: Bearer with a securely injected API key. Cookie writes require a trusted Origin. MCP OAuth cannot manage permanent credentials or provider keys. Replace path IDs and illustrative placeholders with values read from the API.

## GET /api/connections/agent-recipients

List owned active OAuth authorization identities for explicit connector grants; no tokens

Authentication: Interactive owner session.

### Request

```
No body; see live OpenAPI for query parameters.
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## POST /api/connectors/github/authorize

Begin separate GitHub App authorization for a verified installation

Authentication: Interactive owner session.

### Request

```
{"connectionId":"","expectedRevision":1,"installationId":""}
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## GET /api/connectors/github/callback

Complete one-use GitHub authorization bound to the initiating session

Authentication: Interactive owner session.

### Request

```
No body; see live OpenAPI for query parameters.
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## GET /api/connectors/github/repositories

List repositories accessible to the user and selected GitHub installation; connectionId and page query parameters

Authentication: Interactive owner session.

### Request

```
No body; see live OpenAPI for query parameters.
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## POST /api/connectors/github/resolve

Resolve a selected repository branch or tag to an immutable commit

Authentication: Interactive owner session.

### Request

```
{"connectionId":"","repositoryId":"","ref":"main"}
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## POST /api/connectors/github/webhook

Receive signature-verified GitHub installation and authorization revocations

Authentication: Protocol-specific authentication.

### Request

```
{}
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## POST /api/projects/:id/sources/:sourceId/asset

Copy a granted image snapshot into isolated project assets without changing the document

Authentication: Owner session or explicit project connector grant.

### Request

```
{}
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## POST /api/projects/:id/connector-operations/:operationId/reconcile

Reconcile an uncertain Drive upload or GitHub PR using recorded identities; never repeats external writes

Authentication: Owner session or explicit project connector grant.

### Request

```
{"expectedRevision":1}
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## GET /api/projects/:id/connector-operations/:operationId/artifact

Download an authorized prepared PDF, PPTX or React ZIP for inspection before upload

Authentication: Owner session or explicit project connector grant.

### Request

```
No body; see live OpenAPI for query parameters.
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## POST /api/connectors/google-drive/authorize

Begin separate session-bound Google Drive authorization

Authentication: Interactive owner session.

### Request

```
{"connectionId":"","expectedRevision":1}
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## GET /api/connectors/google-drive/callback

Redeem a one-use Google callback for the initiating session

Authentication: Interactive owner session.

### Request

```
No body; see live OpenAPI for query parameters.
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## POST /api/connectors/google-drive/picker

Obtain a transient selected-account access token for Google Picker; never returns refresh credentials

Authentication: Interactive owner session.

### Request

```
{"connectionId":""}
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## POST /api/projects/:id/connector-operations/:operationId/continuation

Supply explicitly reviewed input to a paused MCP operation; creates a separately approved continuation

Authentication: Interactive owner session.

### Request

```
{"expectedRevision":1,"inputResponses":{}}
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## GET /api/projects/:id/runs

List saved run metadata without advancing

Authentication: Owner session or explicit project connector grant.

### Request

```
No body; see live OpenAPI for query parameters.
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## POST /api/projects/:id/runs

Persist a bounded run at exact document and brief versions

Authentication: Owner session or explicit project connector grant.

### Request

```
{"provider":"openai","prompt":"Refine design","bindingIds":[],"sourceSnapshotIds":[],"expectedDocumentRevision":1,"expectedBriefRevision":1,"idempotencyKey":"unique-request-key"}
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## GET /api/projects/:id/runs/:runId

Read run status, authorized proposal and provider usage

Authentication: Owner session or explicit project connector grant.

### Request

```
No body; see live OpenAPI for query parameters.
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## POST /api/projects/:id/runs/:runId/advance

Advance exactly one run step with current grants

Authentication: Owner session or explicit project connector grant.

### Request

```
{"expectedRevision":1}
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## POST /api/projects/:id/runs/:runId/cancel

Cancel future steps and preserve uncertain in-flight outcomes

Authentication: Owner session or explicit project connector grant.

### Request

```
{"expectedRevision":1}
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## GET /api/projects/:id/runs/:runId/proposal

Revalidate a completed unsaved proposal against current authority and versions

Authentication: Owner session or explicit project connector grant.

### Request

```
No body; see live OpenAPI for query parameters.
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## GET /api/projects/:id/sources

List private source metadata; agent results are limited to current source grants

Authentication: Owner session or explicit project connector grant.

### Request

```
No body; see live OpenAPI for query parameters.
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## GET /api/projects/:id/sources/:sourceId

Download an authorized immutable source as inert data

Authentication: Owner session or explicit project connector grant.

### Request

```
No body; see live OpenAPI for query parameters.
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## POST /api/projects/:id/sources/:sourceId/refresh

Import a new source snapshot without replacing existing content or brief

Authentication: Owner session or explicit project connector grant.

### Request

```
{}
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## DELETE /api/projects/:id/sources/:sourceId

Remove an owned source snapshot and invalidate dependent work

Authentication: Interactive owner session.

### Request

```
No body; see live OpenAPI for query parameters.
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## POST /api/projects/:id/connections/:bindingId/sources

Import one selected MCP resource or Drive file as an immutable source snapshot

Authentication: Owner session or explicit project connector grant.

### Request

```
{"uri":"resource://selected"}
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## GET /api/projects/:id/connector-operations

List the latest 50 operation records without private payloads

Authentication: Owner session or explicit project connector grant.

### Request

```
No body; see live OpenAPI for query parameters.
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## POST /api/projects/:id/connector-operations

Prepare a selected tool operation against exact observed versions; unknown effects require human approval

Authentication: Owner session or explicit project connector grant.

### Request

```
{"bindingId":"","action":"","arguments":{},"idempotencyKey":"unique-request-key","expectedVersions":{"connectionRevision":1,"credentialVersion":1,"policyRevision":1,"documentRevision":1,"briefRevision":0,"sourceSnapshotIds":[]}}
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## GET /api/projects/:id/connector-operations/:operationId

Inspect an operation and authorized private payload without advancing it

Authentication: Owner session or explicit project connector grant.

### Request

```
No body; see live OpenAPI for query parameters.
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## POST /api/projects/:id/connector-operations/:operationId/execute

Claim approved operation once; uncertain results are never replayed

Authentication: Owner session or explicit project connector grant.

### Request

```
{"expectedRevision":1}
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## POST /api/projects/:id/connector-operations/:operationId/decision

Approve once or deny the exact operation in an authenticated browser session

Authentication: Interactive owner session.

### Request

```
{"expectedRevision":1,"decision":"approve"}
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## POST /api/projects/:id/connector-operations/:operationId/cancel

Cancel own pending operation with revision protection

Authentication: Owner session or explicit project connector grant.

### Request

```
{"expectedRevision":1}
```

### Response

```
See live OpenAPI and the operation status returned by the server.
```

## GET /api/projects/:id/connections

List project connections

Authentication: Owner session or explicit agent discovery grants.

### Request

```
Project ID.
```

### Response

```
{ connections }; agent selections are restricted by their grants.
```

Requires CONNECTORS_ENABLED. Human sessions can inspect disconnected bindings for recovery; agents receive only authorized connected bindings.

## POST /api/projects/:id/connections

Bind a project connection

Authentication: Interactive session and matching Origin only.

### Request

```
connectionId, role and explicit selection; see OpenAPI.
```

### Response

```
201 { binding } with policyRevision.
```

Creates no agent authority. Grant access separately.

## DELETE /api/projects/:id/connections/:bindingId

Remove a project connection

Authentication: Interactive session and matching Origin only.

### Request

```
{ expectedPolicyRevision }
```

### Response

```
{ ok }; related grants revoked, snapshots removed and dependent work invalidated.
```

## POST /api/projects/:id/connections/:bindingId/grants

Grant project connector access

Authentication: Interactive session and matching Origin only.

### Request

```
recipient, expectedPolicyRevision, capabilities, selection and expiresAt; see OpenAPI.
```

### Response

```
201 { grant }.
```

Selection must be within the binding and expiry within 90 days. API-key, OAuth and WebMCP access are separate.

## DELETE /api/projects/:id/connections/:bindingId/grants/:grantId

Revoke connector access

Authentication: Interactive session and matching Origin only.

### Request

```
Project, binding and grant IDs.
```

### Response

```
{ ok }; subsequent authorization fails.
```

## GET /api/connections

List external connection metadata

Authentication: Owner session; agents require projectId and explicit discovery grant.

### Request

```
Optional projectId query; required for API, OAuth and WebMCP callers.
```

### Response

```
{ connections }; no credentials.
```

Operator must enable CONNECTORS_ENABLED. Connector workflows are experimental and require configured external accounts. Tool-assisted runs use explicit approvals and return unsaved proposals.

## GET /api/connections/:connectionId

Read connection metadata

Authentication: Owner session or explicit project discovery grant.

### Request

```
Connection ID; projectId query for agents.
```

### Response

```
{ connection } with status and revision.
```

## POST /api/connections

Create pending connection

Authentication: Interactive session and matching Origin only.

### Request

```
displayName and config; see OpenAPI schema.
```

### Response

```
201 { connection }; pending until verified.
```

Never put credentials in endpoint URLs. Native connector authorization is not enabled by creating metadata.

## POST /api/connections/:connectionId/disconnect

Disconnect and revoke connector authority

Authentication: Interactive session and matching Origin only.

### Request

```
{ expectedRevision }
```

### Response

```
{ connection }; credentials removed, grants revoked, active work invalidated.
```

## POST /api/connectors/mcp/connect

Verify anonymous or bearer MCP

Authentication: Interactive session and matching Origin only.

### Request

```
connectionId, expectedRevision, optional accessToken in request body.
```

### Response

```
Verified connection metadata and negotiated protocol; no credential.
```

Successful connection does not establish catalog or tool access. API, OAuth and WebMCP callers cannot manage setup.

## POST /api/connectors/mcp/authorize

Start outgoing MCP OAuth

Authentication: Interactive session and matching Origin only.

### Request

```
connectionId, expectedRevision, options; modern CIMD or registered client, explicit legacy DCR.
```

### Response

```
Authorization URL and new revision.
```

New authorization revokes previous grants. Callback is fixed to this installation.

## GET /api/connectors/mcp/client-metadata

Read OAuth client metadata

Authentication: Public when connectors enabled.

### Request

```
No body.
```

### Response

```
Canonical client ID and exact redirect URI; no secret.
```

## GET /api/connectors/mcp/callback

Complete outgoing MCP OAuth

Authentication: Original signed-in browser session.

### Request

```
Authorization server callback state, code, iss or error.
```

### Response

```
Verified connection metadata.
```

One-use state; owner, session, issuer, resource and revision checked. Callback cannot grant local agent authority.

## GET /api/observability/summary

Summarize account activity and measured usage

Authentication: Session or Bearer; owner default, configured operator for scope=all.

### Request

```
Query: scope=owner|all; days=1..30 (default7); projectId, actorId (all only), channel, kind, status, action.
```

### Response

```
{ scope, days, totals, usage, byAction, byActor, byProvider, coverage }
```

Unknown measurements remain null. OAuth cannot read all-account scope.

## GET /api/observability/events

Read paginated activity logs

Authentication: Session or Bearer; owner default.

### Request

```
Summary filters plus limit=1..100 (default50), cursor from previous page.
```

### Response

```
{ events, nextCursor }; safe metadata only, 30-day retention.
```

## GET /api/observability/trace/:id

Follow correlated request steps

Authentication: Session or Bearer; owner default.

### Request

```
Trace ID from X-Request-ID or event. Query: scope, days (default7; maximum30).
```

### Response

```
{ traceId, events, truncated }; 404 for unavailable traces.
```

## POST /api/observability/client-events

Record an allowlisted browser event

Authentication: Same-origin browser; owned project/correlation when supplied.

### Request

```
{ event, page?, action?, projectId?, requestId?, outcome?, errorCode? }; strict enums in OpenAPI schema.
```

### Response

```
Accepted telemetry; optional PostHog forwarding is isolated from product operations.
```

Never send arbitrary text, credentials, names, URLs or exception messages. Not exposed as an agent mutation tool.

## GET /api/health

Check service health

Authentication: Public.

### Request

```
No body.
```

### Response

```
{ "ok": true, "service": "design-studio-ai" }
```

## GET /api/schema

Read live JSON Schemas

Authentication: Public.

### Request

```
No body.
```

### Response

```
{ document: JSONSchema, operations: JSONSchema, designSystem: JSONSchema, interview: JSONSchema, scope: JSONSchema }; semantic validation still runs on writes.
```

## GET /api/openapi

Discover API operations and request schemas

Authentication: Public.

### Request

```
No body.
```

### Response

```
OpenAPI document with path/query parameters, multipart uploads, and shared component schemas.
```

## GET /api/design-systems

List your design systems

Authentication: Session or Bearer token; library owner.

### Request

```
No body.
```

### Response

```
{ systems: DesignSystem[] }; latest saved versions for this owner.
```

## POST /api/design-systems

Create a reusable design system

Authentication: Session or Bearer token; library owner.

### Request

```
Definition object matching /api/schema → designSystem.
```

### Response

```
201 { system }; initial version is 1.
```

Includes theme tokens, component variants and reusable page compositions. Private media references cannot be captured; embed media or use public HTTPS URLs.

## GET /api/design-systems/:id

Read a library version

Authentication: Session or Bearer token; library owner.

### Request

```
Optional positive integer query: version. Omit for latest.
```

### Response

```
{ system: { id, version, definition, createdAt } }
```

## GET /api/design-systems/:id/versions

List immutable library versions

Authentication: Session or Bearer token; library owner.

### Request

```
No body.
```

### Response

```
{ versions: [{ version, createdAt }] }; newest first.
```

## PUT /api/design-systems/:id

Append a library version

Authentication: Session or Bearer token; library owner.

### Request

```
{ expectedVersion, definition }; read the definition and its version first.
```

### Response

```
{ system }; stale expectedVersion returns 409.
```

Previous definitions stay immutable. Never substitute a newer version number to force stale content through a conflict.

## POST /api/design-systems/:id/apply

Apply a saved design system

Authentication: Session or Bearer token; project owner.

### Request

```
{ projectId, expectedRevision, version? }
```

### Response

```
{ project }; project revision increments.
```

Own both library and project. Optional version selects a saved library version. Applies tokens/system while preserving authored component overrides; pins the library version in the project.

## POST /api/design-systems/:id/insert

Insert a library item

Authentication: Session or Bearer token; project owner.

### Request

```
{ projectId, expectedRevision, pageId, itemId, version? }
```

### Response

```
{ project }; inserts the saved component/composition with fresh node IDs and remapped hierarchy/interactions.
```

## DELETE /api/design-systems/:id

Delete a design-system library

Authentication: Session or Bearer token; library owner.

### Request

```
No body.
```

### Response

```
{ "ok": true }
```

Deletes this owned library and its versions. Previously applied project content remains embedded.

## GET /api/fonts

Discover Google Fonts

Authentication: Session or Bearer token.

### Request

```
Optional q query, maximum 200 characters; matches family/category without case sensitivity.
```

### Response

```
{ fonts, source, message, fetchedAt? }; source is live, cache, or fallback.
```

The full catalog uses an operator Google Fonts API key. Without it, returns clearly labeled curated starter families. Choosing a Google font loads its face separately.

## GET /api/providers/:provider/models

Discover provider model IDs

Authentication: Account session or API key.

### Request

```
Provider: openai|anthropic|gemini|openrouter|fal|deepseek|leonardo|grok|custom-<slug>. Optional q query, maximum 200 characters; matches ID/name/category.
```

### Response

```
{ models, source, message, fetchedAt?, truncated? }
```

Uses the saved provider connection. Custom endpoints and unavailable connections return labeled starter suggestions; manual model IDs remain available. OAuth MCP credentials cannot call this endpoint. No raw provider key is returned.

## GET /api/catalog

Read built-in design resources

Authentication: Public.

### Request

```
No body.
```

### Response

```
{ themes, templates, blocks }
```

## GET /api/config

Read public configuration

Authentication: Public.

### Request

```
No body.
```

### Response

```
Public feature configuration, including googleClientId, allowRegistration, githubEnabled, observability eligibility/retention, and analytics availability. Never includes provider keys or server secrets.
```

## POST /api/auth/register

Create an account

Authentication: Public; matching Origin header.

### Request

```
{ "email": "you@example.com", "password": "<12–128 characters>", "name": "Your name" }
```

### Response

```
201 { user: { id, email, name } } + HttpOnly session cookie.
```

Registration must be enabled by the operator. Email is normalized; name is optional. Rate limited.

## POST /api/auth/login

Start an email/password session

Authentication: Public; matching Origin header.

### Request

```
{ "email": "you@example.com", "password": "<your password>" }
```

### Response

```
{ user: { id, email, name } } + HttpOnly session cookie.
```

## GET /api/auth/me

Read the current account

Authentication: Optional session or Bearer token.

### Request

```
No body.
```

### Response

```
{ user: { id, email, name } | null }
```

## GET /api/auth/github

Start GitHub sign-in

Authentication: Public browser navigation; configured GitHub OAuth app.

### Request

```
Navigate using the sign-in button. No request body.
```

### Response

```
Redirects to GitHub authorization with browser-bound state and S256 PKCE; configuration errors redirect to /?auth_error=….
```

## GET /api/auth/github/callback

Complete GitHub sign-in

Authentication: Valid one-use state and initiating browser cookie.

### Request

```
GitHub supplies code and state, or an authorization error.
```

### Response

```
Issues the studio session and redirects home on success. Errors redirect to /?auth_error=….
```

This is an OAuth callback, not an endpoint to call manually. Existing email/password accounts are not automatically linked by email.

## GET /api/auth/github/status

Read your GitHub connection

Authentication: Account browser session only.

### Request

```
No body.
```

### Response

```
{ enabled: boolean, connected: boolean, login: string | null }
```

## POST /api/auth/github/link

Connect GitHub to your existing account

Authentication: Account browser session; matching Origin.

### Request

```
No body.
```

### Response

```
{ url }; navigate to the returned GitHub authorization URL.
```

The callback must complete in the same signed-in session. A GitHub identity already linked to another account is rejected.

## POST /api/auth/logout

End a browser session

Authentication: Session; matching Origin for cookie authentication.

### Request

```
No body.
```

### Response

```
{ "ok": true }; clears the session cookie.
```

Logging out of a browser does not revoke API keys.

## GET /api/projects

Search and list projects

Authentication: Session or Bearer token.

### Request

```
Query: q (name/description), kind (web|slides|report|wireframe|3d|video), sort (updated|created|name).
```

### Response

```
{ projects: ProjectSummary[] }; up to 500 owned projects. Summaries exclude document.
```

## POST /api/projects

Create or clone a project

Authentication: Session or Bearer token.

### Request

```
{ "name": "Product story", "kind": "slides", "templateId": "product-deck" }
```

### Response

```
201 { project: Project }; initial revision is 1.
```

Optional description, themeId, templateId, document. Supplying an owned document creates a new project and copies owned asset bytes; there is no separate REST clone route.

## GET /api/projects/:id

Read a project and revision

Authentication: Session or Bearer token; project owner.

### Request

```
Replace :id with an actual project ID.
```

### Response

```
{ project: { id, name, description, kind, document, revision, createdAt, updatedAt, publishedUrl? } }
```

## PATCH /api/projects/:id

Update project metadata

Authentication: Session or Bearer token; project owner.

### Request

```
{ "name": "Updated name", "description": "Updated description" }
```

### Response

```
{ project: Project }; increments revision.
```

Both fields are optional. This metadata route checks the revision read by the server; use document PUT or CLI rename for an explicit client expectedRevision.

## PUT /api/projects/:id/document

Save the canonical document

Authentication: Session or Bearer token; project owner.

### Request

```
{ "document": "<complete DesignDocument object>", "expectedRevision": 1 }
```

### Response

```
{ project: Project }; revision increments atomically. A stale expectedRevision returns 409.
```

document is an object, not a string: replace the illustrative placeholder. Preserve project ID/kind. Owned asset references must belong to this project. Targeted patch operations are available through CLI/MCP, which reuse this save contract.

## POST /api/projects/:id/merge

Merge concurrent human and agent edits

Authentication: Session or Bearer token; project owner.

### Request

```
{ baseRevision, base, document }; base is the complete document originally read, document is your edited copy.
```

### Response

```
{ project: Project }; saves the reconciled document. Overlapping edits return 409 with error.code merge_conflict and error.details.paths.
```

baseRevision is the positive project revision originally read, separate from the brief revision. Preserve the exact base and project ID/kind. Never alter the base or invent its revision to force a merge; resolve overlapping changes explicitly.

## GET /api/projects/:id/changes

Observe the saved project revision

Authentication: Session or Bearer token; project owner.

### Request

```
Optional query: since, the last observed nonnegative project revision; default 0.
```

### Response

```
{ revision, unchanged: true } when since equals the saved revision; otherwise { revision, project: Project }.
```

Returns the current saved project when changed, not a history or operation log. Does not include unsaved browser edits.

## DELETE /api/projects/:id

Delete a project

Authentication: Session or Bearer token; project owner.

### Request

```
No body.
```

### Response

```
{ "ok": true }
```

Deletes the project, stored assets, and publications. This is destructive.

## GET /api/projects/:id/checks

Inspect the saved design

Authentication: Session or Bearer token; project owner.

### Request

```
No body.
```

### Response

```
{ projectId, revision, issues, counts: { warnings, information, total }, truncated, limitations }
```

Read-only deterministic preflight with node/page IDs and suggestions. Estimates bounds, text fit, opaque-hex contrast, missing/remote media, chart data, and duration limits. Does not certify accessibility or visual quality; inspect the actual preview.

## GET /api/projects/:id/brief

Read the design brief and scope

Authentication: Session or Bearer token; project owner.

### Request

```
No body.
```

### Response

```
{ brief: DesignBrief | null }
```

A brief has its own revision, separate from the document revision, plus request, status, message, questions, answers, scope, approvedAt, and updatedAt.

## PUT /api/projects/:id/brief

Save a brief, interview, answers, or scope

Authentication: Session or Bearer token; project owner.

### Request

```
{ "expectedRevision": 0, "request": "Create a six-slide introduction for our team." }
```

### Response

```
{ brief: DesignBrief }; increments the brief revision. Stale revisions return 409.
```

Revision 0 creates a brief and requires request. Supply at least one of request, interview, answers, or scope. Read interview/scope JSON Schemas at /api/schema. Answers map question IDs to text or multiple-choice arrays. Every edit invalidates prior approval. External agents can supply their own interview and scope without server BYOK.

## POST /api/projects/:id/brief/interview

Generate contextual interview questions or scope

Authentication: Session or Bearer token; project owner.

### Request

```
{ "expectedRevision": 1, "provider": "openai" }
```

### Response

```
{ brief: DesignBrief }; saves the validated provider response with revision protection.
```

Requires an existing brief and configured text-provider BYOK; charges may apply. Providers: openai, anthropic, gemini, openrouter, deepseek, custom-<slug>; model is optional. Returns up to eight contextual questions or a concrete scope. Invalid provider responses leave the saved brief unchanged.

## POST /api/projects/:id/brief/approve

Approve the current scope

Authentication: Session or Bearer token; project owner.

### Request

```
{ "expectedRevision": 2 }
```

### Response

```
{ brief: DesignBrief }; status becomes approved and approvedAt is recorded.
```

Requires a scope and answers to all required questions. Obtain explicit human approval of the current scope before calling. Approval increments the brief revision; it does not generate a design, save the document, or publish.

## GET /api/projects/:id/assets

List project assets

Authentication: Session or Bearer token; project owner.

### Request

```
No body.
```

### Response

```
{ assets: [{ id, name, type, mimeType, url, size }] }
```

## POST /api/projects/:id/assets

Upload private media

Authentication: Session or Bearer token; project owner.

### Request

```
multipart/form-data with a file field. Let your HTTP client set the multipart boundary.
```

### Response

```
{ asset: { id, name, type, mimeType, url, size } }
```

Maximum 20 MB. PNG/JPEG/WebP/GIF, MP3/WAV/OGG, MP4/WebM, and GLB are supported with signature validation. Upload does not place a node on the canvas.

## GET /api/assets/:id

Download private asset bytes

Authentication: Session or Bearer token; asset owner.

### Request

```
Replace :id with an actual asset ID.
```

### Response

```
Binary response with the stored MIME type.
```

## GET /api/projects/:id/messages

Read saved conversation

Authentication: Session or Bearer token; project owner.

### Request

```
No body.
```

### Response

```
{ messages: [{ id, role, text, createdAt }] }; latest 200 messages in chronological order.
```

## POST /api/projects/:id/messages

Append a conversation message

Authentication: Session or Bearer token; project owner.

### Request

```
{ "role": "user", "text": "Make the title more concise." }
```

### Response

```
201 { message: { id, role, text, createdAt } }
```

role is user or assistant; text is 1–30,000 characters. This stores a message; it does not invoke a provider.

## POST /api/projects/:id/generate

Generate a design proposal

Authentication: Session or Bearer token; project owner.

### Request

```
{ "provider": "openai", "prompt": "Make the opening slide more spacious.", "expectedRevision": 1 }
```

### Response

```
{ document: DesignDocument, usage? }
```

Optional model. Providers: openai, anthropic, gemini, openrouter, deepseek, custom-<slug>. Requires configured BYOK, may incur charges, and does not save. Prompt maximum 12,000 characters. Inspect, then save with the original revision.

## POST /api/projects/:id/media

Generate or transform media

Authentication: Session or Bearer token; project owner.

### Request

```
{ "provider": "fal", "kind": "audio", "prompt": "Warm ambient instrumental music", "durationSeconds": 30 }
```

### Response

```
OpenAI, Gemini, Grok, custom: { asset }. fal and Leonardo: 202 { job: { id, status: "queued" } }.
```

kind: image|audio|video. Optional model, voice, sourceAssetId, durationSeconds, strength. Sources must belong to this project. OpenAI image/edit/speech; Gemini, Grok and Leonardo prompt-only images; custom OpenAI/Gemini compatible prompt-only images; fal image/edit, video/edit, music/effects/audio transformation. Requires BYOK and can incur charges.

## GET /api/projects/:id/media/:jobId

Poll a media job

Authentication: Session or Bearer token; project owner.

### Request

```
Use the project ID and returned job ID.
```

### Response

```
{ status: "queued" | "processing" } or { status: "completed", asset }.
```

Supports all fal media kinds. A completed result is reused on later polls. Failures return actionable errors; queued is not completed.

## POST /api/projects/:id/export

Download a rendered file

Authentication: Session or Bearer token; project owner.

### Request

```
{ "format": "png", "pageIndex": 0, "expectedRevision": 1 }
```

### Response

```
File bytes with Content-Type and Content-Disposition. No JSON success envelope.
```

Formats: json, html, svg, png, pdf, pptx, webm, mp4, react, glb, gltf. React returns a runnable frontend ZIP for Web/App or wireframe projects. GLB/glTF export the selected scene with geometry/materials/animation. pageIndex defaults to 0; expectedRevision is optional. PDF/PPTX include all pages. Import remote media before isolated cloud rendering. React source export does not require Chromium; GLB/glTF and raster/video formats use the configured browser renderer. Size and encoder limits apply.

## POST /api/projects/:id/google-slides

Create Google Slides

Authentication: Session or Bearer token; project owner.

### Request

```
{ "accessToken": "<short-lived Google OAuth access token>" }
```

### Response

```
{ url, presentationId }
```

Requires real Google authorization. Native text/shapes/HTTPS images are supported; unsupported complex nodes and private image URLs fail explicitly. Do not put the token in source files.

## POST /api/projects/:id/publish

Publish an immutable snapshot

Authentication: Session or Bearer token; project owner.

### Request

```
No body.
```

### Response

```
{ url, revision }
```

Makes this saved design and its referenced snapshot assets public. Later private edits do not change it.

## DELETE /api/projects/:id/publish

Unpublish a project

Authentication: Session or Bearer token; project owner.

### Request

```
No body.
```

### Response

```
{ "ok": true }; removes all public snapshots of this project.
```

## POST /api/projects/:id/preview

Create a public preview link

Authentication: Session or Bearer token; project owner.

### Request

```
No body.
```

### Response

```
{ url, revision }
```

Creates the same immutable public snapshot as publish, under the preview naming used by agents. Later private edits do not change it.

## DELETE /api/projects/:id/preview

Remove preview links

Authentication: Session or Bearer token; project owner.

### Request

```
No body.
```

### Response

```
{ "ok": true }; removes all public snapshots of this project.
```

## POST /api/projects/:id/share

Create a public share link

Authentication: Session or Bearer token; project owner.

### Request

```
No body.
```

### Response

```
{ url, revision }
```

Creates the same immutable public snapshot as publish, under the share naming used by agents.

## DELETE /api/projects/:id/share

Remove share links

Authentication: Session or Bearer token; project owner.

### Request

```
No body.
```

### Response

```
{ "ok": true }; removes all public snapshots of this project.
```

## GET /published/:slug

View a published snapshot

Authentication: Public.

### Request

```
Use the slug from a publish response.
```

### Response

```
HTML snapshot, including the trusted 3D/timeline viewer where applicable.
```

## GET /published/:slug/assets/:id

Read a snapshot asset

Authentication: Public, scoped to this snapshot.

### Request

```
Use the snapshot asset URL. Private API asset URLs do not become public.
```

### Response

```
Asset bytes only when this publication references the asset.
```

## GET /api/providers

List masked provider settings

Authentication: Account session or API key.

### Request

```
No body.
```

### Response

```
{ providers: [{ provider, name, baseUrl, model, protocol, authMethod, authHeader, configured, apiKey: "••••••••" }] }
```

API-key MCP clients can use list_provider_connections for these masked IDs. MCP OAuth tokens cannot access provider settings.

## PUT /api/providers/:provider

Save a BYOK connection

Authentication: Account session or API key.

### Request

```
{ "apiKey": "<provider secret from secure input>", "model": "<optional model ID>" }
```

### Response

```
{ provider, name, baseUrl, model, protocol, authMethod, authHeader, configured: true, apiKey: "••••••••" }
```

Providers: openai, anthropic, gemini, openrouter, fal, deepseek, leonardo, grok or custom-<slug>. Custom connections require name, baseUrl and model; protocol is openai, anthropic or gemini. authMethod: bearer, api-key (authHeader), basic (username:password credential), none. HTTPS origins must be operator-allowlisted. Omit apiKey to retain it; endpoint/auth changes require a new credential. Secrets are encrypted. Prefer CLI --key-env or --key-stdin; ChatGPT subscriptions do not include OpenAI API access.

## DELETE /api/providers/:provider

Remove a BYOK connection

Authentication: Account session or API key.

### Request

```
No body.
```

### Response

```
{ "ok": true }
```

## GET /api/tokens

List API-key metadata

Authentication: Account session or API key.

### Request

```
No body.
```

### Response

```
{ tokens: [{ id, name, createdAt, lastUsedAt }] }
```

Raw keys are never returned by list. MCP OAuth cannot manage permanent credentials.

## POST /api/tokens

Create an API key

Authentication: Account session or API key.

### Request

```
{ "name": "Local design agent" }
```

### Response

```
201 { id, token }; raw token is returned once.
```

Treat this response as a secret. Use the signed-in key-management UI to create your first key.

## DELETE /api/tokens/:id

Revoke an API key

Authentication: Account session or API key.

### Request

```
Use the key ID from the metadata list, not the secret value.
```

### Response

```
{ "ok": true }; revoked keys no longer authenticate.
```

## Errors and concurrency

Application errors use {error:{code,message,details?}}. OAuth errors use {error,error_description}. Handle 400 invalid input, 401 authentication, 403 origin/scope, 404 unavailable ownership-scoped resources, 409 revision conflicts, 413 byte/pixel limits, 429 rate limits, and 502/503 upstream/configuration failures. Read and reconcile on a revision conflict; never blindly raise expectedRevision.
