Faxes API reference
Updated
8 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.
- POST /v1/faxes sends a quoted fax, and its only required field is quote_id.
- Cancelling a fax is best effort once sending has started.
- The receipt of a fax is served as JSON and as the same facts in a one-page PDF.
Operations
GET /v1/faxesList fax jobs, newest firstPOST /v1/faxesSend a quoted fax (Idempotency-Key recommended)GET /v1/faxes/{fax_id}Read a fax job (with evidence once delivered)GET /v1/faxes/{fax_id}/attemptsAttempt historyPOST /v1/faxes/{fax_id}/cancelCancel if still possible (best effort once sending)GET /v1/faxes/{fax_id}/eventsOrdered events of one faxGET /v1/faxes/{fax_id}/receiptDelivery evidence as a receipt (JSON)GET /v1/faxes/{fax_id}/receipt.pdfThe same receipt as a one-page PDF
How is a fax sent?
POST /v1/faxes with a quote_id. The quote already holds the document, the destination, the sender and the price, so the send repeats none of them. Two optional fields ride along. approval_id is an approved request bound to this quote, and this one send consumes it. client_reference is your own label for the job.
The answer is the job, in state queued. Sending is asynchronous. The call returns as soon as the job is written, and the outcome arrives later on the job and as an event.
Why send an Idempotency-Key?
The summary of the operation recommends the Idempotency-Key header. A send that times out leaves you not knowing whether a job exists. Repeat the call with the same key and the answer is the same job, not a second fax. The list also filters by idempotency_key, so a client can look a job up by the key it used.
Which states can a job be in?
Six: queued, active, delivered, partial, failed and unknown. GET /v1/faxes/{fax_id} returns the state with pages_sent, attempt_count, captured_micro and, when the fax failed, a failure_code. A delivered job carries evidence, the carrier's report of the delivery.
delivered is said only with that evidence. unknown means no outcome was reported in time. A job in unknown or partial is never sent again by the service on its own. The errors page explains each state and what it means for the money held.
How do I follow one fax in detail?
Three reads. GET /v1/faxes/{fax_id}/attempts is the attempt history, one row per try. GET /v1/faxes/{fax_id}/events is the ordered list of events of this fax. GET /v1/faxes lists jobs newest first and filters by state.
For every fax at once, use webhooks, or walk the log in the events group.
Can a fax be cancelled?
POST /v1/faxes/{fax_id}/cancel cancels if that is still possible. A queued job is cancelled at once. Once sending has started the cancel is best effort, as the summary says: the carrier may already have the pages. A fax that has ended answers 409 not_cancelable. The call needs fax:cancel.
What is the receipt?
GET /v1/faxes/{fax_id}/receipt returns the delivery evidence as JSON once the fax has ended. It has the state, the numbers, pages_sent, the amount captured, the hash of the document and of the transmitted copy, the attempts and a note. GET /v1/faxes/{fax_id}/receipt.pdf is the same receipt as a one-page PDF, for a file or a person.
The receipt is the carrier's report, not legal proof of acceptance, and the PDF says so.
What can refuse a send?
A send answers 402 when the wallet cannot cover the quote. It answers 403 when a live API key has neither an approval nor a policy that allows the send. It answers 409 with quote_expired or quote_consumed when the quote can no longer be sent, and with an approval code when the approval does not match. A refused send creates no job.
Which scopes does the group use?
fax:send for the send, fax:cancel for the cancel and fax:read for every read, the receipt included. The default API key carries all three. A read-only API key keeps fax:read and drops the other two.
Each operation in detail
GET /v1/faxes
List fax jobs, newest first
Credential: an API key or a signed-in session. Scope: fax:read.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
state | query | string or null | no | |
idempotency_key | query | string or null | no | Find the send job using its Idempotency-Key. This lookup requires the stored replay record. An empty result does not prove no fax was sent. |
cursor | query | string or null | no | |
limit | query | integer | no | Default 50. |
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. |
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
| Field | Type | Required | Description |
|---|---|---|---|
items | array of object FaxJob | yes | |
next_cursor | string or null | no |
Example
curl https://api.faxforagents.com/v1/faxes \
-H "Authorization: Bearer ffa_test_..."
POST /v1/faxes
Send a quoted fax (Idempotency-Key recommended)
Credential: an API key or a signed-in session. Scope: fax:send.
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
M9: an approved request authorizes the send; without one a quote that needs authorization is evaluated against the caller's delegated policies.
| Field | Type | Required | Description |
|---|---|---|---|
approval_id | string or null | no | An approved approval request bound to this quote. Consumed by this one send. |
client_reference | string or null | no | |
quote_id | string | yes |
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. |
402 | The prepaid balance does not cover the call: insufficient_balance. |
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
| Field | Type | Required | Description |
|---|---|---|---|
amount_micro | integer | yes | |
attempt_count | integer | yes | |
billable_pages | integer | yes | |
cancel_requested_at | string or null | yes | |
captured_micro | integer | yes | |
client_reference | string or null | yes | |
completed_at | string or null | yes | |
cover_pages | integer | yes | |
created_at | string | yes | |
currency | string | yes | |
delete_after_send | boolean | no | |
direction | string | yes | |
document_id | string | yes | |
document_sha256 | string | yes | |
environment | string (live, test) | yes | |
evidence | object or null | no | The carrier's evidence once delivered or partial; null before. |
failure_code | string or null | yes | |
from | string or null | no | |
id | string | yes | |
one_time | object OneTimeJob or null | no | |
one_time_order_id | string or null | no | The one-time order this fax was paid by; null for a wallet fax. |
pages_sent | integer | yes | |
provider | string | yes | |
provider_ref | string or null | yes | |
quality | string | no | |
quote_id | string or null | yes | |
route | string | yes | |
sender_name | string or null | no | |
state | string (queued, active, partial, failed, unknown, delivered) | yes | |
to | string | yes | |
transmitted_sha256 | string or null | yes | |
updated_at | string | yes |
Example
curl https://api.faxforagents.com/v1/faxes \
-X POST \
-H "Authorization: Bearer ffa_test_..." \
-H "Content-Type: application/json" \
-d '{"quote_id":"quote_example"}'
GET /v1/faxes/{fax_id}
Read a fax job (with evidence once delivered)
Credential: an API key or a signed-in session. Scope: fax:read.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
fax_id | path | string | yes |
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
| Field | Type | Required | Description |
|---|---|---|---|
amount_micro | integer | yes | |
attempt_count | integer | yes | |
billable_pages | integer | yes | |
cancel_requested_at | string or null | yes | |
captured_micro | integer | yes | |
client_reference | string or null | yes | |
completed_at | string or null | yes | |
cover_pages | integer | yes | |
created_at | string | yes | |
currency | string | yes | |
delete_after_send | boolean | no | |
direction | string | yes | |
document_id | string | yes | |
document_sha256 | string | yes | |
environment | string (live, test) | yes | |
evidence | object or null | no | The carrier's evidence once delivered or partial; null before. |
failure_code | string or null | yes | |
from | string or null | no | |
id | string | yes | |
one_time | object OneTimeJob or null | no | |
one_time_order_id | string or null | no | The one-time order this fax was paid by; null for a wallet fax. |
pages_sent | integer | yes | |
provider | string | yes | |
provider_ref | string or null | yes | |
quality | string | no | |
quote_id | string or null | yes | |
route | string | yes | |
sender_name | string or null | no | |
state | string (queued, active, partial, failed, unknown, delivered) | yes | |
to | string | yes | |
transmitted_sha256 | string or null | yes | |
updated_at | string | yes |
Example
curl https://api.faxforagents.com/v1/faxes/FAX_ID \
-H "Authorization: Bearer ffa_test_..."
GET /v1/faxes/{fax_id}/attempts
Attempt history
Credential: an API key or a signed-in session. Scope: fax:read.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
fax_id | path | string | yes |
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
| Field | Type | Required | Description |
|---|---|---|---|
items | array of object Attempt | yes |
Example
curl https://api.faxforagents.com/v1/faxes/FAX_ID/attempts \
-H "Authorization: Bearer ffa_test_..."
POST /v1/faxes/{fax_id}/cancel
Cancel if still possible (best effort once sending)
Credential: an API key or a signed-in session. Scope: fax:cancel.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
fax_id | path | string | yes | |
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. |
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. |
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
| Field | Type | Required | Description |
|---|---|---|---|
amount_micro | integer | yes | |
attempt_count | integer | yes | |
billable_pages | integer | yes | |
cancel_requested_at | string or null | yes | |
captured_micro | integer | yes | |
client_reference | string or null | yes | |
completed_at | string or null | yes | |
cover_pages | integer | yes | |
created_at | string | yes | |
currency | string | yes | |
delete_after_send | boolean | no | |
direction | string | yes | |
document_id | string | yes | |
document_sha256 | string | yes | |
environment | string (live, test) | yes | |
evidence | object or null | no | The carrier's evidence once delivered or partial; null before. |
failure_code | string or null | yes | |
from | string or null | no | |
id | string | yes | |
one_time | object OneTimeJob or null | no | |
one_time_order_id | string or null | no | The one-time order this fax was paid by; null for a wallet fax. |
pages_sent | integer | yes | |
provider | string | yes | |
provider_ref | string or null | yes | |
quality | string | no | |
quote_id | string or null | yes | |
route | string | yes | |
sender_name | string or null | no | |
state | string (queued, active, partial, failed, unknown, delivered) | yes | |
to | string | yes | |
transmitted_sha256 | string or null | yes | |
updated_at | string | yes |
Example
curl https://api.faxforagents.com/v1/faxes/FAX_ID/cancel \
-X POST \
-H "Authorization: Bearer ffa_test_..."
GET /v1/faxes/{fax_id}/events
Ordered events of one fax
Credential: an API key or a signed-in session. Scope: fax:read.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
fax_id | path | string | yes |
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
| Field | Type | Required | Description |
|---|---|---|---|
items | array of object Event | yes | |
next_cursor | string or null | no |
Example
curl https://api.faxforagents.com/v1/faxes/FAX_ID/events \
-H "Authorization: Bearer ffa_test_..."
GET /v1/faxes/{fax_id}/receipt
Delivery evidence as a receipt (JSON)
Credential: an API key or a signed-in session. Scope: fax:read.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
fax_id | path | string | yes |
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. |
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
| Field | Type | Required | Description |
|---|---|---|---|
amount_micro | integer | yes | |
attempts | array of object Attempt | yes | |
billable_pages | integer | yes | |
captured_micro | integer | yes | |
completed_at | string or null | yes | |
cover_pages | integer | no | How many of the billable pages are the cover sheet: 0 or 1. |
created_at | string | yes | |
currency | string | yes | |
document_sha256 | string | yes | |
evidence | object or null | yes | |
failure_code | string or null | yes | |
fax_job_id | string | yes | |
from | string or null | no | |
generated_at | string | yes | |
note | string | yes | |
one_time | object OneTimeJob or null | no | Set on the receipt of a fax that a one-time order paid for. It names the order, its status, the card and the amount the card was authorized for. captured_micro in it is the amount charged, written once the payment provider confirmed the capture. For a card order read the money here. Null for a fax paid from the wallet. |
pages_sent | integer | yes | |
provider | string | yes | |
state | string | yes | |
to | string | yes | |
transmitted_sha256 | string or null | yes |
Example
curl https://api.faxforagents.com/v1/faxes/FAX_ID/receipt \
-H "Authorization: Bearer ffa_test_..."
GET /v1/faxes/{fax_id}/receipt.pdf
The same receipt as a one-page PDF
Credential: an API key or a signed-in session. Scope: fax:read.
Parameters
| Name | In | Type | Required | Notes |
|---|---|---|---|---|
fax_id | path | string | yes |
Responses
| Status | Meaning |
|---|---|
200 | The receipt as a PDF |
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. |
Example
curl https://api.faxforagents.com/v1/faxes/FAX_ID/receipt.pdf \
-H "Authorization: Bearer ffa_test_..."