Skip to main content
POST
/
v1
/
contacts
curl --request POST \
  --url https://brew.new/api/v1/contacts \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "email": "jane@example.com",
  "firstName": "Jane",
  "customFields": {
    "plan": "enterprise"
  }
}
'
{
  "summary": {
    "inserted": 2,
    "updated": 0,
    "failed": 0
  },
  "fieldsCreated": [],
  "errors": [],
  "warnings": []
}
{
"contact": {
"email": "jane@example.com",
"firstName": "Jane",
"lastName": "Doe",
"subscribed": true,
"validationStatus": "valid",
"verificationStatus": "valid",
"suppressed": false,
"suppressedReason": null,
"createdAt": "2026-04-08T12:00:00.000Z",
"updatedAt": "2026-04-08T12:05:00.000Z",
"importId": null,
"customFields": {
"plan": "enterprise",
"revenue": 4200
}
},
"created": true,
"fieldsCreated": [
"plan"
],
"warnings": []
}
{
"summary": {
"inserted": 1,
"updated": 0,
"failed": 1
},
"fieldsCreated": [],
"errors": [
{
"email": "not-an-email",
"code": "INVALID_EMAIL",
"message": "not-an-email is not a valid email address."
}
],
"warnings": []
}
{
"error": {
"code": "INVALID_REQUEST",
"type": "invalid_request",
"message": "Request validation failed.",
"suggestion": "Fix the field reported in `param` and retry.",
"docs": "https://docs.brew.new/api-reference/api/errors",
"param": "contacts"
}
}
{
"error": {
"code": "INVALID_API_KEY",
"type": "authentication_error",
"message": "The provided API key is invalid.",
"suggestion": "Check the API key format and retry with a valid active key.",
"docs": "https://docs.brew.new/api-reference/api/authentication"
}
}
{
"error": {
"code": "INSUFFICIENT_PERMISSIONS",
"type": "authorization_error",
"message": "The caller does not have the required permission.",
"suggestion": "Use an API key or session with the required permission.",
"docs": "https://docs.brew.new/api-reference/api/authentication",
"param": "contacts"
}
}
{
"error": {
"code": "IDEMPOTENCY_CONFLICT",
"type": "conflict",
"message": "The same idempotency key was reused with a different request payload.",
"suggestion": "Reuse the original payload or send a new idempotency key.",
"docs": "https://docs.brew.new/api-reference/api/idempotency"
}
}
{
"error": {
"code": "MISSING_EMAIL",
"type": "invalid_request",
"message": "email is required.",
"suggestion": "Provide the contact email address.",
"docs": "https://docs.brew.new/api-reference/api/errors",
"param": "email"
}
}
{
"error": {
"code": "RATE_LIMITED",
"type": "rate_limit",
"message": "Too many requests.",
"suggestion": "Wait for the retry window before sending another request.",
"docs": "https://docs.brew.new/api-reference/api/rate-limits",
"retryAfter": 42
}
}
{
"error": {
"code": "INTERNAL_ERROR",
"type": "internal_error",
"message": "An unexpected error occurred.",
"suggestion": "Retry the request. If it keeps failing, contact support.",
"docs": "https://docs.brew.new/api-reference/api/errors"
}
}

Authorizations

Authorization
string
header
default:Bearer brew_your_api_key
required

Send your Brew API key as Authorization: Bearer brew_xxx.

Headers

Idempotency-Key
string

Optional idempotency key for safe retries. Reusing the same key with the same request body returns the original response for 24 hours.

Required string length: 1 - 100

Body

application/json
email
string
required
Minimum string length: 1
firstName
string
lastName
string
subscribed
boolean
customFields
object
validate
boolean

Optional deliverability check on ingestion. When true, each address is validated with the provider (2 credits per address, charged on success) and the verdict is saved to the contact’s validationStatus. Submissions above the inline cap (100 addresses) upsert first and validate as a background job, returning a validationJobId.

Response

Batch upsert applied (every row succeeded).

summary
object
required
fieldsCreated
string[]
required
errors
object[]
required
warnings
object[]
required
validation
object
validationJobId
string