> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Fax: delivery & inbound-routing model

> The fax channel's termination-policy exception, document model, on-success-charge semantics, inbound routing split between config endpoints and delivery, and the delivery-receipt vocabulary — the lifecycle model that ties the Fax channel page and the inbound-fax workflow guide together.

# Fax: delivery & inbound-routing model

The [Fax channel page](/channels/fax) documents the request shape and limits, and the [inbound fax workflow guide](/guides/inbound-fax-workflow) walks the receive-path setup. This page is the concept layer underneath both: how the end-to-end fax lifecycle is structured, where it deliberately diverges from the SMS/MMS model, and why. Read it before you wire fax into a reconciliation flow or branch webhook handlers on delivery status.

## 1. Termination exception: fax rides Telnyx

The platform's termination policy says outbound voice and SMS exit exclusively through the Devotel softswitch; Telnyx and DIDWW are used for inbound traffic only. Fax is a named exception to that rule — alongside MMS, it is one of the two channels permitted to terminate outbound on Telnyx's Programmable Fax endpoint.

The reason is protocol. A fax is not a message the softswitch's SMS/e-mail switches can carry: it requires a live T.38 (or G.711 fallback) session negotiated endpoint to endpoint between two fax machines. That session looks exactly like a voice call to result, and Telnyx's dedicated fax product supports it natively. Forcing fax through the softswitch would mean re-implementing T.38 relay; routing it through the SMS/MMS planes is a category error — those planes are store-and-forward, and T.38 is not. So fax joins MMS as the allowed exception, and your outbound `POST /api/v1/messages/fax` call terminates on Telnyx by design.

Inbound fax rides Telnyx inbound rather than the softswitch — the carrier delivers a `fax.received` webhook carrying the received PDF as a hosted media URL, and Orbit writes it to the channel-agnostic inbound pipeline. Nothing in this path deviates from your SMS security posture; the exception is narrowly scoped to which provider terminates the fax leg.

## 2. Document model: PDF/TIFF, quality, and the media handoff

A fax is a document, not a text body. The `media_url` you supply at send time points the carrier at your PDF or TIFF, and the carrier converts it to T.38 packets in real time. Orbit never re-hosts the file — the carrier fetches directly from your URL at dispatch.

Three facts define the document model:

* **PDF or TIFF, HTTPS only.** The single permitted file types are PDF and TIFF, and the URL scheme is hard-bounded to HTTPS. Any other scheme is rejected before the carrier ever sees it.
* **`quality` is a resolution setting, not an SLA toggle.** `normal` (default), `high`, and `very_high` control the scanning resolution of the transmitted pages. Higher values raise the resolution of fine graphics but also lengthen the T.38 handshake, which on a lossy line is when `poor_line_quality` failures appear. Pick `high` for documents with small text or signatures; fall back to `normal` on long documents to lossy destinations.
* **The fax lifecycle is a single attempt.** Unlike a data channel, fax has no built-in re-transmission schedule at the carrier: the attempt either succeeds or fails in one go. Orbit's queue worker re-dispatches the send only while the message is still `queued` (a transient provider error before the T.38 session begins); once `sending` begins, the attempt is live and its outcome lands as a delivery receipt.

A governed idempotency key (`orbit-fax:<message-id>`) covers all of this: a retry of the same `POST /messages/fax` dedups at the carrier and does **not** bill twice.

## 3. Charge semantics: on-success-charge, success vs attempt

Fax takes a stricter stance on charging than the SMS/MMS model: your wallet is billed **only when the carrier confirms a successful transmission** (`delivered` or at minimum `sent` for the non-terminal success state), and failed attempts (`busy`, `no_answer`, `poor_line_quality`, and every other failure diagnostic) are not billed.

Success means the carrier completed the T.38 session and acknowledged the transmission — the distinction between `sent` (carrier-completed) and `delivered` (the end station confirmed receipt) matters for your reconciliation, but both are charge-eligible. Attempt means the row moved through `sending` but the handshake never completed — every one of the failure diagnostics documented on the [Fax channel page](/channels/fax) is a non-chargeable attempt.

This matters for how you reconcile your wallet ledger: a failed fax row costs zero, and the `message.failed` events in your webhook stream carry no wallet deduction. Inbound faxes are likewise never billed. The on-success-charge semantics differ from the SMS/MMS per-submit or per-DLR model — see [Wallets, credits, and charges](/concepts/wallets-credits-and-charges) for the generic lifecycle and this section for the fax exception.

## 4. Inbound fax: config endpoints, delivery service, and the routing split

An inbound fax arrives as a Telnyx `fax.received` webhook on the shared inbound endpoint. The webhook handler validates the event, resolves the tenant from the recipient DID, and writes a `messages` row with `channel: "fax"`, `direction: "inbound"`. From there, routing decides where the fax goes — the model deliberately separates **config** from **delivery**:

* **The routing config endpoints** (`GET /api/v1/numbers/:id/fax-routing`, `PUT /api/v1/numbers/:id/fax-routing`) read and upsert a per-DID config: `{ enabled, forward_emails[], deliver_to_inbox, archive_path }`. The config lives in the canonical number inventory record and is keyed on the E.164 of the DID, so it survives number reassignment within your account.
* **The delivery service** runs after the message row is persisted, and only when the config's `enabled` flag is set. It fans the received PDF out to the configured destinations: email forwards (each recipient gets the PDF attached, or a link-only fallback when the media fetch fails) and an inbox ticket (with sender, recipient, and media metadata attached). This service **never throws** — once the webhook has acknowledged the carrier and the message row exists, a downstream delivery failure degrades to a logged warning rather than a 500.

The critical difference from SMS inbound is conceptual. SMS inbound resolves through the generic routing-rules engine (keyword auto-reply, contact resolution, channel-handoff matrix). Fax has no such engine — a received fax is a document, not an interactive message, and subscribers overwhelmingly want one thing: forward it to a mailbox, open an inbox ticket, or both. The dedicated config/service pair gives exactly that without forcing fax through the text-routing machinery. The general inbound model is documented in [Inbound message routing](/concepts/inbound-message-routing); treat this page as the fax exception.

## 5. Delivery receipts: the status vocabulary and wire expectations

Outbound fax receipts don't follow the SMPP DLR vocabulary. Telnyx fax DLRs arrive in the `fax.*` event namespace, and Orbit maps each event onto the same message `status` field you use for every other channel:

| Telnyx fax event      | Mapped `status` |
| --------------------- | --------------- |
| `fax.queued`          | `queued`        |
| `fax.media.processed` | `sending`       |
| `fax.sending.started` | `sent`          |
| `fax.delivered`       | `delivered`     |
| `fax.failed`          | `failed`        |

Three expectations make receipts tractable:

* **The `delivered` vs `sent` split reflects carrier truth.** Some routes promote to `delivered` immediately after transmission; others only after the receiving machine completes the handshake's final page. Design your reconciliation to treat `sent` as carrier-completed-but-non-terminal and `delivered` as the strong "the customer has it" signal, because `sent` rows can still be promoted or demoted.
* **Carriers map failure diagnostics onto `error_code` / `error_message`.** Unknown carrier text passes through verbatim, so branch on the payload fields, not the enum of expected values.
* **Read back through your org-level webhook sink or per-send `status_callback`.** The provider-side `external_id` is attached asynchronously once the transmission is dispatched, and `GET /api/v1/fax/:id/status` returns the provider status with a short per-tenant cache — but the durable reconciliation path is the status callback, because the direct-provider readback is a convenience surface, not the record of truth.

Once the vocabulary is clear, the merge contract in [Message status transition rules](/concepts/message-status-dag) tells you which of these moves your own state store must permit, and the [delivery lifecycle](/concepts/delivery-lifecycle) page explains who drives each transition.

## Where to go next

* [Fax channel page](/channels/fax) — request shape, limits, and common patterns.
* [Inbound fax workflow guide](/guides/inbound-fax-workflow) — end-to-end setup of the receive path.
* [Delivery lifecycle](/concepts/delivery-lifecycle) — the generic state machine.
* [Wallets, credits, and charges](/concepts/wallets-credits-and-charges) — billing lifecycle.
* [Inbound message routing](/concepts/inbound-message-routing) — the generic inbound rules this page is the exception to.
