Error Codes
All Finn API errors follow a single envelope:
{
"error": {
"code": "rate_limited",
"message": "per-minute send limit exceeded",
"retry_after": 42
}
}
Match on code (stable, machine-readable) — message is human text and may change.
| Code | Typical HTTP | Meaning |
|---|---|---|
invalid_input |
400 | Malformed body, missing required field, value out of range |
invalid_email |
400 | Email address failed RFC validation |
invite_required |
400 | POST /v1/accounts without invite_code |
invite_invalid |
403 | Invite code unknown, revoked, or expired |
invite_used_up |
403 | Invite code reached its redemption limit |
disposable_email |
400 | Signup email matched disposable-address blocklist |
activation_pending |
403 | Account not yet activated via signup email link |
unauthorized |
401 | Missing or invalid Authorization: Bearer finn_sk_… |
account_suspended |
403 | Tenant suspended (bounce/complaint threshold or operator action) |
domain_unverified |
403 | from address is neither a verified-domain address nor a single sender |
dmarc_reject |
403 | Sender added against a domain with DMARC p=reject — not allowed |
sandbox_recipient_not_allowed |
403 | Sandbox account sending to a recipient not in the allow-list |
sandbox_recipient_rejected |
409 | Recipient previously declined consent — cannot re-invite |
recipient_suppressed |
422 | Recipient is on the suppression list (prior bounce/complaint) |
content_blocked |
422 | Pre-send moderation rejected the content |
rate_limited |
429 | Per-minute or monthly quota exceeded. retry_after gives seconds to wait |
not_found |
404 | Message/domain/sender ID not found (or not yours) |
send_failed |
500 / 502 | Upstream SES error or internal failure |
Retry-ability:
rate_limited— honorretry_after, then retry.send_failedwith 502 — retriable after a pause.content_blocked,domain_unverified,recipient_suppressed,sandbox_recipient_not_allowed— change the request; same inputs will never succeed.