Errors and job states

Updated

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
CodeStatusWhat to do
invalid_token401the key is missing, revoked or malformed. Get a key from the dashboard
scope_missing403the API key lacks the scope. The message names it
agent_forbidden403an agent key is not allowed on this route. A person does this
not_found404no such resource in your organization. A foreign id looks the same
invalid_request400 or 422the body failed validation. details lists the fields
conflict409a state that forbids the call, or a different body under the same Idempotency-Key.
encrypted_pdf, unsupported_format, page_limit_exceeded422fix the document and create it again. Nothing was stored or charged
conversion_failed, image_too_large422the 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_unavailable503the HTML renderer is down. Retryable
live_provider_unavailable503live sending is not enabled on this server yet, so live quotes, sends and number orders are refused. Test keys keep working. Not retryable
unsupported_destination422no published route, or excluded by policy. Not retryable
quote_expired409quote again. Quotes last ten minutes
insufficient_balance402top up the wallet. The provider was not called
budget_exceeded, agent_budget_exceeded403the cap for the period is reached. A person raises it or waits
approval_required403a live send with no approval and no allowing policy. Ask a person
approval_*409see the approvals page. Quote and ask again
sandbox_only, environment_not_billable403the route is for the other kind of key.
payload_too_large41325 MiB upload cap
rate_limited429600 requests a minute per key. Retryable after RateLimit-Reset
billing_unavailable, temporarily_unavailable, provider_timeout502 or 503retryable with the same Idempotency-Key.
internal_error500retryable. 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
StateDo
queued, activewait 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
deliveredread the receipt and store the provider reference
partialread pages_sent. Decide whether to send the missing pages as a new fax. The service never retransmits on its own
failedread failure_code: busy, no_answer, invalid_number, render_failed, provider_error, canceled. Nothing was charged
unknownwait. 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.