REST API
Get a key, make your first render in four calls, and browse every endpoint.
Everything braaand can do is available over plain HTTPS. The MCP connector and the CLI are usually the comfortable paths, but when you're wiring braaand into your own backend, an orchestrator, or a language without an SDK, this is the surface you build against.
The base URL is:
https://www.braaand.ai/apiBuilding an agent? Pick the shortest path before hand-rolling HTTP:
- MCP — connect
https://mcp.braaand.ai/mcpand your agent gets dozens of ready-made tools whose descriptions carry the on-brand rules (what to set, what to leave to the cascade). Zero integration work. See Connect an AI client. - The CLI —
npm i -g braaandfor coding agents with shell access. Auth is stored once (braaand login), renders land as files on disk instead of flowing through the model's context, and payloads too large for a request body (bulk onboards over ~4 MB) only work here. See Command line. - The Claude skill — the packaged braaand playbook for Claude Code. See Claude skill.
- This page +
GET /api— for your own HTTP wrapper.GET /apireturns a prose orientation written for LLMs; feed your model that plus this page and it can drive the API. One thing neither carries in full: braaand's styling philosophy (letrole, color schemes, and themes drive look — never set fonts or colors inline). If your agent will edit creatives rather than just fill copy, also feed it How your brand flows in. The docs are fetchable as raw markdown — this page lives at/docs/md/agents/rest-api, and/docs/llms.txtindexes everything with deep links.
Get a key
- Go to Settings → Profile → API keys and click New key. Copy the
ae_…value right away — it's shown once and stored hashed. - Or from the terminal:
npm i -g braaand && braaand loginwalks you through device auth and stores a key for the CLI.
Send it as a bearer token on every request:
curl -H "Authorization: Bearer ae_..." https://www.braaand.ai/api/brandsA user key acts as you. For a single-purpose integration scoped to one brand, mint a brand token (bt_…) instead — POST /api/brands/{brandId}/tokens with { "name": "zapier", "role": "editor" } — and it can never touch other brands or manage members.
Quickstart: brief to PNG in four calls
1. Find your brand and a template.
curl -H "Authorization: Bearer $KEY" https://www.braaand.ai/api/brands
# → [{ "id": "acme", "name": "Acme", "role": "owner", ... }]
curl -H "Authorization: Bearer $KEY" https://www.braaand.ai/api/brands/acme/templates
# → [{ "id": "acme-hero-statement-1a2b3c4d", "name": "Hero statement", "elements": [...], ... }]2. Clone the template into a creative.
curl -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
https://www.braaand.ai/api/brands/acme/creatives \
-d '{ "templateId": "acme-hero-statement-1a2b3c4d", "name": "Summer sale hero" }'
# → 201 { "id": "crv_9f8e...", "elements": [{ "id": "heading", ... }], ... }3. Put your copy in. Element ids come from the creative you just received; patches are partial and merge.
curl -X PATCH -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
https://www.braaand.ai/api/brands/acme/creatives/crv_9f8e.../elements/heading \
-d '{ "content": "Up to 50% off" }'4. Render it. The response is the PNG itself (an X-Render-Id header carries the id for your records).
curl -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
https://www.braaand.ai/api/render \
-d '{ "kind": "creative", "brandId": "acme", "creativeId": "crv_9f8e...", "format": "1x1" }' \
--output summer-sale-1x1.pngProducing at scale: workflows
For a batch ("give me a campaign from this brief"), launch a workflow and poll its manifest — there are no webhooks; the manifest is recomputed on every read, so polling always reflects the latest state including later edits.
curl -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
https://www.braaand.ai/api/brands/acme/factory/workflows \
-d '{ "brief": { "raw": "Summer sale, warm and urgent, CTA to acme.com/sale" }, "count": 20 }'
# → 201 { "workflowId": "...", "boardId": "...", "manifestUrl": "...", "boardUrl": "...", "shareUrl": "..." }
curl -H "Authorization: Bearer $KEY" "$MANIFEST_URL"
# → { "status": "running", "creatives": [{ "id": "crv_...", "renders": { "1x1": "https://..." }, "score": 84, ... }] }The brief is free text — how many creatives you want goes in count (1-200), never in the prose. The produced creatives land on a board (boardId) — a durable review place that can hold creatives from more than one run — pre-sorted into an Approved section (score ≥ 75) and Needs review for the rest. Every run is also a live node pipeline; open /brands/{brandId}/factory/{workflowId}/pipeline in the app to watch or edit it. boardUrl is the human review surface; shareUrl is a read-only link you can hand a client without a braaand account. For a full accounting of the run (build stages, scores, cost), pull GET .../factory/workflows/{workflowId}/log.
Conventions
- Status codes.
401bad or missing credentials,403not allowed,404not found,400validation,402out of credits (the body carries a machine-readablecode),507storage quota exceeded,429rate limited (with aRetry-Afterheader),409edit conflict or "run is still building". - Errors are JSON:
{ "error": "human-readable message", "code": "machine_readable_when_relevant" }. Malformed request bodies answer400 { "error": "invalid_json" }; schema failures answer400 { "error": "validation", "details": [{ "path", "message" }] }. - Edit conflicts. Templates and creatives carry a
versionnumber. Send the version your edits are based on in theX-Doc-Versionheader (or asversionin the body) and the save is compare-and-set: if someone else saved first you get a409with thecurrentVersion, so you re-read and re-apply instead of overwriting their work. Partial updates without a version are merged onto a fresh read server-side. - Merging. Config-style PUTs (brand config, templates, creatives) only overwrite the fields present in the body — omit a field to leave it alone.
- Rate limits (per caller): render 120/5 min, batch render 20/5 min, agent chat 60/5 min, onboarding 10/hour, workflow launch 20/hour.
- Formats are named
1x1(1080×1080),4x5(1080×1350),9x16(1080×1920), and16x9(1200×628) by default; each document carries its own list, so readformatsoff the doc rather than assuming. - Ids are stable strings — creatives are prefixed
crv_, keysae_, brand tokensbt_, share linksdt_. - No pagination. List endpoints return everything; filter server-side where query params exist (e.g. creatives by
collection,status,tag). - Asset and render URLs are capabilities. They contain unguessable ids and are safe to hot-link; they're also immutable and cached hard, so the URL changes whenever the content does.
- Stability. There is no versioned prefix yet; the shapes documented here are the supported surface. Build against the documented fields and treat undocumented ones as subject to change.
Endpoints
Generated from the codebase — always current. Internal surfaces (admin, cron, webhooks) are omitted.
Brands
| Route | Method | Auth | What it does |
|---|---|---|---|
/api/brands/{brandId}/ai-board |
GET | brand read | 302 to the (content-addressed) board PNG on the blob CDN. |
/api/brands/{brandId}/allow-domains/{domain} |
DELETE | brand admin (user auth only — brand tokens not accepted) | Remove one allow-domain. |
/api/brands/{brandId}/allow-domains |
GET | brand admin (user auth only — brand tokens not accepted) | List the brand's allow-domains. |
/api/brands/{brandId}/allow-domains |
POST | brand admin (user auth only — brand tokens not accepted) | Add (or re-role) an allow-domain: { domain, defaultRole?: "read" | "editor" | "admin" }. |
/api/brands/{brandId}/assets/{assetId}/analyze |
POST | brand editor | Re-run the POI/metadata vision pass over an asset ALREADY in the library. |
/api/brands/{brandId}/assets/{assetId} |
GET | public | Intentionally public: the asset URL is a capability (unguessable UUID) — renders, the editor preview, and exported creatives all hot-link it. |
/api/brands/{brandId}/assets/{assetId} |
DELETE | brand editor | Delete the asset (cascade-cleans logo-system and default-image references). |
/api/brands/{brandId}/assets/{assetId} |
PUT | brand editor | Replace an asset's bytes, keeping its id / URL / name (multipart file). |
/api/brands/{brandId}/assets/{assetId} |
PATCH | brand editor | Transform the asset in place. |
/api/brands/{brandId}/assets/{assetId}/usage |
GET | brand read | Which of this brand's own templates + creatives reference the asset. |
/api/brands/{brandId}/assets/analyze |
POST | brand editor | Analyze an uploaded image with a vision LLM and return suggested metadata for the asset-upload form. |
/api/brands/{brandId}/assets/from-url |
POST | brand editor | Import a remote image URL into the brand's asset library. |
/api/brands/{brandId}/assets/import-commons |
POST | brand editor | Import PEOPLE from Wikimedia Commons into the brand library: per name, a license-gated search (CC0 / public domain / CC BY / CC BY-SA only — the wikimedia stock adapter's gate),… |
/api/brands/{brandId}/assets/pack |
GET | brand read | Download a brand-identity pack: ?group=fonts|logos|guidelines — one matching asset streams directly, several zip. |
/api/brands/{brandId}/assets |
GET | brand read | List assets; ?type= filters by kind, ?query= runs the same search the in-app palette uses. |
/api/brands/{brandId}/assets |
POST | brand editor | Upload an asset — multipart form (file, plus optional name / type / tags / description / metadata), or JSON { sourceUrl } for direct-to-blob ingest of large files. |
/api/brands/{brandId}/boards/{boardId}/canvas |
PUT | brand editor | Persist the board's node LAYOUT — creative positions, sections, viewport. |
/api/brands/{brandId}/boards/{boardId}/comments |
POST | brand editor | Owner/editor comment ops on the board (add / update / delete a note). |
/api/brands/{brandId}/boards/{boardId}/creatives |
POST | brand editor | Attach standalone creatives to this board (explicit curation — the REST mirror of the MCP add_to_board tool). |
/api/brands/{brandId}/boards/{boardId} |
GET | brand read | The board's full content manifest — every creative that landed on it (from any run), current render URLs, scores, curation, sections. |
/api/brands/{brandId}/boards/{boardId} |
PATCH | brand editor | Rename and/or re-file the board: { title?, collectionId? } → { ok, board }. |
/api/brands/{brandId}/boards/{boardId}/share |
POST | brand editor | POST/DELETE /api/brands/[brandId]/boards/[boardId]/share Mint or revoke the board's read-only DELIVERY LINK — a capability token that lets a non-account party (client, external … |
/api/brands/{brandId}/boards/{boardId}/share |
DELETE | brand editor | POST/DELETE /api/brands/[brandId]/boards/[boardId]/share Mint or revoke the board's read-only DELIVERY LINK — a capability token that lets a non-account party (client, external … |
/api/brands/{brandId}/boards |
GET | brand read | List the brand's boards (id, title, collectionId, createdAt) for pickers. |
/api/brands/{brandId}/boards |
POST | brand editor | Create a board: { title?, collectionId?, share? } → 201 { board, boardUrl, shareUrl? }. |
/api/brands/{brandId}/brand-config |
GET | brand read | Read the full brand config: colors, colorRoles, schemes, themes, fonts, typeStyles, design tokens, logo system, voice and knowledge. |
/api/brands/{brandId}/brand-config |
PUT | brand editor | Merge-save the config — only fields present in the body are overwritten. |
/api/brands/{brandId}/brand-fit/revert |
POST | brand editor | Restore a doc's elements to their pre-brand-fit state using snapshots previously returned in a BrandFitReport.undoElements. |
/api/brands/{brandId}/brand-fit |
POST | brand editor | Run the deterministic brand-fit engine on a doc (system template, brand template, or ad). |
/api/brands/{brandId}/characters/{characterId}/reference-pack |
POST | brand editor | start (or heal) the character's canonical reference-pack generation as a durable workflow, and answer 202 immediately. |
/api/brands/{brandId}/characters/{characterId} |
GET | brand read | One character + derived pack state (none|generating|partial|ready|failed). |
/api/brands/{brandId}/characters/{characterId} |
PATCH | brand editor | Partial update. |
/api/brands/{brandId}/characters/{characterId} |
DELETE | brand editor | Delete. |
/api/brands/{brandId}/characters |
GET | brand read | List the brand's characters, alphabetically. |
/api/brands/{brandId}/characters |
POST | brand editor | Create a character: { name, description? | spec?, person?, sourceAssetIds? } → { character, warnings }. |
/api/brands/{brandId}/collections/{collectionId}/items |
GET | brand read | List the collection's reference links. |
/api/brands/{brandId}/collections/{collectionId}/items |
POST | brand editor | Link members by reference: { kind, ids } → { linked, invalid }. |
/api/brands/{brandId}/collections/{collectionId}/items |
DELETE | brand editor | Remove reference links: { kind, ids } → { unlinked }. |
/api/brands/{brandId}/collections/{collectionId}/merge |
POST | brand editor | Merge sourceId into this collection: { sourceId } → { collection } (the survivor). |
/api/brands/{brandId}/collections/{collectionId} |
GET | brand read | The collection manifest — runs, boards, creatives, linked templates/assets. |
/api/brands/{brandId}/collections/{collectionId} |
PATCH | brand editor | Rename and/or set the description: { name?, description? } → { collection }. |
/api/brands/{brandId}/collections/{collectionId} |
DELETE | brand editor | Delete the collection (un-file semantics — contents survive as Unfiled). |
/api/brands/{brandId}/collections/bulk |
POST | brand editor | Bulk delete / merge. |
/api/brands/{brandId}/collections |
GET | brand read | List the brand's collections, most recently updated first. |
/api/brands/{brandId}/collections |
POST | brand editor | Create a collection: { name, description? } → { collection }. |
/api/brands/{brandId}/color-schemes/{schemeId} |
PATCH | brand editor | partial update of a custom scheme. |
/api/brands/{brandId}/color-schemes/{schemeId} |
DELETE | brand editor | remove a custom scheme. |
/api/brands/{brandId}/color-schemes |
GET | brand read | list every scheme (built-in dark/light + custom). |
/api/brands/{brandId}/color-schemes |
POST | brand editor | create a custom scheme. |
/api/brands/{brandId}/company/offices/{officeId} |
PATCH | brand editor | Update an office, compare-and-set with baseRev. |
/api/brands/{brandId}/company/offices/{officeId} |
DELETE | brand editor | Remove an office. |
/api/brands/{brandId}/company/offices |
POST | brand editor | Add an office. |
/api/brands/{brandId}/company |
GET | brand read | The company and its offices. |
/api/brands/{brandId}/company |
PUT | brand editor | Save the company (created on the first save), compare-and-set with baseRev. |
/api/brands/{brandId}/composition/{primitive} |
POST | brand editor | Run a composition primitive against a doc. |
/api/brands/{brandId}/config-versions |
GET | brand read | The brand's config HISTORY — one row per version bump (newest first) with the three hashes, plus the current version. |
/api/brands/{brandId}/creatives/{creativeId}/duplicate |
POST | brand editor | Duplicate a creative. |
/api/brands/{brandId}/creatives/{creativeId}/elements/{elementId} |
PATCH | brand editor | Per-creative per-element patch. |
/api/brands/{brandId}/creatives/{creativeId}/reconstruct |
POST | brand editor | Rebuild this flat creative as an editable sibling. |
/api/brands/{brandId}/creatives/{creativeId} |
GET | brand read | Read one creative — the full braaand document. |
/api/brands/{brandId}/creatives/{creativeId} |
PUT | brand editor | Merge-save the creative (the editor's autosave path; optimistic concurrency via X-Doc-Version). |
/api/brands/{brandId}/creatives/{creativeId} |
PATCH | brand editor | Re-file the creative into a collection (the explicit move — the ONLY thing that re-files; board placement never does). |
/api/brands/{brandId}/creatives/{creativeId} |
DELETE | brand editor | Delete the creative. |
/api/brands/{brandId}/creatives/{creativeId}/to-pipeline |
POST | brand editor | "Open in node editor" — clone the creative into a fresh, IDLE workflow run seeded with a single Source node, then hand back the run id so the client can route to the pipeline ed… |
/api/brands/{brandId}/creatives/download |
POST | brand read | Render a chunk of creatives for bulk download (persisted, like a batch render) — returns one render URL per creative × format; the browser fetches and zips them. |
/api/brands/{brandId}/creatives/from-asset |
POST | brand editor | Mint (or reuse) one creative per library image. |
/api/brands/{brandId}/creatives |
GET | brand read | List the brand's creatives — full rows (filterable/sortable; ?query= runs the same content search as MCP list_creatives, ranked over name, headline, copy, tags and collectio… |
/api/brands/{brandId}/creatives |
POST | brand editor | Create a creative: clone a brand template ({ templateId, name }) or mint a blank one ({ empty: true }). |
/api/brands/{brandId}/design-system |
GET | brand read | Export the brand's "design system light" as a { path: content } file map: styles.css (entry, with a Tailwind 4 @theme block) + tokens/*.css + motion.css / `motion.json… |
/api/brands/{brandId}/edit-lock |
POST | brand editor | Acquire/heartbeat/takeover/release the doc's editor lock: { docKind, docId, session, action }. |
/api/brands/{brandId}/fonts |
GET | brand read | Brand font config (families, weights, embedded sources) for API consumers. |
/api/brands/{brandId}/fonts/use |
POST | brand editor | Use a library font for type styles: { assetId, roles, weight? } → { family, changes, fonts, typeStyles, warnings }. |
/api/brands/{brandId}/ideas/knowledge |
GET | brand read | List the brand pool's knowledge (for the Ideas node's picker and the /ideas shelf refresh). |
/api/brands/{brandId}/ideas/library |
GET | brand read | text/markdown; ?download=1 saves. |
/api/brands/{brandId}/ideas/references |
GET | brand read | List the brand pool's references for the Ideas node's config rail. |
/api/brands/{brandId}/ideas |
POST | brand editor | generate concepts (credit-metered). |
/api/brands/{brandId}/images/jobs/{jobId}/redeliver |
POST | brand editor | Re-run webhook delivery for a settled image job (same delivery id). |
/api/brands/{brandId}/images/jobs/{jobId} |
GET | brand read | Snapshot of a single image-gen job (status / phase / finished asset card). |
/api/brands/{brandId}/knowledge |
GET | brand read | Read the structured brand instructions without loading visual config fields. |
/api/brands/{brandId}/knowledge |
PUT | brand editor | Replace the structured brand instructions list while preserving all other config fields. |
/api/brands/{brandId}/lint |
POST | brand read | the OFF-BRAND LINTER (braaand check, MCP lint_project). |
/api/brands/{brandId}/members/{userId} |
PUT | brand admin (user auth only — brand tokens not accepted) | Change a collaborator's role. |
/api/brands/{brandId}/members/{userId} |
DELETE | brand admin (user auth only — brand tokens not accepted) | Remove a collaborator. |
/api/brands/{brandId}/members |
GET | brand admin (user auth only — brand tokens not accepted) | List the brand's collaborators. |
/api/brands/{brandId}/members |
POST | brand admin (user auth only — brand tokens not accepted) | Invite a collaborator. |
/api/brands/{brandId}/motion-renders/{jobId} |
GET | brand read | Snapshot of a motion render job: status / phase / per-format results (clip + poster URLs) / error; terminal once nothing more will change. |
/api/brands/{brandId}/motion/presets/import |
POST | brand editor | Import a CSS @keyframes block as a brand motion preset (422 with refused[] when it does not fit the pose vocabulary; 409 when the id already names a preset unless `overwrite: … |
/api/brands/{brandId}/people/{personId} |
GET | brand read | One person. |
/api/brands/{brandId}/people/{personId} |
PATCH | brand editor | Partial update, compare-and-set with baseRev; the sites bound to this person follow. |
/api/brands/{brandId}/people/{personId} |
DELETE | brand editor | Archive (the default), or erase for good with ?erase=1. |
/api/brands/{brandId}/people |
GET | brand read | The brand's people, sorted (sortOrder, then last name). |
/api/brands/{brandId}/people |
POST | brand editor | Create a person. |
/api/brands/{brandId}/people/sync |
POST | brand editor | Seed / top up the brand's people from its person-tagged photos. |
/api/brands/{brandId}/pipeline-templates/{templateId} |
GET | brand read | one recipe. |
/api/brands/{brandId}/pipeline-templates/{templateId} |
PUT | brand editor | one recipe. |
/api/brands/{brandId}/pipeline-templates/{templateId} |
DELETE | brand editor | one recipe. |
/api/brands/{brandId}/pipeline-templates/{templateId}/run |
POST | brand editor | Instantiate a recipe with bindings and either launch a durable RUN (default, spends credits) or create a DRAFT the user runs from the canvas. |
/api/brands/{brandId}/pipeline-templates |
GET | brand read | List every recipe available in the brand: the built-in starters first (flagged starter), then its saved graphs, most recently updated. |
/api/brands/{brandId}/pipeline-templates |
POST | brand editor | Create a pipeline template: { name, graph, variables?, description?, scope? } — scope "team" (default, visible to everyone on the brand) or "private" (creator only). |
/api/brands/{brandId}/projects/{projectId} |
DELETE | brand editor | Forget a linked project (braaand unlink). |
/api/brands/{brandId}/projects |
GET | brand read | The projects that vendored this brand (braaand link): where each lives, which stack, the brand version it copied and how far behind it is. |
/api/brands/{brandId}/projects |
POST | brand editor | Register (or refresh) a linked project — the CLI's braaand link posts this. |
/api/brands/{brandId}/record-links/{linkId} |
PATCH | brand admin, user-only (requireUserBrandAccess) | Update a connected site. |
/api/brands/{brandId}/record-links/{linkId} |
DELETE | brand admin, user-only (requireUserBrandAccess) | Disconnect: the link goes and its token is revoked. |
/api/brands/{brandId}/record-links |
GET | brand admin (user auth only — brand tokens not accepted) | The brand's connected sites. |
/api/brands/{brandId}/record-links |
POST | brand admin (user auth only — brand tokens not accepted) | Connect a site. |
/api/brands/{brandId}/records/changes |
GET | brand read | Changes since a cursor. |
/api/brands/{brandId}/records/conflicts/{conflictId}/resolve |
POST | brand editor | Settle a conflict. |
/api/brands/{brandId}/records/conflicts |
GET | brand read | Open conflicts. |
/api/brands/{brandId}/records/push |
POST | brand editor | Push changes from the master site. |
/api/brands/{brandId}/records |
GET | brand read | Snapshot of the shared records. |
/api/brands/{brandId}/registry/{item} |
GET | brand read | The brand's shadcn REGISTRY — one registry-item.json per item, served at the URL shape the shadcn CLI's {name} template expands to. |
/api/brands/{brandId}/renders |
GET | brand read | List the brand's persisted renders with issuer + trigger metadata. |
/api/brands/{brandId} |
GET | brand read | Read the brand row plus your role on it. |
/api/brands/{brandId} |
PUT | brand editor | Rename or re-describe the brand. |
/api/brands/{brandId} |
DELETE | brand read | Delete the brand — owner only, or a current org admin for team brands. |
/api/brands/{brandId}/sets/{setId} |
GET | brand read | One Set with its rows. |
/api/brands/{brandId}/sets/{setId} |
PATCH | brand editor | Rename a Set, re-describe it, or REPLACE its rows (wholesale, normalized). |
/api/brands/{brandId}/sets/{setId} |
DELETE | brand editor | Delete a Set. |
/api/brands/{brandId}/sets/person |
GET | brand read | Resolve a person by name: ?q=<name> → { resolved, row | candidates }. |
/api/brands/{brandId}/sets/resolve |
POST | brand read | Resolve a For each source: { source } → { count, sample, warnings }. |
/api/brands/{brandId}/sets |
GET | brand read | List the brand's Sets, most recently updated first. |
/api/brands/{brandId}/sets |
POST | brand editor | Create a Set: { name, description?, rows? | csv? } → { set, warnings }. |
/api/brands/{brandId}/sites/{siteId}/deploy-targets |
GET | brand editor | Where this site can be deployed: the brand's connected sites (record links) that can take it, each with the Polyther address that opens the import, and when this site last lande… |
/api/brands/{brandId}/sites/{siteId}/export |
GET | brand read | Download a built site as a zip: format=react (a Next.js + Tailwind 4 + shadcn drop-in) or format=html (static pages + compiled CSS). |
/api/brands/{brandId}/sites/{siteId}/generate |
POST | brand editor | Generate the sitemap inline, or start the durable page fill. |
/api/brands/{brandId}/sites/{siteId}/package |
GET | brand read | The site as ONE document for a Polyther site (or any consumer with no Tailwind build): the site package — lib/sites/site-package.ts. |
/api/brands/{brandId}/sites/{siteId} |
GET | brand read | One site with its pages. |
/api/brands/{brandId}/sites/{siteId} |
PATCH | brand editor | Merge-save the site (optimistic concurrency via X-Doc-Version / body.version). |
/api/brands/{brandId}/sites/{siteId} |
DELETE | brand editor | Delete the site. |
/api/brands/{brandId}/sites/{siteId}/sections/{instanceId}/regenerate |
POST | brand editor | Re-fill one section with a direction, streaming the copy as it is written. |
/api/brands/{brandId}/sites |
GET | brand read | The brand's sites, newest first. |
/api/brands/{brandId}/sites |
POST | brand editor | Create a site. |
/api/brands/{brandId}/slack/bindings/{bindingId} |
DELETE | brand admin, user-only (requireUserBrandAccess) | unbind the channel. |
/api/brands/{brandId}/slack/bindings |
POST | brand admin, user-only (requireUserBrandAccess) | bind a channel to this brand. |
/api/brands/{brandId}/slack/channels |
GET | brand admin, user-only (requireUserBrandAccess) | channels the bot can see. |
/api/brands/{brandId}/slack/installations/{installationId} |
DELETE | brand admin, user-only (requireUserBrandAccess) | disconnect the workspace. |
/api/brands/{brandId}/slack |
GET | brand editor, user-only (requireUserBrandAccess) | installations + bindings for this brand. |
/api/brands/{brandId}/style-guide/diff |
GET | brand read | What changed in the brand's style guide between two versions — colours, fonts, tokens, tag and class rules, structure, motion — with the plain-terms summary lines. |
/api/brands/{brandId}/style-guide/import |
POST | brand editor | Body: exactly one of url | css | tailwind (+ optional filename; with url, optional pages — up to three more pages of the site). |
/api/brands/{brandId}/style-guide |
GET | brand read | The resolved style guide (summary + css.tailwind / css.plain). |
/api/brands/{brandId}/sync-manifest |
GET | brand read | One brand's sync manifest: every text artifact (brand.json, CLAUDE.md, dist/* token builds, guidelines/*.md) with full content, plus the asset list with server-computed local pa… |
/api/brands/{brandId}/template-suggestions |
GET | brand read | starter layouts for a fresh brand, given what the person says they make (?purposes=campaign,quote). |
/api/brands/{brandId}/templates/{templateId}/delete-group |
POST | brand editor | Removes a group from the template: drops every member element, deletes the group entry, and strips the group's id from any cluster's memberIds. |
/api/brands/{brandId}/templates/{templateId}/duplicate-group |
POST | brand editor | Deep-clones the source group's elements with fresh IDs, registers a new Group entry, and appends it to parentClusterId.memberIds. |
/api/brands/{brandId}/templates/{templateId}/duplicate |
POST | brand editor | Duplicate a brand template. |
/api/brands/{brandId}/templates/{templateId}/elements/{elementId} |
PATCH | brand editor | Element-level patch endpoint. |
/api/brands/{brandId}/templates/{templateId} |
GET | brand read | Read one brand template. |
/api/brands/{brandId}/templates/{templateId} |
PUT | brand editor | Merge-save the template (optimistic concurrency via X-Doc-Version). |
/api/brands/{brandId}/templates/{templateId} |
DELETE | brand editor | Delete the template (creatives cloned from it are untouched). |
/api/brands/{brandId}/templates/{templateId}/usage |
GET | brand read | Which creatives were cloned from this template (the pre-delete usage check). |
/api/brands/{brandId}/templates/discover |
GET | brand read | Agent-facing template discovery catalog: every template with its slots and constraints. |
/api/brands/{brandId}/templates |
GET | brand read | List the brand's templates — full rows by default, or ?summary=1 for { templates: TemplateSummary[] } picker rows with preview thumbs (theme-builder scratch filtered out). |
/api/brands/{brandId}/templates |
POST | brand editor | Create a template from scratch (name, plus optional elements / formats / variant). |
/api/brands/{brandId}/theme-builder |
POST | brand editor | open the brand's single Theme Builder doc rendered as variant, and return its templateId so the client can route into the editor. |
/api/brands/{brandId}/themes/{themeId}/preview |
GET | brand read | A theme's rendered specimen (dark or light side) — the durable preview row of kind "theme". |
/api/brands/{brandId}/themes/{themeId} |
PATCH | brand editor | partial update of a custom theme. |
/api/brands/{brandId}/themes/{themeId} |
DELETE | brand editor | remove a custom theme. |
/api/brands/{brandId}/themes |
GET | brand read | list every theme (the implicit Default + custom). |
/api/brands/{brandId}/themes |
POST | brand editor | create a custom theme. |
/api/brands/{brandId}/tokens/{tokenId} |
DELETE | brand admin (user auth only — brand tokens not accepted) | Revoke one brand token. |
/api/brands/{brandId}/tokens |
GET | brand admin (user auth only — brand tokens not accepted) | List the brand's tokens — prefix and role only, never the secret. |
/api/brands/{brandId}/tokens |
POST | brand admin (user auth only — brand tokens not accepted) | Mint a brand token ({ name, role, expiresInDays? }) — the bt_ secret is returned once. |
/api/brands/{brandId}/transfer |
POST | brand owner (user auth only — brand tokens not accepted) | Move a brand between pools: into a Team (shared org pool) or back to the owner's personal account. |
/api/brands/{brandId}/ui-pages/{pageId} |
GET | brand read | ONE page from the sections library — a whole one-pager composed from sections on alternating surfaces. |
/api/brands/{brandId}/ui-sections/{sectionId} |
GET | brand read | ONE section: ?format=tsx|html|both (default both) — the React component as-is, the static HTML twin, or both — with its classes, primitives, the one-line install and the css… |
/api/brands/{brandId}/ui-sections |
GET | brand read | The sections library — compact rows (id, family, label, blurb, the style-guide classes and shadcn primitives each uses, its registry URL) plus a css note saying where the styl… |
/api/brands/{brandId}/videos/jobs/{jobId} |
GET | brand read | Snapshot of a video job: status / phase / the finished clip + poster URLs / error; terminal once nothing more will change. |
/api/brands/{brandId}/videos/jobs/{jobId} |
PATCH | brand editor | Mark an element-clip job as applied — the editor's receipt that the clip is on the document (or was deliberately dropped). |
/api/brands/{brandId}/videos/jobs |
GET | brand read | List a creative's element-clip jobs that still need the editor's attention (?creativeId=). |
/api/brands/{brandId}/webhook-secret |
GET | brand admin | The brand's webhook signing secret, plus how to verify a delivery with it. |
/api/brands |
GET | user auth | The caller's brands — list them, or create an empty brand (bulk onboarding is POST /api/onboard). |
/api/brands |
POST | user auth | The caller's brands — list them, or create an empty brand (bulk onboarding is POST /api/onboard). |
Workflow Engine (workflows)
| Route | Method | Auth | What it does |
|---|---|---|---|
/api/brands/{brandId}/factory/crunch |
POST | brand editor | The "pre-run" the Crunch & match button kicks off: digest the (possibly long / messy) brief into ONE clean, structured brief + extracted goal / audience / tone / message, which … |
/api/brands/{brandId}/factory/drafts |
POST | brand editor | Give an unsaved canvas a home. |
/api/brands/{brandId}/factory/jobs |
GET | brand read | The live per-brand Workflow Engine rows — running jobs first, with status, phase, creatives, creator, attributed credit cost and a mini map of each run's graph. |
/api/brands/{brandId}/factory/recipes |
GET | brand read | The recipe shelf for the New workflow menu — built-in shapes plus the brand's saved graphs the viewer may see, each with a mini map of its graph. |
/api/brands/{brandId}/factory/run-build |
POST | brand editor | The canvas head Run. |
/api/brands/{brandId}/factory/workflows/{workflowId}/aiproduce-node |
POST | brand editor | Run the node's generations (reusing anything already finished). |
/api/brands/{brandId}/factory/workflows/{workflowId}/apply |
POST | brand editor | Run a terminal ACTION node (Delete / Board / Slack) in place: apply it to the creatives wired into it. |
/api/brands/{brandId}/factory/workflows/{workflowId}/edit-node |
POST | brand editor | In-place "Run edit" — the Edit node's interactive Run. |
/api/brands/{brandId}/factory/workflows/{workflowId}/foreach-node |
POST | brand editor | Interactive "Run for each" — the For each node's per-node Run. |
/api/brands/{brandId}/factory/workflows/{workflowId}/ideate-node |
GET | brand read | The node's latest session — what the config rail renders (concepts, judge scores, the current pick) — plus the node's latest ATTEMPT (lastRun). |
/api/brands/{brandId}/factory/workflows/{workflowId}/ideate-node |
POST | brand editor | Run the brainstorm for one Ideas node (always a fresh session). |
/api/brands/{brandId}/factory/workflows/{workflowId}/imagegen-node |
POST | brand editor | Run the Generate-image node's takes (reusing anything already finished). |
/api/brands/{brandId}/factory/workflows/{workflowId}/launch |
POST | brand editor | Run the CURRENT pipeline graph of an EXISTING workflow run DURABLY, server-side. |
/api/brands/{brandId}/factory/workflows/{workflowId}/log |
GET | brand read | The run's shareable log (markdown by default, ?format=json for structured data, ?io=1 to include each stage's exact model input/output). |
/api/brands/{brandId}/factory/workflows/{workflowId}/manifest |
GET | brand read | The workflow delivery manifest — the OUTBOUND surface for external orchestrators (Workflow Brain) and coding agents. |
/api/brands/{brandId}/factory/workflows/{workflowId}/materialize-seeds |
POST | brand editor | Materialize a Source node's picked seeds into THIS run, interactively. |
/api/brands/{brandId}/factory/workflows/{workflowId}/materialized |
GET | brand read | The exploded per-creative view of a run — produce expanded into one branch per creative, each branch's stages (copy/image/fit) joined with the step ledger. |
/api/brands/{brandId}/factory/workflows/{workflowId}/motion-node |
POST | brand editor | Interactive "Render motion" — the Motion node's per-node Run. |
/api/brands/{brandId}/factory/workflows/{workflowId}/pipeline |
PUT | brand editor | PUT — replace the run's authoring graph wholesale. |
/api/brands/{brandId}/factory/workflows/{workflowId}/pipeline |
PATCH | brand editor | PATCH — apply a DELTA to the stored graph (add / set / remove / connect / disconnect), instead of replacing it wholesale. |
/api/brands/{brandId}/factory/workflows/{workflowId}/reconstruct-node |
POST | brand editor | Run the Make-editable node interactively over the wired creatives. |
/api/brands/{brandId}/factory/workflows/{workflowId}/rerun |
POST | brand editor | Addressable per-stage re-run — the heart of "fine tune a creative run". |
/api/brands/{brandId}/factory/workflows/{workflowId}/research-node |
POST | brand editor | Interactive "Run research" — the Research node's per-node Run. |
/api/brands/{brandId}/factory/workflows/{workflowId} |
GET | brand read | hydrate the run status page. |
/api/brands/{brandId}/factory/workflows/{workflowId} |
PATCH | brand editor | Rename: { title: string } — an empty/whitespace title clears the override so the display name falls back to the brief-derived workflowTitle. |
/api/brands/{brandId}/factory/workflows/{workflowId} |
DELETE | brand editor | ?creatives=delete also deletes the run's creatives; ?creatives=keep (default) deletes only the run row and leaves the creatives in the gallery, grouped by their workflow label. |
/api/brands/{brandId}/factory/workflows/{workflowId}/route |
POST | brand editor | In-place "Run route" — resolve a Route node's yes/no QUESTION rules for a set of the run's creatives RIGHT NOW (render + vision pass), caching each answer as an annotation so th… |
/api/brands/{brandId}/factory/workflows/{workflowId}/score |
POST | brand editor | In-place "Run score" — render + critique a set of the run's creatives RIGHT NOW (e.g. |
/api/brands/{brandId}/factory/workflows/{workflowId}/stream |
GET | brand editor | Server-sent events stream for workflow pipeline progress. |
/api/brands/{brandId}/factory/workflows/{workflowId}/translate-node |
POST | brand editor | Interactive "Run translate" — the Translate node's per-node Run. |
/api/brands/{brandId}/factory/workflows/{workflowId}/variation |
POST | brand editor | In-place "Run variation" — clone + transform the run's base creatives on an axis, minting variants RIGHT NOW on the existing run (no full pipeline rebuild). |
/api/brands/{brandId}/factory/workflows/{workflowId}/video-node |
POST | brand editor | Interactive "Run video" — the Video node's per-node Run. |
/api/brands/{brandId}/factory/workflows/{workflowId}/videogen-node |
POST | brand editor | Run the Generate-video node's takes (reusing anything already finished). |
/api/brands/{brandId}/factory/workflows |
POST | brand editor | Create a workflow run AND start its durable workflow (the executor runs independent of any viewer; the run status page's SSE stream reads its progress). |
Rendering
| Route | Method | Auth | What it does |
|---|---|---|---|
/api/render/batch |
POST | brand read via body brandId + rate limit | Batch-render a list of creatives × their formats. |
/api/render/motion |
POST | brand read (html) / editor (mp4) via body brandId + rate limit | Export a document's motion as an animated HTML page (inline) or queue an mp4 render per format (202 + jobId). |
/api/render |
POST | brand read via body brandId + rate limit | Render any persisted braaand document (creative, brand template, or system template) to PNG. |
/api/renders/{renderId} |
GET | public | Download a persisted render PNG. |
Previews
| Route | Method | Auth | What it does |
|---|---|---|---|
/api/previews/{tier}/{id}/{filename} |
GET | brand read OR dt_ share token (?t=) | The stable preview URL — a document's CURRENT preview, served as a 302 to the CDN. |
/api/previews/refresh |
POST | brand read per key OR dt_ share token | Manual "regenerate preview" — the refresh buttons. |
/api/previews/status |
POST | brand read per key OR dt_ share token | Batched preview status — the ONE request a page makes for every card that has no picture yet. |
/api/previews/work |
POST | HMAC-signed self-request (PREVIEW_WORKER_SECRET) | The preview worker. |
System templates
| Route | Method | Auth | What it does |
|---|---|---|---|
/api/system-templates/{templateId}/elements/{elementId} |
PATCH | admin | Element-level patch endpoint for system templates. |
/api/system-templates/{templateId}/instantiate |
POST | brand editor via body brandId | Note: this route gets brandId from the request body, not the URL — withBrandAccess is URL-params-only by design, so the access check stays manual here. |
/api/system-templates/{templateId} |
GET | public | One system template — public read (catalog), admin merge-save and delete. |
/api/system-templates/{templateId} |
PUT | admin | One system template — public read (catalog), admin merge-save and delete. |
/api/system-templates/{templateId} |
DELETE | admin | One system template — public read (catalog), admin merge-save and delete. |
/api/system-templates |
GET | public | System template catalog — public list (the picker reads it), admin create (full body or scaffoldFrom an existing template). |
/api/system-templates |
POST | admin | System template catalog — public list (the picker reads it), admin create (full body or scaffoldFrom an existing template). |
System assets
| Route | Method | Auth | What it does |
|---|---|---|---|
/api/system-assets/{id} |
GET | public | System asset serving route. |
/api/system-assets/{id} |
PATCH | admin | Update a DB-backed system asset's fields (admin-only). |
/api/system-assets/{id} |
PUT | admin | Replace a DB-backed system asset's bytes, keeping its id / URL / name (admin-only). |
/api/system-assets/{id} |
DELETE | admin | Delete a DB-backed system asset (admin-only). |
/api/system-assets/{id}/usage |
GET | admin | Which system templates use this system asset. |
/api/system-assets/analyze |
POST | admin | Analyze an admin-library upload with the vision LLM and return suggested metadata (name, tags, content description, POI, brightness…) for the upload form. |
/api/system-assets |
GET | public | Shared admin/system asset library listing endpoint. |
/api/system-assets |
POST | admin | Upload an asset into the shared admin library. |
Onboarding
| Route | Method | Auth | What it does |
|---|---|---|---|
/api/onboard/blob-upload |
POST | user auth | Client-upload token route for in-app onboarding. |
/api/onboard/from-files |
POST | user auth | Streamed in-app onboarding from dropped brand files (guideline PDF, logos, fonts) — analyze, then create the brand; pauses for a choice when the name is a brand the caller alrea… |
/api/onboard |
POST | user auth | Bulk brand onboarding — brand + config + assets (+ optional website analysis) in one call; shared with the MCP onboard_brand tool. |
/api/onboarding/complete |
POST | Clerk session (writes Clerk user metadata) | Mark the signed-in user's Clerk onboarding metadata complete (intent / client survey). |
Account (me)
| Route | Method | Auth | What it does |
|---|---|---|---|
/api/keys/{keyId} |
DELETE | user auth | Revoke an API key. |
/api/keys |
GET | user auth | List the authenticated user's API keys. |
/api/keys |
POST | user auth | Create a new API key. |
/api/me/billing |
GET | user auth | Billing status for the current viewer. |
/api/me/nav |
GET | Clerk session (dual-identity nav payload) | Navigation payload for the global topbar: the viewer's brands grouped by the pool that pays for them (their own account, plus each Team), and whether they're a platform admin (d… |
/api/me |
GET | user auth | Return the authenticated identity. |
/api/me/teams |
GET | user auth | Teams the viewer may create a brand in. |
Auth (device flow)
| Route | Method | Auth | What it does |
|---|---|---|---|
/api/auth/device/code |
POST | device auth flow | Public endpoint. |
/api/auth/device/token |
POST | device auth flow | Public endpoint. |
/api/auth/device/verify |
POST | device auth flow | Authenticated endpoint. |
Share (delivery links)
| Route | Method | Auth | What it does |
|---|---|---|---|
/api/share/board/{token}/approval |
POST | dt_ share token (capability URL) | The client's verdict on a delivered creative — the SECOND approval (the team already curated internally; this is the external sign-off). |
/api/share/board/{token}/comments |
POST | dt_ share token (capability URL) | PUBLIC comment ops for a share-link visitor. |
/api/share/board/{token} |
GET | dt_ share token (capability URL) | PUBLIC delivery manifest — the outbound surface for a non-account consumer holding a run's read-only delivery token (minted via .../runs/[workflowId]/share). |
Misc
| Route | Method | Auth | What it does |
|---|---|---|---|
/api/downloads/skill |
GET | public | Download the packaged Claude skill (public — it's the same file the learn page links; rebuilt by pnpm build:skill). |
/api/images/capture |
POST | user auth | Screenshot a URL with no browser around it — full page by default, cookie banners and popups dismissed, lazy images loaded, animations held still so the same page captures the s… |
/api/images/convert |
POST | user auth | Convert / compress / resize images (deterministic sharp — no LLM, no credits) and hand back short-lived converted/ download URLs. |
/api/images/edit |
POST | user auth | Apply a full image edit (crop / flip / rotate / trim / exact-resize / adjust / sharpen / blur / chroma-key / region erase-or-fill / flatten / convert) and either save the result… |
/api/images/expand |
POST | user auth | Fill the empty area around a photo with a seamless continuation of it (credit-metered uncrop / outpaint). |
/api/images/generate |
POST | user auth | Generate an image from a prompt, AI-edit a source image guided by a prompt + optional mask, or cut the subject out of one (credit-metered; deterministic post-op + save-to-librar… |
/api/images/jobs |
GET | user auth | List the caller's active + recently-settled image-gen jobs (newest first). |
/api/images/jobs/run |
POST | HMAC-signed self-request (durable image-gen worker) | Detached background worker for asynchronous image jobs. |
/api/images/select |
POST | user auth | Magic-wand SELECTION: flood from a point (or inward from the borders) and return the selected region as a run-length mask, without touching the image. |
/api/images/stitch |
POST | user auth | Glue a run of page screenshots into one tall image, finding the overlap between them rather than being told it. |
/api/knowledge/{knowledgeId}/distill |
POST | user auth | Distill one knowledge into sections + optional lenses. |
/api/knowledge/{knowledgeId} |
GET | user auth | Read one knowledge (distilled sections + lenses included). |
/api/knowledge/{knowledgeId} |
PATCH | user auth | Update the human-editable metadata: title, tags, docType, topics, author, sourceWork. |
/api/knowledge/{knowledgeId} |
DELETE | user auth | Delete a knowledge (row + its PDF blob when it has one). |
/api/knowledge |
GET | user auth | List every knowledge the viewer can see (their teams' shared pools + their personal one), newest first. |
/api/knowledge |
POST | user auth | Ingest a knowledge. |
/api/models/vendors |
GET | user auth | Which model vendors are currently enabled — the node canvas reads this to filter its model pickers (the same boards-style best-effort fetch). |
/api/openapi.json |
GET | public (machine-readable API contract) | machine-readable OpenAPI 3.1 production contract. |
/api/orgs/{orgId}/domains/{domain} |
DELETE | user auth | Remove one auto-join domain from the team. |
/api/orgs/{orgId}/domains |
GET | user auth | Domain auto-join is a Team-tier capability. |
/api/orgs/{orgId}/domains |
POST | user auth | Team email-domain auto-join allowlist. |
/api/playground/media/image |
POST | admin | Generate one image on the media bench and archive it under playground/media/. |
/api/playground/media |
GET | admin | List the media bench's archived generations, newest first. |
/api/playground/media |
DELETE | admin | Delete one archived generation (meta + artifact + reference copies). |
/api/playground/media/video |
POST | admin | Submit one video generation job on the media bench. |
/api/playground/media/video |
GET | admin | Poll a media-bench video job; when the vendor reports completion, download the clip and archive it under playground/media/, then return the record. |
/api/presentation/analytics |
GET | admin | List recent sessions (newest first, capped), optionally ?linkId= filtered. |
/api/presentation/config |
GET | admin | Read the stored deck config (null when never saved). |
/api/presentation/config |
PUT | admin | Replace the stored slide order: { slides: [{ id, hidden }] } → { ok }. |
/api/presentation/links/{linkId} |
PATCH | admin | Patch a link: { name?, archived?, internal? } → { link }, 404 on unknown id. |
/api/presentation/links/{linkId}/sessions |
DELETE | admin | Wipe the link's sessions → { deleted }, 404 on unknown id. |
/api/presentation/links |
GET | admin | List all links, newest first, with per-link session counts. |
/api/presentation/links |
POST | admin | Create a link: { name, slug? } → 201 { link }, 409 when the slug is taken. |
/api/presentation/track |
POST | public | Record a cumulative dwell snapshot for one viewing session. |
/api/references/{referenceId}/analyze |
POST | user auth | Analyze one reference into its structured record. |
/api/references/{referenceId} |
GET | user auth | Read one reference (full analysis record included). |
/api/references/{referenceId} |
PATCH | user auth | Update the human-editable metadata: starred, note, tags. |
/api/references/{referenceId} |
DELETE | user auth | Delete a reference (row + both blobs). |
/api/references |
GET | user auth | List every reference the viewer can see (their teams' shared libraries + their personal one). |
/api/references |
POST | user auth | Ingest a reference image. |
/api/resolve/{entityId} |
GET | user auth | Resolve any braaand entity id to its kind, brand, and app URL. |
/api |
GET | public | Agent-facing prose index of the whole REST API — the onboarding text an LLM reads when it first connects. |
/api/settings/org/{orgId}/jobs |
GET | org member (session + membership check) | Live poll feed for the team (org) Workflow Engine jobs queue. |
/api/slack/events |
POST | Slack request signature (v0 HMAC over the raw body) | Slack Events API (url_verification + event_callback). |
/api/slack/oauth/callback |
GET | signed OAuth state (HMAC, 15-min TTL) | complete the workspace connect. |
/api/slack/oauth/start |
GET | brand admin, user-only (starts the Slack OAuth round trip) | begin the workspace connect. |
/api/sync/report |
POST | brand editor | Record the caller's local sync state (root, machine, CLI version) and/or the Polyther site the brand was published to — a partial update; root is optional when sites is pres… |
/api/sync/shared |
GET | user auth | The brand-agnostic layer of the synced folder: root CLAUDE.md, the preview shell chrome, Braaand house motion presets, and vendored-script URLs. |
/api/sync/status |
GET | user auth | Server side of braaand sync status: every accessible brand's sync metadata (identity version, visual hash, slug) + the caller's last-reported local sync state. |
/api/videos/animate |
POST | user auth | The creative's format whose crop to animate (default: its first). |
/api/videos/generate |
POST | user auth | AI video generation — animate a finished creative. |
/api/videos/jobs |
GET | user auth | List the caller's active + recently-settled video jobs (newest first). |
/api/workflows/running |
GET | user auth | List the caller's running + recently-settled pipeline runs (newest first). |