Auth
All /api/agent/v1/* endpoints accept exactly one auth method: a Bearer API key in the Authorization header. The browser session does NOT work here.
Authorization: Bearer as_live_<publicId>_<secret>API keys carry one or more scopes: projects.read, projects.write, assets.write. Mint and revoke keys at /settings/api-keys.
Capabilities
| Capability | Endpoint | Scope |
|---|---|---|
| Verify API key | GET /api/agent/v1/me | projects.read |
| Create project | POST /api/agent/v1/projects | projects.write |
| Read canonical document | GET /api/agent/v1/projects/{id}/document | projects.read |
| Read resolved family view | GET /api/agent/v1/projects/{id}/view?familyId={familyId} | projects.read |
| Upload an asset | POST /api/agent/v1/projects/{id}/assets/uploads | assets.write |
| Submit a mutation job | POST /api/agent/v1/projects/{id}/jobs | projects.write |
| Poll a job | GET /api/agent/v1/jobs/{jobId} | projects.read |
| Fetch live JSON schemas | GET /api/agent/v1/schema/document | — |
Workflow
- Collect prerequisites from the user — Ask the user for: (1) a Preview Deck API key, (2) the source screenshots/assets, (3) a brief description of the App Store / Play Store story they want to tell.
- Verify the API key — GET /api/agent/v1/me with the key. Stop and report if the request fails.
- Create or open a project — POST /api/agent/v1/projects to create one, or use the projectId the user supplies.
- Upload assets through issued URLs — For every image asset, POST /api/agent/v1/projects/{id}/assets/uploads, then PUT the bytes to the returned signed URL. NEVER inline arbitrary public URLs into the document — they will be rejected as invalid_asset_reference.
- Read the latest document — GET /api/agent/v1/projects/{id}/document. Use the returned document and documentVersion as the canonical base for your edits. For per-family rendering, prefer GET /view?familyId=...
- Submit a full-document replacement job — POST /api/agent/v1/projects/{id}/jobs with { baseDocumentVersion, nextDocument, changeLabel, allowDestructive? }. The endpoint returns 202 + jobId.
- Poll until the job reaches a terminal state — GET /api/agent/v1/jobs/{jobId} until status is succeeded or failed. On success, the response includes a diff, a changeSummary, and a handoffUrl.
- Surface the diff and handoff URL to the user — Always show the user the changeSummary and the handoffUrl so they can review the run in the editor.
- Refetch before iterating — For follow-up edits, refetch the document so your baseDocumentVersion is current. Stale versions return 409 revision_conflict.
Live JSON schemas
Fetch these at runtime — they are authoritative and stable:
- /api/agent/v1/schema/document —
EditorDocumentV1 - /api/agent/v1/schema/job —
AgentMutationJobRequestV1
Error codes
| Code | HTTP | Meaning | Recovery |
|---|---|---|---|
invalid_api_key | 401 | Missing, malformed, expired, or revoked key. | Ask the user for a fresh key. |
insufficient_scope | 403 | Key lacks the scope this endpoint requires. | Ask the user to mint a new key with the correct scopes. |
rate_limited | 429 | Per-minute rate limit hit on this route group. | Back off and retry after one minute. |
project_not_found | 404 | Project does not exist or is not owned by this user. | Re-list projects and retry with a valid id. |
revision_conflict | 409 | Submitted baseDocumentVersion is stale. | Refetch the document, replay your edits on the new version, resubmit. |
destructive_change_denied | 409 | Diff would delete entities and allowDestructive was false. | Confirm with the user, then resubmit with allowDestructive: true. |
invalid_asset_reference | 400 | A document asset reference is not namespaced under the project, or was not issued via the upload endpoint. | Issue a new upload URL, upload the bytes, then reference the returned asset. |
invalid_request | 400 | Request body failed Zod validation. | Inspect the response.issues array, fix the shape, resubmit. |
job_failed | 400 | A queued job entered the failed state. Inspect errorCode/errorMessage on GET /jobs/{jobId}. | Read the failure code and follow that code's recovery. |
job_timeout | 400 | Server-side sweeper marked the job failed after exceeding maxDuration. | Refetch the document and resubmit a smaller job (split into multiple). |
Rules
Must
- Ask the user for an API key before any agent API call.
- Ask the user for source screenshots / assets before composing the document.
- Upload assets only through Preview Deck-issued upload URLs.
- Always submit full-document replacement jobs (no patches).
- Poll the job until status is succeeded or failed.
- Surface the returned diff and handoff URL to the user.
- Refetch the latest document before every follow-up mutation.
- Ask the user for confirmation before submitting destructive edits (allowDestructive=true).
Must not
- Fetch arbitrary asset URLs and inject them into the document.
- Assume browser session auth works for /api/agent/v1/* — only API keys do.
- Treat stale documents as safe to overwrite — refetch first.
- Bypass the user review step. The handoffUrl exists for that.