Skip to main content
The Sendmux API uses standard HTTP status codes and returns a consistent error envelope so you can handle failures programmatically.

Error response format

{
  "ok": false,
  "error": {
    "code": "invalid_parameter",
    "message": "Description of the error.",
    "param": "from_date",
    "doc_url": "https://sendmux.ai/docs/api/errors#invalid_parameter",
    "retryable": false
  },
  "meta": {
    "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}
FieldDescription
codeStable machine-readable code from the table below. Branch your client logic on this, not on the message text.
messageHuman-readable description suitable for logs or surfacing to internal tools. Wording may change without notice.
paramOnly present when the error is tied to a specific request field, usually the field that failed validation.
doc_urlAnchor link into this page. Useful for surfacing inline help.
retryabletrue when the same request can succeed on a later attempt without changes. See Retryable + Retry-After.
errorsOnly present on accumulated validation failures. See Validation errors with multiple issues.
Every response also carries an X-Request-Id HTTP header that matches meta.request_id verbatim. Always include request_id when contacting support.

Retryable + Retry-After

The retryable field tells you whether retrying the same request is likely to succeed. Defaults follow this policy:
HTTP statusDefault retryableWhy
429trueBack off until the rate-limit window resets.
5xxtrueServer-side issue or required service briefly unavailable.
4xx otherfalseCaller-side problem. Fix the request before retrying.
When retryable is true for a 429 or 503, the response also carries a Retry-After HTTP header with the recommended wait in seconds. Honour that value rather than retrying immediately.
HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/json
A handful of codes override the default policy. idempotency_conflict is false: the client should either wait for the in-flight request to finish or use a fresh key for a different request.

Validation errors with multiple issues

When a request body fails schema validation on multiple fields, the error envelope carries an errors array so you can surface every issue in a single round-trip.
{
  "ok": false,
  "error": {
    "code": "invalid_parameter",
    "message": "Invalid request parameters.",
    "param": "filter_rules.0.action",
    "doc_url": "https://sendmux.ai/docs/api/errors#invalid_parameter",
    "retryable": false,
    "errors": [
      {
        "field": "filter_rules.0.action",
        "code": "invalid_enum_value",
        "message": "Expected 'allow' | 'deny'."
      },
      {
        "field": "filter_rules.2.pattern",
        "code": "too_small",
        "message": "String must contain at least 1 character(s)."
      }
    ]
  },
  "meta": { "request_id": "req_clxxxxxxxxxxxxxxxxxxxxxxxxx" }
}
The param at the top of the error matches the first issue’s field for backwards compatibility. The full list lives in errors[]. Status is 400 for syntactic problems (invalid_parameter) and 422 for semantic violations (validation_error).

Error codes

authentication_required

HTTP 401: The request has no Authorization header or the API key is invalid, expired, or revoked.
# Fix: include a valid API key
curl https://app.sendmux.ai/api/v1/providers \
  -H "Authorization: Bearer smx_root_your_key_here"

insufficient_permissions

HTTP 403: The API key is valid but lacks the required permission for this endpoint. Check the permission table to see which permission each endpoint requires.

invalid_parameter

HTTP 400: A query parameter has an invalid format or value. The param field identifies which parameter is at fault.

missing_parameter

HTTP 400: A required query parameter is missing from the request.

not_found

HTTP 404: The requested resource does not exist, or it belongs to a different team than the one associated with your API key.

conflict

HTTP 409: The request cannot be applied because of the resource’s current state. Examples include deleting a domain while mailboxes still use it, creating a mailbox whose email address already exists, or sending a write with a stale If-Match header. Re-fetch the resource and reconcile before retrying.

limit_exceeded

HTTP 409: Your team has reached the create limit for this resource. This can apply to domains, mailboxes, sending accounts, webhooks, or active API keys. Request an increase from the relevant page in the Sendmux app, or delete an existing item before retrying. See Team limits.

idempotency_conflict

HTTP 409: Returned when an Idempotency-Key request header is reused while the original request is still running, or with a request body whose fingerprint differs from the original. Wait and retry for an in-flight request. Use a fresh key for a different request. See the Idempotency guide.

validation_error

HTTP 422: A request body parsed cleanly as JSON but fails a semantic rule. Common cases include choosing an unsupported mailbox storage tier, shrinking mailbox storage below its current usage, referencing a provider or delivery group from a different team, or submitting more than 1,000 filter rules in a single request. The param field identifies the first offending field. The errors array lists every issue.

rate_limit_exceeded

HTTP 429: You have exceeded the rate limit of 600 requests per minute. The response carries a Retry-After HTTP header with the recommended wait in seconds. Back off until then before retrying. retryable is true.

payload_too_large

HTTP 413: The request body exceeds the server-side size limit. Trim the body or split it into smaller requests.

service_unavailable

HTTP 503: A required service is temporarily unavailable. The response may carry a Retry-After header. Requests are safe to retry with exponential backoff because retryable is true. If this persists for more than a few minutes, contact support with the request_id from the response.

internal_error

HTTP 500: An unexpected server error occurred. retryable is true because the failure is server-side. If it persists, contact support with the request_id from the response.