# API errors, limits and retries

Handle an API failure using both the HTTP status and the response body. Keep the operation name and resource ID with the error so you can tell whether a test failed to send, wait, retrieve or clean up a message.

## Read the response before retrying

Error responses can include a message and application error code. Some rate-limit responses also include `retryable`, `retryAfterSeconds` and a `Retry-After` header. These fields are not present on every failure, so handle missing values and retain the original response for diagnosis with secrets redacted.

| Response | Next action |
| --- | --- |
| 400: invalid request | Check required fields, enum values, IDs and request format against the operation reference; fix the input before retrying |
| 401 or 403: authentication or access | Check the API key, owning account, environment and permissions; repeated requests with the same credentials will not resolve access |
| 404: missing resource | Check the resource ID and whether the inbox expired or cleanup already deleted it |
| 408 from a message wait | Inspect delivery and matching conditions using the [wait troubleshooting guide](/docs/wait-troubleshooting/) |
| 409: conflicting state | Read the conflict details and fetch current state before deciding what to do next |
| 402 or 426: billing or plan restriction | Read the explanation and review the account's subscription or allowed operation |
| 429: request or sending restriction | Distinguish a temporary rate limit from an account, plan or sending restriction before retrying |
| 5xx or connection failure | Bound any retry by a deadline and first consider whether the operation could already have completed |

## Distinguish rate limits from quotas

MailSlurp uses 429 responses for more than temporary request throttling. The response may describe a sending restriction or an account limit. Do not interpret every 429 as an instruction to sleep and send again.

When the response explicitly permits a retry, respect its retry delay. If `retryable` is false, stop and resolve the stated condition. When retry metadata is absent, use the error message and application code to classify the failure rather than assuming it is temporary.

For transient throttling, reduce concurrency and use bounded backoff with jitter. For organization policies, review [governance and quotas](/docs/governance/). Use [pagination](/docs/pagination/) to fetch lists in supported batches instead of making an unbounded burst of requests.

## Separate safe reads from actions

A failed response does not always mean the server did no work. If a send request reaches the server but the connection closes before the response, blindly sending again can produce a duplicate email or SMS. The same uncertainty applies to creating a render run or starting another asynchronous job.

- For a read, retry only a transient failure and stop after a bounded number of attempts or an overall deadline.
- For a write, use an idempotency mechanism only where that operation documents support for it. Otherwise, reconcile the existing resource or result before repeating the action.
- For a long wait, inspect its conditions and deadline. Do not turn a delivery timeout into an unlimited series of fresh waits.
- For incoming webhook events, make your own processing repeatable; follow [reliable webhook processing](/docs/pipeline-recovery/).

## Set a retry budget

Choose a total operation deadline before the first request. Each attempt and its delay must fit within the remaining budget. Honor `Retry-After` when supplied; it can be a delay in seconds or an HTTP date. If the required delay exceeds the remaining budget, fail with the original error instead of retrying early.

Check your HTTP library and SDK configuration before adding another retry loop. Multiple retry layers can multiply the number of requests and hide the original failure. Keep connection timeouts, server-side waits and test-runner deadlines consistent.

When requesting help, provide the operation, status, application error code, approximate request time and a redacted reproduction. Never include your API key. Start with [authentication](/docs/authentication/) for key setup or the [API reference](/docs/api/) for operation-specific inputs and responses.
