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
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | ✓ | 1–200 chars. |
email | string | ✓ | Validated server-side. Up to 320 chars. |
message | string | ✓ | 1–10,000 chars. |
phone | string | — | Up to 40 chars. Free-text — no formatting enforced. |
subject | string | — | Up to 200 chars. |
source | string | — | Up to 500 chars. Where the submission originated — page path (/contact), campaign label, anything you want surfaced in the cms inbox row. |
metadata | object | — | Free-form JSON. Round-tripped verbatim into the cms's submission detail view. |
Response
{
"id": "sub_2N5dRkQp",
"createdAt": "2026-05-30T12:34:56.789Z"
}| Field | Type | Notes |
|---|---|---|
id | string | Submission record id. Render it in your thank-you state if you want users to reference it. |
createdAt | string | ISO-8601 timestamp the cms saw the submission. |
Errors
400 Bad Request— validation failed (missing required field, invalid email, oversize message). The body includesclass-validator's field-level error list.401 Unauthorized— missing or invalidX-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.