Agents

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/api

Building an agent? Pick the shortest path before hand-rolling HTTP:

  1. MCP — connect https://mcp.braaand.ai/mcp and 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.
  2. The CLI — npm i -g braaand for 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.
  3. The Claude skill — the packaged braaand playbook for Claude Code. See Claude skill.
  4. This page + GET /api — for your own HTTP wrapper. GET /api returns 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 (let role, 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.txt indexes everything with deep links.

Get a key

  1. Go to Settings → Profile → API keys and click New key. Copy the ae_… value right away — it's shown once and stored hashed.
  2. Or from the terminal: npm i -g braaand && braaand login walks 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/brands

A 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.png

Producing 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. 401 bad or missing credentials, 403 not allowed, 404 not found, 400 validation, 402 out of credits (the body carries a machine-readable code), 507 storage quota exceeded, 429 rate limited (with a Retry-After header), 409 edit conflict or "run is still building".
  • Errors are JSON: { "error": "human-readable message", "code": "machine_readable_when_relevant" }. Malformed request bodies answer 400 { "error": "invalid_json" }; schema failures answer 400 { "error": "validation", "details": [{ "path", "message" }] }.
  • Edit conflicts. Templates and creatives carry a version number. Send the version your edits are based on in the X-Doc-Version header (or as version in the body) and the save is compare-and-set: if someone else saved first you get a 409 with the currentVersion, 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), and 16x9 (1200×628) by default; each document carries its own list, so read formats off the doc rather than assuming.
  • Ids are stable strings — creatives are prefixed crv_, keys ae_, brand tokens bt_, share links dt_.
  • 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.
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).