# Errors and job states

> The error envelope and every code with its action. The six job states. When unknown means wait, why partial never retransmits, how to avoid duplicates.

Page: https://faxforagents.com/docs/errors/
Last changed: 2026-10-28

Updated Oct 28, 2026

Every non-2xx answer is one envelope. The code says what happened. `retryable` says whether the same call can be tried again. `correlation_id` is what to quote when you write to us.

JSON

```
`{"error": {"code": "insufficient_balance", "message": "the wallet holds $0.80 and the quote is $1.17", "retryable": false, "correlation_id": "req_..."}}`
```

## Codes

Error codes and the action for each

| Code | Status | What to do |
| --- | --- | --- |
| `invalid_token` | 401 | the key is missing, revoked or malformed. Get a key from the dashboard |
| `scope_missing` | 403 | the API key lacks the scope. The message names it |
| `agent_forbidden` | 403 | an agent key is not allowed on this route. A person does this |
| `not_found` | 404 | no such resource in your organization. A foreign id looks the same |
| `invalid_request` | 400 or 422 | the body failed validation. `details` lists the fields |
| `conflict` | 409 | a state that forbids the call, or a different body under the same Idempotency-Key. |
| `encrypted_pdf` , `unsupported_format` , `page_limit_exceeded` | 422 | fix the document and create it again. Nothing was stored or charged |
| `conversion_failed` , `image_too_large` | 422 | the HTML took longer than 45 seconds to render, or an image frame is over 50 million pixels. Make it smaller and create it again |
| `render_unavailable` | 503 | the HTML renderer is down. Retryable |
| `live_provider_unavailable` | 503 | live sending is not enabled on this server yet, so live quotes, sends and number orders are refused. Test keys keep working. Not retryable |
| `unsupported_destination` | 422 | no published route, or excluded by policy. Not retryable |
| `quote_expired` | 409 | quote again. Quotes last ten minutes |
| `insufficient_balance` | 402 | top up the wallet. The provider was not called |
| `budget_exceeded` , `agent_budget_exceeded` | 403 | the cap for the period is reached. A person raises it or waits |
| `approval_required` | 403 | a live send with no approval and no allowing policy. Ask a person |
| `approval_*` | 409 | see the [approvals page](https://faxforagents.com/docs/approvals/) . Quote and ask again |
| `sandbox_only` , `environment_not_billable` | 403 | the route is for the other kind of key. |
| `payload_too_large` | 413 | 25 MiB upload cap |
| `rate_limited` | 429 | 600 requests a minute per key. Retryable after `RateLimit-Reset` |
| `billing_unavailable` , `temporarily_unavailable` , `provider_timeout` | 502 or 503 | retryable with the same Idempotency-Key. |
| `internal_error` | 500 | retryable. Quote the correlation id if it persists |

## Why is a failed fax not an HTTP error?

A send answers 201 with a job in `queued`. What happens after is a state on the job, carried by events and webhooks, not an HTTP error.

What your code should do per state

| State | Do |
| --- | --- |
| queued , active | wait for the webhook or poll `GET /v1/faxes/{id}` . A fax takes a minute or more on the line. Busy and no answer are retried up to three times by the service |
| delivered | read the receipt and store the provider reference |
| partial | read `pages_sent` . Decide whether to send the missing pages as a new fax. The service never retransmits on its own |
| failed | read `failure_code` : `busy` , `no_answer` , `invalid_number` , `render_failed` , `provider_error` , `canceled` . Nothing was charged |
| unknown | wait. The hold stays and the reconcile tick keeps asking the provider. Do not send again from your side: a duplicate fax is the one outcome worse than a late one. If it stays unknown, write to us with the job id |

## How do I avoid sending a fax twice?

Send every mutating call with an `Idempotency-Key`, derived from your own record such as the order id. A timeout on your side then becomes a retry that returns the same job. Never create a new quote and send after a timeout without first reading the job list for your key.

## From the blog

- [What a fax API is and how one works, from PDF to T.30](https://faxforagents.com/blog/what-is-a-fax-api/)
