Errors
Every error is application/problem+json (RFC 9457) with
extra fields that make it easy for an agent to act on:
{ "type": "https://docs.simail.ai/errors#rate_limited", "title": "RateLimitedError", "status": 429, "detail": "Too many requests.", "instance": "/v0/inboxes", "name": "RateLimitedError", "code": "rate_limited", "message": "Too many requests.", "fix": "Wait for Retry-After seconds, then retry.", "docs": "https://docs.simail.ai/errors#rate_limited", "retryable": true, "request_id": "req_…"}| Field | Meaning |
|---|---|
code |
stable machine-readable code (below); branch on this, not on message |
retryable |
true only when retrying the same request later can succeed |
fix |
one-line hint for the caller |
request_id |
also in the x-request-id response header; include it when you contact support |
human_message |
when present, a message meant for the human behind the agent; forward it verbatim |
Every 429 and retryable 503 includes Retry-After. Error bodies never contain message content,
codes or secrets.
| Code | HTTP | Retryable |
|---|---|---|
validation_error |
400 | no |
invalid_request |
400 | no |
unauthorized |
401 | no |
step_up_required |
401 | no |
missing_permission |
403 | no |
human_required |
403 | no |
origin_mismatch |
403 | no |
signup_closed |
403 | no |
account_inactive |
403 | no |
account_suspended |
403 | no |
claim_required |
403 | no |
invite_invalid |
403 | no |
not_found |
404 | no |
method_not_allowed |
405 | no |
conflict |
409 | no |
idempotency_conflict |
409 | no |
duplicate_send |
409 | no |
address_unavailable |
409 | no |
gone |
410 | no |
payload_too_large |
413 | no |
message_too_large |
413 | no |
unsupported_media_type |
415 | no |
send_blocked |
422 | no |
invalid_header |
422 | no |
webhook_target_forbidden |
422 | no |
thread_locked |
423 | no |
rate_limited |
429 | yes |
daily_limit_exceeded |
429 | yes |
internal_error |
500 | yes |
not_implemented |
501 | no |
sending_paused |
503 | yes |
upstream_unavailable |
503 | yes |
validation_error
Section titled “validation_error”HTTP 400 · retryable: no · ValidationError
A field is missing, has the wrong type or is out of range. The body has errors: [{ path, message }]. Also returned when a send has no Idempotency-Key, and when POST /v0/waitlist contains human_email or any other unknown field.
Fix: Correct the fields listed in errors and retry.
invalid_request
Section titled “invalid_request”HTTP 400 · retryable: no · InvalidRequestError
The request is malformed in a way that is not about one field (for example an unparseable page_token, or a page token or events cursor used with another key scope or query).
Fix: Check the request format against the API reference.
unauthorized
Section titled “unauthorized”HTTP 401 · retryable: no · UnauthorizedError
The API key is missing, malformed, expired or revoked. Also returned by /mcp without a key, with a human_message pointing to /v0/beta.
Fix: Send a valid API key as Authorization: Bearer <key>.
step_up_required
Section titled “step_up_required”HTTP 401 · retryable: no · StepUpRequiredError
Console only: the action needs a passkey assertion or a fresh email code from the last 5 minutes.
Fix: Re-authenticate with a passkey or a fresh email code, then retry.
missing_permission
Section titled “missing_permission”HTTP 403 · retryable: no · ForbiddenError
The object is in your key’s scope but the key lacks the permission. May carry reason, for example inbox_limit.
Fix: Use a key that has the required permission and scope.
human_required
Section titled “human_required”HTTP 403 · retryable: no · HumanRequiredError
Only a human can do this, in the console: creating API keys or webhooks, loosening lists, releasing held mail, approving sends.
Fix: Only a human can do this, in the console at app.simail.ai.
origin_mismatch
Section titled “origin_mismatch”HTTP 403 · retryable: no · ForbiddenError
Console only: a state-changing request did not come from https://app.simail.ai.
Fix: Console API calls must come from the console origin.
signup_closed
Section titled “signup_closed”HTTP 403 · retryable: no · SignupClosedError
Sign-up without a valid directed code during the private beta. Carries waitlist_url and human_message (en, zh). Do not retry, do not try another username or email; forward human_message to your human. See Private beta.
Fix: Do not retry. Forward human_message to your human; join the waitlist at waitlist_url.
account_inactive
Section titled “account_inactive”HTTP 403 · retryable: no · AccountInactiveError
Console only: the account is waitlisted, invited but not activated, or not accepted.
Fix: This account is not active yet. Check your status page.
account_suspended
Section titled “account_suspended”HTTP 403 · retryable: no · AccountSuspendedError
Sending is paused for the organization (for example after a bounce or complaint spike). Receiving and reading still work. The console shows the reason.
Fix: Sending is suspended for this organization. See the console for the reason.
claim_required
Section titled “claim_required”HTTP 403 · retryable: no · ClaimRequiredError
A restricted key from agent sign-up was used before a human claimed the agent. Only GET /v0/auth/me and GET /v0/beta work until then.
Fix: Ask your human to claim this inbox in the console; until then only /v0/auth/me and /v0/beta work.
invite_invalid
Section titled “invite_invalid”HTTP 403 · retryable: no · InviteInvalidError
The invite code is wrong, used, expired, revoked or bound to another email. Repeated failures lock redemption for an hour.
Fix: Check the code. Codes are single-use, expire, and are bound to one email.
not_found
Section titled “not_found”HTTP 404 · retryable: no · NotFoundError
The object does not exist or is outside your key’s scope. SiMail never reveals whether another organization’s object exists.
Fix: Check the resource ID and that your key’s scope includes it.
method_not_allowed
Section titled “method_not_allowed”HTTP 405 · retryable: no · MethodNotAllowedError
The path exists but not with this HTTP method.
Fix: Use a supported HTTP method.
conflict
Section titled “conflict”HTTP 409 · retryable: no · ConflictError
The object changed state. For cancel: reason is already_sending or already_final.
Fix: Reload the resource and retry with current state.
idempotency_conflict
Section titled “idempotency_conflict”HTTP 409 · retryable: no · IdempotencyConflictError
The Idempotency-Key was already used with a different request body.
Fix: Reuse an Idempotency-Key only with an identical request body.
duplicate_send
Section titled “duplicate_send”HTTP 409 · retryable: no · DuplicateSendError
An identical message (same sender, recipients, subject and body) was sent inside the de-duplication window. Do not resend.
Fix: An identical message was already sent recently; do not resend.
address_unavailable
Section titled “address_unavailable”HTTP 409 · retryable: no · AddressUnavailableError
The username is taken, reserved, too similar to a reserved name, or retired. Addresses are never reassigned to another organization.
Fix: Choose another username; this address is reserved or retired.
HTTP 410 · retryable: no · GoneError
The resource expired or was deleted, for example an events cursor older than 30 days.
Fix: The resource expired or was deleted.
payload_too_large
Section titled “payload_too_large”HTTP 413 · retryable: no · PayloadTooLargeError
The request body exceeds 1 MiB (5 MiB for sends with inline attachments).
Fix: Reduce message or attachment size.
message_too_large
Section titled “message_too_large”HTTP 413 · retryable: no · MessageTooLargeError
The outbound message would exceed 5 MiB including encoding, or has more than 32 attachments. Carries limit_bytes and estimated_bytes.
Fix: Outbound mail is limited to about 5 MiB including attachments (at most 32). Remove or shrink attachments.
unsupported_media_type
Section titled “unsupported_media_type”HTTP 415 · retryable: no · UnsupportedMediaTypeError
The body is not application/json.
Fix: Send application/json.
send_blocked
Section titled “send_blocked”HTTP 422 · retryable: no · SendBlockedError
The pre-send check refused the message. reasons lists why (see Sending); flags may list risk flags.
Fix: The pre-send check rejected this message; see reasons.
invalid_header
Section titled “invalid_header”HTTP 422 · retryable: no · InvalidHeaderError
A header field (subject, display name, address) contains CR, LF, NUL or another control character.
Fix: Remove CR, LF, NUL and non-printable characters from header fields.
webhook_target_forbidden
Section titled “webhook_target_forbidden”HTTP 422 · retryable: no · WebhookTargetForbiddenError
The webhook URL is not a public https:// host on port 443, or points at a SiMail-owned domain.
Fix: Use a public https URL outside simail-owned zones.
thread_locked
Section titled “thread_locked”HTTP 423 · retryable: no · ThreadLockedError
A human has taken over the thread. Wait for thread.unlocked.
Fix: A human has taken over this thread; wait until it is unlocked.
rate_limited
Section titled “rate_limited”HTTP 429 · retryable: yes · RateLimitedError
Too many requests. Wait for Retry-After seconds.
Fix: Wait for Retry-After seconds, then retry.
daily_limit_exceeded
Section titled “daily_limit_exceeded”HTTP 429 · retryable: yes · DailyLimitExceededError
A daily quota is used up. Retry after Retry-After.
Fix: The daily send limit is reached; retry after Retry-After.
internal_error
Section titled “internal_error”HTTP 500 · retryable: yes · InternalServerError
Something failed on our side. Retry with backoff and report the request_id if it persists.
Fix: Retry with backoff; report the request_id if it persists.
not_implemented
Section titled “not_implemented”HTTP 501 · retryable: no · NotImplementedError
The operation is not offered. reason is not_planned (for example custom domains, IMAP/SMTP) or phase_2 (calendar, files, connected accounts).
Fix: This operation is not available in simail yet.
sending_paused
Section titled “sending_paused”HTTP 503 · retryable: yes · SendingPausedError
Platform-wide sending is paused. Already accepted messages wait and are sent after it resumes.
Fix: Platform sending is paused; retry later.
upstream_unavailable
Section titled “upstream_unavailable”HTTP 503 · retryable: yes · UpstreamUnavailableError
A dependency is temporarily unavailable. Retry with backoff.
Fix: Retry with backoff.