Parse a raw CSV string and upsert the rows as contacts (≤ 1000). By default each column header maps to the custom field its name folds to, the same camelCase name POST /v1/contacts stores (Plan → plan, Team Size → teamSize); email is required. A header that spells a core field, ignoring case, spaces, _ and -, or whose field key equals it (First.Name), maps to it: Email, First Name, Last Name and Subscribed fill email, firstName, lastName and subscribed. Pass mapping to remap single columns; the columns it leaves out keep their default mapping, "" leaves a column out, and a key that names no column is a 400. Two columns that land on one custom field (plan,Plan: names fold as on POST /v1/contacts) are a 422 FIELD_NAME_COLLISION before any row is read: map one to another name or leave it out with "". A core field that mapping fills is filled from that column alone: another column whose default would fill it is left out with a CSV_COLUMN_IGNORED warning. Rows with a missing/invalid email are SKIPPED (counted in summary.skipped), not errored; disposable-domain rows are imported with validationStatus: "risky" (deliverable but flagged). Returns the same { summary, fieldsCreated, errors, warnings } as batch-create plus importId — 207 when some rows fail. The batch is listed in Import History under fileName (optional), and each contact it writes carries importId until a later import touches it (filter on it to list them; deleting the import in the app removes the contacts it created). For rows you already hold as JSON, use POST /v1/contacts/import.
CSV cells are text: a column mapped onto an EXISTING field is coerced to that field’s type (dates → epoch ms, 1,234 → 1234, yes/no → booleans), and a cell that cannot be coerced ($49 in a number column) fails ITS row with a per-row errors[] entry (code: FIELD_TYPE_MISMATCH, field) while the other rows still land. A converted cell adds a warnings[] entry (code: FIELD_TYPE_COERCED, field, from, to); a date written to a date field is not reported. An undeclared column is created as a string field unless every value is an ISO date (→ date); predeclare number / bool columns with POST /v1/fields. A column whose field Brew manages (Created At, Validation Status) is not imported and adds a warnings[] entry (code: CSV_COLUMN_IGNORED, field names the column).
A date column is read in ONE day/month order: the order its own dates prove (a day over 12 anywhere in the column, 13/04/2026), else dateOrder (day_first reads 03/04/2026 as 3 April, month_first as 4 March), else month/day with a warnings[] entry (code: DATE_ORDER_ASSUMED, field). Dotted dates (03.04.2026) are day-first. ISO (2026-04-03), Unix seconds or milliseconds, month names (3 Apr 2026), year-first (2026/04/03) and compact (20260403) dates need no order. Convert to YYYY-MM-DD to be unambiguous.
A subscribed column reads true/false and ESP status words (unsubscribed, cleaned, blocklisted, transactional, active, …). An opt-out unsubscribes the contact, new or existing (with onConflict: "skip" an existing contact is left unchanged, and its CONTACT_EXISTS_SKIPPED warning says so). A word that is not a subscription status (maybe) fails its row (code: FIELD_TYPE_MISMATCH, field: subscribed) instead of importing the contact subscribed. A subscribed value only applies to new contacts: a row that asks to re-subscribe a contact who opted out keeps its other fields and adds a warnings[] entry (code: RESUBSCRIBE_SKIPPED, email).
Two opt-in modes. dryRun: true returns the response this import would return (summary, errors, row warnings, fieldsCreated as fields it would create) with dryRun: true and no importId, and writes nothing: no contacts, field definitions or Import History entry; validate is not run and nothing is charged. Insert vs update is decided by the same address match the write uses, so a real run right after returns the same counts. onConflict: "skip" only creates missing contacts: each existing contact is left unchanged (an opt-out row included), counted in summary.skipped with a CONTACT_EXISTS_SKIPPED warning naming its row. Either way inserted + updated + failed + skipped = total. A dry run cannot foresee failures that only happen while writing (a concurrent change, a database refusal), so the real run can still fail where the preview succeeded. With validate: true, inline checks are still metered per submitted row, rows skip left alone included; a request that leaves no address to check is not charged.
The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise 400 BRAND_ID_REQUIRED — there is no default brand); list ids with GET /v1/brands. Brand-scoped credentials may omit it, and sending a different brand returns 403 BRAND_SCOPE_MISMATCH. A brand outside your organization returns 404 BRAND_NOT_FOUND.
Optional deliverability check on ingestion. When true, each imported address is validated with the provider and the verdict is saved to the contact’s validationStatus. Imports of at most 100 submitted CSV data rows validate inline, metered at 2 credits per submitted row on a successful response, including skipped rows and repeated addresses. Larger imports write first and use a background validation workflow billed per address as it runs; validationJobId is returned when a job is queued. The job skips unsubscribed, suppressed and recently validated addresses, and a VALIDATION_SKIPPED warning gives the counts; when every address is skipped no job is queued and validationJobId is absent.
Order for a date column whose dates read either way (03/04/2026): day_first is 3 April, month_first 4 March. A day over 12 in the column overrides it. Default month-first, with a DATE_ORDER_ASSUMED warning.
Name this batch is listed under in Import History (usually the source file name, e.g. customers.csv), also stamped on every contact it writes as csvFileName. A path keeps only its last segment.
When true, returns what this import would return and writes nothing: no contacts, fields, Import History entry or importId; validate is skipped and nothing is charged.
upsert (default) updates existing contacts; skip only creates missing ones, leaving each existing contact unchanged (counted in summary.skipped, with a CONTACT_EXISTS_SKIPPED warning).
This batch's Import History id. Each contact it wrote carries it as importId until a later import touches that contact, so a contact filter on importId lists them. Absent on a dry run.
Present on a dry run: the counts say what the import would do, and nothing was written.
Available options:
true
Was this page helpful?
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Brew Help Docs","colors":{"primary":"#FF772D","light":"#FF772D","dark":"#FF772D"},"logo":{"light":"https://mintcdn.com/brew-796f053a/QjuRdMJynrgWDqeo/logo/lightmode.svg?fit=max\u0026auto=format\u0026n=QjuRdMJynrgWDqeo\u0026q=85\u0026s=5e906ff65142dc905a773e7747b47816","dark":"https://mintcdn.com/brew-796f053a/QjuRdMJynrgWDqeo/logo/darkmode.svg?fit=max\u0026auto=format\u0026n=QjuRdMJynrgWDqeo\u0026q=85\u0026s=d9aa0d94ceaaf92451334849952286c9","href":"https://brew.new/"},"favicon":"https://mintcdn.com/brew-796f053a/QjuRdMJynrgWDqeo/favicon.svg?fit=max\u0026auto=format\u0026n=QjuRdMJynrgWDqeo\u0026q=85\u0026s=bb65587bb488372fc3a5faa7a6b4d2fe","appearance":{"default":"system","strict":false},"background":{"color":{"light":"#f7f7f7","dark":"#262624"}},"navbar":{"links":[{"href":"https://cal.com/team/brewdotnew/brew-demo","label":"Talk with founders"}],"primary":{"type":"button","label":"Log In","href":"https://brew.new/sign-in"}},"footer":{"socials":{"website":"https://www.brew.new","youtube":"https://www.youtube.com/@brewdotnew","twitter":"https://x.com/brewdotnew","linkedin":"https://www.linkedin.com/company/brewdotnew"}},"search":{"prompt":"Ask any question about Brew"},"seo":{"metatags":{"og:image":"https://docs.brew.new/images/og/default.png","description":"Brew is the AI-native email platform for modern teams and AI agents. Describe the email and Brew designs it on brand, builds the audience, and sends it.","keywords":"AI email marketing, Brew, AI-native email platform, on-brand email, email automations, email analytics, AI agents, MCP email server","robots":"index, follow"},"indexing":"all"},"fonts":{"family":"Inter"},"contextual":{"options":["copy","view","claude","chatgpt","grok","perplexity","mcp","cursor","vscode","download-spec"],"display":"header"},"styling":{"latex":true},"navigation":{"global":{},"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"brew-796f053a","hasAudioNarration":false,"actualSubdomain":"brew-796f053a","customDomains":["docs.brew.new"],"gitSource":{"type":"github","owner":"getbrew","repo":"docs","deployBranch":"main","contentDirectory":"","isPrivate":true,"mountPath":"","label":""},"feedback":{"thumbs":true,"edits":true,"issues":true},"entitlements":{"AI_CHAT":{"status":"ENABLED"},"WEB_MCP":{"status":"ENABLED"},"NARRATION":{"status":"ENABLED"}},"buildId":"6aee1463523750835f01043f","clientVersion":"0.0.4087","searchFilterCounts":[{"language":"default","tag":"Developers","count":175},{"language":"default","tag":"Public API v1","count":126},{"language":"default","tag":"Changelog","count":86},{"language":"default","tag":"Docs","count":40},{"language":"default","tag":"2026","count":37},{"language":"default","tag":"Integrations","count":33},{"language":"default","tag":"Emails","count":30},{"language":"default","tag":"Automations","count":29},{"language":"default","tag":"Guides","count":27},{"language":"default","tag":"API Contracts","count":14}]},"assistantConfig":{"deflection":{"enabled":true,"email":"philip@brew.new","showHelpButton":true}},"basePath":"","hasChatPermissions":true,"hasWebMcpPermissions":true,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"comment-mode","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[],"page":{"pagePath":"api-reference/public-v1/contacts/bulk-import-contacts-from-csv","slug":"/api-reference/public-v1/contacts/bulk-import-contacts-from-csv","pageMetadata":{"title":"Bulk-import contacts from CSV","description":"Parse a raw CSV string and upsert the rows as contacts (≤ 1000). By default each column header maps to the custom field its name folds to, the same camelCase name `POST /v1/contacts` stores (`Plan` → `plan`, `Team Size` → `teamSize`); `email` is required. A header that spells a core field, ignoring case, spaces, `_` and `-`, or whose field key equals it (`First.Name`), maps to it: `Email`, `First Name`, `Last Name` and `Subscribed` fill `email`, `firstName`, `lastName` and `subscribed`. Pass `mapping` to remap single columns; the columns it leaves out keep their default mapping, `\"\"` leaves a column out, and a key that names no column is a `400`. Two columns that land on one custom field (`plan,Plan`: names fold as on `POST /v1/contacts`) are a `422 FIELD_NAME_COLLISION` before any row is read: map one to another name or leave it out with `\"\"`. A core field that `mapping` fills is filled from that column alone: another column whose default would fill it is left out with a `CSV_COLUMN_IGNORED` warning. Rows with a missing/invalid email are SKIPPED (counted in `summary.skipped`), not errored; disposable-domain rows are imported with `validationStatus: \"risky\"` (deliverable but flagged). Returns the same `{ summary, fieldsCreated, errors, warnings }` as batch-create plus `importId` — `207` when some rows fail. The batch is listed in Import History under `fileName` (optional), and each contact it writes carries `importId` until a later import touches it (filter on it to list them; deleting the import in the app removes the contacts it created). For rows you already hold as JSON, use `POST /v1/contacts/import`.\n\nCSV cells are text: a column mapped onto an EXISTING field is coerced to that field's type (dates → epoch ms, `1,234` → 1234, `yes`/`no` → booleans), and a cell that cannot be coerced (`$49` in a number column) fails ITS row with a per-row `errors[]` entry (`code: FIELD_TYPE_MISMATCH`, `field`) while the other rows still land. A converted cell adds a `warnings[]` entry (`code: FIELD_TYPE_COERCED`, `field`, `from`, `to`); a date written to a `date` field is not reported. An undeclared column is created as a `string` field unless every value is an ISO date (→ `date`); predeclare `number` / `bool` columns with `POST /v1/fields`. A column whose field Brew manages (`Created At`, `Validation Status`) is not imported and adds a `warnings[]` entry (`code: CSV_COLUMN_IGNORED`, `field` names the column).\n\nA date column is read in ONE day/month order: the order its own dates prove (a day over 12 anywhere in the column, `13/04/2026`), else `dateOrder` (`day_first` reads `03/04/2026` as 3 April, `month_first` as 4 March), else month/day with a `warnings[]` entry (`code: DATE_ORDER_ASSUMED`, `field`). Dotted dates (`03.04.2026`) are day-first. ISO (`2026-04-03`), Unix seconds or milliseconds, month names (`3 Apr 2026`), year-first (`2026/04/03`) and compact (`20260403`) dates need no order. Convert to `YYYY-MM-DD` to be unambiguous.\n\nA `subscribed` column reads true/false and ESP status words (`unsubscribed`, `cleaned`, `blocklisted`, `transactional`, `active`, …). An opt-out unsubscribes the contact, new or existing (with `onConflict: \"skip\"` an existing contact is left unchanged, and its `CONTACT_EXISTS_SKIPPED` warning says so). A word that is not a subscription status (`maybe`) fails its row (`code: FIELD_TYPE_MISMATCH`, `field: subscribed`) instead of importing the contact subscribed. A subscribed value only applies to new contacts: a row that asks to re-subscribe a contact who opted out keeps its other fields and adds a `warnings[]` entry (`code: RESUBSCRIBE_SKIPPED`, `email`).\n\nTwo opt-in modes. `dryRun: true` returns the response this import would return (`summary`, `errors`, row `warnings`, `fieldsCreated` as fields it would create) with `dryRun: true` and no `importId`, and writes nothing: no contacts, field definitions or Import History entry; `validate` is not run and nothing is charged. Insert vs update is decided by the same address match the write uses, so a real run right after returns the same counts. `onConflict: \"skip\"` only creates missing contacts: each existing contact is left unchanged (an opt-out row included), counted in `summary.skipped` with a `CONTACT_EXISTS_SKIPPED` warning naming its `row`. Either way `inserted + updated + failed + skipped = total`. A dry run cannot foresee failures that only happen while writing (a concurrent change, a database refusal), so the real run can still fail where the preview succeeded. With `validate: true`, inline checks are still metered per submitted row, rows `skip` left alone included; a request that leaves no address to check is not charged.","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/contacts/import-csv","href":"/api-reference/public-v1/contacts/bulk-import-contacts-from-csv","autogeneratedByOpenApi":true},"description":{"compiledSource":"\"use strict\";\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n code: \"code\",\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsxs(_Fragment, {\n children: [_jsxs(_components.p, {\n children: [\"Parse a raw CSV string and upsert the rows as contacts (≤ 1000). By default each column header maps to the custom field its name folds to, the same camelCase name \", _jsx(_components.code, {\n children: \"POST /v1/contacts\"\n }), \" stores (\", _jsx(_components.code, {\n children: \"Plan\"\n }), \" → \", _jsx(_components.code, {\n children: \"plan\"\n }), \", \", _jsx(_components.code, {\n children: \"Team Size\"\n }), \" → \", _jsx(_components.code, {\n children: \"teamSize\"\n }), \"); \", _jsx(_components.code, {\n children: \"email\"\n }), \" is required. A header that spells a core field, ignoring case, spaces, \", _jsx(_components.code, {\n children: \"_\"\n }), \" and \", _jsx(_components.code, {\n children: \"-\"\n }), \", or whose field key equals it (\", _jsx(_components.code, {\n children: \"First.Name\"\n }), \"), maps to it: \", _jsx(_components.code, {\n children: \"Email\"\n }), \", \", _jsx(_components.code, {\n children: \"First Name\"\n }), \", \", _jsx(_components.code, {\n children: \"Last Name\"\n }), \" and \", _jsx(_components.code, {\n children: \"Subscribed\"\n }), \" fill \", _jsx(_components.code, {\n children: \"email\"\n }), \", \", _jsx(_components.code, {\n children: \"firstName\"\n }), \", \", _jsx(_components.code, {\n children: \"lastName\"\n }), \" and \", _jsx(_components.code, {\n children: \"subscribed\"\n }), \". Pass \", _jsx(_components.code, {\n children: \"mapping\"\n }), \" to remap single columns; the columns it leaves out keep their default mapping, \", _jsx(_components.code, {\n children: \"\\\"\\\"\"\n }), \" leaves a column out, and a key that names no column is a \", _jsx(_components.code, {\n children: \"400\"\n }), \". Two columns that land on one custom field (\", _jsx(_components.code, {\n children: \"plan,Plan\"\n }), \": names fold as on \", _jsx(_components.code, {\n children: \"POST /v1/contacts\"\n }), \") are a \", _jsx(_components.code, {\n children: \"422 FIELD_NAME_COLLISION\"\n }), \" before any row is read: map one to another name or leave it out with \", _jsx(_components.code, {\n children: \"\\\"\\\"\"\n }), \". A core field that \", _jsx(_components.code, {\n children: \"mapping\"\n }), \" fills is filled from that column alone: another column whose default would fill it is left out with a \", _jsx(_components.code, {\n children: \"CSV_COLUMN_IGNORED\"\n }), \" warning. Rows with a missing/invalid email are SKIPPED (counted in \", _jsx(_components.code, {\n children: \"summary.skipped\"\n }), \"), not errored; disposable-domain rows are imported with \", _jsx(_components.code, {\n children: \"validationStatus: \\\"risky\\\"\"\n }), \" (deliverable but flagged). Returns the same \", _jsx(_components.code, {\n children: \"{ summary, fieldsCreated, errors, warnings }\"\n }), \" as batch-create plus \", _jsx(_components.code, {\n children: \"importId\"\n }), \" — \", _jsx(_components.code, {\n children: \"207\"\n }), \" when some rows fail. The batch is listed in Import History under \", _jsx(_components.code, {\n children: \"fileName\"\n }), \" (optional), and each contact it writes carries \", _jsx(_components.code, {\n children: \"importId\"\n }), \" until a later import touches it (filter on it to list them; deleting the import in the app removes the contacts it created). For rows you already hold as JSON, use \", _jsx(_components.code, {\n children: \"POST /v1/contacts/import\"\n }), \".\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"CSV cells are text: a column mapped onto an EXISTING field is coerced to that field’s type (dates → epoch ms, \", _jsx(_components.code, {\n children: \"1,234\"\n }), \" → 1234, \", _jsx(_components.code, {\n children: \"yes\"\n }), \"/\", _jsx(_components.code, {\n children: \"no\"\n }), \" → booleans), and a cell that cannot be coerced (\", _jsx(_components.code, {\n children: \"$49\"\n }), \" in a number column) fails ITS row with a per-row \", _jsx(_components.code, {\n children: \"errors[]\"\n }), \" entry (\", _jsx(_components.code, {\n children: \"code: FIELD_TYPE_MISMATCH\"\n }), \", \", _jsx(_components.code, {\n children: \"field\"\n }), \") while the other rows still land. A converted cell adds a \", _jsx(_components.code, {\n children: \"warnings[]\"\n }), \" entry (\", _jsx(_components.code, {\n children: \"code: FIELD_TYPE_COERCED\"\n }), \", \", _jsx(_components.code, {\n children: \"field\"\n }), \", \", _jsx(_components.code, {\n children: \"from\"\n }), \", \", _jsx(_components.code, {\n children: \"to\"\n }), \"); a date written to a \", _jsx(_components.code, {\n children: \"date\"\n }), \" field is not reported. An undeclared column is created as a \", _jsx(_components.code, {\n children: \"string\"\n }), \" field unless every value is an ISO date (→ \", _jsx(_components.code, {\n children: \"date\"\n }), \"); predeclare \", _jsx(_components.code, {\n children: \"number\"\n }), \" / \", _jsx(_components.code, {\n children: \"bool\"\n }), \" columns with \", _jsx(_components.code, {\n children: \"POST /v1/fields\"\n }), \". A column whose field Brew manages (\", _jsx(_components.code, {\n children: \"Created At\"\n }), \", \", _jsx(_components.code, {\n children: \"Validation Status\"\n }), \") is not imported and adds a \", _jsx(_components.code, {\n children: \"warnings[]\"\n }), \" entry (\", _jsx(_components.code, {\n children: \"code: CSV_COLUMN_IGNORED\"\n }), \", \", _jsx(_components.code, {\n children: \"field\"\n }), \" names the column).\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"A date column is read in ONE day/month order: the order its own dates prove (a day over 12 anywhere in the column, \", _jsx(_components.code, {\n children: \"13/04/2026\"\n }), \"), else \", _jsx(_components.code, {\n children: \"dateOrder\"\n }), \" (\", _jsx(_components.code, {\n children: \"day_first\"\n }), \" reads \", _jsx(_components.code, {\n children: \"03/04/2026\"\n }), \" as 3 April, \", _jsx(_components.code, {\n children: \"month_first\"\n }), \" as 4 March), else month/day with a \", _jsx(_components.code, {\n children: \"warnings[]\"\n }), \" entry (\", _jsx(_components.code, {\n children: \"code: DATE_ORDER_ASSUMED\"\n }), \", \", _jsx(_components.code, {\n children: \"field\"\n }), \"). Dotted dates (\", _jsx(_components.code, {\n children: \"03.04.2026\"\n }), \") are day-first. ISO (\", _jsx(_components.code, {\n children: \"2026-04-03\"\n }), \"), Unix seconds or milliseconds, month names (\", _jsx(_components.code, {\n children: \"3 Apr 2026\"\n }), \"), year-first (\", _jsx(_components.code, {\n children: \"2026/04/03\"\n }), \") and compact (\", _jsx(_components.code, {\n children: \"20260403\"\n }), \") dates need no order. Convert to \", _jsx(_components.code, {\n children: \"YYYY-MM-DD\"\n }), \" to be unambiguous.\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"A \", _jsx(_components.code, {\n children: \"subscribed\"\n }), \" column reads true/false and ESP status words (\", _jsx(_components.code, {\n children: \"unsubscribed\"\n }), \", \", _jsx(_components.code, {\n children: \"cleaned\"\n }), \", \", _jsx(_components.code, {\n children: \"blocklisted\"\n }), \", \", _jsx(_components.code, {\n children: \"transactional\"\n }), \", \", _jsx(_components.code, {\n children: \"active\"\n }), \", …). An opt-out unsubscribes the contact, new or existing (with \", _jsx(_components.code, {\n children: \"onConflict: \\\"skip\\\"\"\n }), \" an existing contact is left unchanged, and its \", _jsx(_components.code, {\n children: \"CONTACT_EXISTS_SKIPPED\"\n }), \" warning says so). A word that is not a subscription status (\", _jsx(_components.code, {\n children: \"maybe\"\n }), \") fails its row (\", _jsx(_components.code, {\n children: \"code: FIELD_TYPE_MISMATCH\"\n }), \", \", _jsx(_components.code, {\n children: \"field: subscribed\"\n }), \") instead of importing the contact subscribed. A subscribed value only applies to new contacts: a row that asks to re-subscribe a contact who opted out keeps its other fields and adds a \", _jsx(_components.code, {\n children: \"warnings[]\"\n }), \" entry (\", _jsx(_components.code, {\n children: \"code: RESUBSCRIBE_SKIPPED\"\n }), \", \", _jsx(_components.code, {\n children: \"email\"\n }), \").\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"Two opt-in modes. \", _jsx(_components.code, {\n children: \"dryRun: true\"\n }), \" returns the response this import would return (\", _jsx(_components.code, {\n children: \"summary\"\n }), \", \", _jsx(_components.code, {\n children: \"errors\"\n }), \", row \", _jsx(_components.code, {\n children: \"warnings\"\n }), \", \", _jsx(_components.code, {\n children: \"fieldsCreated\"\n }), \" as fields it would create) with \", _jsx(_components.code, {\n children: \"dryRun: true\"\n }), \" and no \", _jsx(_components.code, {\n children: \"importId\"\n }), \", and writes nothing: no contacts, field definitions or Import History entry; \", _jsx(_components.code, {\n children: \"validate\"\n }), \" is not run and nothing is charged. Insert vs update is decided by the same address match the write uses, so a real run right after returns the same counts. \", _jsx(_components.code, {\n children: \"onConflict: \\\"skip\\\"\"\n }), \" only creates missing contacts: each existing contact is left unchanged (an opt-out row included), counted in \", _jsx(_components.code, {\n children: \"summary.skipped\"\n }), \" with a \", _jsx(_components.code, {\n children: \"CONTACT_EXISTS_SKIPPED\"\n }), \" warning naming its \", _jsx(_components.code, {\n children: \"row\"\n }), \". Either way \", _jsx(_components.code, {\n children: \"inserted + updated + failed + skipped = total\"\n }), \". A dry run cannot foresee failures that only happen while writing (a concurrent change, a database refusal), so the real run can still fail where the preview succeeded. With \", _jsx(_components.code, {\n children: \"validate: true\"\n }), \", inline checks are still metered per submitted row, rows \", _jsx(_components.code, {\n children: \"skip\"\n }), \" left alone included; a request that leaves no address to check is not charged.\"]\n })]\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){return _jsx(_Fragment,{})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Bulk-import contacts from CSV","description":"Parse a raw CSV string and upsert the rows as contacts (≤ 1000). By default each column header maps to the custom field its name folds to, the same camelCase name `POST /v1/contacts` stores (`Plan` → `plan`, `Team Size` → `teamSize`); `email` is required. A header that spells a core field, ignoring case, spaces, `_` and `-`, or whose field key equals it (`First.Name`), maps to it: `Email`, `First Name`, `Last Name` and `Subscribed` fill `email`, `firstName`, `lastName` and `subscribed`. Pass `mapping` to remap single columns; the columns it leaves out keep their default mapping, `\"\"` leaves a column out, and a key that names no column is a `400`. Two columns that land on one custom field (`plan,Plan`: names fold as on `POST /v1/contacts`) are a `422 FIELD_NAME_COLLISION` before any row is read: map one to another name or leave it out with `\"\"`. A core field that `mapping` fills is filled from that column alone: another column whose default would fill it is left out with a `CSV_COLUMN_IGNORED` warning. Rows with a missing/invalid email are SKIPPED (counted in `summary.skipped`), not errored; disposable-domain rows are imported with `validationStatus: \"risky\"` (deliverable but flagged). Returns the same `{ summary, fieldsCreated, errors, warnings }` as batch-create plus `importId` — `207` when some rows fail. The batch is listed in Import History under `fileName` (optional), and each contact it writes carries `importId` until a later import touches it (filter on it to list them; deleting the import in the app removes the contacts it created). For rows you already hold as JSON, use `POST /v1/contacts/import`.\n\nCSV cells are text: a column mapped onto an EXISTING field is coerced to that field's type (dates → epoch ms, `1,234` → 1234, `yes`/`no` → booleans), and a cell that cannot be coerced (`$49` in a number column) fails ITS row with a per-row `errors[]` entry (`code: FIELD_TYPE_MISMATCH`, `field`) while the other rows still land. A converted cell adds a `warnings[]` entry (`code: FIELD_TYPE_COERCED`, `field`, `from`, `to`); a date written to a `date` field is not reported. An undeclared column is created as a `string` field unless every value is an ISO date (→ `date`); predeclare `number` / `bool` columns with `POST /v1/fields`. A column whose field Brew manages (`Created At`, `Validation Status`) is not imported and adds a `warnings[]` entry (`code: CSV_COLUMN_IGNORED`, `field` names the column).\n\nA date column is read in ONE day/month order: the order its own dates prove (a day over 12 anywhere in the column, `13/04/2026`), else `dateOrder` (`day_first` reads `03/04/2026` as 3 April, `month_first` as 4 March), else month/day with a `warnings[]` entry (`code: DATE_ORDER_ASSUMED`, `field`). Dotted dates (`03.04.2026`) are day-first. ISO (`2026-04-03`), Unix seconds or milliseconds, month names (`3 Apr 2026`), year-first (`2026/04/03`) and compact (`20260403`) dates need no order. Convert to `YYYY-MM-DD` to be unambiguous.\n\nA `subscribed` column reads true/false and ESP status words (`unsubscribed`, `cleaned`, `blocklisted`, `transactional`, `active`, …). An opt-out unsubscribes the contact, new or existing (with `onConflict: \"skip\"` an existing contact is left unchanged, and its `CONTACT_EXISTS_SKIPPED` warning says so). A word that is not a subscription status (`maybe`) fails its row (`code: FIELD_TYPE_MISMATCH`, `field: subscribed`) instead of importing the contact subscribed. A subscribed value only applies to new contacts: a row that asks to re-subscribe a contact who opted out keeps its other fields and adds a `warnings[]` entry (`code: RESUBSCRIBE_SKIPPED`, `email`).\n\nTwo opt-in modes. `dryRun: true` returns the response this import would return (`summary`, `errors`, row `warnings`, `fieldsCreated` as fields it would create) with `dryRun: true` and no `importId`, and writes nothing: no contacts, field definitions or Import History entry; `validate` is not run and nothing is charged. Insert vs update is decided by the same address match the write uses, so a real run right after returns the same counts. `onConflict: \"skip\"` only creates missing contacts: each existing contact is left unchanged (an opt-out row included), counted in `summary.skipped` with a `CONTACT_EXISTS_SKIPPED` warning naming its `row`. Either way `inserted + updated + failed + skipped = total`. A dry run cannot foresee failures that only happen while writing (a concurrent change, a database refusal), so the real run can still fail where the preview succeeded. With `validate: true`, inline checks are still metered per submitted row, rows `skip` left alone included; a request that leaves no address to check is not charged.","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/contacts/import-csv","href":"/api-reference/public-v1/contacts/bulk-import-contacts-from-csv","autogeneratedByOpenApi":true}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[],"codeExamples":{}},"jsLinks":["/_mintlify/custom/brew-796f053a/b7b4876a6d26628c/ask-ai-menu.js"],"openApiReferenceData":{"operation":{"operationId":"importContactsCsv","tags":["Contacts"],"summary":"Bulk-import contacts from CSV","description":"Parse a raw CSV string and upsert the rows as contacts (≤ 1000). By default each column header maps to the custom field its name folds to, the same camelCase name `POST /v1/contacts` stores (`Plan` → `plan`, `Team Size` → `teamSize`); `email` is required. A header that spells a core field, ignoring case, spaces, `_` and `-`, or whose field key equals it (`First.Name`), maps to it: `Email`, `First Name`, `Last Name` and `Subscribed` fill `email`, `firstName`, `lastName` and `subscribed`. Pass `mapping` to remap single columns; the columns it leaves out keep their default mapping, `\"\"` leaves a column out, and a key that names no column is a `400`. Two columns that land on one custom field (`plan,Plan`: names fold as on `POST /v1/contacts`) are a `422 FIELD_NAME_COLLISION` before any row is read: map one to another name or leave it out with `\"\"`. A core field that `mapping` fills is filled from that column alone: another column whose default would fill it is left out with a `CSV_COLUMN_IGNORED` warning. Rows with a missing/invalid email are SKIPPED (counted in `summary.skipped`), not errored; disposable-domain rows are imported with `validationStatus: \"risky\"` (deliverable but flagged). Returns the same `{ summary, fieldsCreated, errors, warnings }` as batch-create plus `importId` — `207` when some rows fail. The batch is listed in Import History under `fileName` (optional), and each contact it writes carries `importId` until a later import touches it (filter on it to list them; deleting the import in the app removes the contacts it created). For rows you already hold as JSON, use `POST /v1/contacts/import`.\n\nCSV cells are text: a column mapped onto an EXISTING field is coerced to that field's type (dates → epoch ms, `1,234` → 1234, `yes`/`no` → booleans), and a cell that cannot be coerced (`$49` in a number column) fails ITS row with a per-row `errors[]` entry (`code: FIELD_TYPE_MISMATCH`, `field`) while the other rows still land. A converted cell adds a `warnings[]` entry (`code: FIELD_TYPE_COERCED`, `field`, `from`, `to`); a date written to a `date` field is not reported. An undeclared column is created as a `string` field unless every value is an ISO date (→ `date`); predeclare `number` / `bool` columns with `POST /v1/fields`. A column whose field Brew manages (`Created At`, `Validation Status`) is not imported and adds a `warnings[]` entry (`code: CSV_COLUMN_IGNORED`, `field` names the column).\n\nA date column is read in ONE day/month order: the order its own dates prove (a day over 12 anywhere in the column, `13/04/2026`), else `dateOrder` (`day_first` reads `03/04/2026` as 3 April, `month_first` as 4 March), else month/day with a `warnings[]` entry (`code: DATE_ORDER_ASSUMED`, `field`). Dotted dates (`03.04.2026`) are day-first. ISO (`2026-04-03`), Unix seconds or milliseconds, month names (`3 Apr 2026`), year-first (`2026/04/03`) and compact (`20260403`) dates need no order. Convert to `YYYY-MM-DD` to be unambiguous.\n\nA `subscribed` column reads true/false and ESP status words (`unsubscribed`, `cleaned`, `blocklisted`, `transactional`, `active`, …). An opt-out unsubscribes the contact, new or existing (with `onConflict: \"skip\"` an existing contact is left unchanged, and its `CONTACT_EXISTS_SKIPPED` warning says so). A word that is not a subscription status (`maybe`) fails its row (`code: FIELD_TYPE_MISMATCH`, `field: subscribed`) instead of importing the contact subscribed. A subscribed value only applies to new contacts: a row that asks to re-subscribe a contact who opted out keeps its other fields and adds a `warnings[]` entry (`code: RESUBSCRIBE_SKIPPED`, `email`).\n\nTwo opt-in modes. `dryRun: true` returns the response this import would return (`summary`, `errors`, row `warnings`, `fieldsCreated` as fields it would create) with `dryRun: true` and no `importId`, and writes nothing: no contacts, field definitions or Import History entry; `validate` is not run and nothing is charged. Insert vs update is decided by the same address match the write uses, so a real run right after returns the same counts. `onConflict: \"skip\"` only creates missing contacts: each existing contact is left unchanged (an opt-out row included), counted in `summary.skipped` with a `CONTACT_EXISTS_SKIPPED` warning naming its `row`. Either way `inserted + updated + failed + skipped = total`. A dry run cannot foresee failures that only happen while writing (a concurrent change, a database refusal), so the real run can still fail where the preview succeeded. With `validate: true`, inline checks are still metered per submitted row, rows `skip` left alone included; a request that leaves no address to check is not charged.","requestBody":"3f4217b8-d36e-4cc1-b752-717884455f13","responses":{"200":"267b2df4-fd36-4d58-b02a-fa005e8e7be7","207":"7d940253-bbb6-4453-a6b3-5f130a8d94ad","400":"37fcd27a-0867-4536-be5c-88f0a66feba7","401":"26dc6355-0608-4bdc-a373-d9b6cd252de6","402":"a5f25c7e-8bb0-46f4-8f37-b55bc1b8ddaa","403":"d0cda269-2dfb-4728-9f88-a5c266a73859","404":"df9d9284-d8d8-4f0a-8cc1-810f1fb210e2","409":"90ef244d-7622-4efd-9450-171ec1922c97","422":"fca8cc3d-adf2-4d04-a186-eb70144f4a64","429":"c94d3331-c4a2-462e-beaa-f4bd73f101dd","500":"e776d521-6839-4e97-9b2d-b1142ab92e36","503":"8b799897-de9f-492a-ac7e-d9eabf2156a8"},"parameters":["152a2e8c-c20d-4fd9-9cbb-3ca38538f71a"],"x-brew-scope":"contacts","x-brew-brand-scope":"brand","x-brew-idempotency":"replay","x-brew-credited":true,"x-brew-rate-policy":"contacts.write_batch","method":"post","type":"path","servers":["16779731-d97b-4178-b35d-ab9db802c966","d75b81f5-e341-4448-9191-a43a58d2508e"],"security":["3becd03d-c396-4bc3-84c1-231cdbf0a23e","a3a3e731-b20f-48f7-873a-3123be78670a"],"path":"/v1/contacts/import-csv","baseUrlOptions":["https://brew.new/api","http://localhost:3000/api"],"title":"Bulk-import contacts from CSV","codeSamples":[],"requiredOnlyExamples":false,"requestExampleType":"generated","responseExampleType":"generated"},"dependencies":{"parameters":{"152a2e8c-c20d-4fd9-9cbb-3ca38538f71a":{"name":"X-Brand-Id","in":"header","required":false,"description":"The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.","schema":{"type":"string","minLength":1,"maxLength":64,"isRequired":false,"description":"The brand this request acts on. REQUIRED for organization-scoped credentials (otherwise `400 BRAND_ID_REQUIRED` — there is no default brand); list ids with `GET /v1/brands`. Brand-scoped credentials may omit it, and sending a different brand returns `403 BRAND_SCOPE_MISMATCH`. A brand outside your organization returns `404 BRAND_NOT_FOUND`.","uniqueKey":"","typeLabel":"string"},"example":"kx7b3s7fapqz8mjm12ekz1kxdx87yceg"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"csv":{"type":"string","minLength":1,"maxLength":5000000,"isRequired":true,"uniqueKey":"csv","typeLabel":"string"},"mapping":{"type":"object","additionalProperties":{"type":"string","uniqueKey":"mapping.additionalProperties","typeLabel":"string"},"uniqueKey":"mapping","typeLabel":"object"},"validate":{"type":"boolean","description":"Optional deliverability check on ingestion. When true, each imported address is validated with the provider and the verdict is saved to the contact’s `validationStatus`. Imports of at most 100 submitted CSV data rows validate inline, metered at 2 credits per submitted row on a successful response, including skipped rows and repeated addresses. Larger imports write first and use a background validation workflow billed per address as it runs; `validationJobId` is returned when a job is queued. The job skips unsubscribed, suppressed and recently validated addresses, and a `VALIDATION_SKIPPED` warning gives the counts; when every address is skipped no job is queued and `validationJobId` is absent.","uniqueKey":"validate","typeLabel":"boolean"},"consent":{"type":"object","properties":{"source":{"type":"string","enum":["api","form","import"],"description":"Who captured it: `api`, `form`, or `import`. (`app` is reserved for the in-app CSV wizard.)","isRequired":true,"uniqueKey":"consent.source","typeLabel":"enum\u003cstring>"},"capturedAt":{"type":"string","format":"date-time","description":"ISO 8601; defaults to now.","uniqueKey":"consent.capturedAt","typeLabel":"string\u003cdate-time>"},"policyVersion":{"type":"string","minLength":1,"maxLength":64,"uniqueKey":"consent.policyVersion","typeLabel":"string"},"evidence":{"type":"string","minLength":1,"maxLength":500,"uniqueKey":"consent.evidence","typeLabel":"string"}},"required":["source"],"additionalProperties":false,"description":"Consent record stamped on every imported row (typically `{ \"source\": \"import\" }`).","uniqueKey":"consent","typeLabel":"object"},"dateOrder":{"type":"string","enum":["month_first","day_first"],"description":"Order for a date column whose dates read either way (`03/04/2026`): `day_first` is 3 April, `month_first` 4 March. A day over 12 in the column overrides it. Default month-first, with a DATE_ORDER_ASSUMED warning.","uniqueKey":"dateOrder","typeLabel":"enum\u003cstring>"},"fileName":{"type":"string","minLength":1,"maxLength":255,"description":"Name this batch is listed under in Import History (usually the source file name, e.g. `customers.csv`), also stamped on every contact it writes as `csvFileName`. A path keeps only its last segment.","uniqueKey":"fileName","typeLabel":"string"},"dryRun":{"type":"boolean","description":"When true, returns what this import would return and writes nothing: no contacts, fields, Import History entry or `importId`; `validate` is skipped and nothing is charged.","uniqueKey":"dryRun","typeLabel":"boolean"},"onConflict":{"type":"string","enum":["upsert","skip"],"description":"`upsert` (default) updates existing contacts; `skip` only creates missing ones, leaving each existing contact unchanged (counted in `summary.skipped`, with a `CONTACT_EXISTS_SKIPPED` warning).","uniqueKey":"onConflict","typeLabel":"enum\u003cstring>"}},"required":["csv"],"additionalProperties":false,"uniqueKey":"","typeLabel":"object"},"example":{"csv":"email,firstName,lastName\nada@example.com,Ada,Lovelace\ngrace@example.com,Grace,Hopper","mapping":{"email":"email","firstName":"firstName","lastName":"lastName"},"fileName":"customers.csv"},"examples":{"Example":{"title":"Example","value":{"csv":"email,firstName,lastName\nada@example.com,Ada,Lovelace\ngrace@example.com,Grace,Hopper","mapping":{"email":"email","firstName":"firstName","lastName":"lastName"},"fileName":"customers.csv"}}},"exampleType":"examples"}},"exampleType":"examples"},"responses":{"267b2df4-fd36-4d58-b02a-fa005e8e7be7":{"description":"Import summary (all rows valid).","headers":{"x-request-id":{"schema":{"type":"string","description":"Unique request identifier. Share this with support when debugging a request.","example":"req_8cac13fd94e6420cacdd75a1aa403a28"},"required":true,"description":"Unique request identifier. Share this with support when debugging a request."},"X-RateLimit-Limit":{"schema":{"type":"integer","description":"Requests allowed in the current rolling rate limit window.","example":100},"required":true,"description":"Requests allowed in the current rolling rate limit window."},"X-RateLimit-Remaining":{"schema":{"type":"integer","description":"Requests remaining in the current rolling rate limit window.","example":99},"required":true,"description":"Requests remaining in the current rolling rate limit window."},"X-RateLimit-Reset":{"schema":{"type":"integer","description":"Unix timestamp in seconds when the oldest recorded request leaves the rolling window.","example":1712592360},"required":true,"description":"Unix timestamp in seconds when the oldest recorded request leaves the rolling window."}},"content":{"application/json":{"schema":{"type":"object","properties":{"summary":{"type":"object","properties":{"inserted":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"summary.inserted","typeLabel":"integer"},"updated":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"summary.updated","typeLabel":"integer"},"failed":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"summary.failed","typeLabel":"integer"},"skipped":{"type":"integer","minimum":0,"description":"Rows not written and not failed: existing contacts left alone by `onConflict: \"skip\"` (one `CONTACT_EXISTS_SKIPPED` warning each), and CSV rows omitted for a missing/invalid email or merged into a later duplicate (up to 100 `CSV_ROW_SKIPPED` warnings name each `row`; a final warning counts further skipped rows).","isRequired":true,"uniqueKey":"summary.skipped","typeLabel":"integer"},"total":{"type":"integer","minimum":0,"description":"Rows submitted (JSON contacts, or CSV data rows). Always `inserted + updated + failed + skipped`.","isRequired":true,"uniqueKey":"summary.total","typeLabel":"integer"}},"required":["inserted","updated","failed","skipped","total"],"additionalProperties":false,"isRequired":true,"uniqueKey":"summary","typeLabel":"object"},"fieldsCreated":{"type":"array","items":{"type":"string","uniqueKey":"fieldsCreated.items.[INDEX]","typeLabel":"string"},"isRequired":true,"uniqueKey":"fieldsCreated","typeLabel":"string[]"},"errors":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","isRequired":true,"uniqueKey":"errors.items.[INDEX].email","typeLabel":"string"},"code":{"type":"string","isRequired":true,"uniqueKey":"errors.items.[INDEX].code","typeLabel":"string"},"message":{"type":"string","isRequired":true,"uniqueKey":"errors.items.[INDEX].message","typeLabel":"string"},"row":{"type":"integer","exclusiveMinimum":0,"description":"The 1-based row that failed: `contacts[row - 1]`, or the CSV data row (header and blank lines not counted).","uniqueKey":"errors.items.[INDEX].row","typeLabel":"integer"},"field":{"type":"string","uniqueKey":"errors.items.[INDEX].field","typeLabel":"string"}},"required":["email","code","message"],"additionalProperties":false,"uniqueKey":"errors.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"errors","typeLabel":"object[]"},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"warnings.items.[INDEX].code","typeLabel":"string"},"message":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"warnings.items.[INDEX].message","typeLabel":"string"},"email":{"type":"string","minLength":1,"uniqueKey":"warnings.items.[INDEX].email","typeLabel":"string"},"row":{"type":"integer","exclusiveMinimum":0,"description":"The 1-based row it is about (CSV: data row; header and blank lines not counted).","uniqueKey":"warnings.items.[INDEX].row","typeLabel":"integer"},"field":{"type":"string","minLength":1,"uniqueKey":"warnings.items.[INDEX].field","typeLabel":"string"},"from":{"type":"string","minLength":1,"uniqueKey":"warnings.items.[INDEX].from","typeLabel":"string"},"to":{"type":"string","minLength":1,"uniqueKey":"warnings.items.[INDEX].to","typeLabel":"string"},"original":{"type":"string","minLength":1,"uniqueKey":"warnings.items.[INDEX].original","typeLabel":"string"},"normalized":{"type":"string","minLength":1,"uniqueKey":"warnings.items.[INDEX].normalized","typeLabel":"string"}},"required":["code","message"],"additionalProperties":false,"uniqueKey":"warnings.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"warnings","typeLabel":"object[]"},"validation":{"type":"object","properties":{"valid":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"validation.valid","typeLabel":"integer"},"risky":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"validation.risky","typeLabel":"integer"},"invalid":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"validation.invalid","typeLabel":"integer"},"unscored":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"validation.unscored","typeLabel":"integer"},"persistence":{"type":"object","properties":{"matched":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"validation.persistence.matched","typeLabel":"integer"},"modified":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"validation.persistence.modified","typeLabel":"integer"},"failed":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"validation.persistence.failed","typeLabel":"integer"}},"required":["matched","modified","failed"],"additionalProperties":false,"uniqueKey":"validation.persistence","typeLabel":"object"}},"required":["valid","risky","invalid","unscored"],"additionalProperties":false,"uniqueKey":"validation","typeLabel":"object"},"validationJobId":{"type":"string","uniqueKey":"validationJobId","typeLabel":"string"},"importId":{"type":"string","description":"This batch's Import History id. Each contact it wrote carries it as `importId` until a later import touches that contact, so a contact filter on `importId` lists them. Absent on a dry run.","uniqueKey":"importId","typeLabel":"string"},"dryRun":{"type":"boolean","enum":[true],"description":"Present on a dry run: the counts say what the import would do, and nothing was written.","uniqueKey":"dryRun","typeLabel":"enum\u003cboolean>"}},"required":["summary","fieldsCreated","errors","warnings"],"additionalProperties":false,"uniqueKey":"","typeLabel":"object"},"example":{"summary":{"inserted":2,"updated":0,"failed":0,"skipped":0,"total":2},"fieldsCreated":[],"errors":[],"warnings":[],"importId":"imp_01JABCDEF0123456789XYZ"},"examples":{"Example":{"title":"Example","value":{"summary":{"inserted":2,"updated":0,"failed":0,"skipped":0,"total":2},"fieldsCreated":[],"errors":[],"warnings":[],"importId":"imp_01JABCDEF0123456789XYZ"}}},"exampleType":"examples"}},"exampleType":"examples"},"7d940253-bbb6-4453-a6b3-5f130a8d94ad":{"description":"Partial success — some rows failed validation.","headers":{"x-request-id":{"schema":{"type":"string","description":"Unique request identifier. Share this with support when debugging a request.","example":"req_8cac13fd94e6420cacdd75a1aa403a28"},"required":true,"description":"Unique request identifier. Share this with support when debugging a request."},"X-RateLimit-Limit":{"schema":{"type":"integer","description":"Requests allowed in the current rolling rate limit window.","example":100},"required":true,"description":"Requests allowed in the current rolling rate limit window."},"X-RateLimit-Remaining":{"schema":{"type":"integer","description":"Requests remaining in the current rolling rate limit window.","example":99},"required":true,"description":"Requests remaining in the current rolling rate limit window."},"X-RateLimit-Reset":{"schema":{"type":"integer","description":"Unix timestamp in seconds when the oldest recorded request leaves the rolling window.","example":1712592360},"required":true,"description":"Unix timestamp in seconds when the oldest recorded request leaves the rolling window."}},"content":{"application/json":{"schema":{"type":"object","properties":{"summary":{"type":"object","properties":{"inserted":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"summary.inserted","typeLabel":"integer"},"updated":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"summary.updated","typeLabel":"integer"},"failed":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"summary.failed","typeLabel":"integer"},"skipped":{"type":"integer","minimum":0,"description":"Rows not written and not failed: existing contacts left alone by `onConflict: \"skip\"` (one `CONTACT_EXISTS_SKIPPED` warning each), and CSV rows omitted for a missing/invalid email or merged into a later duplicate (up to 100 `CSV_ROW_SKIPPED` warnings name each `row`; a final warning counts further skipped rows).","isRequired":true,"uniqueKey":"summary.skipped","typeLabel":"integer"},"total":{"type":"integer","minimum":0,"description":"Rows submitted (JSON contacts, or CSV data rows). Always `inserted + updated + failed + skipped`.","isRequired":true,"uniqueKey":"summary.total","typeLabel":"integer"}},"required":["inserted","updated","failed","skipped","total"],"additionalProperties":false,"isRequired":true,"uniqueKey":"summary","typeLabel":"object"},"fieldsCreated":{"type":"array","items":{"type":"string","uniqueKey":"fieldsCreated.items.[INDEX]","typeLabel":"string"},"isRequired":true,"uniqueKey":"fieldsCreated","typeLabel":"string[]"},"errors":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","isRequired":true,"uniqueKey":"errors.items.[INDEX].email","typeLabel":"string"},"code":{"type":"string","isRequired":true,"uniqueKey":"errors.items.[INDEX].code","typeLabel":"string"},"message":{"type":"string","isRequired":true,"uniqueKey":"errors.items.[INDEX].message","typeLabel":"string"},"row":{"type":"integer","exclusiveMinimum":0,"description":"The 1-based row that failed: `contacts[row - 1]`, or the CSV data row (header and blank lines not counted).","uniqueKey":"errors.items.[INDEX].row","typeLabel":"integer"},"field":{"type":"string","uniqueKey":"errors.items.[INDEX].field","typeLabel":"string"}},"required":["email","code","message"],"additionalProperties":false,"uniqueKey":"errors.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"errors","typeLabel":"object[]"},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"warnings.items.[INDEX].code","typeLabel":"string"},"message":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"warnings.items.[INDEX].message","typeLabel":"string"},"email":{"type":"string","minLength":1,"uniqueKey":"warnings.items.[INDEX].email","typeLabel":"string"},"row":{"type":"integer","exclusiveMinimum":0,"description":"The 1-based row it is about (CSV: data row; header and blank lines not counted).","uniqueKey":"warnings.items.[INDEX].row","typeLabel":"integer"},"field":{"type":"string","minLength":1,"uniqueKey":"warnings.items.[INDEX].field","typeLabel":"string"},"from":{"type":"string","minLength":1,"uniqueKey":"warnings.items.[INDEX].from","typeLabel":"string"},"to":{"type":"string","minLength":1,"uniqueKey":"warnings.items.[INDEX].to","typeLabel":"string"},"original":{"type":"string","minLength":1,"uniqueKey":"warnings.items.[INDEX].original","typeLabel":"string"},"normalized":{"type":"string","minLength":1,"uniqueKey":"warnings.items.[INDEX].normalized","typeLabel":"string"}},"required":["code","message"],"additionalProperties":false,"uniqueKey":"warnings.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"warnings","typeLabel":"object[]"},"validation":{"type":"object","properties":{"valid":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"validation.valid","typeLabel":"integer"},"risky":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"validation.risky","typeLabel":"integer"},"invalid":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"validation.invalid","typeLabel":"integer"},"unscored":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"validation.unscored","typeLabel":"integer"},"persistence":{"type":"object","properties":{"matched":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"validation.persistence.matched","typeLabel":"integer"},"modified":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"validation.persistence.modified","typeLabel":"integer"},"failed":{"type":"integer","minimum":0,"isRequired":true,"uniqueKey":"validation.persistence.failed","typeLabel":"integer"}},"required":["matched","modified","failed"],"additionalProperties":false,"uniqueKey":"validation.persistence","typeLabel":"object"}},"required":["valid","risky","invalid","unscored"],"additionalProperties":false,"uniqueKey":"validation","typeLabel":"object"},"validationJobId":{"type":"string","uniqueKey":"validationJobId","typeLabel":"string"},"importId":{"type":"string","description":"This batch's Import History id. Each contact it wrote carries it as `importId` until a later import touches that contact, so a contact filter on `importId` lists them. Absent on a dry run.","uniqueKey":"importId","typeLabel":"string"},"dryRun":{"type":"boolean","enum":[true],"description":"Present on a dry run: the counts say what the import would do, and nothing was written.","uniqueKey":"dryRun","typeLabel":"enum\u003cboolean>"}},"required":["summary","fieldsCreated","errors","warnings"],"additionalProperties":false,"uniqueKey":"","typeLabel":"object"},"example":{"summary":{"inserted":1,"updated":0,"failed":1,"skipped":2,"total":4},"fieldsCreated":[],"errors":[{"email":"john@example.com","row":2,"code":"FIELD_TYPE_MISMATCH","field":"customFields.plan","message":"Field 'customFields.plan' is type 'number' but received string '$49'."}],"warnings":[{"code":"CSV_ROW_SKIPPED","row":3,"message":"Row 3 has no email address, so it was skipped."},{"code":"CSV_ROW_SKIPPED","row":4,"email":"not-an-email","message":"Row 4 holds 'not-an-email', which is not a valid email address, so it was skipped."}],"importId":"imp_01JABCDEF0123456789XYZ"},"examples":{"Example":{"title":"Example","value":{"summary":{"inserted":1,"updated":0,"failed":1,"skipped":2,"total":4},"fieldsCreated":[],"errors":[{"email":"john@example.com","row":2,"code":"FIELD_TYPE_MISMATCH","field":"customFields.plan","message":"Field 'customFields.plan' is type 'number' but received string '$49'."}],"warnings":[{"code":"CSV_ROW_SKIPPED","row":3,"message":"Row 3 has no email address, so it was skipped."},{"code":"CSV_ROW_SKIPPED","row":4,"email":"not-an-email","message":"Row 4 holds 'not-an-email', which is not a valid email address, so it was skipped."}],"importId":"imp_01JABCDEF0123456789XYZ"}}},"exampleType":"examples"}},"exampleType":"examples"},"37fcd27a-0867-4536-be5c-88f0a66feba7":{"description":"`BRAND_ID_REQUIRED`: An organization-scoped credential called a brand-scoped operation without naming the brand.\n\n`INVALID_REQUEST`: The body or query failed validation: an unknown key, a wrong type, or a missing required field. `param` names the first offender; with more than one problem, `details.issues[]` lists each one (`{ param?, message }`, at most 20).","headers":{"x-request-id":{"schema":{"type":"string","description":"Unique request identifier. Share this with support when debugging a request.","example":"req_8cac13fd94e6420cacdd75a1aa403a28"},"required":true,"description":"Unique request identifier. Share this with support when debugging a request."}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["ACCOUNT_SUSPENDED","API_KEY_REVOKED","AUDIENCE_BUILD_ACTIVE","AUDIENCE_BUILD_ALREADY_ACTIVE","AUDIENCE_EDIT_CONFLICT","AUDIENCE_MEMBERSHIP_NOT_EXPRESSIBLE","AUDIENCE_NOT_FOUND","AUDIENCE_RUN_NOT_FOUND","AUDIT_NOT_FOUND","AUTHENTICATION_REQUIRED","AUTOMATION_GRAPH_INVALID","AUTOMATION_NOT_FOUND","AUTOMATION_NOT_PAUSABLE","AUTOMATION_NOT_PUBLISHED","AUTOMATION_RUN_NOT_FOUND","AUTOMATION_VERSION_CONFLICT","AUTOMATION_VERSION_NOT_FOUND","BATCH_TOO_LARGE","BRAND_DOMAIN_CONFLICT","BRAND_ID_REQUIRED","BRAND_LIMIT_REACHED","BRAND_NOT_FOUND","BRAND_NOT_READY","BRAND_SCOPE_MISMATCH","CHAT_NOT_FOUND","COMMENT_NOT_FOUND","CONSENT_REQUIRED","CONTACT_NOT_FOUND","CONTENT_OPERATION_FAILED","CONTRACT_LOCKED_BY_PUBLISHED_AUTOMATIONS","CORE_FIELD_IMMUTABLE","DOMAIN_ALREADY_EXISTS","DOMAIN_CLAIMED_ELSEWHERE","DOMAIN_NOT_FOUND","DOMAIN_NOT_READY","DOMAIN_OTHER_BRAND","DOMAIN_PROVIDER_ERROR","DOMAIN_PURPOSE_NOT_ALLOWED","DOMAIN_VERIFICATION_FAILED","DOMAIN_VERIFIED_ELSEWHERE","EMAIL_GENERATION_FAILED","EMAIL_GROUP_NAME_CONFLICT","EMAIL_GROUP_NOT_FOUND","EMAIL_IMAGES_MISSING","EMAIL_IMPORT_FAILED","EMAIL_IMPORT_PERSISTENCE_FAILED","EMAIL_IN_PROGRESS","EMAIL_IN_USE_BY_AUTOMATION","EMAIL_NOT_FOUND","EMAIL_NOT_READY","EMAIL_RESULT_UNAVAILABLE","EMAIL_RUN_AMBIGUOUS","EMAIL_TEMPLATE_INVALID","EMAIL_VERSION_NOT_FOUND","EXPORT_PROVIDER_ERROR","EXPORT_UNSUPPORTED","FIELD_NAME_COLLISION","FIELD_NOT_FOUND","FIELD_TYPE_MISMATCH","FIGMA_ACCESS_DENIED","FIGMA_CONVERSION_FAILED","FIGMA_FRAME_NOT_FOUND","FIGMA_NOT_CONNECTED","FIGMA_UNAVAILABLE","FIGMA_URL_INVALID","FLOW_NOT_FOUND","IDEMPOTENCY_CONFLICT","IDEMPOTENCY_IN_PROGRESS","INSIGHT_NOT_FOUND","INSUFFICIENT_CREDITS","INSUFFICIENT_PERMISSIONS","INSUFFICIENT_ROLE","INTEGRATION_NOT_CONNECTED","INTERNAL_ERROR","INVALID_API_KEY","INVALID_EMAIL","INVALID_PAYLOAD","INVALID_REQUEST","LIQUID_RENDER_ERROR","METHOD_NOT_ALLOWED","MISSING_EMAIL","NO_ELIGIBLE_RECIPIENTS","NO_PUBLISHED_AUTOMATION","NOT_FOUND","NOT_IMPLEMENTED","ORG_SCOPE_REQUIRED","PAYLOAD_SCHEMA_EMAIL_REQUIRED","PAYLOAD_TOO_LARGE","PREVIEW_NOT_FOUND","PUBLISH_VALIDATION_FAILED","RATE_LIMITED","RECIPIENT_UNSUBSCRIBED","REFERENCE_EMAIL_NOT_FOUND","RESUBSCRIBE_NOT_ALLOWED","RUN_IN_PROGRESS","RUN_NOT_CANCELLABLE","RUN_NOT_PAUSABLE","RUN_NOT_PAUSED","RUN_NOT_RESUMABLE","RUN_START_FAILED","RUN_STOP_FAILED","SEND_NOT_CANCELLABLE","SEND_NOT_FOUND","SEND_NOT_PAUSABLE","SEND_NOT_RESUMABLE","SEND_QUOTA_EXCEEDED","SERVICE_UNAVAILABLE","TEMPLATE_NOT_FOUND","TEST_RECIPIENT_NOT_ALLOWED","TRIGGER_ALREADY_EXISTS","TRIGGER_EVENT_NOT_FOUND","TRIGGER_HAS_DEPENDENT_AUTOMATIONS","TRIGGER_IMMUTABLE","TRIGGER_INSTANCE_NOT_FOUND","TRIGGER_LIMIT_REACHED","TRIGGER_NOT_FIREABLE","UPLOAD_IN_PROGRESS","UPLOAD_NOT_FOUND","UPLOAD_NOT_RECEIVED"],"isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"type":{"type":"string","enum":["authentication_error","authorization_error","invalid_request","not_found","not_implemented","conflict","rate_limit","payment_required","service_unavailable","internal_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"suggestion":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.suggestion","typeLabel":"string"},"docs":{"type":"string","format":"uri","isRequired":true,"uniqueKey":"error.docs","typeLabel":"string\u003curi>"},"param":{"type":"string","minLength":1,"uniqueKey":"error.param","typeLabel":"string"},"retryAfter":{"type":"integer","minimum":0,"uniqueKey":"error.retryAfter","typeLabel":"integer"},"details":{"type":"object","additionalProperties":{"oneOf":[{}],"uniqueKey":"error.details.additionalProperties","typeLabel":"any"},"uniqueKey":"error.details","typeLabel":"object"}},"required":["code","type","message","suggestion","docs"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"required":["error"],"uniqueKey":"","typeLabel":"object"},"examples":{"brandIdRequired":{"title":"brandIdRequired","value":{"error":{"code":"BRAND_ID_REQUIRED","type":"invalid_request","message":"An organization-scoped credential called a brand-scoped operation without naming the brand.","suggestion":"List brands with GET /v1/brands, then name one with the X-Brand-Id header. There is no default brand.","docs":"https://docs.brew.new/api-reference/api/authentication"}}},"invalidRequest":{"title":"invalidRequest","value":{"error":{"code":"INVALID_REQUEST","type":"invalid_request","message":"The body or query failed validation: an unknown key, a wrong type, or a missing required field. `param` names the first offender; with more than one problem, `details.issues[]` lists each one (`{ param?, message }`, at most 20).","suggestion":"Fix the field reported in `param`, and every entry in `details.issues[]` when present, then retry.","docs":"https://docs.brew.new/api-reference/api/errors"}}}},"exampleType":"examples"}},"exampleType":"examples"},"26dc6355-0608-4bdc-a373-d9b6cd252de6":{"description":"`API_KEY_REVOKED`: The API key was revoked.\n\n`AUTHENTICATION_REQUIRED`: No API key or session accompanied the request.\n\n`INVALID_API_KEY`: The API key is malformed or unknown.","headers":{"x-request-id":{"schema":{"type":"string","description":"Unique request identifier. Share this with support when debugging a request.","example":"req_8cac13fd94e6420cacdd75a1aa403a28"},"required":true,"description":"Unique request identifier. Share this with support when debugging a request."}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["ACCOUNT_SUSPENDED","API_KEY_REVOKED","AUDIENCE_BUILD_ACTIVE","AUDIENCE_BUILD_ALREADY_ACTIVE","AUDIENCE_EDIT_CONFLICT","AUDIENCE_MEMBERSHIP_NOT_EXPRESSIBLE","AUDIENCE_NOT_FOUND","AUDIENCE_RUN_NOT_FOUND","AUDIT_NOT_FOUND","AUTHENTICATION_REQUIRED","AUTOMATION_GRAPH_INVALID","AUTOMATION_NOT_FOUND","AUTOMATION_NOT_PAUSABLE","AUTOMATION_NOT_PUBLISHED","AUTOMATION_RUN_NOT_FOUND","AUTOMATION_VERSION_CONFLICT","AUTOMATION_VERSION_NOT_FOUND","BATCH_TOO_LARGE","BRAND_DOMAIN_CONFLICT","BRAND_ID_REQUIRED","BRAND_LIMIT_REACHED","BRAND_NOT_FOUND","BRAND_NOT_READY","BRAND_SCOPE_MISMATCH","CHAT_NOT_FOUND","COMMENT_NOT_FOUND","CONSENT_REQUIRED","CONTACT_NOT_FOUND","CONTENT_OPERATION_FAILED","CONTRACT_LOCKED_BY_PUBLISHED_AUTOMATIONS","CORE_FIELD_IMMUTABLE","DOMAIN_ALREADY_EXISTS","DOMAIN_CLAIMED_ELSEWHERE","DOMAIN_NOT_FOUND","DOMAIN_NOT_READY","DOMAIN_OTHER_BRAND","DOMAIN_PROVIDER_ERROR","DOMAIN_PURPOSE_NOT_ALLOWED","DOMAIN_VERIFICATION_FAILED","DOMAIN_VERIFIED_ELSEWHERE","EMAIL_GENERATION_FAILED","EMAIL_GROUP_NAME_CONFLICT","EMAIL_GROUP_NOT_FOUND","EMAIL_IMAGES_MISSING","EMAIL_IMPORT_FAILED","EMAIL_IMPORT_PERSISTENCE_FAILED","EMAIL_IN_PROGRESS","EMAIL_IN_USE_BY_AUTOMATION","EMAIL_NOT_FOUND","EMAIL_NOT_READY","EMAIL_RESULT_UNAVAILABLE","EMAIL_RUN_AMBIGUOUS","EMAIL_TEMPLATE_INVALID","EMAIL_VERSION_NOT_FOUND","EXPORT_PROVIDER_ERROR","EXPORT_UNSUPPORTED","FIELD_NAME_COLLISION","FIELD_NOT_FOUND","FIELD_TYPE_MISMATCH","FIGMA_ACCESS_DENIED","FIGMA_CONVERSION_FAILED","FIGMA_FRAME_NOT_FOUND","FIGMA_NOT_CONNECTED","FIGMA_UNAVAILABLE","FIGMA_URL_INVALID","FLOW_NOT_FOUND","IDEMPOTENCY_CONFLICT","IDEMPOTENCY_IN_PROGRESS","INSIGHT_NOT_FOUND","INSUFFICIENT_CREDITS","INSUFFICIENT_PERMISSIONS","INSUFFICIENT_ROLE","INTEGRATION_NOT_CONNECTED","INTERNAL_ERROR","INVALID_API_KEY","INVALID_EMAIL","INVALID_PAYLOAD","INVALID_REQUEST","LIQUID_RENDER_ERROR","METHOD_NOT_ALLOWED","MISSING_EMAIL","NO_ELIGIBLE_RECIPIENTS","NO_PUBLISHED_AUTOMATION","NOT_FOUND","NOT_IMPLEMENTED","ORG_SCOPE_REQUIRED","PAYLOAD_SCHEMA_EMAIL_REQUIRED","PAYLOAD_TOO_LARGE","PREVIEW_NOT_FOUND","PUBLISH_VALIDATION_FAILED","RATE_LIMITED","RECIPIENT_UNSUBSCRIBED","REFERENCE_EMAIL_NOT_FOUND","RESUBSCRIBE_NOT_ALLOWED","RUN_IN_PROGRESS","RUN_NOT_CANCELLABLE","RUN_NOT_PAUSABLE","RUN_NOT_PAUSED","RUN_NOT_RESUMABLE","RUN_START_FAILED","RUN_STOP_FAILED","SEND_NOT_CANCELLABLE","SEND_NOT_FOUND","SEND_NOT_PAUSABLE","SEND_NOT_RESUMABLE","SEND_QUOTA_EXCEEDED","SERVICE_UNAVAILABLE","TEMPLATE_NOT_FOUND","TEST_RECIPIENT_NOT_ALLOWED","TRIGGER_ALREADY_EXISTS","TRIGGER_EVENT_NOT_FOUND","TRIGGER_HAS_DEPENDENT_AUTOMATIONS","TRIGGER_IMMUTABLE","TRIGGER_INSTANCE_NOT_FOUND","TRIGGER_LIMIT_REACHED","TRIGGER_NOT_FIREABLE","UPLOAD_IN_PROGRESS","UPLOAD_NOT_FOUND","UPLOAD_NOT_RECEIVED"],"isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"type":{"type":"string","enum":["authentication_error","authorization_error","invalid_request","not_found","not_implemented","conflict","rate_limit","payment_required","service_unavailable","internal_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"suggestion":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.suggestion","typeLabel":"string"},"docs":{"type":"string","format":"uri","isRequired":true,"uniqueKey":"error.docs","typeLabel":"string\u003curi>"},"param":{"type":"string","minLength":1,"uniqueKey":"error.param","typeLabel":"string"},"retryAfter":{"type":"integer","minimum":0,"uniqueKey":"error.retryAfter","typeLabel":"integer"},"details":{"type":"object","additionalProperties":{"oneOf":[{}],"uniqueKey":"error.details.additionalProperties","typeLabel":"any"},"uniqueKey":"error.details","typeLabel":"object"}},"required":["code","type","message","suggestion","docs"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"required":["error"],"uniqueKey":"","typeLabel":"object"},"examples":{"apiKeyRevoked":{"title":"apiKeyRevoked","value":{"error":{"code":"API_KEY_REVOKED","type":"authentication_error","message":"The API key was revoked.","suggestion":"Create a new active API key and retry.","docs":"https://docs.brew.new/api-reference/api/authentication"}}},"authenticationRequired":{"title":"authenticationRequired","value":{"error":{"code":"AUTHENTICATION_REQUIRED","type":"authentication_error","message":"No API key or session accompanied the request.","suggestion":"Provide a valid API key or sign in with an organization session.","docs":"https://docs.brew.new/api-reference/api/authentication"}}},"invalidApiKey":{"title":"invalidApiKey","value":{"error":{"code":"INVALID_API_KEY","type":"authentication_error","message":"The API key is malformed or unknown.","suggestion":"Check the API key format and retry with a valid active key.","docs":"https://docs.brew.new/api-reference/api/authentication"}}}},"exampleType":"examples"}},"exampleType":"examples"},"a5f25c7e-8bb0-46f4-8f37-b55bc1b8ddaa":{"description":"`INSUFFICIENT_CREDITS`: The credit balance is below what this operation requires; `details.cost` is the amount needed.","headers":{"x-request-id":{"schema":{"type":"string","description":"Unique request identifier. Share this with support when debugging a request.","example":"req_8cac13fd94e6420cacdd75a1aa403a28"},"required":true,"description":"Unique request identifier. Share this with support when debugging a request."}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["ACCOUNT_SUSPENDED","API_KEY_REVOKED","AUDIENCE_BUILD_ACTIVE","AUDIENCE_BUILD_ALREADY_ACTIVE","AUDIENCE_EDIT_CONFLICT","AUDIENCE_MEMBERSHIP_NOT_EXPRESSIBLE","AUDIENCE_NOT_FOUND","AUDIENCE_RUN_NOT_FOUND","AUDIT_NOT_FOUND","AUTHENTICATION_REQUIRED","AUTOMATION_GRAPH_INVALID","AUTOMATION_NOT_FOUND","AUTOMATION_NOT_PAUSABLE","AUTOMATION_NOT_PUBLISHED","AUTOMATION_RUN_NOT_FOUND","AUTOMATION_VERSION_CONFLICT","AUTOMATION_VERSION_NOT_FOUND","BATCH_TOO_LARGE","BRAND_DOMAIN_CONFLICT","BRAND_ID_REQUIRED","BRAND_LIMIT_REACHED","BRAND_NOT_FOUND","BRAND_NOT_READY","BRAND_SCOPE_MISMATCH","CHAT_NOT_FOUND","COMMENT_NOT_FOUND","CONSENT_REQUIRED","CONTACT_NOT_FOUND","CONTENT_OPERATION_FAILED","CONTRACT_LOCKED_BY_PUBLISHED_AUTOMATIONS","CORE_FIELD_IMMUTABLE","DOMAIN_ALREADY_EXISTS","DOMAIN_CLAIMED_ELSEWHERE","DOMAIN_NOT_FOUND","DOMAIN_NOT_READY","DOMAIN_OTHER_BRAND","DOMAIN_PROVIDER_ERROR","DOMAIN_PURPOSE_NOT_ALLOWED","DOMAIN_VERIFICATION_FAILED","DOMAIN_VERIFIED_ELSEWHERE","EMAIL_GENERATION_FAILED","EMAIL_GROUP_NAME_CONFLICT","EMAIL_GROUP_NOT_FOUND","EMAIL_IMAGES_MISSING","EMAIL_IMPORT_FAILED","EMAIL_IMPORT_PERSISTENCE_FAILED","EMAIL_IN_PROGRESS","EMAIL_IN_USE_BY_AUTOMATION","EMAIL_NOT_FOUND","EMAIL_NOT_READY","EMAIL_RESULT_UNAVAILABLE","EMAIL_RUN_AMBIGUOUS","EMAIL_TEMPLATE_INVALID","EMAIL_VERSION_NOT_FOUND","EXPORT_PROVIDER_ERROR","EXPORT_UNSUPPORTED","FIELD_NAME_COLLISION","FIELD_NOT_FOUND","FIELD_TYPE_MISMATCH","FIGMA_ACCESS_DENIED","FIGMA_CONVERSION_FAILED","FIGMA_FRAME_NOT_FOUND","FIGMA_NOT_CONNECTED","FIGMA_UNAVAILABLE","FIGMA_URL_INVALID","FLOW_NOT_FOUND","IDEMPOTENCY_CONFLICT","IDEMPOTENCY_IN_PROGRESS","INSIGHT_NOT_FOUND","INSUFFICIENT_CREDITS","INSUFFICIENT_PERMISSIONS","INSUFFICIENT_ROLE","INTEGRATION_NOT_CONNECTED","INTERNAL_ERROR","INVALID_API_KEY","INVALID_EMAIL","INVALID_PAYLOAD","INVALID_REQUEST","LIQUID_RENDER_ERROR","METHOD_NOT_ALLOWED","MISSING_EMAIL","NO_ELIGIBLE_RECIPIENTS","NO_PUBLISHED_AUTOMATION","NOT_FOUND","NOT_IMPLEMENTED","ORG_SCOPE_REQUIRED","PAYLOAD_SCHEMA_EMAIL_REQUIRED","PAYLOAD_TOO_LARGE","PREVIEW_NOT_FOUND","PUBLISH_VALIDATION_FAILED","RATE_LIMITED","RECIPIENT_UNSUBSCRIBED","REFERENCE_EMAIL_NOT_FOUND","RESUBSCRIBE_NOT_ALLOWED","RUN_IN_PROGRESS","RUN_NOT_CANCELLABLE","RUN_NOT_PAUSABLE","RUN_NOT_PAUSED","RUN_NOT_RESUMABLE","RUN_START_FAILED","RUN_STOP_FAILED","SEND_NOT_CANCELLABLE","SEND_NOT_FOUND","SEND_NOT_PAUSABLE","SEND_NOT_RESUMABLE","SEND_QUOTA_EXCEEDED","SERVICE_UNAVAILABLE","TEMPLATE_NOT_FOUND","TEST_RECIPIENT_NOT_ALLOWED","TRIGGER_ALREADY_EXISTS","TRIGGER_EVENT_NOT_FOUND","TRIGGER_HAS_DEPENDENT_AUTOMATIONS","TRIGGER_IMMUTABLE","TRIGGER_INSTANCE_NOT_FOUND","TRIGGER_LIMIT_REACHED","TRIGGER_NOT_FIREABLE","UPLOAD_IN_PROGRESS","UPLOAD_NOT_FOUND","UPLOAD_NOT_RECEIVED"],"isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"type":{"type":"string","enum":["authentication_error","authorization_error","invalid_request","not_found","not_implemented","conflict","rate_limit","payment_required","service_unavailable","internal_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"suggestion":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.suggestion","typeLabel":"string"},"docs":{"type":"string","format":"uri","isRequired":true,"uniqueKey":"error.docs","typeLabel":"string\u003curi>"},"param":{"type":"string","minLength":1,"uniqueKey":"error.param","typeLabel":"string"},"retryAfter":{"type":"integer","minimum":0,"uniqueKey":"error.retryAfter","typeLabel":"integer"},"details":{"type":"object","additionalProperties":{"oneOf":[{}],"uniqueKey":"error.details.additionalProperties","typeLabel":"any"},"uniqueKey":"error.details","typeLabel":"object"}},"required":["code","type","message","suggestion","docs"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"required":["error"],"uniqueKey":"","typeLabel":"object"},"examples":{"insufficientCredits":{"title":"insufficientCredits","value":{"error":{"code":"INSUFFICIENT_CREDITS","type":"payment_required","message":"The credit balance is below what this operation requires; `details.cost` is the amount needed.","suggestion":"Upgrade your plan or wait for the next billing period to reset. Check your balance up front with GET /v1/usage.","docs":"https://docs.brew.new/api-reference/api/credits","details":{"cost":5,"remaining":0,"planKey":"free"}}}}},"exampleType":"examples"}},"exampleType":"examples"},"d0cda269-2dfb-4728-9f88-a5c266a73859":{"description":"`ACCOUNT_SUSPENDED`: The organization behind the credential is suspended.\n\n`BRAND_SCOPE_MISMATCH`: A brand-scoped credential named a brand other than the one it is bound to.\n\n`INSUFFICIENT_PERMISSIONS`: The credential lacks the permission scope the operation needs.\n\n`INSUFFICIENT_ROLE`: The caller lacks the access the operation needs: `param` names `member` (access to the brand) or `org_admin` (the organization role).","headers":{"x-request-id":{"schema":{"type":"string","description":"Unique request identifier. Share this with support when debugging a request.","example":"req_8cac13fd94e6420cacdd75a1aa403a28"},"required":true,"description":"Unique request identifier. Share this with support when debugging a request."}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["ACCOUNT_SUSPENDED","API_KEY_REVOKED","AUDIENCE_BUILD_ACTIVE","AUDIENCE_BUILD_ALREADY_ACTIVE","AUDIENCE_EDIT_CONFLICT","AUDIENCE_MEMBERSHIP_NOT_EXPRESSIBLE","AUDIENCE_NOT_FOUND","AUDIENCE_RUN_NOT_FOUND","AUDIT_NOT_FOUND","AUTHENTICATION_REQUIRED","AUTOMATION_GRAPH_INVALID","AUTOMATION_NOT_FOUND","AUTOMATION_NOT_PAUSABLE","AUTOMATION_NOT_PUBLISHED","AUTOMATION_RUN_NOT_FOUND","AUTOMATION_VERSION_CONFLICT","AUTOMATION_VERSION_NOT_FOUND","BATCH_TOO_LARGE","BRAND_DOMAIN_CONFLICT","BRAND_ID_REQUIRED","BRAND_LIMIT_REACHED","BRAND_NOT_FOUND","BRAND_NOT_READY","BRAND_SCOPE_MISMATCH","CHAT_NOT_FOUND","COMMENT_NOT_FOUND","CONSENT_REQUIRED","CONTACT_NOT_FOUND","CONTENT_OPERATION_FAILED","CONTRACT_LOCKED_BY_PUBLISHED_AUTOMATIONS","CORE_FIELD_IMMUTABLE","DOMAIN_ALREADY_EXISTS","DOMAIN_CLAIMED_ELSEWHERE","DOMAIN_NOT_FOUND","DOMAIN_NOT_READY","DOMAIN_OTHER_BRAND","DOMAIN_PROVIDER_ERROR","DOMAIN_PURPOSE_NOT_ALLOWED","DOMAIN_VERIFICATION_FAILED","DOMAIN_VERIFIED_ELSEWHERE","EMAIL_GENERATION_FAILED","EMAIL_GROUP_NAME_CONFLICT","EMAIL_GROUP_NOT_FOUND","EMAIL_IMAGES_MISSING","EMAIL_IMPORT_FAILED","EMAIL_IMPORT_PERSISTENCE_FAILED","EMAIL_IN_PROGRESS","EMAIL_IN_USE_BY_AUTOMATION","EMAIL_NOT_FOUND","EMAIL_NOT_READY","EMAIL_RESULT_UNAVAILABLE","EMAIL_RUN_AMBIGUOUS","EMAIL_TEMPLATE_INVALID","EMAIL_VERSION_NOT_FOUND","EXPORT_PROVIDER_ERROR","EXPORT_UNSUPPORTED","FIELD_NAME_COLLISION","FIELD_NOT_FOUND","FIELD_TYPE_MISMATCH","FIGMA_ACCESS_DENIED","FIGMA_CONVERSION_FAILED","FIGMA_FRAME_NOT_FOUND","FIGMA_NOT_CONNECTED","FIGMA_UNAVAILABLE","FIGMA_URL_INVALID","FLOW_NOT_FOUND","IDEMPOTENCY_CONFLICT","IDEMPOTENCY_IN_PROGRESS","INSIGHT_NOT_FOUND","INSUFFICIENT_CREDITS","INSUFFICIENT_PERMISSIONS","INSUFFICIENT_ROLE","INTEGRATION_NOT_CONNECTED","INTERNAL_ERROR","INVALID_API_KEY","INVALID_EMAIL","INVALID_PAYLOAD","INVALID_REQUEST","LIQUID_RENDER_ERROR","METHOD_NOT_ALLOWED","MISSING_EMAIL","NO_ELIGIBLE_RECIPIENTS","NO_PUBLISHED_AUTOMATION","NOT_FOUND","NOT_IMPLEMENTED","ORG_SCOPE_REQUIRED","PAYLOAD_SCHEMA_EMAIL_REQUIRED","PAYLOAD_TOO_LARGE","PREVIEW_NOT_FOUND","PUBLISH_VALIDATION_FAILED","RATE_LIMITED","RECIPIENT_UNSUBSCRIBED","REFERENCE_EMAIL_NOT_FOUND","RESUBSCRIBE_NOT_ALLOWED","RUN_IN_PROGRESS","RUN_NOT_CANCELLABLE","RUN_NOT_PAUSABLE","RUN_NOT_PAUSED","RUN_NOT_RESUMABLE","RUN_START_FAILED","RUN_STOP_FAILED","SEND_NOT_CANCELLABLE","SEND_NOT_FOUND","SEND_NOT_PAUSABLE","SEND_NOT_RESUMABLE","SEND_QUOTA_EXCEEDED","SERVICE_UNAVAILABLE","TEMPLATE_NOT_FOUND","TEST_RECIPIENT_NOT_ALLOWED","TRIGGER_ALREADY_EXISTS","TRIGGER_EVENT_NOT_FOUND","TRIGGER_HAS_DEPENDENT_AUTOMATIONS","TRIGGER_IMMUTABLE","TRIGGER_INSTANCE_NOT_FOUND","TRIGGER_LIMIT_REACHED","TRIGGER_NOT_FIREABLE","UPLOAD_IN_PROGRESS","UPLOAD_NOT_FOUND","UPLOAD_NOT_RECEIVED"],"isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"type":{"type":"string","enum":["authentication_error","authorization_error","invalid_request","not_found","not_implemented","conflict","rate_limit","payment_required","service_unavailable","internal_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"suggestion":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.suggestion","typeLabel":"string"},"docs":{"type":"string","format":"uri","isRequired":true,"uniqueKey":"error.docs","typeLabel":"string\u003curi>"},"param":{"type":"string","minLength":1,"uniqueKey":"error.param","typeLabel":"string"},"retryAfter":{"type":"integer","minimum":0,"uniqueKey":"error.retryAfter","typeLabel":"integer"},"details":{"type":"object","additionalProperties":{"oneOf":[{}],"uniqueKey":"error.details.additionalProperties","typeLabel":"any"},"uniqueKey":"error.details","typeLabel":"object"}},"required":["code","type","message","suggestion","docs"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"required":["error"],"uniqueKey":"","typeLabel":"object"},"examples":{"accountSuspended":{"title":"accountSuspended","value":{"error":{"code":"ACCOUNT_SUSPENDED","type":"authorization_error","message":"The organization behind the credential is suspended.","suggestion":"The organization behind this credential is suspended. Contact support@brew.new; do not retry.","docs":"https://docs.brew.new/api-reference/api/authentication"}}},"brandScopeMismatch":{"title":"brandScopeMismatch","value":{"error":{"code":"BRAND_SCOPE_MISMATCH","type":"authorization_error","message":"A brand-scoped credential named a brand other than the one it is bound to.","suggestion":"Omit the brand to use the one this credential is bound to, or use an organization-scoped credential to reach other brands.","docs":"https://docs.brew.new/api-reference/api/authentication"}}},"insufficientPermissions":{"title":"insufficientPermissions","value":{"error":{"code":"INSUFFICIENT_PERMISSIONS","type":"authorization_error","message":"The credential lacks the permission scope the operation needs.","suggestion":"Use an API key or session with the required permission.","docs":"https://docs.brew.new/api-reference/api/authentication"}}},"insufficientRole":{"title":"insufficientRole","value":{"error":{"code":"INSUFFICIENT_ROLE","type":"authorization_error","message":"The caller lacks the access the operation needs: `param` names `member` (access to the brand) or `org_admin` (the organization role).","suggestion":"Ask an organization admin to run this, to add you to the brand, or to make you an admin.","docs":"https://docs.brew.new/api-reference/api/authentication"}}}},"exampleType":"examples"}},"exampleType":"examples"},"df9d9284-d8d8-4f0a-8cc1-810f1fb210e2":{"description":"`BRAND_NOT_FOUND`: The named or bound brand does not exist in this organization (unknown, deleting, or another organization).","headers":{"x-request-id":{"schema":{"type":"string","description":"Unique request identifier. Share this with support when debugging a request.","example":"req_8cac13fd94e6420cacdd75a1aa403a28"},"required":true,"description":"Unique request identifier. Share this with support when debugging a request."}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["ACCOUNT_SUSPENDED","API_KEY_REVOKED","AUDIENCE_BUILD_ACTIVE","AUDIENCE_BUILD_ALREADY_ACTIVE","AUDIENCE_EDIT_CONFLICT","AUDIENCE_MEMBERSHIP_NOT_EXPRESSIBLE","AUDIENCE_NOT_FOUND","AUDIENCE_RUN_NOT_FOUND","AUDIT_NOT_FOUND","AUTHENTICATION_REQUIRED","AUTOMATION_GRAPH_INVALID","AUTOMATION_NOT_FOUND","AUTOMATION_NOT_PAUSABLE","AUTOMATION_NOT_PUBLISHED","AUTOMATION_RUN_NOT_FOUND","AUTOMATION_VERSION_CONFLICT","AUTOMATION_VERSION_NOT_FOUND","BATCH_TOO_LARGE","BRAND_DOMAIN_CONFLICT","BRAND_ID_REQUIRED","BRAND_LIMIT_REACHED","BRAND_NOT_FOUND","BRAND_NOT_READY","BRAND_SCOPE_MISMATCH","CHAT_NOT_FOUND","COMMENT_NOT_FOUND","CONSENT_REQUIRED","CONTACT_NOT_FOUND","CONTENT_OPERATION_FAILED","CONTRACT_LOCKED_BY_PUBLISHED_AUTOMATIONS","CORE_FIELD_IMMUTABLE","DOMAIN_ALREADY_EXISTS","DOMAIN_CLAIMED_ELSEWHERE","DOMAIN_NOT_FOUND","DOMAIN_NOT_READY","DOMAIN_OTHER_BRAND","DOMAIN_PROVIDER_ERROR","DOMAIN_PURPOSE_NOT_ALLOWED","DOMAIN_VERIFICATION_FAILED","DOMAIN_VERIFIED_ELSEWHERE","EMAIL_GENERATION_FAILED","EMAIL_GROUP_NAME_CONFLICT","EMAIL_GROUP_NOT_FOUND","EMAIL_IMAGES_MISSING","EMAIL_IMPORT_FAILED","EMAIL_IMPORT_PERSISTENCE_FAILED","EMAIL_IN_PROGRESS","EMAIL_IN_USE_BY_AUTOMATION","EMAIL_NOT_FOUND","EMAIL_NOT_READY","EMAIL_RESULT_UNAVAILABLE","EMAIL_RUN_AMBIGUOUS","EMAIL_TEMPLATE_INVALID","EMAIL_VERSION_NOT_FOUND","EXPORT_PROVIDER_ERROR","EXPORT_UNSUPPORTED","FIELD_NAME_COLLISION","FIELD_NOT_FOUND","FIELD_TYPE_MISMATCH","FIGMA_ACCESS_DENIED","FIGMA_CONVERSION_FAILED","FIGMA_FRAME_NOT_FOUND","FIGMA_NOT_CONNECTED","FIGMA_UNAVAILABLE","FIGMA_URL_INVALID","FLOW_NOT_FOUND","IDEMPOTENCY_CONFLICT","IDEMPOTENCY_IN_PROGRESS","INSIGHT_NOT_FOUND","INSUFFICIENT_CREDITS","INSUFFICIENT_PERMISSIONS","INSUFFICIENT_ROLE","INTEGRATION_NOT_CONNECTED","INTERNAL_ERROR","INVALID_API_KEY","INVALID_EMAIL","INVALID_PAYLOAD","INVALID_REQUEST","LIQUID_RENDER_ERROR","METHOD_NOT_ALLOWED","MISSING_EMAIL","NO_ELIGIBLE_RECIPIENTS","NO_PUBLISHED_AUTOMATION","NOT_FOUND","NOT_IMPLEMENTED","ORG_SCOPE_REQUIRED","PAYLOAD_SCHEMA_EMAIL_REQUIRED","PAYLOAD_TOO_LARGE","PREVIEW_NOT_FOUND","PUBLISH_VALIDATION_FAILED","RATE_LIMITED","RECIPIENT_UNSUBSCRIBED","REFERENCE_EMAIL_NOT_FOUND","RESUBSCRIBE_NOT_ALLOWED","RUN_IN_PROGRESS","RUN_NOT_CANCELLABLE","RUN_NOT_PAUSABLE","RUN_NOT_PAUSED","RUN_NOT_RESUMABLE","RUN_START_FAILED","RUN_STOP_FAILED","SEND_NOT_CANCELLABLE","SEND_NOT_FOUND","SEND_NOT_PAUSABLE","SEND_NOT_RESUMABLE","SEND_QUOTA_EXCEEDED","SERVICE_UNAVAILABLE","TEMPLATE_NOT_FOUND","TEST_RECIPIENT_NOT_ALLOWED","TRIGGER_ALREADY_EXISTS","TRIGGER_EVENT_NOT_FOUND","TRIGGER_HAS_DEPENDENT_AUTOMATIONS","TRIGGER_IMMUTABLE","TRIGGER_INSTANCE_NOT_FOUND","TRIGGER_LIMIT_REACHED","TRIGGER_NOT_FIREABLE","UPLOAD_IN_PROGRESS","UPLOAD_NOT_FOUND","UPLOAD_NOT_RECEIVED"],"isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"type":{"type":"string","enum":["authentication_error","authorization_error","invalid_request","not_found","not_implemented","conflict","rate_limit","payment_required","service_unavailable","internal_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"suggestion":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.suggestion","typeLabel":"string"},"docs":{"type":"string","format":"uri","isRequired":true,"uniqueKey":"error.docs","typeLabel":"string\u003curi>"},"param":{"type":"string","minLength":1,"uniqueKey":"error.param","typeLabel":"string"},"retryAfter":{"type":"integer","minimum":0,"uniqueKey":"error.retryAfter","typeLabel":"integer"},"details":{"type":"object","additionalProperties":{"oneOf":[{}],"uniqueKey":"error.details.additionalProperties","typeLabel":"any"},"uniqueKey":"error.details","typeLabel":"object"}},"required":["code","type","message","suggestion","docs"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"required":["error"],"uniqueKey":"","typeLabel":"object"},"examples":{"brandNotFound":{"title":"brandNotFound","value":{"error":{"code":"BRAND_NOT_FOUND","type":"not_found","message":"The named or bound brand does not exist in this organization (unknown, deleting, or another organization).","suggestion":"List the brands this credential can reach with GET /v1/brands.","docs":"https://docs.brew.new/api-reference/api/errors"}}}},"exampleType":"examples"}},"exampleType":"examples"},"90ef244d-7622-4efd-9450-171ec1922c97":{"description":"`IDEMPOTENCY_CONFLICT`: The same Idempotency-Key was reused with a different request body.\n\n`IDEMPOTENCY_IN_PROGRESS`: A request with this Idempotency-Key is still executing.","headers":{"x-request-id":{"schema":{"type":"string","description":"Unique request identifier. Share this with support when debugging a request.","example":"req_8cac13fd94e6420cacdd75a1aa403a28"},"required":true,"description":"Unique request identifier. Share this with support when debugging a request."}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["ACCOUNT_SUSPENDED","API_KEY_REVOKED","AUDIENCE_BUILD_ACTIVE","AUDIENCE_BUILD_ALREADY_ACTIVE","AUDIENCE_EDIT_CONFLICT","AUDIENCE_MEMBERSHIP_NOT_EXPRESSIBLE","AUDIENCE_NOT_FOUND","AUDIENCE_RUN_NOT_FOUND","AUDIT_NOT_FOUND","AUTHENTICATION_REQUIRED","AUTOMATION_GRAPH_INVALID","AUTOMATION_NOT_FOUND","AUTOMATION_NOT_PAUSABLE","AUTOMATION_NOT_PUBLISHED","AUTOMATION_RUN_NOT_FOUND","AUTOMATION_VERSION_CONFLICT","AUTOMATION_VERSION_NOT_FOUND","BATCH_TOO_LARGE","BRAND_DOMAIN_CONFLICT","BRAND_ID_REQUIRED","BRAND_LIMIT_REACHED","BRAND_NOT_FOUND","BRAND_NOT_READY","BRAND_SCOPE_MISMATCH","CHAT_NOT_FOUND","COMMENT_NOT_FOUND","CONSENT_REQUIRED","CONTACT_NOT_FOUND","CONTENT_OPERATION_FAILED","CONTRACT_LOCKED_BY_PUBLISHED_AUTOMATIONS","CORE_FIELD_IMMUTABLE","DOMAIN_ALREADY_EXISTS","DOMAIN_CLAIMED_ELSEWHERE","DOMAIN_NOT_FOUND","DOMAIN_NOT_READY","DOMAIN_OTHER_BRAND","DOMAIN_PROVIDER_ERROR","DOMAIN_PURPOSE_NOT_ALLOWED","DOMAIN_VERIFICATION_FAILED","DOMAIN_VERIFIED_ELSEWHERE","EMAIL_GENERATION_FAILED","EMAIL_GROUP_NAME_CONFLICT","EMAIL_GROUP_NOT_FOUND","EMAIL_IMAGES_MISSING","EMAIL_IMPORT_FAILED","EMAIL_IMPORT_PERSISTENCE_FAILED","EMAIL_IN_PROGRESS","EMAIL_IN_USE_BY_AUTOMATION","EMAIL_NOT_FOUND","EMAIL_NOT_READY","EMAIL_RESULT_UNAVAILABLE","EMAIL_RUN_AMBIGUOUS","EMAIL_TEMPLATE_INVALID","EMAIL_VERSION_NOT_FOUND","EXPORT_PROVIDER_ERROR","EXPORT_UNSUPPORTED","FIELD_NAME_COLLISION","FIELD_NOT_FOUND","FIELD_TYPE_MISMATCH","FIGMA_ACCESS_DENIED","FIGMA_CONVERSION_FAILED","FIGMA_FRAME_NOT_FOUND","FIGMA_NOT_CONNECTED","FIGMA_UNAVAILABLE","FIGMA_URL_INVALID","FLOW_NOT_FOUND","IDEMPOTENCY_CONFLICT","IDEMPOTENCY_IN_PROGRESS","INSIGHT_NOT_FOUND","INSUFFICIENT_CREDITS","INSUFFICIENT_PERMISSIONS","INSUFFICIENT_ROLE","INTEGRATION_NOT_CONNECTED","INTERNAL_ERROR","INVALID_API_KEY","INVALID_EMAIL","INVALID_PAYLOAD","INVALID_REQUEST","LIQUID_RENDER_ERROR","METHOD_NOT_ALLOWED","MISSING_EMAIL","NO_ELIGIBLE_RECIPIENTS","NO_PUBLISHED_AUTOMATION","NOT_FOUND","NOT_IMPLEMENTED","ORG_SCOPE_REQUIRED","PAYLOAD_SCHEMA_EMAIL_REQUIRED","PAYLOAD_TOO_LARGE","PREVIEW_NOT_FOUND","PUBLISH_VALIDATION_FAILED","RATE_LIMITED","RECIPIENT_UNSUBSCRIBED","REFERENCE_EMAIL_NOT_FOUND","RESUBSCRIBE_NOT_ALLOWED","RUN_IN_PROGRESS","RUN_NOT_CANCELLABLE","RUN_NOT_PAUSABLE","RUN_NOT_PAUSED","RUN_NOT_RESUMABLE","RUN_START_FAILED","RUN_STOP_FAILED","SEND_NOT_CANCELLABLE","SEND_NOT_FOUND","SEND_NOT_PAUSABLE","SEND_NOT_RESUMABLE","SEND_QUOTA_EXCEEDED","SERVICE_UNAVAILABLE","TEMPLATE_NOT_FOUND","TEST_RECIPIENT_NOT_ALLOWED","TRIGGER_ALREADY_EXISTS","TRIGGER_EVENT_NOT_FOUND","TRIGGER_HAS_DEPENDENT_AUTOMATIONS","TRIGGER_IMMUTABLE","TRIGGER_INSTANCE_NOT_FOUND","TRIGGER_LIMIT_REACHED","TRIGGER_NOT_FIREABLE","UPLOAD_IN_PROGRESS","UPLOAD_NOT_FOUND","UPLOAD_NOT_RECEIVED"],"isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"type":{"type":"string","enum":["authentication_error","authorization_error","invalid_request","not_found","not_implemented","conflict","rate_limit","payment_required","service_unavailable","internal_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"suggestion":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.suggestion","typeLabel":"string"},"docs":{"type":"string","format":"uri","isRequired":true,"uniqueKey":"error.docs","typeLabel":"string\u003curi>"},"param":{"type":"string","minLength":1,"uniqueKey":"error.param","typeLabel":"string"},"retryAfter":{"type":"integer","minimum":0,"uniqueKey":"error.retryAfter","typeLabel":"integer"},"details":{"type":"object","additionalProperties":{"oneOf":[{}],"uniqueKey":"error.details.additionalProperties","typeLabel":"any"},"uniqueKey":"error.details","typeLabel":"object"}},"required":["code","type","message","suggestion","docs"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"required":["error"],"uniqueKey":"","typeLabel":"object"},"examples":{"idempotencyConflict":{"title":"idempotencyConflict","value":{"error":{"code":"IDEMPOTENCY_CONFLICT","type":"conflict","message":"The same Idempotency-Key was reused with a different request body.","suggestion":"Reuse the original payload or send a new idempotency key.","docs":"https://docs.brew.new/api-reference/api/idempotency"}}},"idempotencyInProgress":{"title":"idempotencyInProgress","value":{"error":{"code":"IDEMPOTENCY_IN_PROGRESS","type":"conflict","message":"A request with this Idempotency-Key is still executing.","suggestion":"Wait for the original request to finish, then retry the same key to replay its response.","docs":"https://docs.brew.new/api-reference/api/idempotency"}}}},"exampleType":"examples"}},"exampleType":"examples"},"fca8cc3d-adf2-4d04-a186-eb70144f4a64":{"description":"`FIELD_NAME_COLLISION`: Two keys in one request name the same contact field (`plan` and `Plan`, `team_size` and `Team Size`), so one value would be lost.","headers":{"x-request-id":{"schema":{"type":"string","description":"Unique request identifier. Share this with support when debugging a request.","example":"req_8cac13fd94e6420cacdd75a1aa403a28"},"required":true,"description":"Unique request identifier. Share this with support when debugging a request."}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["ACCOUNT_SUSPENDED","API_KEY_REVOKED","AUDIENCE_BUILD_ACTIVE","AUDIENCE_BUILD_ALREADY_ACTIVE","AUDIENCE_EDIT_CONFLICT","AUDIENCE_MEMBERSHIP_NOT_EXPRESSIBLE","AUDIENCE_NOT_FOUND","AUDIENCE_RUN_NOT_FOUND","AUDIT_NOT_FOUND","AUTHENTICATION_REQUIRED","AUTOMATION_GRAPH_INVALID","AUTOMATION_NOT_FOUND","AUTOMATION_NOT_PAUSABLE","AUTOMATION_NOT_PUBLISHED","AUTOMATION_RUN_NOT_FOUND","AUTOMATION_VERSION_CONFLICT","AUTOMATION_VERSION_NOT_FOUND","BATCH_TOO_LARGE","BRAND_DOMAIN_CONFLICT","BRAND_ID_REQUIRED","BRAND_LIMIT_REACHED","BRAND_NOT_FOUND","BRAND_NOT_READY","BRAND_SCOPE_MISMATCH","CHAT_NOT_FOUND","COMMENT_NOT_FOUND","CONSENT_REQUIRED","CONTACT_NOT_FOUND","CONTENT_OPERATION_FAILED","CONTRACT_LOCKED_BY_PUBLISHED_AUTOMATIONS","CORE_FIELD_IMMUTABLE","DOMAIN_ALREADY_EXISTS","DOMAIN_CLAIMED_ELSEWHERE","DOMAIN_NOT_FOUND","DOMAIN_NOT_READY","DOMAIN_OTHER_BRAND","DOMAIN_PROVIDER_ERROR","DOMAIN_PURPOSE_NOT_ALLOWED","DOMAIN_VERIFICATION_FAILED","DOMAIN_VERIFIED_ELSEWHERE","EMAIL_GENERATION_FAILED","EMAIL_GROUP_NAME_CONFLICT","EMAIL_GROUP_NOT_FOUND","EMAIL_IMAGES_MISSING","EMAIL_IMPORT_FAILED","EMAIL_IMPORT_PERSISTENCE_FAILED","EMAIL_IN_PROGRESS","EMAIL_IN_USE_BY_AUTOMATION","EMAIL_NOT_FOUND","EMAIL_NOT_READY","EMAIL_RESULT_UNAVAILABLE","EMAIL_RUN_AMBIGUOUS","EMAIL_TEMPLATE_INVALID","EMAIL_VERSION_NOT_FOUND","EXPORT_PROVIDER_ERROR","EXPORT_UNSUPPORTED","FIELD_NAME_COLLISION","FIELD_NOT_FOUND","FIELD_TYPE_MISMATCH","FIGMA_ACCESS_DENIED","FIGMA_CONVERSION_FAILED","FIGMA_FRAME_NOT_FOUND","FIGMA_NOT_CONNECTED","FIGMA_UNAVAILABLE","FIGMA_URL_INVALID","FLOW_NOT_FOUND","IDEMPOTENCY_CONFLICT","IDEMPOTENCY_IN_PROGRESS","INSIGHT_NOT_FOUND","INSUFFICIENT_CREDITS","INSUFFICIENT_PERMISSIONS","INSUFFICIENT_ROLE","INTEGRATION_NOT_CONNECTED","INTERNAL_ERROR","INVALID_API_KEY","INVALID_EMAIL","INVALID_PAYLOAD","INVALID_REQUEST","LIQUID_RENDER_ERROR","METHOD_NOT_ALLOWED","MISSING_EMAIL","NO_ELIGIBLE_RECIPIENTS","NO_PUBLISHED_AUTOMATION","NOT_FOUND","NOT_IMPLEMENTED","ORG_SCOPE_REQUIRED","PAYLOAD_SCHEMA_EMAIL_REQUIRED","PAYLOAD_TOO_LARGE","PREVIEW_NOT_FOUND","PUBLISH_VALIDATION_FAILED","RATE_LIMITED","RECIPIENT_UNSUBSCRIBED","REFERENCE_EMAIL_NOT_FOUND","RESUBSCRIBE_NOT_ALLOWED","RUN_IN_PROGRESS","RUN_NOT_CANCELLABLE","RUN_NOT_PAUSABLE","RUN_NOT_PAUSED","RUN_NOT_RESUMABLE","RUN_START_FAILED","RUN_STOP_FAILED","SEND_NOT_CANCELLABLE","SEND_NOT_FOUND","SEND_NOT_PAUSABLE","SEND_NOT_RESUMABLE","SEND_QUOTA_EXCEEDED","SERVICE_UNAVAILABLE","TEMPLATE_NOT_FOUND","TEST_RECIPIENT_NOT_ALLOWED","TRIGGER_ALREADY_EXISTS","TRIGGER_EVENT_NOT_FOUND","TRIGGER_HAS_DEPENDENT_AUTOMATIONS","TRIGGER_IMMUTABLE","TRIGGER_INSTANCE_NOT_FOUND","TRIGGER_LIMIT_REACHED","TRIGGER_NOT_FIREABLE","UPLOAD_IN_PROGRESS","UPLOAD_NOT_FOUND","UPLOAD_NOT_RECEIVED"],"isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"type":{"type":"string","enum":["authentication_error","authorization_error","invalid_request","not_found","not_implemented","conflict","rate_limit","payment_required","service_unavailable","internal_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"suggestion":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.suggestion","typeLabel":"string"},"docs":{"type":"string","format":"uri","isRequired":true,"uniqueKey":"error.docs","typeLabel":"string\u003curi>"},"param":{"type":"string","minLength":1,"uniqueKey":"error.param","typeLabel":"string"},"retryAfter":{"type":"integer","minimum":0,"uniqueKey":"error.retryAfter","typeLabel":"integer"},"details":{"type":"object","additionalProperties":{"oneOf":[{}],"uniqueKey":"error.details.additionalProperties","typeLabel":"any"},"uniqueKey":"error.details","typeLabel":"object"}},"required":["code","type","message","suggestion","docs"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"required":["error"],"uniqueKey":"","typeLabel":"object"},"examples":{"fieldNameCollision":{"title":"fieldNameCollision","value":{"error":{"code":"FIELD_NAME_COLLISION","type":"invalid_request","message":"Two keys in one request name the same contact field (`plan` and `Plan`, `team_size` and `Team Size`), so one value would be lost.","suggestion":"Send one of the two keys, or rename one so it names a different field.","docs":"https://docs.brew.new/api-reference/api/errors"}}}},"exampleType":"examples"}},"exampleType":"examples"},"c94d3331-c4a2-462e-beaa-f4bd73f101dd":{"description":"`RATE_LIMITED`: The credential exhausted the rolling window for this route policy; Retry-After is when the oldest recorded request leaves, and the refused request does not take a slot.","headers":{"x-request-id":{"schema":{"type":"string","description":"Unique request identifier. Share this with support when debugging a request.","example":"req_8cac13fd94e6420cacdd75a1aa403a28"},"required":true,"description":"Unique request identifier. Share this with support when debugging a request."},"X-RateLimit-Limit":{"schema":{"type":"integer","description":"Requests allowed in the current rolling rate limit window.","example":10},"required":true,"description":"Requests allowed in the current rolling rate limit window."},"X-RateLimit-Remaining":{"schema":{"type":"integer","description":"Requests remaining in the current rolling rate limit window.","example":0},"required":true,"description":"Requests remaining in the current rolling rate limit window."},"X-RateLimit-Reset":{"schema":{"type":"integer","description":"Unix timestamp in seconds when the oldest recorded request leaves the rolling window.","example":1712592360},"required":true,"description":"Unix timestamp in seconds when the oldest recorded request leaves the rolling window."},"Retry-After":{"schema":{"type":"integer","description":"Seconds to wait before retrying the request.","example":42},"required":true,"description":"Seconds to wait before retrying the request."}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["ACCOUNT_SUSPENDED","API_KEY_REVOKED","AUDIENCE_BUILD_ACTIVE","AUDIENCE_BUILD_ALREADY_ACTIVE","AUDIENCE_EDIT_CONFLICT","AUDIENCE_MEMBERSHIP_NOT_EXPRESSIBLE","AUDIENCE_NOT_FOUND","AUDIENCE_RUN_NOT_FOUND","AUDIT_NOT_FOUND","AUTHENTICATION_REQUIRED","AUTOMATION_GRAPH_INVALID","AUTOMATION_NOT_FOUND","AUTOMATION_NOT_PAUSABLE","AUTOMATION_NOT_PUBLISHED","AUTOMATION_RUN_NOT_FOUND","AUTOMATION_VERSION_CONFLICT","AUTOMATION_VERSION_NOT_FOUND","BATCH_TOO_LARGE","BRAND_DOMAIN_CONFLICT","BRAND_ID_REQUIRED","BRAND_LIMIT_REACHED","BRAND_NOT_FOUND","BRAND_NOT_READY","BRAND_SCOPE_MISMATCH","CHAT_NOT_FOUND","COMMENT_NOT_FOUND","CONSENT_REQUIRED","CONTACT_NOT_FOUND","CONTENT_OPERATION_FAILED","CONTRACT_LOCKED_BY_PUBLISHED_AUTOMATIONS","CORE_FIELD_IMMUTABLE","DOMAIN_ALREADY_EXISTS","DOMAIN_CLAIMED_ELSEWHERE","DOMAIN_NOT_FOUND","DOMAIN_NOT_READY","DOMAIN_OTHER_BRAND","DOMAIN_PROVIDER_ERROR","DOMAIN_PURPOSE_NOT_ALLOWED","DOMAIN_VERIFICATION_FAILED","DOMAIN_VERIFIED_ELSEWHERE","EMAIL_GENERATION_FAILED","EMAIL_GROUP_NAME_CONFLICT","EMAIL_GROUP_NOT_FOUND","EMAIL_IMAGES_MISSING","EMAIL_IMPORT_FAILED","EMAIL_IMPORT_PERSISTENCE_FAILED","EMAIL_IN_PROGRESS","EMAIL_IN_USE_BY_AUTOMATION","EMAIL_NOT_FOUND","EMAIL_NOT_READY","EMAIL_RESULT_UNAVAILABLE","EMAIL_RUN_AMBIGUOUS","EMAIL_TEMPLATE_INVALID","EMAIL_VERSION_NOT_FOUND","EXPORT_PROVIDER_ERROR","EXPORT_UNSUPPORTED","FIELD_NAME_COLLISION","FIELD_NOT_FOUND","FIELD_TYPE_MISMATCH","FIGMA_ACCESS_DENIED","FIGMA_CONVERSION_FAILED","FIGMA_FRAME_NOT_FOUND","FIGMA_NOT_CONNECTED","FIGMA_UNAVAILABLE","FIGMA_URL_INVALID","FLOW_NOT_FOUND","IDEMPOTENCY_CONFLICT","IDEMPOTENCY_IN_PROGRESS","INSIGHT_NOT_FOUND","INSUFFICIENT_CREDITS","INSUFFICIENT_PERMISSIONS","INSUFFICIENT_ROLE","INTEGRATION_NOT_CONNECTED","INTERNAL_ERROR","INVALID_API_KEY","INVALID_EMAIL","INVALID_PAYLOAD","INVALID_REQUEST","LIQUID_RENDER_ERROR","METHOD_NOT_ALLOWED","MISSING_EMAIL","NO_ELIGIBLE_RECIPIENTS","NO_PUBLISHED_AUTOMATION","NOT_FOUND","NOT_IMPLEMENTED","ORG_SCOPE_REQUIRED","PAYLOAD_SCHEMA_EMAIL_REQUIRED","PAYLOAD_TOO_LARGE","PREVIEW_NOT_FOUND","PUBLISH_VALIDATION_FAILED","RATE_LIMITED","RECIPIENT_UNSUBSCRIBED","REFERENCE_EMAIL_NOT_FOUND","RESUBSCRIBE_NOT_ALLOWED","RUN_IN_PROGRESS","RUN_NOT_CANCELLABLE","RUN_NOT_PAUSABLE","RUN_NOT_PAUSED","RUN_NOT_RESUMABLE","RUN_START_FAILED","RUN_STOP_FAILED","SEND_NOT_CANCELLABLE","SEND_NOT_FOUND","SEND_NOT_PAUSABLE","SEND_NOT_RESUMABLE","SEND_QUOTA_EXCEEDED","SERVICE_UNAVAILABLE","TEMPLATE_NOT_FOUND","TEST_RECIPIENT_NOT_ALLOWED","TRIGGER_ALREADY_EXISTS","TRIGGER_EVENT_NOT_FOUND","TRIGGER_HAS_DEPENDENT_AUTOMATIONS","TRIGGER_IMMUTABLE","TRIGGER_INSTANCE_NOT_FOUND","TRIGGER_LIMIT_REACHED","TRIGGER_NOT_FIREABLE","UPLOAD_IN_PROGRESS","UPLOAD_NOT_FOUND","UPLOAD_NOT_RECEIVED"],"isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"type":{"type":"string","enum":["authentication_error","authorization_error","invalid_request","not_found","not_implemented","conflict","rate_limit","payment_required","service_unavailable","internal_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"suggestion":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.suggestion","typeLabel":"string"},"docs":{"type":"string","format":"uri","isRequired":true,"uniqueKey":"error.docs","typeLabel":"string\u003curi>"},"param":{"type":"string","minLength":1,"uniqueKey":"error.param","typeLabel":"string"},"retryAfter":{"type":"integer","minimum":0,"uniqueKey":"error.retryAfter","typeLabel":"integer"},"details":{"type":"object","additionalProperties":{"oneOf":[{}],"uniqueKey":"error.details.additionalProperties","typeLabel":"any"},"uniqueKey":"error.details","typeLabel":"object"}},"required":["code","type","message","suggestion","docs"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"required":["error"],"uniqueKey":"","typeLabel":"object"},"examples":{"rateLimited":{"title":"rateLimited","value":{"error":{"code":"RATE_LIMITED","type":"rate_limit","message":"The credential exhausted the rolling window for this route policy; Retry-After is when the oldest recorded request leaves, and the refused request does not take a slot.","suggestion":"Wait the Retry-After time, then retry the same request.","docs":"https://docs.brew.new/api-reference/api/rate-limits","retryAfter":42,"details":{"scope":"credential","limit":10,"remaining":0,"reset":1712592360,"consumed":false}}}}},"exampleType":"examples"}},"exampleType":"examples"},"e776d521-6839-4e97-9b2d-b1142ab92e36":{"description":"`INTERNAL_ERROR`: An unexpected failure; the x-request-id header identifies it.","headers":{"x-request-id":{"schema":{"type":"string","description":"Unique request identifier. Share this with support when debugging a request.","example":"req_8cac13fd94e6420cacdd75a1aa403a28"},"required":true,"description":"Unique request identifier. Share this with support when debugging a request."}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["ACCOUNT_SUSPENDED","API_KEY_REVOKED","AUDIENCE_BUILD_ACTIVE","AUDIENCE_BUILD_ALREADY_ACTIVE","AUDIENCE_EDIT_CONFLICT","AUDIENCE_MEMBERSHIP_NOT_EXPRESSIBLE","AUDIENCE_NOT_FOUND","AUDIENCE_RUN_NOT_FOUND","AUDIT_NOT_FOUND","AUTHENTICATION_REQUIRED","AUTOMATION_GRAPH_INVALID","AUTOMATION_NOT_FOUND","AUTOMATION_NOT_PAUSABLE","AUTOMATION_NOT_PUBLISHED","AUTOMATION_RUN_NOT_FOUND","AUTOMATION_VERSION_CONFLICT","AUTOMATION_VERSION_NOT_FOUND","BATCH_TOO_LARGE","BRAND_DOMAIN_CONFLICT","BRAND_ID_REQUIRED","BRAND_LIMIT_REACHED","BRAND_NOT_FOUND","BRAND_NOT_READY","BRAND_SCOPE_MISMATCH","CHAT_NOT_FOUND","COMMENT_NOT_FOUND","CONSENT_REQUIRED","CONTACT_NOT_FOUND","CONTENT_OPERATION_FAILED","CONTRACT_LOCKED_BY_PUBLISHED_AUTOMATIONS","CORE_FIELD_IMMUTABLE","DOMAIN_ALREADY_EXISTS","DOMAIN_CLAIMED_ELSEWHERE","DOMAIN_NOT_FOUND","DOMAIN_NOT_READY","DOMAIN_OTHER_BRAND","DOMAIN_PROVIDER_ERROR","DOMAIN_PURPOSE_NOT_ALLOWED","DOMAIN_VERIFICATION_FAILED","DOMAIN_VERIFIED_ELSEWHERE","EMAIL_GENERATION_FAILED","EMAIL_GROUP_NAME_CONFLICT","EMAIL_GROUP_NOT_FOUND","EMAIL_IMAGES_MISSING","EMAIL_IMPORT_FAILED","EMAIL_IMPORT_PERSISTENCE_FAILED","EMAIL_IN_PROGRESS","EMAIL_IN_USE_BY_AUTOMATION","EMAIL_NOT_FOUND","EMAIL_NOT_READY","EMAIL_RESULT_UNAVAILABLE","EMAIL_RUN_AMBIGUOUS","EMAIL_TEMPLATE_INVALID","EMAIL_VERSION_NOT_FOUND","EXPORT_PROVIDER_ERROR","EXPORT_UNSUPPORTED","FIELD_NAME_COLLISION","FIELD_NOT_FOUND","FIELD_TYPE_MISMATCH","FIGMA_ACCESS_DENIED","FIGMA_CONVERSION_FAILED","FIGMA_FRAME_NOT_FOUND","FIGMA_NOT_CONNECTED","FIGMA_UNAVAILABLE","FIGMA_URL_INVALID","FLOW_NOT_FOUND","IDEMPOTENCY_CONFLICT","IDEMPOTENCY_IN_PROGRESS","INSIGHT_NOT_FOUND","INSUFFICIENT_CREDITS","INSUFFICIENT_PERMISSIONS","INSUFFICIENT_ROLE","INTEGRATION_NOT_CONNECTED","INTERNAL_ERROR","INVALID_API_KEY","INVALID_EMAIL","INVALID_PAYLOAD","INVALID_REQUEST","LIQUID_RENDER_ERROR","METHOD_NOT_ALLOWED","MISSING_EMAIL","NO_ELIGIBLE_RECIPIENTS","NO_PUBLISHED_AUTOMATION","NOT_FOUND","NOT_IMPLEMENTED","ORG_SCOPE_REQUIRED","PAYLOAD_SCHEMA_EMAIL_REQUIRED","PAYLOAD_TOO_LARGE","PREVIEW_NOT_FOUND","PUBLISH_VALIDATION_FAILED","RATE_LIMITED","RECIPIENT_UNSUBSCRIBED","REFERENCE_EMAIL_NOT_FOUND","RESUBSCRIBE_NOT_ALLOWED","RUN_IN_PROGRESS","RUN_NOT_CANCELLABLE","RUN_NOT_PAUSABLE","RUN_NOT_PAUSED","RUN_NOT_RESUMABLE","RUN_START_FAILED","RUN_STOP_FAILED","SEND_NOT_CANCELLABLE","SEND_NOT_FOUND","SEND_NOT_PAUSABLE","SEND_NOT_RESUMABLE","SEND_QUOTA_EXCEEDED","SERVICE_UNAVAILABLE","TEMPLATE_NOT_FOUND","TEST_RECIPIENT_NOT_ALLOWED","TRIGGER_ALREADY_EXISTS","TRIGGER_EVENT_NOT_FOUND","TRIGGER_HAS_DEPENDENT_AUTOMATIONS","TRIGGER_IMMUTABLE","TRIGGER_INSTANCE_NOT_FOUND","TRIGGER_LIMIT_REACHED","TRIGGER_NOT_FIREABLE","UPLOAD_IN_PROGRESS","UPLOAD_NOT_FOUND","UPLOAD_NOT_RECEIVED"],"isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"type":{"type":"string","enum":["authentication_error","authorization_error","invalid_request","not_found","not_implemented","conflict","rate_limit","payment_required","service_unavailable","internal_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"suggestion":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.suggestion","typeLabel":"string"},"docs":{"type":"string","format":"uri","isRequired":true,"uniqueKey":"error.docs","typeLabel":"string\u003curi>"},"param":{"type":"string","minLength":1,"uniqueKey":"error.param","typeLabel":"string"},"retryAfter":{"type":"integer","minimum":0,"uniqueKey":"error.retryAfter","typeLabel":"integer"},"details":{"type":"object","additionalProperties":{"oneOf":[{}],"uniqueKey":"error.details.additionalProperties","typeLabel":"any"},"uniqueKey":"error.details","typeLabel":"object"}},"required":["code","type","message","suggestion","docs"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"required":["error"],"uniqueKey":"","typeLabel":"object"},"examples":{"internalError":{"title":"internalError","value":{"error":{"code":"INTERNAL_ERROR","type":"internal_error","message":"An unexpected failure; the x-request-id header identifies it.","suggestion":"Retry the request. If it keeps failing, contact support with the x-request-id header.","docs":"https://docs.brew.new/api-reference/api/errors"}}}},"exampleType":"examples"}},"exampleType":"examples"},"8b799897-de9f-492a-ac7e-d9eabf2156a8":{"description":"`SERVICE_UNAVAILABLE`: A dependency the operation must consult (billing, the idempotency store) is temporarily unavailable, so the request was refused rather than run unmetered.","headers":{"x-request-id":{"schema":{"type":"string","description":"Unique request identifier. Share this with support when debugging a request.","example":"req_8cac13fd94e6420cacdd75a1aa403a28"},"required":true,"description":"Unique request identifier. Share this with support when debugging a request."},"Retry-After":{"schema":{"type":"integer","description":"Seconds to wait before retrying the request.","example":42},"required":true,"description":"Seconds to wait before retrying the request."}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["ACCOUNT_SUSPENDED","API_KEY_REVOKED","AUDIENCE_BUILD_ACTIVE","AUDIENCE_BUILD_ALREADY_ACTIVE","AUDIENCE_EDIT_CONFLICT","AUDIENCE_MEMBERSHIP_NOT_EXPRESSIBLE","AUDIENCE_NOT_FOUND","AUDIENCE_RUN_NOT_FOUND","AUDIT_NOT_FOUND","AUTHENTICATION_REQUIRED","AUTOMATION_GRAPH_INVALID","AUTOMATION_NOT_FOUND","AUTOMATION_NOT_PAUSABLE","AUTOMATION_NOT_PUBLISHED","AUTOMATION_RUN_NOT_FOUND","AUTOMATION_VERSION_CONFLICT","AUTOMATION_VERSION_NOT_FOUND","BATCH_TOO_LARGE","BRAND_DOMAIN_CONFLICT","BRAND_ID_REQUIRED","BRAND_LIMIT_REACHED","BRAND_NOT_FOUND","BRAND_NOT_READY","BRAND_SCOPE_MISMATCH","CHAT_NOT_FOUND","COMMENT_NOT_FOUND","CONSENT_REQUIRED","CONTACT_NOT_FOUND","CONTENT_OPERATION_FAILED","CONTRACT_LOCKED_BY_PUBLISHED_AUTOMATIONS","CORE_FIELD_IMMUTABLE","DOMAIN_ALREADY_EXISTS","DOMAIN_CLAIMED_ELSEWHERE","DOMAIN_NOT_FOUND","DOMAIN_NOT_READY","DOMAIN_OTHER_BRAND","DOMAIN_PROVIDER_ERROR","DOMAIN_PURPOSE_NOT_ALLOWED","DOMAIN_VERIFICATION_FAILED","DOMAIN_VERIFIED_ELSEWHERE","EMAIL_GENERATION_FAILED","EMAIL_GROUP_NAME_CONFLICT","EMAIL_GROUP_NOT_FOUND","EMAIL_IMAGES_MISSING","EMAIL_IMPORT_FAILED","EMAIL_IMPORT_PERSISTENCE_FAILED","EMAIL_IN_PROGRESS","EMAIL_IN_USE_BY_AUTOMATION","EMAIL_NOT_FOUND","EMAIL_NOT_READY","EMAIL_RESULT_UNAVAILABLE","EMAIL_RUN_AMBIGUOUS","EMAIL_TEMPLATE_INVALID","EMAIL_VERSION_NOT_FOUND","EXPORT_PROVIDER_ERROR","EXPORT_UNSUPPORTED","FIELD_NAME_COLLISION","FIELD_NOT_FOUND","FIELD_TYPE_MISMATCH","FIGMA_ACCESS_DENIED","FIGMA_CONVERSION_FAILED","FIGMA_FRAME_NOT_FOUND","FIGMA_NOT_CONNECTED","FIGMA_UNAVAILABLE","FIGMA_URL_INVALID","FLOW_NOT_FOUND","IDEMPOTENCY_CONFLICT","IDEMPOTENCY_IN_PROGRESS","INSIGHT_NOT_FOUND","INSUFFICIENT_CREDITS","INSUFFICIENT_PERMISSIONS","INSUFFICIENT_ROLE","INTEGRATION_NOT_CONNECTED","INTERNAL_ERROR","INVALID_API_KEY","INVALID_EMAIL","INVALID_PAYLOAD","INVALID_REQUEST","LIQUID_RENDER_ERROR","METHOD_NOT_ALLOWED","MISSING_EMAIL","NO_ELIGIBLE_RECIPIENTS","NO_PUBLISHED_AUTOMATION","NOT_FOUND","NOT_IMPLEMENTED","ORG_SCOPE_REQUIRED","PAYLOAD_SCHEMA_EMAIL_REQUIRED","PAYLOAD_TOO_LARGE","PREVIEW_NOT_FOUND","PUBLISH_VALIDATION_FAILED","RATE_LIMITED","RECIPIENT_UNSUBSCRIBED","REFERENCE_EMAIL_NOT_FOUND","RESUBSCRIBE_NOT_ALLOWED","RUN_IN_PROGRESS","RUN_NOT_CANCELLABLE","RUN_NOT_PAUSABLE","RUN_NOT_PAUSED","RUN_NOT_RESUMABLE","RUN_START_FAILED","RUN_STOP_FAILED","SEND_NOT_CANCELLABLE","SEND_NOT_FOUND","SEND_NOT_PAUSABLE","SEND_NOT_RESUMABLE","SEND_QUOTA_EXCEEDED","SERVICE_UNAVAILABLE","TEMPLATE_NOT_FOUND","TEST_RECIPIENT_NOT_ALLOWED","TRIGGER_ALREADY_EXISTS","TRIGGER_EVENT_NOT_FOUND","TRIGGER_HAS_DEPENDENT_AUTOMATIONS","TRIGGER_IMMUTABLE","TRIGGER_INSTANCE_NOT_FOUND","TRIGGER_LIMIT_REACHED","TRIGGER_NOT_FIREABLE","UPLOAD_IN_PROGRESS","UPLOAD_NOT_FOUND","UPLOAD_NOT_RECEIVED"],"isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"type":{"type":"string","enum":["authentication_error","authorization_error","invalid_request","not_found","not_implemented","conflict","rate_limit","payment_required","service_unavailable","internal_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"suggestion":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"error.suggestion","typeLabel":"string"},"docs":{"type":"string","format":"uri","isRequired":true,"uniqueKey":"error.docs","typeLabel":"string\u003curi>"},"param":{"type":"string","minLength":1,"uniqueKey":"error.param","typeLabel":"string"},"retryAfter":{"type":"integer","minimum":0,"uniqueKey":"error.retryAfter","typeLabel":"integer"},"details":{"type":"object","additionalProperties":{"oneOf":[{}],"uniqueKey":"error.details.additionalProperties","typeLabel":"any"},"uniqueKey":"error.details","typeLabel":"object"}},"required":["code","type","message","suggestion","docs"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"required":["error"],"uniqueKey":"","typeLabel":"object"},"examples":{"serviceUnavailable":{"title":"serviceUnavailable","value":{"error":{"code":"SERVICE_UNAVAILABLE","type":"service_unavailable","message":"A dependency the operation must consult (billing, the idempotency store) is temporarily unavailable, so the request was refused rather than run unmetered.","suggestion":"Retry the request after a short delay.","docs":"https://docs.brew.new/api-reference/api/errors"}}}},"exampleType":"examples"}},"exampleType":"examples"}},"security":{"3becd03d-c396-4bc3-84c1-231cdbf0a23e":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API key","description":"Send your Brew API key as `Authorization: Bearer brew_xxx`.","x-default":"Bearer brew_your_api_key","scopes":[],"schemeName":"bearerAuth"}},"a3a3e731-b20f-48f7-873a-3123be78670a":{"apiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Send your Brew API key as `X-API-Key: brew_xxx`.","x-default":"brew_your_api_key","scopes":[],"schemeName":"apiKeyAuth"}}},"servers":{"16779731-d97b-4178-b35d-ab9db802c966":{"url":"https://brew.new/api","description":"Production"},"d75b81f5-e341-4448-9191-a43a58d2508e":{"url":"http://localhost:3000/api","description":"Local development"}},"processedSecurityOptions":[{"schemes":[{"scheme":{"type":"http","scheme":"bearer","bearerFormat":"API key","description":"Send your Brew API key as `Authorization: Bearer brew_xxx`.","x-default":"Bearer brew_your_api_key","scopes":[],"schemeName":"bearerAuth"},"schema":{"title":"Bearer Auth","type":"string","isRequired":true,"description":"Send your Brew API key as `Authorization: Bearer brew_xxx`.","format":"bearer","default":"Bearer brew_your_api_key","typeLabel":"string\u003cbearer>","deprecated":false},"schemeName":"bearerAuth","name":"Authorization"}],"title":"bearerAuth"},{"schemes":[{"scheme":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Send your Brew API key as `X-API-Key: brew_xxx`.","x-default":"brew_your_api_key","scopes":[],"schemeName":"apiKeyAuth"},"schema":{"title":"X-API-Key","type":"string","description":"Send your Brew API key as `X-API-Key: brew_xxx`.","isRequired":true,"default":"brew_your_api_key","typeLabel":"string","deprecated":false},"schemeName":"apiKeyAuth","name":"X-API-Key"}],"title":"apiKeyAuth"}]},"originalFileLocation":"api-reference/openapi-public-v1.yaml"},"subdomain":"brew-796f053a","siteName":"Brew Help Docs","title":"Bulk-import contacts from CSV - Brew Help Docs","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-11-06T17:55:00.488Z","originalFileLocation":"api-reference/public-v1/contacts/bulk-import-contacts-from-csv.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Parse a raw CSV string and upsert the rows as contacts (≤ 1000). By default each column header maps to the custom field its name folds to, the same camelCase name POST /v1/contacts stores (Plan → plan, Team Size → teamSize); email is required. A header that spells a core field, ignoring case, spaces, _ and -, or whose field key equals it (First.Name), maps to it: Email, First Name, Last Name and Subscribed fill email, firstName, lastName and subscribed. Pass mapping to remap single columns; the columns it leaves out keep their default mapping, \u0026quot;\u0026quot; leaves a column out, and a key that names no column is a 400. Two columns that land on one custom field (plan,Plan: names fold as on POST /v1/contacts) are a 422 FIELD_NAME_COLLISION before any row is read: map one to another name or leave it out with \u0026quot;\u0026quot;. A core field that mapping fills is filled from that column alone: another column whose default would fill it is left out with a CSV_COLUMN_IGNORED warning. Rows with a missing/invalid email are SKIPPED (counted in summary.skipped), not errored; disposable-domain rows are imported with validationStatus: \u0026quot;risky\u0026quot; (deliverable but flagged). Returns the same { summary, fieldsCreated, errors, warnings } as batch-create plus importId — 207 when some rows fail. The batch is listed in Import History under fileName (optional), and each contact it writes carries importId until a later import touches it (filter on it to list them; deleting the import in the app removes the contacts it created). For rows you already hold as JSON, use POST /v1/contacts/import. CSV cells are text: a column mapped onto an EXISTING field is coerced to that field\u0026#x27;s type (dates → epoch ms, 1,234 → 1234, yes/no → booleans), and a cell that cannot be coerced ($49 in a number column) fails ITS row with a per-row errors[] entry (code: FIELD_TYPE_MISMATCH, field) while the other rows still land. A converted cell adds a warnings[] entry (code: FIELD_TYPE_COERCED, field, from, to); a date written to a date field is not reported. An undeclared column is created as a string field unless every value is an ISO date (→ date); predeclare number / bool columns with POST /v1/fields. A column whose field Brew manages (Created At, Validation Status) is not imported and adds a warnings[] entry (code: CSV_COLUMN_IGNORED, field names the column). A date column is read in ONE day/month order: the order its own dates prove (a day over 12 anywhere in the column, 13/04/2026), else dateOrder (day_first reads 03/04/2026 as 3 April, month_first as 4 March), else month/day with a warnings[] entry (code: DATE_ORDER_ASSUMED, field). Dotted dates (03.04.2026) are day-first. ISO (2026-04-03), Unix seconds or milliseconds, month names (3 Apr 2026), year-first (2026/04/03) and compact (20260403) dates need no order. Convert to YYYY-MM-DD to be unambiguous. A subscribed column reads true/false and ESP status words (unsubscribed, cleaned, blocklisted, transactional, active, …). An opt-out unsubscribes the contact, new or existing (with onConflict: \u0026quot;skip\u0026quot; an existing contact is left unchanged, and its CONTACT_EXISTS_SKIPPED warning says so). A word that is not a subscription status (maybe) fails its row (code: FIELD_TYPE_MISMATCH, field: subscribed) instead of importing the contact subscribed. A subscribed value only applies to new contacts: a row that asks to re-subscribe a contact who opted out keeps its other fields and adds a warnings[] entry (code: RESUBSCRIBE_SKIPPED, email). Two opt-in modes. dryRun: true returns the response this import would return (summary, errors, row warnings, fieldsCreated as fields it would create) with dryRun: true and no importId, and writes nothing: no contacts, field definitions or Import History entry; validate is not run and nothing is charged. Insert vs update is decided by the same address match the write uses, so a real run right after returns the same counts. onConflict: \u0026quot;skip\u0026quot; only creates missing contacts: each existing contact is left unchanged (an opt-out row included), counted in summary.skipped with a CONTACT_EXISTS_SKIPPED warning naming its row. Either way inserted + updated + failed + skipped = total. A dry run cannot foresee failures that only happen while writing (a concurrent change, a database refusal), so the real run can still fail where the preview succeeded. With validate: true, inline checks are still metered per submitted row, rows skip left alone included; a request that leaves no address to check is not charged.\">\u003cmeta data-mint-head name=\"keywords\" content=\"AI email marketing, Brew, AI-native email platform, on-brand email, email automations, email analytics, AI agents, MCP email server\">\u003cmeta data-mint-head name=\"application-name\" content=\"Brew Help Docs\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003cmeta data-mint-head name=\"robots\" content=\"index, follow\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/brew-796f053a/Sm1C1504JEJ_FZ8Q/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/brew-796f053a/Sm1C1504JEJ_FZ8Q/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/brew-796f053a/Sm1C1504JEJ_FZ8Q/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/brew-796f053a/Sm1C1504JEJ_FZ8Q/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/brew-796f053a/Sm1C1504JEJ_FZ8Q/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/brew-796f053a/Sm1C1504JEJ_FZ8Q/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/brew-796f053a/Sm1C1504JEJ_FZ8Q/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/brew-796f053a/Sm1C1504JEJ_FZ8Q/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/brew-796f053a/Sm1C1504JEJ_FZ8Q/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Bulk-import contacts from CSV - Brew Help Docs\">\u003cmeta data-mint-head property=\"og:description\" content=\"Parse a raw CSV string and upsert the rows as contacts (≤ 1000). By default each column header maps to the custom field its name folds to, the same camelCase name POST /v1/contacts stores (Plan → plan, Team Size → teamSize); email is required. A header that spells a core field, ignoring case, spaces, _ and -, or whose field key equals it (First.Name), maps to it: Email, First Name, Last Name and Subscribed fill email, firstName, lastName and subscribed. Pass mapping to remap single columns; the columns it leaves out keep their default mapping, \u0026quot;\u0026quot; leaves a column out, and a key that names no column is a 400. Two columns that land on one custom field (plan,Plan: names fold as on POST /v1/contacts) are a 422 FIELD_NAME_COLLISION before any row is read: map one to another name or leave it out with \u0026quot;\u0026quot;. A core field that mapping fills is filled from that column alone: another column whose default would fill it is left out with a CSV_COLUMN_IGNORED warning. Rows with a missing/invalid email are SKIPPED (counted in summary.skipped), not errored; disposable-domain rows are imported with validationStatus: \u0026quot;risky\u0026quot; (deliverable but flagged). Returns the same { summary, fieldsCreated, errors, warnings } as batch-create plus importId — 207 when some rows fail. The batch is listed in Import History under fileName (optional), and each contact it writes carries importId until a later import touches it (filter on it to list them; deleting the import in the app removes the contacts it created). For rows you already hold as JSON, use POST /v1/contacts/import. CSV cells are text: a column mapped onto an EXISTING field is coerced to that field\u0026#x27;s type (dates → epoch ms, 1,234 → 1234, yes/no → booleans), and a cell that cannot be coerced ($49 in a number column) fails ITS row with a per-row errors[] entry (code: FIELD_TYPE_MISMATCH, field) while the other rows still land. A converted cell adds a warnings[] entry (code: FIELD_TYPE_COERCED, field, from, to); a date written to a date field is not reported. An undeclared column is created as a string field unless every value is an ISO date (→ date); predeclare number / bool columns with POST /v1/fields. A column whose field Brew manages (Created At, Validation Status) is not imported and adds a warnings[] entry (code: CSV_COLUMN_IGNORED, field names the column). A date column is read in ONE day/month order: the order its own dates prove (a day over 12 anywhere in the column, 13/04/2026), else dateOrder (day_first reads 03/04/2026 as 3 April, month_first as 4 March), else month/day with a warnings[] entry (code: DATE_ORDER_ASSUMED, field). Dotted dates (03.04.2026) are day-first. ISO (2026-04-03), Unix seconds or milliseconds, month names (3 Apr 2026), year-first (2026/04/03) and compact (20260403) dates need no order. Convert to YYYY-MM-DD to be unambiguous. A subscribed column reads true/false and ESP status words (unsubscribed, cleaned, blocklisted, transactional, active, …). An opt-out unsubscribes the contact, new or existing (with onConflict: \u0026quot;skip\u0026quot; an existing contact is left unchanged, and its CONTACT_EXISTS_SKIPPED warning says so). A word that is not a subscription status (maybe) fails its row (code: FIELD_TYPE_MISMATCH, field: subscribed) instead of importing the contact subscribed. A subscribed value only applies to new contacts: a row that asks to re-subscribe a contact who opted out keeps its other fields and adds a warnings[] entry (code: RESUBSCRIBE_SKIPPED, email). Two opt-in modes. dryRun: true returns the response this import would return (summary, errors, row warnings, fieldsCreated as fields it would create) with dryRun: true and no importId, and writes nothing: no contacts, field definitions or Import History entry; validate is not run and nothing is charged. Insert vs update is decided by the same address match the write uses, so a real run right after returns the same counts. onConflict: \u0026quot;skip\u0026quot; only creates missing contacts: each existing contact is left unchanged (an opt-out row included), counted in summary.skipped with a CONTACT_EXISTS_SKIPPED warning naming its row. Either way inserted + updated + failed + skipped = total. A dry run cannot foresee failures that only happen while writing (a concurrent change, a database refusal), so the real run can still fail where the preview succeeded. With validate: true, inline checks are still metered per submitted row, rows skip left alone included; a request that leaves no address to check is not charged.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Brew Help Docs\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.brew.new/api-reference/public-v1/contacts/bulk-import-contacts-from-csv\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://docs.brew.new/images/og/default.png\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Bulk-import contacts from CSV - Brew Help Docs\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Parse a raw CSV string and upsert the rows as contacts (≤ 1000). By default each column header maps to the custom field its name folds to, the same camelCase name POST /v1/contacts stores (Plan → plan, Team Size → teamSize); email is required. A header that spells a core field, ignoring case, spaces, _ and -, or whose field key equals it (First.Name), maps to it: Email, First Name, Last Name and Subscribed fill email, firstName, lastName and subscribed. Pass mapping to remap single columns; the columns it leaves out keep their default mapping, \u0026quot;\u0026quot; leaves a column out, and a key that names no column is a 400. Two columns that land on one custom field (plan,Plan: names fold as on POST /v1/contacts) are a 422 FIELD_NAME_COLLISION before any row is read: map one to another name or leave it out with \u0026quot;\u0026quot;. A core field that mapping fills is filled from that column alone: another column whose default would fill it is left out with a CSV_COLUMN_IGNORED warning. Rows with a missing/invalid email are SKIPPED (counted in summary.skipped), not errored; disposable-domain rows are imported with validationStatus: \u0026quot;risky\u0026quot; (deliverable but flagged). Returns the same { summary, fieldsCreated, errors, warnings } as batch-create plus importId — 207 when some rows fail. The batch is listed in Import History under fileName (optional), and each contact it writes carries importId until a later import touches it (filter on it to list them; deleting the import in the app removes the contacts it created). For rows you already hold as JSON, use POST /v1/contacts/import. CSV cells are text: a column mapped onto an EXISTING field is coerced to that field\u0026#x27;s type (dates → epoch ms, 1,234 → 1234, yes/no → booleans), and a cell that cannot be coerced ($49 in a number column) fails ITS row with a per-row errors[] entry (code: FIELD_TYPE_MISMATCH, field) while the other rows still land. A converted cell adds a warnings[] entry (code: FIELD_TYPE_COERCED, field, from, to); a date written to a date field is not reported. An undeclared column is created as a string field unless every value is an ISO date (→ date); predeclare number / bool columns with POST /v1/fields. A column whose field Brew manages (Created At, Validation Status) is not imported and adds a warnings[] entry (code: CSV_COLUMN_IGNORED, field names the column). A date column is read in ONE day/month order: the order its own dates prove (a day over 12 anywhere in the column, 13/04/2026), else dateOrder (day_first reads 03/04/2026 as 3 April, month_first as 4 March), else month/day with a warnings[] entry (code: DATE_ORDER_ASSUMED, field). Dotted dates (03.04.2026) are day-first. ISO (2026-04-03), Unix seconds or milliseconds, month names (3 Apr 2026), year-first (2026/04/03) and compact (20260403) dates need no order. Convert to YYYY-MM-DD to be unambiguous. A subscribed column reads true/false and ESP status words (unsubscribed, cleaned, blocklisted, transactional, active, …). An opt-out unsubscribes the contact, new or existing (with onConflict: \u0026quot;skip\u0026quot; an existing contact is left unchanged, and its CONTACT_EXISTS_SKIPPED warning says so). A word that is not a subscription status (maybe) fails its row (code: FIELD_TYPE_MISMATCH, field: subscribed) instead of importing the contact subscribed. A subscribed value only applies to new contacts: a row that asks to re-subscribe a contact who opted out keeps its other fields and adds a warnings[] entry (code: RESUBSCRIBE_SKIPPED, email). Two opt-in modes. dryRun: true returns the response this import would return (summary, errors, row warnings, fieldsCreated as fields it would create) with dryRun: true and no importId, and writes nothing: no contacts, field definitions or Import History entry; validate is not run and nothing is charged. Insert vs update is decided by the same address match the write uses, so a real run right after returns the same counts. onConflict: \u0026quot;skip\u0026quot; only creates missing contacts: each existing contact is left unchanged (an opt-out row included), counted in summary.skipped with a CONTACT_EXISTS_SKIPPED warning naming its row. Either way inserted + updated + failed + skipped = total. A dry run cannot foresee failures that only happen while writing (a concurrent change, a database refusal), so the real run can still fail where the preview succeeded. With validate: true, inline checks are still metered per submitted row, rows skip left alone included; a request that leaves no address to check is not charged.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://docs.brew.new/images/og/default.png\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/brew-796f053a/Sm1C1504JEJ_FZ8Q/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Brew Help Docs\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#FF772D\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.brew.new/api-reference/public-v1/contacts/bulk-import-contacts-from-csv\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/api-reference/public-v1/contacts/bulk-import-contacts-from-csv.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.brew.new/#organization\",\"name\":\"Brew Help Docs\",\"url\":\"https://docs.brew.new\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/brew-796f053a/QjuRdMJynrgWDqeo/logo/lightmode.svg?fit=max\u0026auto=format\u0026n=QjuRdMJynrgWDqeo\u0026q=85\u0026s=5e906ff65142dc905a773e7747b47816\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.brew.new#website\",\"name\":\"Brew Help Docs\",\"url\":\"https://docs.brew.new\",\"publisher\":{\"@id\":\"https://docs.brew.new/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.brew.new/api-reference/public-v1/contacts/bulk-import-contacts-from-csv#webpage\",\"url\":\"https://docs.brew.new/api-reference/public-v1/contacts/bulk-import-contacts-from-csv\",\"name\":\"Bulk-import contacts from CSV\",\"description\":\"Parse a raw CSV string and upsert the rows as contacts (≤ 1000). By default each column header maps to the custom field its name folds to, the same camelCase name POST /v1/contacts stores (Plan → plan, Team Size → teamSize); email is required. A header that spells a core field, ignoring case, spaces, _ and -, or whose field key equals it (First.Name), maps to it: Email, First Name, Last Name and Subscribed fill email, firstName, lastName and subscribed. Pass mapping to remap single columns; the columns it leaves out keep their default mapping, \\\"\\\" leaves a column out, and a key that names no column is a 400. Two columns that land on one custom field (plan,Plan: names fold as on POST /v1/contacts) are a 422 FIELD_NAME_COLLISION before any row is read: map one to another name or leave it out with \\\"\\\". A core field that mapping fills is filled from that column alone: another column whose default would fill it is left out with a CSV_COLUMN_IGNORED warning. Rows with a missing/invalid email are SKIPPED (counted in summary.skipped), not errored; disposable-domain rows are imported with validationStatus: \\\"risky\\\" (deliverable but flagged). Returns the same { summary, fieldsCreated, errors, warnings } as batch-create plus importId — 207 when some rows fail. The batch is listed in Import History under fileName (optional), and each contact it writes carries importId until a later import touches it (filter on it to list them; deleting the import in the app removes the contacts it created). For rows you already hold as JSON, use POST /v1/contacts/import. CSV cells are text: a column mapped onto an EXISTING field is coerced to that field's type (dates → epoch ms, 1,234 → 1234, yes/no → booleans), and a cell that cannot be coerced ($49 in a number column) fails ITS row with a per-row errors[] entry (code: FIELD_TYPE_MISMATCH, field) while the other rows still land. A converted cell adds a warnings[] entry (code: FIELD_TYPE_COERCED, field, from, to); a date written to a date field is not reported. An undeclared column is created as a string field unless every value is an ISO date (→ date); predeclare number / bool columns with POST /v1/fields. A column whose field Brew manages (Created At, Validation Status) is not imported and adds a warnings[] entry (code: CSV_COLUMN_IGNORED, field names the column). A date column is read in ONE day/month order: the order its own dates prove (a day over 12 anywhere in the column, 13/04/2026), else dateOrder (day_first reads 03/04/2026 as 3 April, month_first as 4 March), else month/day with a warnings[] entry (code: DATE_ORDER_ASSUMED, field). Dotted dates (03.04.2026) are day-first. ISO (2026-04-03), Unix seconds or milliseconds, month names (3 Apr 2026), year-first (2026/04/03) and compact (20260403) dates need no order. Convert to YYYY-MM-DD to be unambiguous. A subscribed column reads true/false and ESP status words (unsubscribed, cleaned, blocklisted, transactional, active, …). An opt-out unsubscribes the contact, new or existing (with onConflict: \\\"skip\\\" an existing contact is left unchanged, and its CONTACT_EXISTS_SKIPPED warning says so). A word that is not a subscription status (maybe) fails its row (code: FIELD_TYPE_MISMATCH, field: subscribed) instead of importing the contact subscribed. A subscribed value only applies to new contacts: a row that asks to re-subscribe a contact who opted out keeps its other fields and adds a warnings[] entry (code: RESUBSCRIBE_SKIPPED, email). Two opt-in modes. dryRun: true returns the response this import would return (summary, errors, row warnings, fieldsCreated as fields it would create) with dryRun: true and no importId, and writes nothing: no contacts, field definitions or Import History entry; validate is not run and nothing is charged. Insert vs update is decided by the same address match the write uses, so a real run right after returns the same counts. onConflict: \\\"skip\\\" only creates missing contacts: each existing contact is left unchanged (an opt-out row included), counted in summary.skipped with a CONTACT_EXISTS_SKIPPED warning naming its row. Either way inserted + updated + failed + skipped = total. A dry run cannot foresee failures that only happen while writing (a concurrent change, a database refusal), so the real run can still fail where the preview succeeded. With validate: true, inline checks are still metered per submitted row, rows skip left alone included; a request that leaves no address to check is not charged.\",\"dateModified\":\"2026-11-06T17:55:00.488Z\",\"isPartOf\":{\"@id\":\"https://docs.brew.new#website\"},\"breadcrumb\":{\"@id\":\"https://docs.brew.new/api-reference/public-v1/contacts/bulk-import-contacts-from-csv#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.brew.new/api-reference/public-v1/contacts/bulk-import-contacts-from-csv#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Public API v1\",\"item\":\"https://docs.brew.new/api-reference/public-v1/emails/list-email-designs\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Contacts\",\"item\":\"https://docs.brew.new/api-reference/public-v1/contacts/list-contacts\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Bulk-import contacts from CSV\",\"item\":\"https://docs.brew.new/api-reference/public-v1/contacts/bulk-import-contacts-from-csv\"}]},{\"@type\":[\"TechArticle\",\"APIReference\"],\"@id\":\"https://docs.brew.new/api-reference/public-v1/contacts/bulk-import-contacts-from-csv#apireference\",\"headline\":\"Bulk-import contacts from CSV\",\"name\":\"Bulk-import contacts from CSV\",\"description\":\"Parse a raw CSV string and upsert the rows as contacts (≤ 1000). By default each column header maps to the custom field its name folds to, the same camelCase name POST /v1/contacts stores (Plan → plan, Team Size → teamSize); email is required. A header that spells a core field, ignoring case, spaces, _ and -, or whose field key equals it (First.Name), maps to it: Email, First Name, Last Name and Subscribed fill email, firstName, lastName and subscribed. Pass mapping to remap single columns; the columns it leaves out keep their default mapping, \\\"\\\" leaves a column out, and a key that names no column is a 400. Two columns that land on one custom field (plan,Plan: names fold as on POST /v1/contacts) are a 422 FIELD_NAME_COLLISION before any row is read: map one to another name or leave it out with \\\"\\\". A core field that mapping fills is filled from that column alone: another column whose default would fill it is left out with a CSV_COLUMN_IGNORED warning. Rows with a missing/invalid email are SKIPPED (counted in summary.skipped), not errored; disposable-domain rows are imported with validationStatus: \\\"risky\\\" (deliverable but flagged). Returns the same { summary, fieldsCreated, errors, warnings } as batch-create plus importId — 207 when some rows fail. The batch is listed in Import History under fileName (optional), and each contact it writes carries importId until a later import touches it (filter on it to list them; deleting the import in the app removes the contacts it created). For rows you already hold as JSON, use POST /v1/contacts/import. CSV cells are text: a column mapped onto an EXISTING field is coerced to that field's type (dates → epoch ms, 1,234 → 1234, yes/no → booleans), and a cell that cannot be coerced ($49 in a number column) fails ITS row with a per-row errors[] entry (code: FIELD_TYPE_MISMATCH, field) while the other rows still land. A converted cell adds a warnings[] entry (code: FIELD_TYPE_COERCED, field, from, to); a date written to a date field is not reported. An undeclared column is created as a string field unless every value is an ISO date (→ date); predeclare number / bool columns with POST /v1/fields. A column whose field Brew manages (Created At, Validation Status) is not imported and adds a warnings[] entry (code: CSV_COLUMN_IGNORED, field names the column). A date column is read in ONE day/month order: the order its own dates prove (a day over 12 anywhere in the column, 13/04/2026), else dateOrder (day_first reads 03/04/2026 as 3 April, month_first as 4 March), else month/day with a warnings[] entry (code: DATE_ORDER_ASSUMED, field). Dotted dates (03.04.2026) are day-first. ISO (2026-04-03), Unix seconds or milliseconds, month names (3 Apr 2026), year-first (2026/04/03) and compact (20260403) dates need no order. Convert to YYYY-MM-DD to be unambiguous. A subscribed column reads true/false and ESP status words (unsubscribed, cleaned, blocklisted, transactional, active, …). An opt-out unsubscribes the contact, new or existing (with onConflict: \\\"skip\\\" an existing contact is left unchanged, and its CONTACT_EXISTS_SKIPPED warning says so). A word that is not a subscription status (maybe) fails its row (code: FIELD_TYPE_MISMATCH, field: subscribed) instead of importing the contact subscribed. A subscribed value only applies to new contacts: a row that asks to re-subscribe a contact who opted out keeps its other fields and adds a warnings[] entry (code: RESUBSCRIBE_SKIPPED, email). Two opt-in modes. dryRun: true returns the response this import would return (summary, errors, row warnings, fieldsCreated as fields it would create) with dryRun: true and no importId, and writes nothing: no contacts, field definitions or Import History entry; validate is not run and nothing is charged. Insert vs update is decided by the same address match the write uses, so a real run right after returns the same counts. onConflict: \\\"skip\\\" only creates missing contacts: each existing contact is left unchanged (an opt-out row included), counted in summary.skipped with a CONTACT_EXISTS_SKIPPED warning naming its row. Either way inserted + updated + failed + skipped = total. A dry run cannot foresee failures that only happen while writing (a concurrent change, a database refusal), so the real run can still fail where the preview succeeded. With validate: true, inline checks are still metered per submitted row, rows skip left alone included; a request that leaves no address to check is not charged.\",\"url\":\"https://docs.brew.new/api-reference/public-v1/contacts/bulk-import-contacts-from-csv\",\"mainEntityOfPage\":{\"@id\":\"https://docs.brew.new/api-reference/public-v1/contacts/bulk-import-contacts-from-csv#webpage\"},\"image\":\"https://docs.brew.new/images/og/default.png\",\"dateModified\":\"2026-11-06T17:55:00.488Z\",\"publisher\":{\"@id\":\"https://docs.brew.new/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.brew.new#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Brew Help Docs\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Brew Help Docs","nav":{"global":{},"tabs":[{"tab":"Docs","pages":[{"title":"Docs","href":"/get-started/welcome"}]},{"tab":"Guides","pages":[{"title":"Guides","href":"/brew-university"}]},{"tab":"Integrations","pages":[{"title":"Integrations","href":"/integrations/integrations"}]},{"tab":"Developers","groups":[{"group":"Start Here","pages":[{"title":"Build with Brew","href":"/api-reference/overview"},{"title":"API Introduction","href":"/api-reference/api/api-introduction"},{"title":"Send Your First Email from Code","href":"/api-reference/guides/send-your-first-email-from-code"},{"title":"API Catalog","href":"/api-reference/api/api-catalog"}]},{"group":"Public API v1","pages":[{"group":"Emails","pages":[{"title":"List email designs","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/emails","href":"/api-reference/public-v1/emails/list-email-designs"},{"title":"Generate an email design","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/emails","href":"/api-reference/public-v1/emails/generate-an-email-design"},{"title":"Get an email design","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/emails/{emailId}","href":"/api-reference/public-v1/emails/get-an-email-design"},{"title":"Delete an email design","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml delete /v1/emails/{emailId}","href":"/api-reference/public-v1/emails/delete-an-email-design"},{"title":"Edit an email design","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml patch /v1/emails/{emailId}","href":"/api-reference/public-v1/emails/edit-an-email-design"},{"title":"Import an email","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/emails/import","href":"/api-reference/public-v1/emails/import-an-email"},{"title":"Import a Figma frame","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/emails/figma","href":"/api-reference/public-v1/emails/import-a-figma-frame"},{"title":"Clone an email design","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/emails/{emailId}/clone","href":"/api-reference/public-v1/emails/clone-an-email-design"},{"title":"Restore a historical version","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/emails/{emailId}/restore","href":"/api-reference/public-v1/emails/restore-a-historical-version"},{"title":"Export a design to an ESP","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/emails/{emailId}/export","href":"/api-reference/public-v1/emails/export-a-design-to-an-esp"},{"title":"Audit an email","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/emails/audit","href":"/api-reference/public-v1/emails/audit-an-email"},{"title":"Preview across clients \u0026 devices","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/emails/{emailId}/client-previews","href":"/api-reference/public-v1/emails/preview-across-clients-\u0026-devices"},{"title":"List inbox placement tests","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/emails/{emailId}/inbox-placement-tests","href":"/api-reference/public-v1/emails/list-inbox-placement-tests"},{"title":"Run an inbox placement test","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/emails/{emailId}/inbox-placement-tests","href":"/api-reference/public-v1/emails/run-an-inbox-placement-test"},{"title":"Get inbox placement test results","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/emails/{emailId}/inbox-placement-tests/{testId}","href":"/api-reference/public-v1/emails/get-inbox-placement-test-results"},{"title":"Read a saved email audit","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/emails/audits/{auditId}","href":"/api-reference/public-v1/emails/read-a-saved-email-audit"},{"title":"Read email rendering progress","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/emails/client-previews/{previewId}","href":"/api-reference/public-v1/emails/read-email-rendering-progress"},{"title":"Create an authenticated email canvas embed session","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/canvas/sessions","href":"/api-reference/public-v1/emails/create-an-authenticated-email-canvas-embed-session"},{"title":"Refresh a canvas session","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/canvas/sessions/{sessionId}/refresh","href":"/api-reference/public-v1/emails/refresh-a-canvas-session"},{"title":"Revoke a canvas session","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml delete /v1/canvas/sessions/{sessionId}","href":"/api-reference/public-v1/emails/revoke-a-canvas-session"},{"title":"List email groups","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/email-groups","href":"/api-reference/public-v1/emails/list-email-groups"},{"title":"Create an email group","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/email-groups","href":"/api-reference/public-v1/emails/create-an-email-group"},{"title":"Get an email group","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/email-groups/{groupId}","href":"/api-reference/public-v1/emails/get-an-email-group"},{"title":"Delete an email group","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml delete /v1/email-groups/{groupId}","href":"/api-reference/public-v1/emails/delete-an-email-group"},{"title":"Update an email group","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml patch /v1/email-groups/{groupId}","href":"/api-reference/public-v1/emails/update-an-email-group"},{"title":"Send an email","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/sends","href":"/api-reference/public-v1/emails/send-an-email"},{"title":"Cancel a send","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/sends/{sendId}/cancel","href":"/api-reference/public-v1/emails/cancel-a-send"},{"title":"Pause a gradual send","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/sends/{sendId}/pause","href":"/api-reference/public-v1/emails/pause-a-gradual-send"},{"title":"Resume a paused gradual send","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/sends/{sendId}/resume","href":"/api-reference/public-v1/emails/resume-a-paused-gradual-send"},{"title":"List email comments","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/emails/{emailId}/comments","href":"/api-reference/public-v1/emails/list-email-comments"}]},{"group":"Sends","pages":[{"title":"List sends","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/sends","href":"/api-reference/public-v1/sends/list-sends"},{"title":"Get a send","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/sends/{sendId}","href":"/api-reference/public-v1/sends/get-a-send"}]},{"group":"Analytics","pages":[{"title":"Brand overview (totals, rates, timeseries)","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/analytics/overview","href":"/api-reference/public-v1/analytics/brand-overview-totals-rates-timeseries"},{"title":"Automation performance","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/analytics/automations","href":"/api-reference/public-v1/analytics/automation-performance"},{"title":"Unified events feed","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/analytics/events","href":"/api-reference/public-v1/analytics/unified-events-feed"}]},{"group":"Automations","pages":[{"title":"List automations","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/automations","href":"/api-reference/public-v1/automations/list-automations"},{"title":"Create an automation","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/automations","href":"/api-reference/public-v1/automations/create-an-automation"},{"title":"Get an automation","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/automations/{automationId}","href":"/api-reference/public-v1/automations/get-an-automation"},{"title":"Delete an automation","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml delete /v1/automations/{automationId}","href":"/api-reference/public-v1/automations/delete-an-automation"},{"title":"Update or publish an automation","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml patch /v1/automations/{automationId}","href":"/api-reference/public-v1/automations/update-or-publish-an-automation"},{"title":"Test an automation","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/automations/{automationId}/test","href":"/api-reference/public-v1/automations/test-an-automation"},{"title":"Run a manual-audience automation","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/automations/{automationId}/run","href":"/api-reference/public-v1/automations/run-a-manual-audience-automation"},{"title":"List manual-audience runs","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/automations/audience-runs","href":"/api-reference/public-v1/automations/list-manual-audience-runs"},{"title":"Get a manual-audience run","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/automations/audience-runs/{audienceRunId}","href":"/api-reference/public-v1/automations/get-a-manual-audience-run"},{"title":"Pause a manual-audience run","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/automations/audience-runs/{audienceRunId}/pause","href":"/api-reference/public-v1/automations/pause-a-manual-audience-run"},{"title":"Resume a manual-audience run","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/automations/audience-runs/{audienceRunId}/resume","href":"/api-reference/public-v1/automations/resume-a-manual-audience-run"},{"title":"Cancel a manual-audience run","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/automations/audience-runs/{audienceRunId}/cancel","href":"/api-reference/public-v1/automations/cancel-a-manual-audience-run"},{"title":"List automation runs","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/automations/runs","href":"/api-reference/public-v1/automations/list-automation-runs"},{"title":"Get an automation run","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/automations/runs/{automationRunId}","href":"/api-reference/public-v1/automations/get-an-automation-run"},{"title":"Cancel an automation run","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/automations/runs/{automationRunId}/cancel","href":"/api-reference/public-v1/automations/cancel-an-automation-run"},{"title":"Get or create an unsubscribe trigger","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/automations/triggers/brew-events","href":"/api-reference/public-v1/automations/get-or-create-an-unsubscribe-trigger"},{"title":"List triggers","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/automations/triggers","href":"/api-reference/public-v1/automations/list-triggers"},{"title":"Create a trigger","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/automations/triggers","href":"/api-reference/public-v1/automations/create-a-trigger"},{"title":"Get a trigger","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/automations/triggers/{triggerEventId}","href":"/api-reference/public-v1/automations/get-a-trigger"},{"title":"Delete a trigger","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml delete /v1/automations/triggers/{triggerEventId}","href":"/api-reference/public-v1/automations/delete-a-trigger"},{"title":"Update a trigger","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml patch /v1/automations/triggers/{triggerEventId}","href":"/api-reference/public-v1/automations/update-a-trigger"},{"title":"Check a trigger is ready to fire","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/automations/triggers/{triggerEventId}/readiness","href":"/api-reference/public-v1/automations/check-a-trigger-is-ready-to-fire"},{"title":"Fire a trigger","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/automations/triggers/{triggerEventId}/fire","href":"/api-reference/public-v1/automations/fire-a-trigger"},{"title":"Get a trigger payload contract","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/automations/triggers/{triggerEventId}/contract","href":"/api-reference/public-v1/automations/get-a-trigger-payload-contract"},{"title":"Declare a trigger payload contract","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml put /v1/automations/triggers/{triggerEventId}/contract","href":"/api-reference/public-v1/automations/declare-a-trigger-payload-contract"},{"title":"Validate a trigger payload","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/automations/triggers/{triggerEventId}/contract/validate","href":"/api-reference/public-v1/automations/validate-a-trigger-payload"},{"title":"Infer a payload contract from an example","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/payload-contracts/infer","href":"/api-reference/public-v1/automations/infer-a-payload-contract-from-an-example"},{"title":"List trigger instances","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/automations/trigger-instances","href":"/api-reference/public-v1/automations/list-trigger-instances"},{"title":"Get a trigger instance","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/automations/trigger-instances/{triggerInstanceId}","href":"/api-reference/public-v1/automations/get-a-trigger-instance"}]},{"group":"Contacts","pages":[{"title":"List contacts","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/contacts","href":"/api-reference/public-v1/contacts/list-contacts"},{"title":"Create or update contacts","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/contacts","href":"/api-reference/public-v1/contacts/create-or-update-contacts"},{"title":"Get a contact","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/contacts/{email}","href":"/api-reference/public-v1/contacts/get-a-contact"},{"title":"Delete a contact","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml delete /v1/contacts/{email}","href":"/api-reference/public-v1/contacts/delete-a-contact"},{"title":"Update a contact","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml patch /v1/contacts/{email}","href":"/api-reference/public-v1/contacts/update-a-contact"},{"title":"Get contacts","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/contacts/search","href":"/api-reference/public-v1/contacts/get-contacts"},{"title":"Validate email deliverability","description":"Batch deliverability check (up to 100 addresses) — run BEFORE importing or sending. Each address is classified `valid` (safe), `risky` (deliverable but flagged — e.g. role account, disposable, catch-all), or `invalid` (undeliverable / do-not-send), with a machine-readable `reason` and a `didYouMean` typo correction when applicable. Partial outages retain the legacy `status: risky` with `checkOutcome: unavailable` (not a completed risky verdict) and preserve the stored verdict. `persistence` reports matched, modified and failed update-only writes; validation never grants subscription or clears suppression. Cost: 2 credits PER ADDRESS (`X-Credit-Cost` = 2 × the number of addresses), charged ONLY on success — if the check cannot complete for the whole batch, the call returns `503` (transient outages are retryable; configuration failures need support) and is NOT billed.","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/contacts/validate","href":"/api-reference/public-v1/contacts/validate-email-deliverability"},{"title":"Bulk-import contacts from CSV","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/contacts/import-csv","href":"/api-reference/public-v1/contacts/bulk-import-contacts-from-csv"},{"title":"Bulk-import contacts from JSON","description":"Create or update up to 1000 contacts from JSON rows and record them as one Import History batch: the JSON twin of `POST /v1/contacts/import-csv`. Rows take the batch-create shape (`email`, `firstName`, `lastName`, `subscribed`, `customFields`, `consent`) and follow its rules: a missing or invalid email, or an address repeated in the batch, fails its row (`errors[]`, `207`) while the others land. New contacts are subscribed unless the row says `subscribed: false`; re-subscribing a contact who opted out keeps its other fields and adds a `RESUBSCRIBE_SKIPPED` warning.\n\nThe batch is listed in Import History under `fileName` (optional), and each contact it writes carries the returned `importId` until a later import touches it (filter on it to list them; deleting the import in the app removes the contacts it created). `POST /v1/contacts` with `contacts[]` writes the same rows without an Import History entry, for recurring syncs.\n\nTwo opt-in modes. `dryRun: true` returns the response this import would return (`summary`, `errors`, row `warnings`, `fieldsCreated` as fields it would create) with `dryRun: true` and no `importId`, and writes nothing: no contacts, field definitions or Import History entry; `validate` is not run and nothing is charged. Insert vs update is decided by the same address match the write uses, so a real run right after returns the same counts. `onConflict: \"skip\"` only creates missing contacts: each existing contact is left unchanged (an opt-out row included), counted in `summary.skipped` with a `CONTACT_EXISTS_SKIPPED` warning naming its `row`. Either way `inserted + updated + failed + skipped = total`. A dry run cannot foresee failures that only happen while writing (a concurrent change, a database refusal), so the real run can still fail where the preview succeeded. With `validate: true`, inline checks are still metered per submitted row, rows `skip` left alone included; a request that leaves no address to check is not charged.","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/contacts/import","href":"/api-reference/public-v1/contacts/bulk-import-contacts-from-json"},{"title":"Batch-delete contacts","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/contacts/batch-delete","href":"/api-reference/public-v1/contacts/batch-delete-contacts"}]},{"group":"Contact Fields","pages":[{"title":"List contact fields","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/fields","href":"/api-reference/public-v1/contact-fields/list-contact-fields"},{"title":"Create a contact field","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/fields","href":"/api-reference/public-v1/contact-fields/create-a-contact-field"},{"title":"Get a contact field","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/fields/{fieldName}","href":"/api-reference/public-v1/contact-fields/get-a-contact-field"},{"title":"Delete a contact field","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml delete /v1/fields/{fieldName}","href":"/api-reference/public-v1/contact-fields/delete-a-contact-field"}]},{"group":"Audiences","pages":[{"title":"List audiences","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/audiences","href":"/api-reference/public-v1/audiences/list-audiences"},{"title":"Create an audience","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/audiences","href":"/api-reference/public-v1/audiences/create-an-audience"},{"title":"Get an audience","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/audiences/{audienceId}","href":"/api-reference/public-v1/audiences/get-an-audience"},{"title":"Delete an audience","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml delete /v1/audiences/{audienceId}","href":"/api-reference/public-v1/audiences/delete-an-audience"},{"title":"Update an audience","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml patch /v1/audiences/{audienceId}","href":"/api-reference/public-v1/audiences/update-an-audience"},{"title":"Create an audience from analytics events","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/audiences/from-events","href":"/api-reference/public-v1/audiences/create-an-audience-from-analytics-events"},{"title":"Duplicate an audience","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/audiences/{audienceId}/duplicate","href":"/api-reference/public-v1/audiences/duplicate-an-audience"}]},{"group":"Domains","pages":[{"title":"List domains","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/domains","href":"/api-reference/public-v1/domains/list-domains"},{"title":"Add a domain","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/domains","href":"/api-reference/public-v1/domains/add-a-domain"},{"title":"Get a domain","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/domains/{domainId}","href":"/api-reference/public-v1/domains/get-a-domain"},{"title":"Delete a domain","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml delete /v1/domains/{domainId}","href":"/api-reference/public-v1/domains/delete-a-domain"},{"title":"Update domain settings","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml patch /v1/domains/{domainId}","href":"/api-reference/public-v1/domains/update-domain-settings"},{"title":"Verify a domain","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/domains/{domainId}/verify","href":"/api-reference/public-v1/domains/verify-a-domain"},{"title":"List a domain's unsubscribes","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/domains/{domainId}/unsubscribes","href":"/api-reference/public-v1/domains/list-a-domains-unsubscribes"},{"title":"Add addresses to a domain's unsubscribe list","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/domains/{domainId}/unsubscribes","href":"/api-reference/public-v1/domains/add-addresses-to-a-domains-unsubscribe-list"},{"title":"Remove an address from a domain's unsubscribe list","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml delete /v1/domains/{domainId}/unsubscribes/{email}","href":"/api-reference/public-v1/domains/remove-an-address-from-a-domains-unsubscribe-list"},{"title":"Import a CSV into a domain's unsubscribe list","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/domains/{domainId}/unsubscribes/import","href":"/api-reference/public-v1/domains/import-a-csv-into-a-domains-unsubscribe-list"},{"title":"Export a domain's unsubscribe list","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/domains/{domainId}/unsubscribes/export","href":"/api-reference/public-v1/domains/export-a-domains-unsubscribe-list"},{"title":"Get domain health","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/domains/{domainId}/health","href":"/api-reference/public-v1/domains/get-domain-health"}]},{"group":"Templates","pages":[{"title":"List templates","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/templates","href":"/api-reference/public-v1/templates/list-templates"},{"title":"Get a public template","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/templates/{templateId}","href":"/api-reference/public-v1/templates/get-a-public-template"},{"title":"List flows","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/flows","href":"/api-reference/public-v1/templates/list-flows"},{"title":"Get a flow","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/flows/{slug}","href":"/api-reference/public-v1/templates/get-a-flow"}]},{"group":"Brand","pages":[{"title":"Get the brand bound to this API key","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/brand","href":"/api-reference/public-v1/brand/get-the-brand-bound-to-this-api-key"},{"title":"Update brand identity + design system","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml patch /v1/brand","href":"/api-reference/public-v1/brand/update-brand-identity-+-design-system"},{"title":"Get brand images","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/brand/images","href":"/api-reference/public-v1/brand/get-brand-images"},{"title":"Delete a brand image","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml delete /v1/brand/images/{assetId}","href":"/api-reference/public-v1/brand/delete-a-brand-image"}]},{"group":"Brands","pages":[{"title":"List the brands this credential can reach","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/brands","href":"/api-reference/public-v1/brands/list-the-brands-this-credential-can-reach"},{"title":"Create a brand and start its extraction","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/brands","href":"/api-reference/public-v1/brands/create-a-brand-and-start-its-extraction"},{"title":"Get one brand’s lifecycle state","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/brands/{brandId}","href":"/api-reference/public-v1/brands/get-one-brand’s-lifecycle-state"}]},{"group":"Content","pages":[{"title":"Generate an image","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/content/generate-image","href":"/api-reference/public-v1/content/generate-an-image"},{"title":"Generate a GIF","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/content/gif","href":"/api-reference/public-v1/content/generate-a-gif"},{"title":"Transform an image","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/content/transform","href":"/api-reference/public-v1/content/transform-an-image"},{"title":"Render HTML to a PNG","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/content/html-to-png","href":"/api-reference/public-v1/content/render-html-to-a-png"},{"title":"Add image","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/content/add-image","href":"/api-reference/public-v1/content/add-image"},{"title":"Create an image upload","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/content/image-uploads","href":"/api-reference/public-v1/content/create-an-image-upload"}]},{"group":"Usage","pages":[{"title":"Get usage","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/usage","href":"/api-reference/public-v1/usage/get-usage"}]},{"group":"Integrations","pages":[{"title":"List integrations","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/integrations","href":"/api-reference/public-v1/integrations/list-integrations"}]},{"group":"API Keys","pages":[{"title":"List API keys","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/api-keys","href":"/api-reference/public-v1/api-keys/list-api-keys"},{"title":"Create an API key","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml post /v1/api-keys","href":"/api-reference/public-v1/api-keys/create-an-api-key"},{"title":"Revoke an API key","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml delete /v1/api-keys/{keyId}","href":"/api-reference/public-v1/api-keys/revoke-an-api-key"}]},{"group":"Health","pages":[{"title":"Liveness probe","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/health","href":"/api-reference/public-v1/health/liveness-probe"}]},{"group":"Meta","pages":[{"title":"Machine-readable API catalog","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/help","href":"/api-reference/public-v1/meta/machine-readable-api-catalog"}]},{"group":"Chats","pages":[{"title":"List chats","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/chats","href":"/api-reference/public-v1/chats/list-chats"},{"title":"Get chat context","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/chats/{chatId}","href":"/api-reference/public-v1/chats/get-chat-context"}]},{"group":"Insights","pages":[{"title":"List insights","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/insights","href":"/api-reference/public-v1/insights/list-insights"},{"title":"Get an insight","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/insights/{insightId}","href":"/api-reference/public-v1/insights/get-an-insight"}]},{"group":"Notifications","pages":[{"title":"List notifications","deprecated":null,"version":null,"openapi":"/api-reference/openapi-public-v1.yaml get /v1/notifications","href":"/api-reference/public-v1/notifications/list-notifications"}]}]},{"group":"API Contracts","pages":[{"title":"Authentication and Security","href":"/api-reference/api/authentication"},{"title":"Organization and Brand Credentials","href":"/api-reference/api/organization-and-brand-scope"},{"title":"Data Model","href":"/api-reference/api/data-model"},{"title":"Rate Limits","href":"/api-reference/api/rate-limits"},{"title":"Idempotency","href":"/api-reference/api/idempotency"},{"title":"Pagination","href":"/api-reference/api/pagination"},{"title":"Batch Operations","href":"/api-reference/api/batch-operations"},{"title":"Async Jobs and Polling","href":"/api-reference/api/async-jobs"},{"title":"API Credits","sidebarTitle":"Credits","href":"/api-reference/api/credits"},{"title":"Events and Webhooks","href":"/api-reference/api/events-and-webhooks"},{"title":"API Errors","sidebarTitle":"Errors","href":"/api-reference/api/errors"},{"title":"Response Headers","href":"/api-reference/api/response-headers"},{"title":"API Design Notes","href":"/api-reference/api/design-notes"},{"title":"Migrate to the New v1 Surface","href":"/api-reference/api/v1-migration"}]},{"group":"API Guides","pages":[{"title":"Check Brand Readiness Before Generating","href":"/api-reference/guides/check-brand-readiness"},{"title":"Upload a Local Image","href":"/api-reference/guides/upload-a-local-image"},{"title":"Monitor Email Sends","href":"/api-reference/guides/monitor-campaign-sends"},{"title":"Explore Per-Contact Engagement","href":"/api-reference/guides/per-contact-engagement"},{"title":"Read Brew Insights","href":"/api-reference/guides/read-brew-insights"},{"title":"Typed Payload Contracts","href":"/api-reference/guides/typed-payload-contracts"}]},{"group":"MCP Server","pages":[{"title":"Brew MCP Server","href":"/api-reference/mcp/overview"},{"title":"MCP Quickstart","href":"/api-reference/mcp/quickstart"},{"title":"Connect Your MCP Client","sidebarTitle":"Connect Your Client","href":"/api-reference/mcp/connect-your-client"},{"title":"MCP Tools","href":"/api-reference/mcp/tools"},{"title":"MCP Workflows","href":"/api-reference/mcp/workflows"},{"title":"Sync a CRM into Brew over MCP","href":"/api-reference/mcp/sync-a-crm"},{"title":"Sync Brew and Attio over MCP","href":"/api-reference/mcp/attio"},{"title":"MCP Authentication and Scoping","href":"/api-reference/mcp/authentication-and-scoping"}]},{"group":"CLI","pages":[{"title":"Brew CLI","href":"/api-reference/cli/overview"},{"title":"CLI Quickstart","href":"/api-reference/cli/quickstart"},{"title":"CLI Installation","sidebarTitle":"Installation","href":"/api-reference/cli/installation"},{"title":"CLI Authentication","sidebarTitle":"Authentication","href":"/api-reference/cli/authentication"},{"title":"CLI Commands","sidebarTitle":"Commands","href":"/api-reference/cli/commands"},{"title":"CLI Common Flows","sidebarTitle":"Common Flows","href":"/api-reference/cli/common-flows"},{"title":"Use the CLI from AI Agents","sidebarTitle":"Use from AI Agents","href":"/api-reference/cli/agents"}]},{"group":"SDKs","pages":[{"title":"SDK Overview","href":"/sdks/overview"},{"title":"SDK Authentication","sidebarTitle":"Authentication","href":"/sdks/authentication"},{"title":"Generate Your Own SDK","href":"/sdks/openapi-codegen"},{"title":"TypeScript Installation","href":"/sdks/typescript/installation"},{"title":"TypeScript Quickstart","href":"/sdks/typescript/quickstart"},{"title":"TypeScript Resource Surface","href":"/sdks/typescript/resources"},{"title":"Build a White-Label Email Editor","sidebarTitle":"White-Label Integration","href":"/sdks/typescript/white-label-email-editor"},{"title":"Embed the Email Canvas","href":"/sdks/typescript/embedded-email-canvas"},{"title":"TypeScript Error Handling","href":"/sdks/typescript/error-handling"},{"title":"Agentic Cookbook","href":"/sdks/typescript/agentic-cookbook"}]}]},{"tab":"Changelog","pages":[{"title":"Changelog","href":"/changelog/overview"}]},{"tab":"Legal","pages":[{"title":"Legal","href":"/legal/terms-of-service"}]}]},"basePath":"","title":"Bulk-import contacts from CSV - Brew Help Docs","buildId":"dpl_FWZhTb2vab28gFGFH4ojka6qEznQ","deploymentId":"dpl_FWZhTb2vab28gFGFH4ojka6qEznQ","dynamics":["c2aa737661","2b790eda92","b0f84f53ff","a9bb46feb3"],"chunks":["OpenApiReferenceProvider-CBsVopKK.js","utils-DZAk68jJ.js","cloneDeep-izs3Hzxb.js","_Uint8Array-BVIqJ90l.js","isObjectLike-C8vmzPEN.js","isArray-Dcu1dQ5t.js","utils-D32AYZrP.js","toString-BX-iyh8G.js","isSymbol-CSH9U2Gm.js","addUniqueKeysToSchema-D_A5_cny.js","snippetPresets-xNRfS9th.js","style-to-object-BY3JEAdk.js","v4-DIgz8zy6.js","conditional-requirements-CFM0id0Q.js","ApiExamples-BIB25-tq.js","isEqual-BfaiBbcl.js","usePlaygroundInputsStore-CydJ4w4j.js","shallow-CYPBeQSG.js","getApiPlaygroundDisplay-A5xJVBOu.js","CodeSnippet-BVRTgi3m.js","CodeSnippets-DjD6BSlt.js","Page-Dr40SSJq.js","getPastedJson-D4V4JyrR.js","icon-uhcnG22T.js","MethodPill-CM-ZQdGH.js","DuplicateIcon-B_WnOiNf.js","createIcon-CJsb8utt.js","DynamicMarkdown-D-2HDKEp.js","SectionHeading-KP5xmMgQ.js","axios-vUo_bRtp.js","Markdown-D_k0dg6k.js","clsx-DK3K4Z1S.js","lib-DuNMoZ05.js","lib-B8HbPgcC.js","html-void-elements-mCSPHezU.js","dist-DE3EVdvd.js","katex-YMM-FMeD.js","marked.esm-CZWythHk.js","AssistantPageLink-fN9H9n9g.js"]}