One-time send by API

Updated

A one-time send is one fax paid by card, with no wallet and no top-up. This page is its API contract. A person always pays. The API answers a link, and the person opens it and pays there by card. Code cannot pay an order, and neither can an AI agent.

This is not the wallet send, which the send a fax page covers. A person who wants a form and no code uses the send a fax page of the site.

The flow

  1. Create the order. Without a key, from a file or text. Or with a live key, from a quote. The answer carries the price, a status token and a status link.
  2. A person pays. Give them the status link. For an order that software created, they first accept the acceptable use policy and the terms on that page. The card is authorized there and nothing is charged yet.
  3. The sender confirms. A mail goes to the address of the order. One click on its link proves the address and releases the fax. An address the organization has already proven skips this step.
  4. The fax goes out. The card is charged only for the pages the carrier confirms.
  5. Read the order until next says done.

Is it open, and what does it cost?

Shell
export FFA=https://api.faxforagents.com/v1
curl -s $FFA/one-time-sends/config

The config route takes no credential. It answers enabled, the routes with flat_micro, included_pages and extra_page_micro, then max_document_pages, max_upload_bytes, the accepted formats and the URLs of the policy the sender accepts. Money is in integer micro-units of a US dollar, so 1,000,000 is one dollar.

One fax costs $2.49 for up to 5 document pages to the United States and Canada, then $0.49 for each page after that. One order takes 20 pages at most, which is $9.84. The cover sheet is included and is not counted.

Prices as of 2026-11-12, rate table launch-v3. Sources and methods: oneTimeFlat, oneTimeExtraPage, oneTimeMaxPages, oneTimeMaxPrice.

Create an order without a credential

POST /v1/one-time-sends takes no credential. Send multipart/form-data with a file, or application/json with text.

Shell
curl -s $FFA/one-time-sends \
  -H "Idempotency-Key: lease-2026-11-12" \
  -F "email=dana@example.com" \
  -F "sender_name=Dana Whitfield" \
  -F "to=+14155550142" \
  -F "accept_aup=true" \
  -F "to_name=Records office" \
  -F "subject=Signed lease" \
  -F "file=@lease.pdf;type=application/pdf"

The same order from text, as JSON:

Shell
curl -s $FFA/one-time-sends -H "Content-Type: application/json" \
  -d '{"email": "dana@example.com", "sender_name": "Dana Whitfield", "to": "+14155550142", "accept_aup": true, "subject": "Notice", "text": "Please find my notice below.", "text_format": "text"}'
Fields of POST /v1/one-time-sends
FieldRequiredWhat it is
emailyes, without a keyWhere the confirmation link and the receipt go. It is printed on the cover sheet. With a key it may be left out, and the order then uses the address of the organization.
sender_nameyesThe name printed on the cover sheet, 2 to 120 characters.
toyesThe destination fax number in E.164 form.
accept_aupyes, without a credentialtrue: the sender accepts the acceptable use policy and the terms that the config route names. With an API credential the value is not recorded. The person who pays accepts on the order page instead.
fileone of file or textMultipart only. One PDF, PNG, JPEG or TIFF file.
textone of file or textThe document as plain text or Markdown.
text_formatnotext or markdown. The default is text.
to_name, subject, messagenoLines for the cover sheet.
delete_after_sendnotrue deletes the document and the copy that was sent when the fax ends delivered, partial or failed.
source_refnoA short tag that says where the sender came from. Never a URL.

The answer is 201 with the order. Read id, status, next, amount_micro, document_pages, status_token and status_url. Nothing is charged and nothing is sent by this call. An account is opened for the email address so the receipt has a place to stay. If nobody pays, the order expires after 48 hours.

Send the header Idempotency-Key. A repeat with the same header value and the same content within 24 hours answers the same order. A file sent again counts as the same content.

Create an order from a quote

Software that already has a document and a quote can turn the quote into an order. This is the path for a wallet that does not cover a send. It needs a live key with the scope fax:send.

Shell
curl -s $FFA/one-time-sends/from-quote -H "Authorization: Bearer $FFA_KEY" \
  -H "Content-Type: application/json" -H "Idempotency-Key: card-for-quote-1" \
  -d '{"quote_id": "quote_...", "sender_name": "Acme Records", "approval_id": "apr_..."}'

The body takes quote_id and sender_name, and optionally approval_id, email, delete_after_send, source_ref and accept_aup. The quote supplies the document, the destination and the cover sheet. The price is the one-time price above, not the per page amount on the quote. The quote then belongs to the order and the wallet route no longer sends it.

Who authorizes it

A card payment is money, not consent. An order made with an API credential is a send by software, so it needs exactly what POST /v1/faxes needs for the same quote. That is approval_id, an approved request from the approvals flow, or a delegated policy that allows the send. Whatever the wallet route would answer for that caller and that quote, this route answers too. Without an approval or a policy the answer is 403 approval_required and no order is made.

The policy is asked about what the order will send and cost: the one-time price and the pages with the cover sheet. The order records the approval or the policy version, and the fax job carries it. If the approval is revoked or the policy changes before the fax is released, the order ends refused and the card is not charged. The same rule holds for POST /v1/one-time-sends with a live credential, where only a policy can allow the order. An order from a signed-in session needs neither.

The accept_aup field is for a session. Software cannot accept the policy for a person, so an order it creates has aup_accepted false. The person who pays ticks the box on the order page before the payment opens.

Without email the order uses the address of the organization. An address that a member has signed in with is already proven, so the fax goes out as soon as the person has paid. Any other address gets the confirmation mail first. A test key is refused with invalid_request. An order is always live, and the sandbox is free.

When a wallet send is refused with insufficient_balance, details.one_time_offer is present if this route would take the same quote. It carries amount_micro for that document.

The status token

The create answers status_token. Without a key, send it as the header X-FFA-Order-Token. The query parameter t works too, but the header stays out of request logs.

Shell
curl -s $FFA/one-time-sends/$ORDER -H "X-FFA-Order-Token: $TOKEN"

The token works for 7 days. It reads its one order and the receipt of that order's fax, opens the checkout and asks for the confirmation mail again. It cannot confirm an order, list orders or read another one. A wrong token answers 404 not_found, exactly like an order that does not exist.

A key or a signed-in session of the order's organization reads the same routes with no token. Its read also carries status_url again while the order is not done, so software that lost the first answer can still hand the link over. The scopes are fax:read to read and fax:send for the checkout and the mail.

The pay link

status_url is the order's page in the dashboard, with the token in it. Give it to the person who pays. The page shows the price, takes them to the card payment and then follows the fax. This is the link an agent hands over.

To send the person straight to the card payment, open the checkout yourself:

Shell
curl -s -X POST $FFA/one-time-sends/$ORDER/checkout -H "X-FFA-Order-Token: $TOKEN" \
  -H "Content-Type: application/json" -d '{"accept_aup": true}'

An order whose aup_accepted is false needs the body {"accept_aup": true} on this call, once. It is taken from the status token or a session, and refused from an API credential. That is the person's acceptance, and the order page sends it when they tick the box.

The answer is 201 with checkout_url, expires_at, amount_micro and currency. checkout_url is a payment page hosted by Stripe. A second call answers the same page while it can still be paid, and a new one after it expired. The payment authorizes the card. It does not charge it.

The confirm step

After the payment the order is awaiting_confirmation unless its address was already proven. A mail with a link goes to the address. The person clicks it, and the page behind the link makes these two calls with the token from the link:

Shell
# what the link is for, without using it
curl -s $FFA/one-time-sends/by-token/$CONFIRM_TOKEN

# use it: the address is proven and the fax is released
curl -s -X POST $FFA/one-time-sends/$ORDER/confirm -H "Content-Type: application/json" \
  -d '{"token": "'$CONFIRM_TOKEN'"}'

The link works once and for 48 hours after the payment. The status token cannot stand in for it, because the click is the proof that the sender reads that mailbox. An order nobody confirms in time expires, the authorization is given back and nothing is charged.

Shell
# mail the confirmation link again
curl -s -X POST $FFA/one-time-sends/$ORDER/resend-confirmation -H "X-FFA-Order-Token: $TOKEN"

# the receipt of the fax as a one-page PDF, once the fax has ended
curl -s -o receipt.pdf $FFA/one-time-sends/$ORDER/receipt.pdf -H "X-FFA-Order-Token: $TOKEN"

The mail can be asked for again a few times per order, with a pause between two mails. resend_allowed_at on the order says when the next one may go, and a call before that answers 429 rate_limited.

States

next is what the caller does now: checkout, confirm, wait or done. status is the finer state.

The states of a one-time order
statusnextMeaning
draftcheckoutCreated and priced. Nobody has paid.
checkout_opencheckoutA payment page is open. checkout_url carries it.
awaiting_confirmationconfirmThe card is authorized. The sender has to click the link in the mail.
authorizedwaitThe card is authorized and the address is proven. The fax is being released.
releasedwaitThe fax went to the carrier. Its own state is in fax.state.
capturingwaitThe carrier confirmed pages. The charge is in progress and not confirmed yet.
cancelingwaitThe authorization is being given back and that is not confirmed yet.
captureddoneThe card was charged. captured_micro is the amount.
released_holddoneNothing was charged. The authorization was given back, and failure_code says why.
expireddoneNobody paid, or nobody confirmed in time. Nothing was charged.
refuseddoneThe order was refused after payment and the authorization was given back.
settle_faileddoneThe card settlement did not complete. An operator looks at it. Do not create a second order.

Once the order is released, fax is the fax job with its own state and, when the carrier has reported, its evidence. Do not say charged or not charged from the fax state alone. capturing means pages arrived and the charge is not confirmed yet.

What is charged, and when

  • amount_micro is the price of the order and the amount the card is authorized for.
  • captured_micro is what the card was charged. It is set only after the payment provider confirmed the charge.
  • Delivered: the card is charged the price of the order.
  • Partial: the card is charged for the document pages the carrier confirmed, by the same price rule. With no confirmed document page nothing is charged.
  • Failed: nothing is charged and the authorization is given back.
  • No report from the carrier: the authorization is given back 48 hours after the fax went out, and nothing is charged.

The refunds page has the full rules. An organization with a webhook gets one_time_send.authorized, one_time_send.captured and one_time_send.released next to the fax events. The webhooks page covers signatures and retries.

Time limits read from the server's code on 2026-11-12. Sources and methods: oneTimeUnpaidHours, oneTimeConfirmHours, oneTimeUnknownHours, oneTimeStatusLinkDays.

Limits

  • Fax numbers in the United States and Canada only. Other countries go through the prepaid wallet.
  • One document of up to 20 pages and 10 MB: PDF, PNG, JPEG, TIFF, plain text or Markdown. No HTML and no office formats.
  • Live only. No order is created with a test key.
  • Daily limits per email address, per destination number and per network address. Over one, the create answers 429 rate_limited and details.cap names it.
  • Sending only. An order has no fax number and receives nothing.

Upload limit as of 2026-11-10. Source and method: oneTimeMaxUploadMb.

Error codes

Errors use the envelope of the errors page: error.code, error.message and error.details.

Error codes of the one-time routes
CodeHTTPWhat it means
invalid_request422A field is missing or wrong, accept_aup is not true, or the credential is a test one
invalid_destination, unsupported_destination422The number is not E.164, or it is outside the United States and Canada
too_many_pages, document_too_large422The document is over the page limit or the upload limit. Use the prepaid wallet for a longer one
unsupported_format, encrypted_pdf422The file is not one of the four formats, or the PDF has a password
blocked_destination, account_suspended403The destination or the account is blocked. Not retryable
invalid_token401The from-quote route was called without a live key
approval_required403An order made with an API credential has no approval and no policy that allows it. details.policy carries the verdict. Paying by card does not replace either
approval_not_granted, approval_expired, approval_mismatch, approval_consumed409The approval_id does not cover this quote as it is now. Quote and ask again
scope_missing403The scope fax:send is missing, or fax:read for a read
not_found404No such order for this caller. A wrong status token and an order of another organization answer the same
quote_consumed, quote_expired, document_hash_mismatch409The quote was used, expired, or its document changed. Quote again
already_paid, order_closed409The checkout was asked for an order that is paid or has ended
link_invalid404The confirmation token is not one of this order
link_used, link_expired, link_other_session409The confirmation link was used, ran out, or was opened in a browser signed in as someone else
conflict409Nothing is waiting for a confirmation mail, or the receipt was asked before the fax ended
idempotency_key_conflict409The same Idempotency-Key was sent with a different body
rate_limited429A daily limit or the request limit was reached. details.cap names the limit and Retry-After says when to try again
billing_not_configured, billing_unavailable503The payment provider cannot be reached. Try the checkout again later
one_time_unavailable503One-time sends are closed on this server. The prepaid wallet still works

From an MCP client

The hosted MCP server has two tools for this path. request_card_payment takes a quote id, the name for the cover sheet and, when the send needs one, the approval_id. It answers the order with status_url. The agent gives that link to a person, who accepts the policy and pays there. get_card_payment_status reads the order back with the fax and its evidence, and returns the link again while the person still has to act. Neither tool can accept, pay or confirm.

The authorization is the same as for send_approved_fax. An agent whose policy denies a number gets approval_required from both tools.

When send_approved_fax is refused because the wallet is short, its message names request_card_payment if the same quote can be paid by card.