Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

Error Codes

Complete reference of HTTP status codes and error-response shapes across every ScaiSend endpoint. For the conceptual overview and retry guidance, see Errors.

Response shapes#

ScaiSend returns errors in one of two shapes depending on the endpoint:

SendGrid-style (for /v3/mail/send and related sending endpoints):

json
1
2
3
4
5
{
  "errors": [
    {"message": "...", "field": "...", "help": "..."}
  ]
}

FastAPI-style (everywhere else):

json
1
{"detail": "..."}

For Pydantic validation errors, detail becomes an array of {"loc": [...], "msg": "...", "type": "..."} objects.

HTTP status codes#

200 OK#

Generic success. Returned on read endpoints and on updates.

201 Created#

Resource was created successfully. Response body contains the new resource.

202 Accepted#

Queued for asynchronous processing. Returned exclusively by POST /v3/mail/send. The message is queued; delivery will happen in the background.

204 No Content#

Success with no body. Returned on successful deletes and some idempotent operations (e.g., POST /api/admin/users/{id}/roles/{role_id}).

400 Bad Request#

The request is malformed or violates a logical constraint.

Endpoint family Example cause
/v3/mail/send template_id doesn't start with d-; both content and template_id supplied; personalizations empty
/v3/templates/* Cannot delete only active version; referenced template not dynamic
/v3/api_keys Unknown scope name
/api/admin/domains Invalid DMARC policy value
/v3/suppression/bounces (DELETE) delete_all=true missing from bulk delete query

401 Unauthorized#

Missing or invalid credentials.

Body When
{"detail": "Missing Authorization header"} No Authorization header present
{"detail": "Invalid API key"} Key not found in DB; typo; revoked
{"detail": "JWT expired"} Access token past exp
{"detail": "JWT signature invalid"} Token signature didn't verify against JWKS

403 Forbidden#

Authenticated but not authorized for this action.

Body When
{"detail": "Missing required scope: <scope>"} Credential lacks the scope
{"detail": "Tenant suspended"} Tenant has been administratively suspended in ScaiKey
{"detail": "Sender domain not verified"} from.email domain hasn't been verified (live sends only)
{"detail": "Cross-tenant access denied"} Trying to access another tenant's resource

404 Not Found#

Resource does not exist, or belongs to a different tenant.

Endpoint family Example
/v3/messages/{id} Unknown message ID
/v3/templates/{id} Unknown template ID
/v3/api_keys/{id} Unknown or revoked key
/v3/user/webhooks/{id} Unknown endpoint
/v3/suppression/bounces/{email} Address not on the list
/api/admin/domains/{id} Unknown domain
/i/{image_id} Unknown image (as opposed to 410 Gone for deleted)

409 Conflict#

State conflict.

Endpoint family Example
/api/admin/domains Domain already exists for this tenant
/api/admin/roles Role name already used
/v3/templates Template name already used

410 Gone#

The resource existed but has been deleted.

Endpoint When
/i/{image_id} Image was deleted after being referenced in a sent email

413 Payload Too Large#

Request body exceeds the configured limit.

Endpoint Limit
/v3/mail/send 20 MB total body (including base64 attachments)
/v3/images 10 MB per image

422 Unprocessable Entity#

Pydantic schema validation failed. detail is an array:

json
1
2
3
4
5
{
  "detail": [
    {"loc": ["body", "personalizations"], "msg": "field required", "type": "value_error.missing"}
  ]
}

429 Too Many Requests#

Rate limit exceeded.

Response headers:

Header Notes
Retry-After Seconds to wait before retrying
X-RateLimit-Limit Limit for this endpoint/credential
X-RateLimit-Remaining Remaining requests in the current window
X-RateLimit-Reset Unix timestamp when the window resets

See Rate Limiting.

500 Internal Server Error#

Unexpected server error. Capture the response headers — the X-Request-ID (or X-Scaisend-Request-Id) is needed for support tickets.

503 Service Unavailable#

A dependency is down (MySQL, Redis, ScaiKey JWKS). Retry after a delay.

Common error sources#

mail_settings.sandbox_mode forced to true#

If the credential is a test key (sg_test_*), any value of sandbox_mode.enable is ignored and sandbox is active. This is a feature, not an error — the message is accepted normally.

from.email domain not verified#

Live sends require a verified sender domain. Sandbox sends (test key or sandbox_mode.enable: true) skip this check.

Template rendering failure#

Renders happen in the worker, after the 202 response. A template error doesn't cause a send-time 4xx. Instead:

  • Message status becomes FAILED.
  • error_message on the message record has the exception.
  • A dropped event is emitted with reason template_render_error.

Webhook endpoint auto-disabled#

If a webhook endpoint fails 10 consecutive deliveries, ScaiSend sets disabled_at. Subsequent events are not delivered to this endpoint until you re-enable with PATCH {"enabled": true}.

Retry classification#

Status Retry? How
400, 401, 403, 404, 409, 410, 413, 422 No Fix the request
429 Yes Honor Retry-After
500 Yes, limited 2–3 attempts with exponential backoff
503 Yes Exponential backoff

See Errors for recommended retry loops.

Updated 2026-05-17 01:33:27 View source (.md) rev 1