Troubleshooting: fax sends fail or never arrive
Fax failures split into four classes, and the fix is different for each: the API refused the send (content/destination reject), the carrier failed the transmission (passthrough failure with a diagnostic), a transient gateway error sits between your client and the carrier, or the record terminal’dsent but the recipient never received pages. This page walks all four,
with the billing rule that decides what each one costs you.
If the row is stuck pre-queue (queued, pending), work the
queue-side troubleshooting page instead. This
page assumes the send was dispatched.
Symptom map
Three surfaces read the same fax row: the Delivery Log filtered by channel (/messages/delivery-log?channel=fax), the authoritative row on
GET /api/v1/messages/:id, and the message.failed webhook payload with
channel: "fax". Match the symptom to its class first — the same status
word points at different layers.
Cause → fix
Work the class you matched above. Each fix is a one-shot check before you resend — fax is single-attempt from the queue side (the worker only re-dispatches while the row isqueued), so a terminal failed row is
re-sent as a new message.
What not to do
- Do not retry a destination reject (
busy,no answer,no fax tone) in a loop. These are deterministic — the same send fails the same way until the line frees or the recipient confirms the number. One sensible re-send after the line clears, not a retry loop. - Do not resend the same payload against
poor_line_qualitywithout loweringquality. The handshake length is the variable; unchanged, the re-send fails the same way. - Do not count a
sent-hold as delivered. Carriers ackdeliveredat different points; treatsentas carrier-completed and onlydeliveredas end-station-confirmed. - Do not bypass
retry_afteron a 5xx. A single retry is the shape defined here; repeated immediate retries against a provider 5xx amplify the queue rather than recover it.
Billing note
Fax is on-success-charge — your wallet deducts only when the carrier confirms a successful transmission. Every failure class above (content reject, destination reject, gateway 5xx, line failure, delivered-never-received) is not billed — this holds for both the initial send and any sensible re-send. The provider-side idempotency key (orbit-fax:<message-id>) also
keeps a legitimate same-message retry from double-charging. Charged rows
appear on your billing overview only after a
successful transmission.
Escalation bundle
Open a support ticket when one of these holds:- A 502
MESSAGE_SEND_FAILEDpersists after one retry and your tenantfax_connection_idresolves cleanly. - A destination reports fax-reachable and the carrier returns
handshake_rejectedon every attempt. - A row held at
sentfor several hours with nodeliveredorfailedterminal.
- Tenant ID (dashboard → Settings → Organization; API →
GET /api/v1/mereturns it asorganizationId) - Re-enquire
request_id— the send POST’smeta.request_id(returned in the error envelope for the 4xx/5xx classes, or in the successful enqueue response for the terminalfailedclass) - Destination number in E.164
- Fax/Message ID —
msg_…from the row (On routeGET /api/v1/fax/:id, the provider-sideexternal_idattaches after dispatch — include both where present)
sent row, run the self-serve
route-trace timeline
(GET /api/v1/messages/:id/trace) first — the failure stage
(validation / submission / carrier) narrows which class above to
escalate.
See also
- Fax channel page — send fields, errors, limits, and the status lifecycle this page decodes
- Outbound fax workflow — the complete send-side walkthrough: billing timing, receipts, and document guidance
- Delivery log — the dashboard surface behind the
channel=faxfilter - Message undelivered or failed —
the channel-agnostic failure decoder (the classifier
metadata.classified_error_code) - Error codes — the JSON error envelope and the
MESSAGE_SEND_FAILED/ validation code catalog - Webhook events — the
message.delivered/message.failedpayloads (channel: "fax"events arrive on the channel-agnostic surface)