Email Builder API
Drag-and-drop email template builder and asset management Base path:/api/v1/messages/email-builder
Endpoint count: 5
title: “Errors worth branching on” description: “Per-endpoint failure templates matching the envelope — what actually fires, what to retry, what to surface to the operator.”
Errors worth branching on
These five failures cover the template save (POST /api/v1/messages/email-builder/save), which the visual editor autosaves against. Each block below is a full{ error, meta } envelope as the API returns it, and the matrix at the bottom answers retry vs surface for the same five classes. For the platform-wide decision table these branches plug into, see the error handling guide.
401 — Unauthorized
401 on this page is the bearer key failing before the route ran — it never means the resource is wrong. Rotate the key or re-mint the scoped token; retrying the same request changes nothing.
403 — Forbidden
403 means the key authenticated but the operation is gated by scope — check the key’s scopes on the developer page; a 403 is never a data-not-found shape.
422 — Schema
422 means the payload did not match the request schema — branch on error.details.field and resave against the head version after re-fetching the template instead of blind-retrying the same body.
429 — Rate
Retry-After header and error.details.retry_after are both set on every 429 — resend the SAME request after the lower of the two.
409 — Conflict
60-second retry matrix
List saved email-builder templates for the tenant
GET /api/v1/messages/email-builder/listemail), freshest-first, each with its editable blocks array, rendered plain-text body, previewText, and metadata — the shape the dashboard’s ‘Load template’ picker re-hydrates the builder canvas from. Cursor-paginated via the opaque cursor value returned in pagination.cursor; limit defaults to 50 (max 50). An empty tenant returns an empty data list.
string
—
any
—
string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to
true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.Transpile MJML to HTML email
POST /api/v1/messages/email-builder/mjml/renderhtml plus an errors list that reports unsupported components or structural problems without failing the request, and the extracted previewText. Nothing is persisted and no email is sent.
string
Stripe-style idempotency token. Pass a stable, client-generated value (1-255 chars) to dedupe retries on transient timeouts. The same key+credential+path replays the original response for 24h on 2xx (5min on 4xx, 30s on 5xx). Returns 409 if a concurrent request with the same key is already in flight; replayed responses include the
Idempotency-Replay: true response header.string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to
true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.string
required
The MJML source document to transpile, as a complete
<mjml>…</mjml> markup string (1–262,144 characters / 256 KiB). Unsupported components and structural problems are reported in the response errors array without failing the request, so you still receive best-effort HTML.Render email template to HTML
POST /api/v1/messages/email-builder/rendername plus an ordered blocks array — into a complete, cross-client HTML email document. The response carries both the static HTML and an AMP-for-Email (text/x-amp-html) alternative built from the same blocks, plus the template id (templateId) so the caller can correlate a render with a later save. Nothing is persisted and no email is sent; pair with /api/v1/messages/email-builder/save to store the definition or /api/v1/messages/email-builder/send-test to deliver a proof.
string
Stripe-style idempotency token. Pass a stable, client-generated value (1-255 chars) to dedupe retries on transient timeouts. The same key+credential+path replays the original response for 24h on 2xx (5min on 4xx, 30s on 5xx). Returns 409 if a concurrent request with the same key is already in flight; replayed responses include the
Idempotency-Replay: true response header.string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to
true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.Save email template
POST /api/v1/messages/email-builder/savename, ordered blocks, optional previewText / metadata, and optional id — for later editing in the drag-and-drop builder. The content is stored as a { body, blocks } envelope: the plain-text body serves list snippets and send-time fallbacks, and blocks re-hydrates the builder canvas. Re-saving the same name without an id updates the existing template in place; passing an id that collides with a different template’s name returns 409 TEMPLATE_NAME_ALREADY_EXISTS. Rendering is not part of this call — use /api/v1/messages/email-builder/render for HTML.
string
Stripe-style idempotency token. Pass a stable, client-generated value (1-255 chars) to dedupe retries on transient timeouts. The same key+credential+path replays the original response for 24h on 2xx (5min on 4xx, 30s on 5xx). Returns 409 if a concurrent request with the same key is already in flight; replayed responses include the
Idempotency-Replay: true response header.string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to
true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.Send test email
POST /api/v1/messages/email-builder/send-testblocks and sends a test email to to with the subject [Test] <templateName>, and records the send in the tenant’s message history (visible in the dashboard Messages tab) with a test-sent status. The send is BILLED at the channel rate (debited before the provider send — a real paid MT through the shared Resend account), rate-limited per tenant (5/minute), and tenants on the platform’s shared email account must pass the same gates as production sends: the recipient must be a verified org member, the email feature must not be suspended, and a daily test-send cap applies. Requires an explicit, valid to address.
string
Stripe-style idempotency token. Pass a stable, client-generated value (1-255 chars) to dedupe retries on transient timeouts. The same key+credential+path replays the original response for 24h on 2xx (5min on 4xx, 30s on 5xx). Returns 409 if a concurrent request with the same key is already in flight; replayed responses include the
Idempotency-Replay: true response header.string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to
true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.