Fax quotes API reference

Updated

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.

  • 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

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 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 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 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 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
NameInTypeRequiredNotes
Idempotency-KeyheaderstringnoReplay 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
FieldTypeRequiredDescription
coverobject or nullnoCover sheet fields: to_name, from_name, subject, message. Counts as a page.
delete_after_sendbooleannoDelete 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_idstringyes
fromstring or nullnoA number you own; omit for the shared pool.
qualitystring (standard, fine, superfine, ultra)noFax 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_namestring or nullnoThe 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.
tostringyesDestination in E.164, for example +12025550123.

Responses

POST /v1/fax-quotes responses
StatusMeaning
201Successful Response
401No 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.
403The 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.
404not_found: no such resource for this credential. A resource of another organization answers the same.
409The 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.
422A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule.
429rate_limited. Retry-After and the RateLimit-* headers say when to try again.

Response fields

POST /v1/fax-quotes response fields
FieldTypeRequiredDescription
amount_microintegeryes
authorization_requiredbooleanyes
billable_pagesintegeryes
consumed_by_job_idstring or nullyes
coverobject or nullyes
cover_pagesintegeryes
created_atstringyes
currencystringyes
delete_after_sendbooleanno
document_idstringyes
document_pagesintegeryes
document_sha256stringyes
environmentstring (live, test)yes
expiredbooleanyes
expires_atstringyes
fromstring or nullno
idstringyes
per_page_microintegerno
price_versionstringyes
qualitystringno
routestringyes
route_labelstringno
sender_namestring or nullno
tostringyes
warningsarray of objectyes

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
NameInTypeRequiredNotes
quote_idpathstringyes

Responses

GET /v1/fax-quotes/{quote_id} responses
StatusMeaning
200Successful Response
401No 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.
403The 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.
404not_found: no such resource for this credential. A resource of another organization answers the same.
422A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule.
429rate_limited. Retry-After and the RateLimit-* headers say when to try again.

Response fields

GET /v1/fax-quotes/{quote_id} response fields
FieldTypeRequiredDescription
amount_microintegeryes
authorization_requiredbooleanyes
billable_pagesintegeryes
consumed_by_job_idstring or nullyes
coverobject or nullyes
cover_pagesintegeryes
created_atstringyes
currencystringyes
delete_after_sendbooleanno
document_idstringyes
document_pagesintegeryes
document_sha256stringyes
environmentstring (live, test)yes
expiredbooleanyes
expires_atstringyes
fromstring or nullno
idstringyes
per_page_microintegerno
price_versionstringyes
qualitystringno
routestringyes
route_labelstringno
sender_namestring or nullno
tostringyes
warningsarray of objectyes

Example

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