Brandfine Docs
REST API

POST /external/submissions

Ingest a contact-form submission for this workspace. Appears in the cms's Submissions inbox.

Accepts a contact-form submission and routes it to the workspace's Submissions inbox in the cms. The submitter never sees Brandfine — your consumer site shows the form, posts to this endpoint, and renders its own thank-you / error state.

POST /external/submissions
X-Api-Key: bk_live_xxx
Content-Type: application/json

{
  "name": "Alex Liu",
  "email": "alex@example.com",
  "message": "I'd like a demo.",
  "phone": "+1 555 0100",
  "subject": "Demo request",
  "source": "/contact",
  "metadata": { "utm_source": "twitter", "utm_campaign": "spring-2026" }
}

Fields

FieldTypeRequiredNotes
namestring1–200 chars.
emailstringValidated server-side. Up to 320 chars.
messagestring1–10,000 chars.
phonestringUp to 40 chars. Free-text — no formatting enforced.
subjectstringUp to 200 chars.
sourcestringUp to 500 chars. Where the submission originated — page path (/contact), campaign label, anything you want surfaced in the cms inbox row.
metadataobjectFree-form JSON. Round-tripped verbatim into the cms's submission detail view.

Response

{
  "id": "sub_2N5dRkQp",
  "createdAt": "2026-05-30T12:34:56.789Z"
}
FieldTypeNotes
idstringSubmission record id. Render it in your thank-you state if you want users to reference it.
createdAtstringISO-8601 timestamp the cms saw the submission.

Errors

  • 400 Bad Request — validation failed (missing required field, invalid email, oversize message). The body includes class-validator's field-level error list.
  • 401 Unauthorized — missing or invalid X-Api-Key.

CORS

Lives under /external/*, so it inherits the permissive CORS — any origin may POST with Content-Type: application/json + X-Api-Key.

SDK

import { createBrandfineClient, BrandfineApiError } from '@brandfine/client'

const bf = createBrandfineClient({
  baseUrl: process.env.BRANDFINE_API_URL!,
  apiKey: process.env.BRANDFINE_API_KEY!,
})

try {
  const { id, createdAt } = await bf.submissions.create({
    name: form.name,
    email: form.email,
    message: form.message,
    source: window.location.pathname,
  })
  // success — render thank-you state
} catch (err) {
  if (err instanceof BrandfineApiError && err.status === 400) {
    // surface field errors from err.body
  } else {
    // network / 5xx
  }
}

Where to view incoming submissions

CMS sidebar → Forms → Submissions. The inbox shows every submission for every workspace in the current team, with an unread badge in the sidebar. Per-team retention + email notifications are configured per-workspace under the workspace's settings.

On this page