Error codes and retries
Every error code with its status, whether it is retryable and its message, when to retry, and the request ids and logs that trace a failure.
The shape
Every non-2xx answer carries one body:
{
"error": {
"code": "concurrent_idempotent_requests",
"message": "A request with this idempotency key is still being processed. Retry shortly.",
"retryable": true,
"request_id": "req_019a2b3c-4d5e-7f60-8a9b-0c1d2e3f4a5b"
}
}| Field | Meaning |
|---|---|
code |
A stable identifier from the table below. Branch on this, not on the message. |
message |
What happened and what to do next. A validation message names the first invalid field by its full path (Missing `definition.). |
retryable |
True when repeating the same request with the same idempotency key can succeed. |
request_id |
The request's id, see Request ids and logs. |
issues |
Validation only: [{ "path": "attachments., one per invalid field, with dotted paths into the request body. |
A failed item of a batch carries { "code", "message", "retryable" } in its own result.
Retrying
- When
retryableis true, repeat the request with the sameIdempotency-Key: the key makes sure a retry never sends a second email. Aretry-afterheader says how many seconds to wait first; it comes with429 rate_limit_exceededand409 concurrent_idempotent_requests. 500errors and502 upstream_unavailableare retryable.502 outcome_unknownis not: the provider's answer was lost, so the email may have gone out, and it is failed rather than sent again (Never sent twice).429 daily_quota_exceededlasts until the next UTC day, or until the cap is raised in the project's settings.- Validation errors (
400,422) need a changed request;issuesnames the fields. - A body that is not valid JSON is
422 validation_error, and a body sent without a JSON content type is415 unsupported_media_type. SendContent-Type: application/json, whichfetchleaves out for a string body. A request with no body at all reads as{}. 501 not_implementedmeans the route is not served yet. It is not retryable.
Codes
| Code | Status | Retryable | Message |
|---|---|---|---|
invalid_idempotency_key | 400 | no | The idempotency key must be between 1 and 256 characters. |
invalid_sign_in_code | 400 | no | That sign-in code is not valid. Check it and try again, or ask for a new code. |
missing_api_key | 401 | no | Missing API key in the authorization header. |
restricted_api_key | 401 | no | This API key is restricted to only send emails. |
unauthorized | 401 | no | Sign in to continue. |
account_blocked | 403 | no | This account is blocked. Contact Minket if you think this is a mistake. |
domain_authentication_failed | 403 | no | SPF, DKIM or DMARC is failing for this domain. Sending resumes when DNS is fixed. |
domain_not_verified | 403 | no | This domain is not verified yet. Finish its DNS records in the console. |
forbidden | 403 | no | Your role does not allow this. Ask an owner or admin of the organization. |
invalid_access | 403 | no | Access to this resource is not allowed. |
invalid_api_key | 403 | no | API key is invalid. |
invalid_from_address | 403 | no | The from address does not belong to a verified domain of this project. |
organization_suspended | 403 | no | This organization is suspended. Contact Minket to restore sending. |
signup_closed | 403 | no | Sign-up is closed. Ask an owner of an organization for an invitation. |
test_mode_only | 403 | no | Test keys cannot do this. Use a live key. |
not_found | 404 | no | The requested item does not exist. |
method_not_allowed | 405 | no | This method is not allowed for this endpoint. |
concurrent_idempotent_requests | 409 | yes | A request with this idempotency key is still being processed. Retry shortly. |
conflict | 409 | no | This already exists. |
invalid_state | 409 | no | This action is not possible in the item's current state. Check its status first. |
mailbox_unavailable | 409 | no | This mailbox needs to be reconnected before it can send. |
payload_too_large | 413 | no | The request body is too large. |
unsupported_media_type | 415 | no | Send JSON with a content-type of application/json. |
content_blocked | 422 | no | The content failed a deliverability check. See issues for details. |
invalid_attachment | 422 | no | An attachment is invalid. |
invalid_idempotent_request | 422 | no | This idempotency key was already used with a different request. |
invalid_parameter | 422 | no | A parameter has an invalid value. |
invalid_region | 422 | no | This region is not supported. |
missing_required_field | 422 | no | A required field is missing. |
stream_rule_violation | 422 | no | Marketing email needs an unsubscribe link and List-Unsubscribe headers. |
validation_error | 422 | no | The request is not valid. |
daily_quota_exceeded | 429 | no | This organization has used its daily sending quota. It resets at midnight UTC; ask Minket to raise it. |
monthly_quota_exceeded | 429 | no | This organization has used its monthly sending quota. It resets on the first of the month (UTC); ask Minket to raise it. |
rate_limit_exceeded | 429 | yes | Too many requests. Slow down and retry after the time in retry-after. |
security_error | 451 | no | This request was blocked for security reasons. |
application_error | 500 | yes | Something went wrong on our side. Retry with the same idempotency key. |
internal_server_error | 500 | yes | Something went wrong on our side. Retry with the same idempotency key. |
not_implemented | 501 | no | This endpoint is not available yet. Check the deployment's version. |
outcome_unknown | 502 | no | The provider's answer was lost, so it is unknown whether this email went out. It was not sent again, to avoid a duplicate. |
upstream_unavailable | 502 | yes | A provider did not respond. Retry with the same idempotency key. |
sending_paused | 503 | yes | Sending is paused for this project. Check alerts in the console. |
Request ids and logs
Every response carries an x-request-id header. Send your own (8 to 128 characters from A-Z, a-z, 0-9, _ and -) and it comes back unchanged; otherwise the API makes one, such as req_019a2b3c-4d5e-7f60-8a9b-0c1d2e3f4a5b.
Every request made with a key is logged with its method, route pattern (/v1/emails/:id, never the concrete path), status, latency, key id, environment, mode, error code, request id, the caller's address and user agent, and the SHA-256 of its Idempotency-Key. Bodies and recipients are never logged. GET /v1/logs lists a key's own environment and mode, newest first, filtered by status, path, api_key_id, error_code, from_date and to_date; GET /v1/logs/{id} returns one. Logs are kept 30 days, and the console shows them under Logs.
curl "https://api.minket.com/v1/logs?error_code=rate_limit_exceeded" \
-H "Authorization: Bearer $MINKET_API_KEY"