Fax

Fax lets you send faxes from your account's fax servers, follow their delivery, and read the faxes you receive. Every Fax endpoint lives under https://api.emaktalk.com/api/v1/fax. This page is the overview; each endpoint page has the fields, parameters and errors.

Quickstart

Send your account API key as a bearer token. Fax needs a key with All permissions: a Scoped key sees no fax servers and is refused everything else. See Authentication.

1. Find your fax server. GET /fax/servers lists your fax servers. The fax_uuid of the one to send from is your fax_server_id.

curl https://api.emaktalk.com/api/v1/fax/servers \
  -H "Authorization: Bearer $EMAK_API_KEY"

2. Send a PDF. POST /fax/send takes each PDF Base64-encoded in documents. to_number can be written the way people type it; it's normalized to E.164 (see Destination numbers).

PDF=$(base64 < invoice.pdf | tr -d '\n')

curl https://api.emaktalk.com/api/v1/fax/send \
  -H "Authorization: Bearer $EMAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "fax_server_id": "$FAX_SERVER_ID",
  "to_number": "(514) 555-0199",
  "to_name": "Dr. Tremblay",
  "subject": "Invoice 4471",
  "documents": [{ "content_base64": "$PDF" }]
}
EOF

The answer is { "message": "Fax Queued for Sending.", "row": { … }, "scheduled_send_at": null }. Keep row.fax_log_uuid: it's the fax's id. scheduled_send_at is null unless the fax is held (see Caller-ID verification and held faxes).

Always send Content-Type: application/json: any other type, including the form type curl -d sends without -H, is refused with 415 Send the request body as application/json.

Or send a document by URL. Instead of content_base64, give a url we fetch once, when you send. It must be a public https link to the PDF itself; a signed link that expires is fine while it's valid. You can mix both kinds, and a coversheet, in one fax. Prefer links from your own storage or a host you control: some sites refuse requests from cloud networks (see Documents and retention).

curl https://api.emaktalk.com/api/v1/fax/send \
  -H "Authorization: Bearer $EMAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "fax_server_id": "'"$FAX_SERVER_ID"'",
    "to_number": "(514) 555-0199",
    "to_name": "Dr. Tremblay",
    "documents": [{ "url": "https://files.acme.example/invoices/4471.pdf?sig=8f2c1e" }]
  }'

3. Add a coversheet. coversheet puts a page in front of your documents with your fax server's logo, name and number, the recipient, the date, a subject and a message. Send it with documents, or alone.

curl https://api.emaktalk.com/api/v1/fax/send \
  -H "Authorization: Bearer $EMAK_API_KEY" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "fax_server_id": "$FAX_SERVER_ID",
  "to_number": "5145550199",
  "to_name": "Dr. Tremblay",
  "language": "fr-ca",
  "coversheet": { "subject": "Facture 4471", "message": "Merci de nous appeler pour toute question." },
  "documents": [{ "content_base64": "$PDF" }]
}
EOF

4. Check delivery. There is no delivery webhook: read the fax's log with GET /fax/logs/{logId}. The answer is an array; read it at [0]. The fax is done when fax_status is delivered or cancelled, or failed with fax_result_code 99. Once a minute is plenty.

curl https://api.emaktalk.com/api/v1/fax/logs/$FAX_LOG_ID \
  -H "Authorization: Bearer $EMAK_API_KEY"

To follow many faxes at once, list the ones still in progress with GET /fax/logs:

curl -G https://api.emaktalk.com/api/v1/fax/logs \
  -H "Authorization: Bearer $EMAK_API_KEY" \
  --data-urlencode "fx_mode=tx" \
  --data-urlencode "fax_status=queued,media.processed,sending,failed" \
  --data-urlencode "fax_date_gte=2026-10-19T00:00:00Z"

5. Retry or cancel. A fax that failed for good, for a reason a retry can fix (user_busy, receiver_no_answer and others), can be sent again with POST /fax/retry/{faxLogId}: it goes out as a new fax. A fax of your account still queued, media.processed or sending can be stopped with POST /fax/cancel/{faxId}; any other id answers 404 Fax not found.

curl -X POST https://api.emaktalk.com/api/v1/fax/retry/$FAX_LOG_ID \
  -H "Authorization: Bearer $EMAK_API_KEY"

curl -X POST https://api.emaktalk.com/api/v1/fax/cancel/$FAX_LOG_ID \
  -H "Authorization: Bearer $EMAK_API_KEY"

Concepts

ConceptWhat it isWhere
Fax serverA virtual fax line on one of your numbers: faxes you send go out from its number and name, and faxes to that number arrive on it. It has a notification email, a retention setting and the users assigned to it in the web app. Each uses one fax license of your subscription.GET /fax/servers
Fax logOne sent (fx_mode tx) or received (rx) fax: its parties, subject, pages, status and result. The list gives a summary; one fax log in full adds its automatic retries, email deliveries and access history.GET /fax/logs, GET /fax/logs/{logId}
CoversheetA page put in front of a sent fax. Its subject becomes the fax's subject. English, or French with language fr-ca or fr-fr; the date is printed in timezone, else your account's time zone.coversheet on POST /fax/send
SubjectTyped by the sender: subject, or the coversheet's when there is a coversheet. Every fax sent without one gets an AI-generated subject of up to six words, written from its content, when one can be written. A received fax's subject is always written from its document.fax_subject
Access historyWho viewed, downloaded or deleted a fax's document, and who cancelled it. Reading a fax log through the API isn't recorded; record a view or download with POST /fax/audit.access_history

Destination numbers

The fax network accepts destinations in E.164 only (+15145550199), so to_number is normalized before anything is sent. A number without a country code is read as North American: 8553301239, (855) 330-1239, 1-855-330-1239 and +18553301239 are all the same number. Other countries need + and the country code (+44 20 7183 8750). A number that isn't a valid phone number, a partial number, or one with an extension (514-555-0199 x22) is refused with 400 Invalid destination fax number!, before your documents are stored or anything is sent. The fax log keeps the normalized number in fax_to_number.

Statuses

A sent fax moves through queued → media.processed (the document is ready) → sending → delivered. A fax that doesn't get through is retried automatically, as below. Read fax_status with fax_result_code and fax_result_text:

fax_statusfax_result_codefax_result_textMeaningFinal
queued, media.processed, sendingnullnullOn its way. Can be cancelled.No
delivered0OKDelivered.Yes
failednullRetry SendingThis attempt failed; an automatic retry goes out in about three minutes. fax_retry_attempts counts them.No
failed99the reason, such as user_busyFailed for good. Retry if the reason allows it.Yes
cancelled98Cancelled by userCancelled.Yes

A received fax is received (fax_result_code 0) or failed, with a readable reason in fax_result_text, such as The call dropped prematurely. A failed receive is usually the sender's line dropping; hide_failed_receives=true leaves them out of the list. Ignore a status you don't know.

Automatic retries. A sent fax that fails is retried up to four times, three minutes apart (five attempts in all), unless the reason means a retry can't help: account_disabled, destination_invalid, destination_not_in_countries_whitelist, destination_not_in_service_plan, destination_unreachable, no_outbound_profile, receiver_invalid_number_format or receiver_unallocated_number. When a sent fax is delivered or fails for good, the fax server's notification address is emailed.

Manual retries. POST /fax/retry/{faxLogId} takes a fax that failed for good with one of these reasons: connection_channel_limit_exceeded, fax_signaling_error, invalid_ecm_response_from_receiver, outbound_profile_channel_limit_exceeded, outbound_profile_daily_spend_limit_exceeded, receiver_call_dropped, receiver_communication_error, receiver_decline, receiver_incompatible_destination, receiver_no_answer, receiver_no_response, receiver_recovery_on_timer_expire, user_busy, user_channel_limit_exceeded or service_unavailable. It sends a new fax and doesn't return its id: find it as the newest sent fax in the list. Calling it twice sends twice.

Caller-ID verification and held faxes

A fax server's number is verified once before faxes go out from it right away. Until it is, sending a fax starts the number's verification, through the web app or the API alike, and holds the fax: it goes out about three minutes later. The answer says so: scheduled_send_at is when the held fax goes out, and null for a fax that goes out now. Either way you get a 200 and a queued fax log. If the number still isn't verified when the fax goes out, the fax fails, and is retried like any other failure.

Documents and retention

  • Sending: one or more PDFs per fax in documents, faxed in the order given, after the coversheet. Each is either inline, content_base64 in standard Base64 (with its = padding; line breaks are fine; no data: URI, no URL-safe alphabet), or a url. A document is a PDF when %PDF- appears within its first 1,024 bytes; nothing is converted, so send other formats as PDF. Every document is checked before any is stored, and the documents of a send that is refused or fails are removed.
  • By URL: the link is fetched once, when you send, with a plain GET (user agent EMAK-Fax/1.0 (+https://docs.emak.tech)) and no cookies or credentials, so it must work on its own. Rules: https on the default port; no user name or password in the URL; a host name, not an IP address; not a private host or our own platform; at most 8,192 characters; at most 3 redirects, each checked by the same rules; the final answer a 200 carrying the PDF, not an HTML page, of at most 50 MB. All the URLs of one send share a 60-second deadline. The URL is never stored or logged: the fax keeps our copy of the document.
  • Cloud-blocking sites: some sites refuse requests from cloud networks and answer 403 (documents[i] could not be fetched: HTTP 403) even when the link works in a browser: use links from your own storage (signed S3, Google Cloud Storage or Azure links) or a host you control, or send the document as Base64.
  • Storage: a sent fax's document is kept with its fax log. It's removed after its fax server's retention (fax_lifecycle, in days; null keeps it), rounded up to 1, 7, 14, 30, 60, 90, 120, 180 or 365 days. fax_lifecycle_date says when.
  • Deleting: DELETE /fax/logs/{logId} deletes a fax's document at once and for good. The fax log stays, with is_deleted true. A subject written from the document is cleared with it.
  • Deleting a fax server: six days later, its fax logs are deleted and its documents removed.

Limits

LimitValueOver it
Documents per fax1 or more, or none with a coversheet400 documents must be a non-empty array (omit it for a coversheet-only fax)
Inline documents, combined, decoded10 MB (10,485,760 bytes)413 Inline documents are limited to 10 MB combined
Each document by URL50 MB413 documents[i] is over 50 MB
The fax as sent, coversheet included50 MB400 The fax is over 50 MB
The fax as sent, coversheet included350 pages400 The fax is over 350 pages
subject, to_name, coversheet subject255 characters400 subject must be a string of at most 255 characters (naming the field)
Coversheet message5,000 characters400 coversheet.message must be a string of at most 5000 characters
URL length8,192 characters400 documents[i].url is longer than 8192 characters
Redirects per URL3400 documents[i] could not be fetched: too many redirects
Time to fetch a send's URLs60 seconds in all400 documents[i] could not be fetched: timed out
Request body, as sent20 MB (20,971,520 bytes), every request413 The request body is limited to 20 MB
Fax logs per page1 to 500 (default 10)Cut to 500
Fax serversOne per fax license403 License Limit Reached

Base64 is a third larger than the PDF it carries, so 10 MB of PDF is about 14 MB of Base64. For larger documents, send a url. JSON encoders that escape characters add more: .NET's default encoder writes each + as \u002B and PHP's json_encode writes / as \/. Send the Base64 unescaped when you can: in .NET, JavaScriptEncoder.UnsafeRelaxedJsonEscaping; in PHP, JSON_UNESCAPED_SLASHES.

Errors

Errors are JSON with an error category and a readable message. Each endpoint's page lists its messages exactly.

{ "error": "Invalid Data", "message": "Invalid destination fax number!" }
StatusWhen
400The request is invalid: a field, a document, a destination number, an id that isn't a UUID. A field the API doesn't take is refused, not ignored (Unknown field "files"). A document link that's refused or can't be fetched is a 400 too (documents[i].url is not allowed, documents[i] could not be fetched: HTTP 404), and so is a fax over 50 MB or 350 pages. Fix it before retrying.
401No usable API key. The body is { "authorized": false, "method": "…", "message": "…", "status": 401 }.
403A Scoped key, or a fax server or fax that isn't on your account. Creating a fax server with no license left is 403 License Limit Reached.
404No fax or fax server with this id on your account. Fetching one by id answers an empty array instead.
409A fax server's logo changed meanwhile, or a call flow still sends calls to the fax server you're deleting.
413The request body, the inline documents or a document by URL is too large; see Limits.
415The body wasn't sent as application/json.
422The fax isn't in a state that allows a retry or a cancel.
500, 502Something failed on our side. Read the fax log before retrying a send: a retried send can fax twice.
503With Retry-After: your key couldn't be checked, or your documents couldn't be stored, just now; retry after that many seconds.