Skip to Content
Errors

Errors

Every failure uses one envelope:

{ "error": { "code": "contact_already_exists", "message": "A contact with this email already exists in this audience", "param": "email", "request_id": "req_8fk2..." } }
  • code is the contract. Branch on it, never on message.
  • message is for humans and may change anytime.
  • param names the offending field, when there is one.
  • request_id is always present. Include it when you contact support.

Codes

StatusCodeMeaning
400invalid_requestMalformed body, or a value failed validation.
400invalid_emailNot a valid email address.
400invalid_filterA stored segment filter no longer parses, so its members can’t be listed. A filter rejected on write is invalid_request.
400batch_too_largeMore than 1,000 items in one batch.
400email_suppressedOn POST /emails: the address hard-bounced, complained, or was provider-suppressed.
401invalid_api_keyMissing, malformed, or unknown key.
401revoked_api_keyThe key was revoked.
403plan_limit_reachedOut of subscriber headroom or monthly send allowance.
403sending_disabledSending is off for this account.
403domain_not_verifiedThe from domain isn’t a verified sending domain.
403sandbox_recipient_not_allowedFree plan, and the recipient isn’t a member of your organization.
403insufficient_scopeThe key lacks campaigns:send, automations:enroll or webhooks:manage.
403test_keys_not_supportedA day3_test_ key was used.
403forbiddenNot allowed for this key or account state.
404not_foundNo such object. Also returned for another organization’s ids.
409contact_already_existsThe email is already in the audience, and you didn’t pass ?upsert=true.
409email_suppressedOn contact writes: the address is on the account’s suppression list.
409idempotency_conflictSame Idempotency-Key, different body. Or that key is already in flight.
409invalid_requestConflicts with the object’s state: editing a campaign that left draft, or enrolling into an unpublished automation.
422immutable_fieldChanging something that can’t change, such as a field’s key.
429rate_limit_exceededOver the request limit. Carries Retry-After.
500internal_errorOur fault. Retry, and send us the request_id.

What to retry

CodeRetry?
rate_limit_exceededYes, after Retry-After seconds.
internal_errorYes, with backoff.
idempotency_conflict (“already in progress”)Yes, shortly.
plan_limit_reachedNo. The user needs to upgrade.
domain_not_verifiedNo. Verify the domain.
email_suppressedNever. Retrying damages your sending reputation.
sandbox_recipient_not_allowedNo. Upgrade, or send to an organization member.
insufficient_scopeNo. Mint a key with the scope.
invalid_request, invalid_emailNo. Fix the payload; param names the field.
invalid_filterNo. Rewrite the segment’s filter in the app or over the API.

Why email_suppressed has two statuses

  • 400 on POST /emails: you asked to send to an unmailable address.
  • 409 on contact writes: the contact conflicts with account-wide suppression state.

Both mean the address is unmailable. Retry neither.

Last updated on