# Fax quotes API reference

> The quote operations of the Fax for Agents API. Price one exact document to one destination, with the cover, the resolution, the sender name and the expiry.

Page: https://faxforagents.com/docs/api/reference/quotes/
Last changed: 2026-11-13

Updated Nov 13, 2026

2 operations of the Fax for Agents API, from the OpenAPI document version 1.20.0, snapshot of 2026-11-13. The base URL is `https://api.faxforagents.com/v1`. This is one group of the [full reference](https://faxforagents.com/docs/api/reference/).

- A quote prices one exact document, identified by its sha256, to one destination.
- A cover sheet on a quote counts as a page and is billed as one.
- The price of a quote is the same at every quality level, from standard to ultra.

## Operations

- `POST /v1/fax-quotes` Price an exact document to one destination
- `GET /v1/fax-quotes/{quote_id}` Read a quote

## Why does a send start with a quote?

Because the quote is what gets approved and what gets charged. `POST /v1/fax-quotes` takes a document and a destination and answers with the price before anything is sent. The send in the [faxes group](https://faxforagents.com/docs/api/reference/faxes/) then names the quote and nothing else about the fax. Whatever the quote fixed is what goes out.

A quote costs nothing and sends nothing. An agent can quote, show the amount to a person and stop there.

## What goes into a quote?

Two required fields. `document_id` names the document and `to` is the destination in E.164, for example `+12025550123`.

The optional fields shape the fax. `from` is a number you own. Leave it out and the fax goes out from the shared pool. `cover` adds a cover sheet with `to_name`, `from_name`, `subject` and `message`. `sender_name` is the name that identifies the sender, and the carrier gets it as the caller name for its header line. `delete_after_send` deletes the document and the transmitted copy the moment the fax ends in delivered, partial or failed.

`quality` sets the resolution. The schema lists four words. `standard` is the fax standard's 204 by 98 dpi. `fine` is 204 by 196 and the default. `superfine` and `ultra` are finer still. The [send guide](https://faxforagents.com/docs/send-fax/#quotes) has the measurement behind the last two and which one suits small print.

## What does the answer fix?

The route and its label, `document_pages`, `cover_pages` and `billable_pages`, the amount in `amount_micro` with the currency, and `per_page_micro`. `price_version` names the rate table the price came from. `document_sha256` is the hash of the document at the moment of the quote.

Two fields tell an agent what comes next. `authorization_required` is true when a live send of this quote needs a person's approval, because no policy allows it. `warnings` lists the service's warnings for this quote.

A destination outside the published routes is refused. The quote does not exist then, and neither can a send.

## How long is a quote good for?

Until `expires_at`. `GET /v1/fax-quotes/{quote_id}` reads a quote again, and `expired` says whether its time has passed. An expired quote cannot be sent. Quote again, and if a person had approved the old one, ask again too: an approval is bound to its quote and expires with it. The [limits page](https://faxforagents.com/docs/limits/) has the life of a quote as a value.

A quote is used once. After a send, `consumed_by_job_id` names the fax that used it. A second send needs a second quote, even for the same document and number.

## What can change between the quote and the send?

Nothing that matters. The document is immutable, so the hash on the quote is the hash that is sent. The price comes from the quote, not from the rate table of a later minute.

That is the reason the API splits one action in two. The approval request in the [approvals group](https://faxforagents.com/docs/api/reference/approvals/) copies the quote. A person who approves sees the same pages, number and amount that the send will use.

## Which scope does a quote need?

`fax:quote`, for the create and the read. The default API key carries it. A key that may quote and may not send lets an agent prepare a fax and leave the sending to someone else.

## Each operation in detail

### POST `/v1/fax-quotes`

Price an exact document to one destination

Credential: an API key or a signed-in session. Scope: `fax:quote`.

#### Parameters

POST /v1/fax-quotes parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `Idempotency-Key` | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |

#### Request body application/json, required

POST /v1/fax-quotes request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `cover` | object or null | no | Cover sheet fields: to_name, from_name, subject, message. Counts as a page. |
| `delete_after_send` | boolean | no | Delete the document and the transmitted copy the moment the fax ends in delivered, partial or failed. The job, its receipt and the carrier evidence stay; they hold no document content. A fax that ends unknown keeps the document until a reconcile settles it. Default: keep the document for the retention period. |
| `document_id` | string | yes |  |
| `from` | string or null | no | A number you own; omit for the shared pool. |
| `quality` | string (standard, fine, superfine, ultra) | no | Fax resolution. standard is the fax standard's 204 by 98 dpi, fine (the default) 204 by 196, superfine 204 by 392. ultra asks the carrier for its darkest text processing at the same superfine resolution and takes longer to process: measured 2026-11-09, a page sent at ultra and one at superfine both arrived as 1728 by 4112 pixels, 204 by 391 dpi. The price does not change. The job echoes the level. |
| `sender_name` | string or null | no | The name that identifies the sender. The carrier gets it as the caller name for its header line. A fax without a cover sheet prints it in one line at the top of page one. The line also gives the sending number and the time in UTC. Letters, digits, spaces and - _ ~ ! . + only, at most 128 characters. Omit to use the organization's name. |
| `to` | string | yes | Destination in E.164, for example +12025550123. |

#### Responses

POST /v1/fax-quotes responses

| Status | Meaning |
| --- | --- |
| `201` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `403` | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
| `404` | not_found: no such resource for this credential. A resource of another organization answers the same. |
| `409` | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
| `422` | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Response fields

POST /v1/fax-quotes response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `amount_micro` | integer | yes |  |
| `authorization_required` | boolean | yes |  |
| `billable_pages` | integer | yes |  |
| `consumed_by_job_id` | string or null | yes |  |
| `cover` | object or null | yes |  |
| `cover_pages` | integer | yes |  |
| `created_at` | string | yes |  |
| `currency` | string | yes |  |
| `delete_after_send` | boolean | no |  |
| `document_id` | string | yes |  |
| `document_pages` | integer | yes |  |
| `document_sha256` | string | yes |  |
| `environment` | string (live, test) | yes |  |
| `expired` | boolean | yes |  |
| `expires_at` | string | yes |  |
| `from` | string or null | no |  |
| `id` | string | yes |  |
| `per_page_micro` | integer | no |  |
| `price_version` | string | yes |  |
| `quality` | string | no |  |
| `route` | string | yes |  |
| `route_label` | string | no |  |
| `sender_name` | string or null | no |  |
| `to` | string | yes |  |
| `warnings` | array of object | yes |  |

#### Example

```
`curl https://api.faxforagents.com/v1/fax-quotes \ -X POST \ -H "Authorization: Bearer ffa_test_..." \ -H "Content-Type: application/json" \ -d '{"document_id":"document_example","to":"+15550000001"}'`
```

### GET `/v1/fax-quotes/{quote_id}`

Read a quote

Credential: an API key or a signed-in session. Scope: `fax:quote`.

#### Parameters

GET /v1/fax-quotes/{quote_id} parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `quote_id` | path | string | yes |  |

#### Responses

GET /v1/fax-quotes/{quote_id} responses

| Status | Meaning |
| --- | --- |
| `200` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `403` | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
| `404` | not_found: no such resource for this credential. A resource of another organization answers the same. |
| `422` | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Response fields

GET /v1/fax-quotes/{quote_id} response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `amount_micro` | integer | yes |  |
| `authorization_required` | boolean | yes |  |
| `billable_pages` | integer | yes |  |
| `consumed_by_job_id` | string or null | yes |  |
| `cover` | object or null | yes |  |
| `cover_pages` | integer | yes |  |
| `created_at` | string | yes |  |
| `currency` | string | yes |  |
| `delete_after_send` | boolean | no |  |
| `document_id` | string | yes |  |
| `document_pages` | integer | yes |  |
| `document_sha256` | string | yes |  |
| `environment` | string (live, test) | yes |  |
| `expired` | boolean | yes |  |
| `expires_at` | string | yes |  |
| `from` | string or null | no |  |
| `id` | string | yes |  |
| `per_page_micro` | integer | no |  |
| `price_version` | string | yes |  |
| `quality` | string | no |  |
| `route` | string | yes |  |
| `route_label` | string | no |  |
| `sender_name` | string or null | no |  |
| `to` | string | yes |  |
| `warnings` | array of object | yes |  |

#### Example

```
`curl https://api.faxforagents.com/v1/fax-quotes/QUOTE_ID \ -H "Authorization: Bearer ffa_test_..."`
```
