# REST API

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

Base URL: https://studio.datxanhmientrung.ai. 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.

## POST /api/projects/:id/inspect

Visually inspect a saved page or project

Authentication: Session or Bearer token; project owner.

### Request

```
JSON: mode page|overview (default overview), pageId or zero-based pageIndex (page mode only), expectedRevision, time 0–3600 (default 0), offset (default 0), limit 1–12 (default 6), columns 1–4 (default 3), tileSize 160–800 (default 400), maxDimension 256–2048 (default 1600). Discover visualInspection in /api/schema.
```

### Response

```
{ scope: page|project, source: saved, total, offset, nextOffset, items, images }; PNG base64 in images[].data. Items map project/page IDs, revision, original dimensions, time and pixel bounds to imageIndex.
```

Private read-only rendering; no publication, provider call, or document/brief mutation. Page selectors are exclusive; page mode defaults to the first page. Overview paginates pages. Save unsaved browser edits first. Decode and actually view the PNG before claiming visual review. Renderer limits apply; invalid selections, stale revisions and rendering failures are explicit errors.

## POST /api/projects/inspect

Visually inspect workspace covers

Authentication: Session or Bearer token; owned projects only.

### Request

```
JSON: offset (default 0), limit 1–12 (default 6), time 0–3600 (default 0), tileSize 160–800 (default 400). Discover workspaceInspection in /api/schema.
```

### Response

```
{ scope: workspace, source: saved, total, offset, nextOffset, items, images }; first-page PNG covers with per-project saved revisions. Empty results have no items/images.
```

Projects ordered by ID. Follow nextOffset until null for remaining covers; concurrent creation/deletion can change offset pagination. Revisions describe individual project snapshots, not one atomic workspace snapshot. No publication or AI provider call. Use project page/overview inspection for the other pages.

## GET /api/community/taxonomy

Discover Community categories, formats and limits

Authentication: Public.

### Request

```
No body.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## GET /api/community/listings

Search live community designs with category, tags, formats, sort and cursor filters

Authentication: Public.

### Request

```
q, kind, tags, format, period, creator, collection, sort, cursor, limit.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## GET /api/community/listings/{id}

Read a live design and its download files

Authentication: Public.

### Request

```
No body.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## GET /api/community/creators/{handle}

Read a public creator profile

Authentication: Public.

### Request

```
No body.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## GET /api/community/collections

List curated Community collections

Authentication: Public.

### Request

```
No body.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## GET /api/community/collections/{id}

Read a curated Community collection

Authentication: Public.

### Request

```
No body.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## GET /api/community/listings/{id}/versions/{version}/preview

Get sandboxed HTML preview of a retained live version

Authentication: Public.

### Request

```
No body.
```

### Response

```
Ready file bytes; Content-Type identifies the actual format.
```

## GET /api/community/listings/{id}/versions/{version}/files/{fileId}

Download real ready file bytes; first eligible download contributes to creator impact

Authentication: Public.

### Request

```
No body.
```

### Response

```
Ready file bytes; Content-Type identifies the actual format.
```

## POST /api/community/preflight

Review the public projection, disclosures, formats and digest before publishing

Authentication: Session or Bearer token; owner checks apply.

### Request

```
Canonical request in /api/schema → community. JSON body requires the fields listed there.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## POST /api/community/metadata/generate

Draft a listing title, description and tags using an owned saved project revision and configured text provider. Sends bounded visible text/structure plus entered fields/instructions, incurs provider usage, and never saves or publishes. Defaults to the first configured text connection. Review the suggestion and run preflight with the approved fields before publication.

Authentication: Session or Bearer token; owner checks apply.

### Request

```
Canonical request in /api/schema → community. JSON body requires the fields listed there.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## POST /api/community/listings

Explicitly confirm CC-BY-4.0 and public disclosure to publish the reviewed revision; reuse exact operation ID and payload on retry

Authentication: Session or Bearer token; owner checks apply.

### Request

```
Canonical request in /api/schema → community. JSON body requires the fields listed there.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## POST /api/community/listings/{id}/releases

Publish a new immutable release at the reviewed project and listing revisions

Authentication: Session or Bearer token; owner checks apply.

### Request

```
Canonical request in /api/schema → community. JSON body requires the fields listed there.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## POST /api/community/listings/{id}/unlist

Revoke public access to all listing versions at the observed listing revision

Authentication: Session or Bearer token; owner checks apply.

### Request

```
Canonical request in /api/schema → community. JSON body requires the fields listed there.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## GET /api/community/jobs/{operationId}

Read your durable Community operation status and result

Authentication: Session or Bearer token; owner checks apply.

### Request

```
No body.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## GET /api/community/jobs/{operationId}/preview

Read your private staged publication preview

Authentication: Session or Bearer token; owner checks apply.

### Request

```
No body.
```

### Response

```
Ready file bytes; Content-Type identifies the actual format.
```

## GET /api/community/jobs/{operationId}/files/{fileId}

Download your private staged file

Authentication: Session or Bearer token; owner checks apply.

### Request

```
No body.
```

### Response

```
Ready file bytes; Content-Type identifies the actual format.
```

## POST /api/community/listings/{id}/remix

Create an independent private project with owned assets and attribution from a pinned public version

Authentication: Session or Bearer token; owner checks apply.

### Request

```
Canonical request in /api/schema → community. JSON body requires the fields listed there.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## POST /api/community/imports

Import a portable ZIP into an independent private project; operationId makes exact retries safe

Authentication: Session or Bearer token; owner checks apply.

### Request

```
Multipart file ZIP and operationId; 20 MiB package limit.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## GET /api/community/me/listings

List your publications including private management states

Authentication: Session or Bearer token; owner checks apply.

### Request

```
No body.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## GET /api/community/me/bookmarks

List your private saved Community designs

Authentication: Session or Bearer token; owner checks apply.

### Request

```
No body.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## GET /api/community/me/impact

Read server-confirmed creator impact and milestone badges

Authentication: Session or Bearer token; owner checks apply.

### Request

```
No body.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## GET /api/community/me/profile

Read your opt-in Community profile and revision

Authentication: Session or Bearer token; owner checks apply.

### Request

```
No body.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## PUT /api/community/me/profile

Create or update your public profile at its observed revision

Authentication: Session or Bearer token; owner checks apply.

### Request

```
Canonical request in /api/schema → community. JSON body requires the fields listed there.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## POST /api/community/me/profile/generate

Use your configured text provider to suggest a public display name, handle and bio. Incurs provider usage; sends only supplied fields/instructions, defaults to your first configured text connection, and never saves or publishes. Review before set-profile; handle availability is checked again when saving.

Authentication: Session or Bearer token; owner checks apply.

### Request

```
Canonical request in /api/schema → community. JSON body requires the fields listed there.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## PUT /api/community/listings/{id}/bookmark

Idempotently save a live design to your private bookmarks

Authentication: Session or Bearer token; owner checks apply.

### Request

```
No body.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## DELETE /api/community/listings/{id}/bookmark

Idempotently remove a private bookmark

Authentication: Session or Bearer token; owner checks apply.

### Request

```
No body.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## POST /api/community/listings/{id}/reports

Report a pinned design version with a reason and exact-retry operation ID

Authentication: Session or Bearer token; owner checks apply.

### Request

```
Canonical request in /api/schema → community. JSON body requires the fields listed there.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## GET /api/community/moderation/reports

Operator session/API key only: list private reports

Authentication: Operator session or API key; no OAuth.

### Request

```
No body.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## GET /api/community/moderation/collections

Operator only: list collections including unavailable reviewed items

Authentication: Operator session or API key; no OAuth.

### Request

```
No body.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## GET /api/community/moderation/reports/{id}

Operator only: inspect a pinned report and content availability

Authentication: Operator session or API key; no OAuth.

### Request

```
No body.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## GET /api/community/moderation/reports/{id}/preview

Operator only: preview retained reported content

Authentication: Operator session or API key; no OAuth.

### Request

```
No body.
```

### Response

```
Ready file bytes; Content-Type identifies the actual format.
```

## GET /api/community/moderation/reports/{id}/files/{fileId}

Operator only: download retained evidence bound to the report

Authentication: Operator session or API key; no OAuth.

### Request

```
No body.
```

### Response

```
Ready file bytes; Content-Type identifies the actual format.
```

## POST /api/community/moderation/reports/{id}/resolve

Operator only: hide, restore or dismiss with observed report/listing revisions and a reason

Authentication: Operator session or API key; no OAuth.

### Request

```
Canonical request in /api/schema → community. JSON body requires the fields listed there.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## POST /api/community/moderation/collections

Operator only: curate explicitly reviewed listing versions

Authentication: Operator session or API key; no OAuth.

### Request

```
Canonical request in /api/schema → community. JSON body requires the fields listed there.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## PUT /api/community/moderation/collections/{id}

Operator only: update ordered curation at the observed collection revision

Authentication: Operator session or API key; no OAuth.

### Request

```
Canonical request in /api/schema → community. JSON body requires the fields listed there.
```

### Response

```
Validated JSON response; asynchronous writes return durable job status.
```

## GET /api/projects/:id/scene

Inspect 3D mesh and rig

Authentication: Session or Bearer token; project owner.

### Request

```
Optional pageId and time (seconds).
```

### Response

```
Revision, topology diagnostics, bones and sampled deformation bounds.
```

## POST /api/projects/:id/scene

Author 3D character

Authentication: Session or Bearer token; project owner.

### Request

```
pageId, command, expectedRevision, preview (default true). Discover sceneCommands in /api/schema.
```

### Response

```
Preview or applied revision with compact diagnostics. Apply uses atomic owner/revision validation.
```

## GET /api/projects/:id/thumbnail

Load a persisted project cover

Authentication: Session or Bearer token; project owner.

### Request

```
Optional query revision: positive saved revision; defaults to current.
```

### Response

```
200 image/png (maximum 480px per side); 202 {status: rendering, revision} with Retry-After: 2 while another render is active.
```

Owner-only. Cache misses render once using the isolated server renderer; project summaries expose thumbnailUrl for the current revision and thumbnailRevision for the latest ready cover. Retains two latest completed revisions; older missing covers return 404. Failures preserve the previous cover, with a 30-second retry cooldown. Import external media into the project first. No AI provider call.

## GET /api/projects/:id/motion

Inspect character motion

Authentication: Session or Bearer token; project owner.

### Request

```
Optional query: characterId, nodeId, time (seconds).
```

### Response

```
Revision, rigs, clips, skins, constraints and optional sampled pose.
```

## 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", "revision": "<deployed commit> | null" }
```

revision is the commit stamped into the built site; it is null for local and self-hosted builds that have no release marker.

## 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. Optional expectedBriefRevision guards reviewed proposals against brief changes. 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, motion, png-sequence, spritesheet, scene-angles, editable-scene. scene-angles at start returns four PNGs; adding end and reviewSamples (2–25, default 5) returns four views per sampled time, contact-sheet.png and views.json diagnostics. editable-scene requires nodeId and returns canonical JSON with a hidden original-GLB checkpoint, without saving; project asset references remain. Frame ZIPs accept start/end/fps. 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.
