Skip to main content

Errors

API errors use this JSON envelope. A network failure or a response from an intermediary may not include it, so handle those separately.

{
"status": 422,
"type": "invalid_schedule",
"message": "scheduled_at must be within 72 hours",
"request_id": "req_01J8K2P...",
"doc_url": "https://docs.epostix.com/errors/invalid_schedule",
"details": []
}

Branch on type, never on message. Messages are written for people and are rewritten whenever the wording can be improved. Treat an unrecognised type as a generic failure rather than crashing on it.

request_id identifies the request in our logs. Quote it in a support ticket and we can find the exact call. doc_url is the page for that type on this site.

details is populated when a specific field is at fault. Each entry names the field, a message, and a code you can match on.

{
"details": [
{"field": "from", "message": "property \"from\" is missing", "code": "required"}
]
}

Deciding whether to retry​

  • For validation and permission errors, correct the request or configuration first. A definitively rejected POST can have a cached 4xx result; use a new idempotency key for the corrected request.
  • For rate_limit_exceeded or idempotency_in_progress, respect Retry-After and retry within a bounded deadline.
  • For daily or monthly quota errors, wait for the allowance to reset or change the plan. An immediate retry loop will not help.
  • For internal_error, service_unavailable or a transport failure, use bounded backoff and keep the original idempotency key. An uncertain response can follow partial work; inspect message state before manually resubmitting.

See handling errors for SDK error handling and idempotency for the deduplication window and its limits.

The catalogue​

TypeStatusMeaning
invalid_request400The body is not parseable JSON
authentication_failed401The API key is missing, malformed or unknown
api_key_expired401The key passed its expiry date
monthly_quota_exceeded402The monthly send allowance is used up
insufficient_scope403The key lacks the permission this route needs
api_key_ip_restricted403The key is not allowed from your address
domain_scope_restricted403The key is limited to other domains
domain_not_verified403The sending domain is not verified
workspace_suspended403The workspace is suspended
test_mode_restricted403A test key attempted a live-only operation
not_found404No such endpoint, or no such record
domain_not_found404The domain is unknown to this workspace
template_not_found404The template is unknown to this workspace
attachment_not_found404The attachment is unknown to this workspace
method_not_allowed405Wrong HTTP method for this path
email_not_cancellable409The message has already left this stage
idempotency_conflict409The key was reused with a different body
idempotency_in_progress409A request with this key is still running
api_key_in_use409You tried to delete the key you are using
payload_too_large413The request body is over the size limit
attachment_too_large413The attachments exceed the total size limit
unsupported_media_type415Content-Type is not application/json
validation_error422The body parsed but a field is invalid
invalid_from_address422The from address is not a usable mailbox
invalid_schedule422scheduled_at is in the past or too far ahead
duplicate_detected422The same message was sent repeatedly
batch_too_large422The batch is outside the allowed size
template_render_failed422The template could not be rendered
attachment_expired422The pre-uploaded attachment has expired
attachment_fetch_failed422An attachment URL could not be read
webhook_limit_reached422The workspace has all the endpoints it may have
webhook_url_not_allowed422The webhook URL is not a public address
rate_limit_exceeded429Too many requests in the current window
daily_quota_exceeded429The daily send allowance is used up
internal_error500Something failed on our side
service_unavailable503The service is restarting