Use the server origin as your base URL. Request bodies are JSON unless stated otherwise. IDs in route patterns are placeholders: read real IDs from the server.
curl "$DESIGN_STUDIO_URL/api/projects?sort=updated" \
-H "Authorization: Bearer $DESIGN_STUDIO_API_KEY"105 of 105 endpoints
POST/api/projects/:id/inspectVisually inspect a saved page or project
Visually inspect a saved page or project
Session or Bearer token; project ownerRequest
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/inspectVisually inspect workspace covers
Visually inspect workspace covers
Session or Bearer token; owned projects onlyRequest
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/taxonomyDiscover Community categories, formats and limits
Discover Community categories, formats and limits
PublicRequest
No body.Response
Validated JSON response; asynchronous writes return durable job status.GET/api/community/listingsSearch live community designs with category, tags, formats, sort and cursor filters
Search live community designs with category, tags, formats, sort and cursor filters
PublicRequest
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
Read a live design and its download files
PublicRequest
No body.Response
Validated JSON response; asynchronous writes return durable job status.GET/api/community/creators/{handle}Read a public creator profile
Read a public creator profile
PublicRequest
No body.Response
Validated JSON response; asynchronous writes return durable job status.GET/api/community/collectionsList curated Community collections
List curated Community collections
PublicRequest
No body.Response
Validated JSON response; asynchronous writes return durable job status.GET/api/community/collections/{id}Read a curated Community collection
Read a curated Community collection
PublicRequest
No body.Response
Validated JSON response; asynchronous writes return durable job status.GET/api/community/listings/{id}/versions/{version}/previewGet sandboxed HTML preview of a retained live version
Get sandboxed HTML preview of a retained live version
PublicRequest
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
Download real ready file bytes; first eligible download contributes to creator impact
PublicRequest
No body.Response
Ready file bytes; Content-Type identifies the actual format.POST/api/community/preflightReview the public projection, disclosures, formats and digest before publishing
Review the public projection, disclosures, formats and digest before publishing
Session or Bearer token; owner checks applyRequest
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/generateDraft 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.
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.
Session or Bearer token; owner checks applyRequest
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/listingsExplicitly confirm CC-BY-4.0 and public disclosure to publish the reviewed revision; reuse exact operation ID and payload on retry
Explicitly confirm CC-BY-4.0 and public disclosure to publish the reviewed revision; reuse exact operation ID and payload on retry
Session or Bearer token; owner checks applyRequest
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}/releasesPublish a new immutable release at the reviewed project and listing revisions
Publish a new immutable release at the reviewed project and listing revisions
Session or Bearer token; owner checks applyRequest
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}/unlistRevoke public access to all listing versions at the observed listing revision
Revoke public access to all listing versions at the observed listing revision
Session or Bearer token; owner checks applyRequest
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
Read your durable Community operation status and result
Session or Bearer token; owner checks applyRequest
No body.Response
Validated JSON response; asynchronous writes return durable job status.GET/api/community/jobs/{operationId}/previewRead your private staged publication preview
Read your private staged publication preview
Session or Bearer token; owner checks applyRequest
No body.Response
Ready file bytes; Content-Type identifies the actual format.GET/api/community/jobs/{operationId}/files/{fileId}Download your private staged file
Download your private staged file
Session or Bearer token; owner checks applyRequest
No body.Response
Ready file bytes; Content-Type identifies the actual format.POST/api/community/listings/{id}/remixCreate an independent private project with owned assets and attribution from a pinned public version
Create an independent private project with owned assets and attribution from a pinned public version
Session or Bearer token; owner checks applyRequest
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/importsImport a portable ZIP into an independent private project; operationId makes exact retries safe
Import a portable ZIP into an independent private project; operationId makes exact retries safe
Session or Bearer token; owner checks applyRequest
Multipart file ZIP and operationId; 20 MiB package limit.Response
Validated JSON response; asynchronous writes return durable job status.GET/api/community/me/listingsList your publications including private management states
List your publications including private management states
Session or Bearer token; owner checks applyRequest
No body.Response
Validated JSON response; asynchronous writes return durable job status.GET/api/community/me/bookmarksList your private saved Community designs
List your private saved Community designs
Session or Bearer token; owner checks applyRequest
No body.Response
Validated JSON response; asynchronous writes return durable job status.GET/api/community/me/impactRead server-confirmed creator impact and milestone badges
Read server-confirmed creator impact and milestone badges
Session or Bearer token; owner checks applyRequest
No body.Response
Validated JSON response; asynchronous writes return durable job status.GET/api/community/me/profileRead your opt-in Community profile and revision
Read your opt-in Community profile and revision
Session or Bearer token; owner checks applyRequest
No body.Response
Validated JSON response; asynchronous writes return durable job status.PUT/api/community/me/profileCreate or update your public profile at its observed revision
Create or update your public profile at its observed revision
Session or Bearer token; owner checks applyRequest
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/generateUse 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.
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.
Session or Bearer token; owner checks applyRequest
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}/bookmarkIdempotently save a live design to your private bookmarks
Idempotently save a live design to your private bookmarks
Session or Bearer token; owner checks applyRequest
No body.Response
Validated JSON response; asynchronous writes return durable job status.DELETE/api/community/listings/{id}/bookmarkIdempotently remove a private bookmark
Idempotently remove a private bookmark
Session or Bearer token; owner checks applyRequest
No body.Response
Validated JSON response; asynchronous writes return durable job status.POST/api/community/listings/{id}/reportsReport a pinned design version with a reason and exact-retry operation ID
Report a pinned design version with a reason and exact-retry operation ID
Session or Bearer token; owner checks applyRequest
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/reportsOperator session/API key only: list private reports
Operator session/API key only: list private reports
Operator session or API key; no OAuthRequest
No body.Response
Validated JSON response; asynchronous writes return durable job status.GET/api/community/moderation/collectionsOperator only: list collections including unavailable reviewed items
Operator only: list collections including unavailable reviewed items
Operator session or API key; no OAuthRequest
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
Operator only: inspect a pinned report and content availability
Operator session or API key; no OAuthRequest
No body.Response
Validated JSON response; asynchronous writes return durable job status.GET/api/community/moderation/reports/{id}/previewOperator only: preview retained reported content
Operator only: preview retained reported content
Operator session or API key; no OAuthRequest
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
Operator only: download retained evidence bound to the report
Operator session or API key; no OAuthRequest
No body.Response
Ready file bytes; Content-Type identifies the actual format.POST/api/community/moderation/reports/{id}/resolveOperator only: hide, restore or dismiss with observed report/listing revisions and a reason
Operator only: hide, restore or dismiss with observed report/listing revisions and a reason
Operator session or API key; no OAuthRequest
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/collectionsOperator only: curate explicitly reviewed listing versions
Operator only: curate explicitly reviewed listing versions
Operator session or API key; no OAuthRequest
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
Operator only: update ordered curation at the observed collection revision
Operator session or API key; no OAuthRequest
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/sceneInspect 3D mesh and rig
Inspect 3D mesh and rig
Session or Bearer token; project ownerRequest
Optional pageId and time (seconds).Response
Revision, topology diagnostics, bones and sampled deformation bounds.POST/api/projects/:id/sceneAuthor 3D character
Author 3D character
Session or Bearer token; project ownerRequest
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/thumbnailLoad a persisted project cover
Load a persisted project cover
Session or Bearer token; project ownerRequest
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/motionInspect character motion
Inspect character motion
Session or Bearer token; project ownerRequest
Optional query: characterId, nodeId, time (seconds).Response
Revision, rigs, clips, skins, constraints and optional sampled pose.GET/api/observability/summarySummarize account activity and measured usage
Summarize account activity and measured usage
Session or Bearer; owner default, configured operator for scope=allRequest
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/eventsRead paginated activity logs
Read paginated activity logs
Session or Bearer; owner defaultRequest
Summary filters plus limit=1..100 (default50), cursor from previous page.Response
{ events, nextCursor }; safe metadata only, 30-day retention.GET/api/observability/trace/:idFollow correlated request steps
Follow correlated request steps
Session or Bearer; owner defaultRequest
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-eventsRecord an allowlisted browser event
Record an allowlisted browser event
Same-origin browser; owned project/correlation when suppliedRequest
{ 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/healthCheck service health
Check service health
PublicRequest
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/schemaRead live JSON Schemas
Read live JSON Schemas
PublicRequest
No body.Response
{ document: JSONSchema, operations: JSONSchema, designSystem: JSONSchema, interview: JSONSchema, scope: JSONSchema }; semantic validation still runs on writes.GET/api/openapiDiscover API operations and request schemas
Discover API operations and request schemas
PublicRequest
No body.Response
OpenAPI document with path/query parameters, multipart uploads, and shared component schemas.GET/api/design-systemsList your design systems
List your design systems
Session or Bearer token; library ownerRequest
No body.Response
{ systems: DesignSystem[] }; latest saved versions for this owner.POST/api/design-systemsCreate a reusable design system
Create a reusable design system
Session or Bearer token; library ownerRequest
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/:idRead a library version
Read a library version
Session or Bearer token; library ownerRequest
Optional positive integer query: version. Omit for latest.Response
{ system: { id, version, definition, createdAt } }GET/api/design-systems/:id/versionsList immutable library versions
List immutable library versions
Session or Bearer token; library ownerRequest
No body.Response
{ versions: [{ version, createdAt }] }; newest first.PUT/api/design-systems/:idAppend a library version
Append a library version
Session or Bearer token; library ownerRequest
{ 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/applyApply a saved design system
Apply a saved design system
Session or Bearer token; project ownerRequest
{ 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/insertInsert a library item
Insert a library item
Session or Bearer token; project ownerRequest
{ projectId, expectedRevision, pageId, itemId, version? }Response
{ project }; inserts the saved component/composition with fresh node IDs and remapped hierarchy/interactions.DELETE/api/design-systems/:idDelete a design-system library
Delete a design-system library
Session or Bearer token; library ownerRequest
No body.Response
{ "ok": true }Deletes this owned library and its versions. Previously applied project content remains embedded.
GET/api/fontsDiscover Google Fonts
Discover Google Fonts
Session or Bearer tokenRequest
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/modelsDiscover provider model IDs
Discover provider model IDs
Account session or API keyRequest
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/catalogRead built-in design resources
Read built-in design resources
PublicRequest
No body.Response
{ themes, templates, blocks }GET/api/configRead public configuration
Read public configuration
PublicRequest
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/registerCreate an account
Create an account
Public; matching Origin headerRequest
{ "email": "[email protected]", "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/loginStart an email/password session
Start an email/password session
Public; matching Origin headerRequest
{ "email": "[email protected]", "password": "<your password>" }Response
{ user: { id, email, name } } + HttpOnly session cookie.GET/api/auth/meRead the current account
Read the current account
Optional session or Bearer tokenRequest
No body.Response
{ user: { id, email, name } | null }GET/api/auth/githubStart GitHub sign-in
Start GitHub sign-in
Public browser navigation; configured GitHub OAuth appRequest
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/callbackComplete GitHub sign-in
Complete GitHub sign-in
Valid one-use state and initiating browser cookieRequest
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/statusRead your GitHub connection
Read your GitHub connection
Account browser session onlyRequest
No body.Response
{ enabled: boolean, connected: boolean, login: string | null }POST/api/auth/github/linkConnect GitHub to your existing account
Connect GitHub to your existing account
Account browser session; matching OriginRequest
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/logoutEnd a browser session
End a browser session
Session; matching Origin for cookie authenticationRequest
No body.Response
{ "ok": true }; clears the session cookie.Logging out of a browser does not revoke API keys.
GET/api/projectsSearch and list projects
Search and list projects
Session or Bearer tokenRequest
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/projectsCreate or clone a project
Create or clone a project
Session or Bearer tokenRequest
{ "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/:idRead a project and revision
Read a project and revision
Session or Bearer token; project ownerRequest
Replace :id with an actual project ID.Response
{ project: { id, name, description, kind, document, revision, createdAt, updatedAt, publishedUrl? } }PATCH/api/projects/:idUpdate project metadata
Update project metadata
Session or Bearer token; project ownerRequest
{ "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/documentSave the canonical document
Save the canonical document
Session or Bearer token; project ownerRequest
{ "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/mergeMerge concurrent human and agent edits
Merge concurrent human and agent edits
Session or Bearer token; project ownerRequest
{ 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/changesObserve the saved project revision
Observe the saved project revision
Session or Bearer token; project ownerRequest
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/:idDelete a project
Delete a project
Session or Bearer token; project ownerRequest
No body.Response
{ "ok": true }Deletes the project, stored assets, and publications. This is destructive.
GET/api/projects/:id/checksInspect the saved design
Inspect the saved design
Session or Bearer token; project ownerRequest
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/briefRead the design brief and scope
Read the design brief and scope
Session or Bearer token; project ownerRequest
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/briefSave a brief, interview, answers, or scope
Save a brief, interview, answers, or scope
Session or Bearer token; project ownerRequest
{ "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/interviewGenerate contextual interview questions or scope
Generate contextual interview questions or scope
Session or Bearer token; project ownerRequest
{ "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/approveApprove the current scope
Approve the current scope
Session or Bearer token; project ownerRequest
{ "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/assetsList project assets
List project assets
Session or Bearer token; project ownerRequest
No body.Response
{ assets: [{ id, name, type, mimeType, url, size }] }POST/api/projects/:id/assetsUpload private media
Upload private media
Session or Bearer token; project ownerRequest
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/:idDownload private asset bytes
Download private asset bytes
Session or Bearer token; asset ownerRequest
Replace :id with an actual asset ID.Response
Binary response with the stored MIME type.GET/api/projects/:id/messagesRead saved conversation
Read saved conversation
Session or Bearer token; project ownerRequest
No body.Response
{ messages: [{ id, role, text, createdAt }] }; latest 200 messages in chronological order.POST/api/projects/:id/messagesAppend a conversation message
Append a conversation message
Session or Bearer token; project ownerRequest
{ "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/generateGenerate a design proposal
Generate a design proposal
Session or Bearer token; project ownerRequest
{ "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/mediaGenerate or transform media
Generate or transform media
Session or Bearer token; project ownerRequest
{ "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/:jobIdPoll a media job
Poll a media job
Session or Bearer token; project ownerRequest
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/exportDownload a rendered file
Download a rendered file
Session or Bearer token; project ownerRequest
{ "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-slidesCreate Google Slides
Create Google Slides
Session or Bearer token; project ownerRequest
{ "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/publishPublish an immutable snapshot
Publish an immutable snapshot
Session or Bearer token; project ownerRequest
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/publishUnpublish a project
Unpublish a project
Session or Bearer token; project ownerRequest
No body.Response
{ "ok": true }; removes all public snapshots of this project.POST/api/projects/:id/previewCreate a public preview link
Create a public preview link
Session or Bearer token; project ownerRequest
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/previewRemove preview links
Remove preview links
Session or Bearer token; project ownerRequest
No body.Response
{ "ok": true }; removes all public snapshots of this project.POST/api/projects/:id/shareCreate a public share link
Create a public share link
Session or Bearer token; project ownerRequest
No body.Response
{ url, revision }Creates the same immutable public snapshot as publish, under the share naming used by agents.
DELETE/api/projects/:id/shareRemove share links
Remove share links
Session or Bearer token; project ownerRequest
No body.Response
{ "ok": true }; removes all public snapshots of this project.GET/published/:slugView a published snapshot
View a published snapshot
PublicRequest
Use the slug from a publish response.Response
HTML snapshot, including the trusted 3D/timeline viewer where applicable.GET/published/:slug/assets/:idRead a snapshot asset
Read a snapshot asset
Public, scoped to this snapshotRequest
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/providersList masked provider settings
List masked provider settings
Account session or API keyRequest
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/:providerSave a BYOK connection
Save a BYOK connection
Account session or API keyRequest
{ "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/:providerRemove a BYOK connection
Remove a BYOK connection
Account session or API keyRequest
No body.Response
{ "ok": true }GET/api/tokensList API-key metadata
List API-key metadata
Account session or API keyRequest
No body.Response
{ tokens: [{ id, name, createdAt, lastUsedAt }] }Raw keys are never returned by list. MCP OAuth cannot manage permanent credentials.
POST/api/tokensCreate an API key
Create an API key
Account session or API keyRequest
{ "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/:idRevoke an API key
Revoke an API key
Account session or API keyRequest
Use the key ID from the metadata list, not the secret value.Response
{ "ok": true }; revoked keys no longer authenticate.Errors you can act on
{
"error": {
"code": "revision_conflict",
"message": "Project changed. Reload before saving."
}
}| Status | Meaning | Next step |
|---|---|---|
| 400 | Invalid JSON, schema, source, or capability | Inspect error.code and optional validation details. |
| 401 | Missing/invalid authentication | Sign in or supply a valid Bearer token. |
| 403 | Origin, scope, or configuration restriction | Use the correct account credential and trusted origin. |
| 404 | Missing or other-user resource | Read IDs from your owned project list. |
| 409 | Revision or account conflict | Read current state and reconcile; do not blindly retry. |
| 413 | Request, asset, or rendering budget exceeded | Reduce bytes, dimensions, or workload. |
| 429 | Rate limited | Back off before retrying. |
| 502 / 503 | Upstream failure or unavailable rendering/configuration | Read the actionable message; fix provider/browser configuration. |
OAuth endpoints use the OAuth error shape, { error, error_description }, rather than the application JSON envelope.
Try the API
Requests run against this studio. Writes change your real project. The key stays in this page’s memory and is cleared when you leave.
CLI equivalent uses your environment key; no secret is included here.
curl -X GET 'https://studio.example/api/health' -H "Authorization: Bearer $DESIGN_STUDIO_API_KEY"