Error reference
Error reference
Every API error has the same shape: an error object with a stable code, a readable message, a fields object (empty unless a field failed validation) and a request_id.
Response shape
Error body
{
"error": {
"code": "not_found",
"message": "Resource not found.",
"fields": {},
"request_id": "req_3k9QxV2mT7bLw8RfY1aZ"
}
}
Match on error.code. Codes are stable; message text may change.
Request IDs
Every response, successful or not, has an X-Request-Id header. Error bodies repeat the same value as error.request_id. Log it with your test output and include it when you contact support@mailsocket.app, so we can find the exact request.
Retrying 429s
Every 429 response carries a Retry-After header with the number of seconds to wait. The wait endpoint has two codes of its own:
| Code | Limit | What to do |
|---|---|---|
too_many_wait_requests | Concurrent waits per account: 2 Free / 3 Pro / 8 Scale / 16 Business. | Wait Retry-After seconds, or for one of your open waits to return. Run fewer waits in parallel, or move to a plan with more. |
wait_capacity | A service-wide limit on open waits, shared by all accounts. | Wait Retry-After seconds and retry. This is temporary and does not count against your plan. |
Codes
| Code | HTTP | Meaning | How to handle |
|---|---|---|---|
authentication_required |
401 |
Missing or invalid API key. | Send a valid Authorization: Bearer <key> header. |
account_forbidden |
403 |
The account is not permitted to use the API (unverified, suspended, or inactive). | Verify your email, or contact support. |
not_found |
404 |
The resource does not exist or is not owned by this key. | Check the id. Ids that belong to another account return the same 404. |
method_not_allowed |
405 |
The HTTP method is not supported for this path. | Use the documented method for the endpoint. |
not_acceptable |
406 |
The requested response format is not acceptable. | Request application/json. |
conflict |
409 |
The request conflicts with the current state (for example, address allocation failed). | Retry the request. |
plan_limit_reached |
409 |
The plan limit for this action has been reached. | Upgrade your plan, or free capacity first. |
slug_taken |
409 |
The requested inbox routing_key is already in use. | Choose a different routing_key, or omit it for a random one. |
unsupported_media_type |
415 |
The request media type is not supported. | Send a JSON request body. |
validation_error |
422 |
The request body or a parameter failed validation. | Read the fields object for per-field messages. |
rate_limited |
429 |
The per-key request rate limit was exceeded. | Wait for the number of seconds in Retry-After, then retry. |
too_many_wait_requests |
429 |
Your plan's concurrent-wait cap was reached (2 Free / 3 Pro / 8 Scale / 16 Business). | Wait for Retry-After seconds, or for one of your open waits to return. |
wait_capacity |
429 |
The service-wide concurrent-wait limit was reached. | Wait for Retry-After seconds, then retry. |
plan_upgrade_required |
402 |
Batch message operations require a paid plan. | Upgrade to Pro or higher to use POST /messages/batch. |
webhook_entitlement_required |
403 |
Webhooks require a paid plan (Pro or higher). | Upgrade your plan to configure or test a webhook. |
webhook_not_configured |
404 |
No webhook is configured for this inbox. | Create a webhook for the inbox before testing it. |
webhook_ssrf_rejected |
400 |
The webhook URL resolves to a private, loopback or link-local address. | Use a public HTTPS URL. |
webhook_unreachable |
502 |
The webhook receiver could not be reached (timeout, TLS, or network error). | Check the receiver is up and reachable over HTTPS. |
server_error |
500 |
An internal error occurred. | Retry. If it persists, send us the request_id. |
byod_disabled |
403 |
Custom domains are not enabled for this account. | Contact support to enable custom domains. |
domain_entitlement_required |
403 |
Custom domains require a Business plan. | Upgrade to Business to add a custom domain. |
domain_limit_reached |
403 |
The custom-domain limit for this plan has been reached. | Remove an existing domain. |
domain_taken |
409 |
The domain name is already registered. | Choose a different domain, or contact support if you own it. |
domain_has_inboxes |
409 |
The domain still has inboxes bound to it. | Remove the bound inboxes before deleting the domain. |
domain_verify_rate_limited |
429 |
Too many manual domain-verify attempts. | Wait for Retry-After seconds, then retry. |
domain_not_found_or_unverified |
422 |
The domain id was not found, is not owned by this account, or is not verified. | Create and verify the domain first, or omit `domain` to use the shared domain. |
public_not_allowed_on_custom_domain |
422 |
Only shared-domain inboxes can be public. | Omit `public`, or omit `domain`. |
metadata_must_be_object |
422 |
`metadata` must be a JSON object. | Send `metadata` as an object, e.g. {"run": "ci-123"}. |
metadata_too_large |
422 |
`metadata` exceeds 4096 bytes (compact UTF-8 JSON) or 50 top-level keys. | Keep metadata to correlation ids. |
catch_all_entitlement_required |
403 |
Catch-all requires a Business plan. | Upgrade to Business to enable catch-all. |
domain_not_verified |
409 |
The domain must be verified before catch-all can be enabled. | Verify the domain first (`POST /domains/{id}/verify`). |
catch_all_target |
409 |
This inbox receives the domain's catch-all mail, so it cannot be deleted or disabled. | Disable catch-all on the domain first (`PATCH /domains/{id}/catch_all` with `catch_all: false`). |
catch_all_target_invalid |
422 |
The `inbox_id` is not a live inbox bound to this domain. | Pass an enabled inbox bound to this domain, or omit inbox_id to create one. |
inbox_limit_reached |
403 |
Creating the catch-all inbox would exceed the plan's inbox limit. | Remove an inbox, or pass an existing inbox_id. |
catch_all_rate_limited |
429 |
Too many catch-all changes for this domain. | Wait for Retry-After seconds, then retry. |
smtp_verify_disabled |
403 |
Full SMTP verification (`mode: "full"`) is not available. | Use `mode: "safe"` (the default). |
verify_full_entitlement_required |
403 |
Full SMTP verification requires a Business plan. | Use `mode: "safe"` (the default). |
batch_too_large |
422 |
The batch has more unique addresses than allowed (100). | Split the batch into smaller requests. |
file_too_large |
422 |
The uploaded file is larger than 64 KB. | Split the file, or send the addresses as `text` or `emails`. |
unsupported_file_type |
422 |
The uploaded file must be a `.csv` or `.txt` file. | Re-export the file as .csv or .txt. |
malformed_file |
422 |
The uploaded file is not UTF-8 text. | Re-save the file as plain UTF-8 text. |