Errors, and what to do with each
Every answer the API can give, the cause and the fix.
Every error answer has the same shape:
{ "message": "The domain mail.company.com is not verified yet." }
Validation errors carry the fields too:
{
"message": "The given data was invalid.",
"errors": {
"to": ["A recipient is required."]
}
}
The sentence can change language with the Accept-Language header. The status
code and the field names never change, and those are what you program against.
401 · Not authenticated
| Message | Cause | Fix |
|---|---|---|
| Invalid or revoked API key | Key missing, wrong or revoked | Check the Authorization: Bearer ... header and the key's state in the panel |
A copy and paste mistake catches plenty of people: a trailing space on the key, or the key put in the username instead of the password over SMTP.
403 · Forbidden
| Message | Cause | Fix |
|---|---|---|
| This key cannot send on the stream of this domain | The key is limited to a stream and the domain is on the other | Use the right key, or create one with no limit |
404 · Not found
A message, a domain or a webhook that does not exist in this account. A call
with an identifier from another account also answers 404, not 403: whoever
is asking is not entitled to learn that the identifier exists.
422 · The request cannot be carried out
The most common, and the most informative.
| Message | Cause | Fix |
|---|---|---|
| The domain ... is not registered in this account | The from points at a domain that is not yours |
Add the domain, or fix the from |
| The domain ... is not verified yet | The DNS records do not all resolve | See The DNS records |
| The address ... is on the suppression list | The recipient is suppressed | Do not retry. See Suppressions |
| A marketing message needs an unsubscribe_url | Marketing stream with no unsubscribe | See Unsubscribing |
Per field errors in errors |
Validation | Read each field |
A 422 for a suppression is not a failure of your integration: it is the system
stopping a send that was going to bounce again. Treat it as a result.
429 · Too many requests
Two different things answer 429, and the Retry-After header tells them apart
by size: seconds is the key's rate limit, 600 a minute; minutes or hours is the
account's quota, for this hour or this day.
Either way, wait what Retry-After says and retry. Opening more connections in
parallel makes it worse, because the rate limit is per minute and the quota
belongs to the whole account: more connections spend the same account faster.
You do not have to get here to know where you stand: every 202 carries
X-CConnect-Quota-Remaining, and the panel's summary shows both windows. See
Sending over the API.
Nothing was written and nothing was sent. A 429 leaves no message behind.
503 · Service unavailable
Two situations, both temporary, both carrying Retry-After.
On domain verification it means one very specific thing: we could not query DNS right now. It does not mean the records are not published.
That is why it is a 503 and not a 200 with everything reported as missing: a
client receiving 200 would go and republish records that were already correct.
On sending it means the platform cannot carry the message at this moment:
either no route out serves your domain, or the pool of IPs it would leave
through has delivered what it can today, or more messages are waiting than are
going out. We would rather say so at the door: the alternative was accepting
with 202 and leaving the message sitting for days with nobody the wiser.
5xx · Ours
Retry with a growing delay. If it persists, talk to us with the message identifier or the time of the request.
SMTP codes, on submission
| Code | What it is |
|---|---|
535 |
Authentication refused: wrong key, revoked, or in the wrong field |
530 |
You tried to authenticate before STARTTLS |
550 |
Message refused: unverified domain, suppressed address, or marketing with no unsubscribe |
421 |
We are throttling the connection; go slower |
What to retry and what not to
- Retry:
429,5xx,503. - Do not retry:
401,403,404,422. The request is the same and the answer will be the same. - Careful with
202: retrying a request that was already accepted sends a second message. Store theidbefore deciding.