Skip to main content

Brand kits (REST)

Full CRUD-ish lifecycle for brand kits. All endpoints under /v1/brand-kits.

Endpoints

Default kit

The first brand kit created for a team becomes the default automatically. POST /v1/tasks with no brand_kit_id uses the default. At most one default per team. The default is server-managed — there is no is_default field you can PATCH; the user changes defaults in the Moda app UI.

List

default_theme_canvas_id is the prefixed cvs_… ID of the kit’s saved default slides theme canvas (null if none). Returned on reads and writable via PATCH (see below). Fresh-canvas design tasks auto-apply it when present. Cursor-paginated; iterate with ?cursor=. See pagination.md.

Create from URL

Server scrapes the URL via Firecrawl and extracts colors, fonts, logos, tone, values, aesthetic. Takes 10–30 seconds — a legitimate case for Prefer: wait=30:
Returns the created brand-kit record (same shape as list items). URL accepts bare domain (stripe.com) or full URL (https://stripe.com). Cached — re-calling with the same URL returns the cached result quickly. If the URL can’t be scraped (blocked by robots, 404, login-required): 422 scraping_user_error.

Update (partial)

Pass only the fields to change. Omitted fields keep their current values. Array fields replace wholesale. Passing colors overwrites the entire array — not a merge. To add one color, fetch the existing array, append, and PATCH the full list:
Same rule for fonts, brand_values, brand_aesthetic, brand_tone_of_voice. Setting the default theme canvas. PATCH default_theme_canvas_id with a cvs_… ID (a bare UUID is also accepted) to point the kit at a slides theme canvas; send null to clear it:
The ID must reference a canvas with template_type='theme' on the same team — anything else returns 400 invalid_theme_canvas. Omitting the field leaves the current value unchanged. Returns the updated record.

Add images (logos / references / assets)

Requires an existing file_id from POST /v1/uploads. Attaches the uploaded file to the kit in the named role. Role here is about the kit (what this image represents in the brand) — different from the role field on task attachments (source / reference / asset / import). Returns the updated brand-kit record.

Delete

Returns 204 No Content. Soft delete — historical tasks that referenced this kit continue to show it in their audit record. New design tasks with brand_kit_id pointing at a deleted kit get 404 not_found. If the deleted kit was the team’s default, there is no new default automatically. The team operates brand-kit-less until another kit is promoted (in the app UI) or a new kit is created.

In-task usage

Pass brand_kit_id explicitly on POST /v1/tasks to override the default:
Or skip_brand_kit: true to apply no kit:
skip_brand_kit overrides brand_kit_id when both are present.

Common wrong guesses

  • Merging array updates client-side without reading first. You’ll overwrite the kit’s colors / fonts with just the new entries. Always read, append, PATCH.
  • Treating is_default as writable. It’s server-managed. Default changes happen in the app UI.
  • Using POST /v1/brand-kits without Prefer: wait and blocking on the response. The HTTP call returns the completed kit, but it took 10–30s — budget accordingly.
  • Passing brand_kit_id for a deleted kit. 404. Check the kit exists before submitting the task.
  • Mixing up the task-attachment role and the brand-kit-image role. Task role is source / reference / asset / import. Brand-kit image role is logo / reference / asset. Similar words, different values.
  • Pointing default_theme_canvas_id at a deck instead of a theme. It must be a template_type='theme' canvas on the same team, not a regular design/deck canvas. Anything else is 400 invalid_theme_canvas.

Upstream