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" }]
}
EOFThe 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" }]
}
EOF4. 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
| Concept | What it is | Where |
|---|---|---|
| Fax server | A 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 log | One 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} |
| Coversheet | A 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 |
| Subject | Typed 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 history | Who 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_status | fax_result_code | fax_result_text | Meaning | Final |
|---|---|---|---|---|
queued, media.processed, sending | null | null | On its way. Can be cancelled. | No |
delivered | 0 | OK | Delivered. | Yes |
failed | null | Retry Sending | This attempt failed; an automatic retry goes out in about three minutes. fax_retry_attempts counts them. | No |
failed | 99 | the reason, such as user_busy | Failed for good. Retry if the reason allows it. | Yes |
cancelled | 98 | Cancelled by user | Cancelled. | 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_base64in standard Base64 (with its=padding; line breaks are fine; nodata:URI, no URL-safe alphabet), or aurl. 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 agentEMAK-Fax/1.0 (+https://docs.emak.tech)) and no cookies or credentials, so it must work on its own. Rules:httpson 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;nullkeeps it), rounded up to 1, 7, 14, 30, 60, 90, 120, 180 or 365 days.fax_lifecycle_datesays when. - Deleting:
DELETE /fax/logs/{logId}deletes a fax's document at once and for good. The fax log stays, withis_deletedtrue. 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
| Limit | Value | Over it |
|---|---|---|
| Documents per fax | 1 or more, or none with a coversheet | 400 documents must be a non-empty array (omit it for a coversheet-only fax) |
| Inline documents, combined, decoded | 10 MB (10,485,760 bytes) | 413 Inline documents are limited to 10 MB combined |
| Each document by URL | 50 MB | 413 documents[i] is over 50 MB |
| The fax as sent, coversheet included | 50 MB | 400 The fax is over 50 MB |
| The fax as sent, coversheet included | 350 pages | 400 The fax is over 350 pages |
subject, to_name, coversheet subject | 255 characters | 400 subject must be a string of at most 255 characters (naming the field) |
Coversheet message | 5,000 characters | 400 coversheet.message must be a string of at most 5000 characters |
| URL length | 8,192 characters | 400 documents[i].url is longer than 8192 characters |
| Redirects per URL | 3 | 400 documents[i] could not be fetched: too many redirects |
| Time to fetch a send's URLs | 60 seconds in all | 400 documents[i] could not be fetched: timed out |
| Request body, as sent | 20 MB (20,971,520 bytes), every request | 413 The request body is limited to 20 MB |
| Fax logs per page | 1 to 500 (default 10) | Cut to 500 |
| Fax servers | One per fax license | 403 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!" }| Status | When |
|---|---|
| 400 | The 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. |
| 401 | No usable API key. The body is { "authorized": false, "method": "…", "message": "…", "status": 401 }. |
| 403 | A 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. |
| 404 | No fax or fax server with this id on your account. Fetching one by id answers an empty array instead. |
| 409 | A fax server's logo changed meanwhile, or a call flow still sends calls to the fax server you're deleting. |
| 413 | The request body, the inline documents or a document by URL is too large; see Limits. |
| 415 | The body wasn't sent as application/json. |
| 422 | The fax isn't in a state that allows a retry or a cancel. |
| 500, 502 | Something failed on our side. Read the fax log before retrying a send: a retried send can fax twice. |
| 503 | With Retry-After: your key couldn't be checked, or your documents couldn't be stored, just now; retry after that many seconds. |
