Errors and safe retries
Use HTTP status, stable code, request ID, and your original idempotency evidence together. Public errors intentionally avoid revealing internal tenant or provider detail.
Error envelope
{
"code": "invalid_request",
"message": "The request could not be completed.",
"requestId": "req_...",
"retryable": false,
"fieldErrors": []
}Retain the response X-Request-Id and JSON requestId. Do not expose authorization headers or message bodies in application logs.
Status and action
| Status | Typical code | Caller action |
|---|---|---|
| 400 | invalid_request | Correct method, path, query, identifier, channel, recipient, template, variables, or key format. Do not retry unchanged. |
| 401 | unauthorized | Verify the credential is present, active, unexpired, correctly stored, and in the right environment. |
| 403 | forbidden | Check actions, channels, Server App status, tenant hierarchy state, and exact Project/App match. |
| 404 | not_found | Check the caller-scoped identifier or currency. Cross-tenant records are not enumerable. |
| 409 | idempotency_conflict | Stop. The key was used with different material; reconcile caller state before choosing a new operation. |
| 402 | insufficient_funds | Resolve account funding or billing readiness; do not loop retries. |
| 403 | budget_blocked or entitlement_blocked | Review the authoritative account policy and do not bypass it by changing identifiers. |
| 503 | provider_unavailable | No message is accepted when a required price or route is unavailable. Retry later with bounded backoff and the same operation key. |
| 500 | internal_error | Treat the result as ambiguous, retry the exact request with the same idempotency key, and escalate with the request ID if persistent. |
Retry policy
- Retry only transient network failures, selected 5xx responses, or documented availability responses.
- Use exponential backoff with jitter and a maximum attempt or time budget.
- Reuse the same message body and idempotency key after an ambiguous POST.
- Do not retry authentication, authorization, validation, policy, funding, or conflict failures unchanged.
- Use circuit breaking when persistent failures could amplify load.
Support evidence
Provide the safe MessageHop request ID, message ID, project ID, app ID, approximate UTC time, endpoint, HTTP status, stable error code, and whether the operation was retried. Never provide the raw credential, OTP, recipient list, or full message body.