Faxday API
Fax as an API — with the parts other fax APIs leave out: AI-extracted fields, Smart Fax returns that link themselves, instant delivery between Faxday workspaces, and signed proof of delivery.
Authentication
Create a key in Settings → Integrations → API keys (workspace admins). Keys are shown once, scoped, and revocable. Send it as a bearer token:
curl https://faxday.com/api/v1/me \
-H "Authorization: Bearer fd_live_…"faxes:read— List and read faxes, documents and certificatesfaxes:send— Send faxesfaxes:write— Update work status, assignee and due date; delete faxeswebhooks:manage— Create, list and delete webhook endpoints
Keys are for server-to-server use: never ship one in a browser or mobile app.
Send a fax
JSON with base64-encoded PDFs (up to 20 documents, 25 MB):
curl https://faxday.com/api/v1/faxes \
-H "Authorization: Bearer $FAXDAY_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: referral-8842" \
-d '{
"to": "+13125550142",
"subject": "Referral – cardiology",
"documents": [{ "content": "'"$(base64 -w0 referral.pdf)"'" }],
"cover": { "enabled": true, "smart": true, "toName": "Northside Cardiology", "message": "Please complete and return." },
"chase": { "enabled": true, "afterHours": 48, "max": 2 }
}'Or multipart — the same fields, with objects as JSON strings:
curl https://faxday.com/api/v1/faxes -H "Authorization: Bearer $FAXDAY_KEY" \
-F to=+13125550142 -F [email protected] \
-F 'cover={"enabled":true,"smart":true}'The response is the fax object (201). status is sending on the phone network, or delivered immediately when the recipient is on the Faxday Network (deliveryChannel: "network"). Smart Faxes carry a trackingCode and a reply QR; the return is linked automatically and fax.returned fires.
If the destination looks risky (blocked, reported as spam, a person answered last time, or the number was retired), you get 409 with code: "confirm_risk" and a risks list. Re-send with "confirmRisk": true to override (audited).
Read faxes
curl "https://faxday.com/api/v1/faxes?direction=inbound&limit=50" -H "Authorization: Bearer $FAXDAY_KEY"
curl https://faxday.com/api/v1/faxes/{id}/document -H "Authorization: Bearer $FAXDAY_KEY" -o fax.pdfInbound faxes include Sanga's summary, tags and extracted fields. Lists are newest first; pass nextCursor as cursor while hasMore is true.
Webhooks
Events: fax.received, fax.returned, fax.delivered, fax.failed. Choose JSON or a FHIR R4 DocumentReference for EHR ingestion. Each delivery is signed — verify before trusting it:
import crypto from "crypto";
export function verifyFaxday(rawBody: string, header: string, secret: string) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
const got = Buffer.from(parts.v1 ?? ""), want = Buffer.from(expected);
return fresh && got.length === want.length && crypto.timingSafeEqual(got, want);
}Respond with any 2xx quickly; non-2xx responses are retried with exponential backoff. The payload's document link is valid for one hour.
Endpoints
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /me | — | Workspace, plan, usage, key scopes |
| GET | /numbers | faxes:read | Your fax numbers (use id as fromNumberId) |
| POST | /faxes | faxes:send | Send a fax (JSON + base64, or multipart) |
| GET | /faxes | faxes:read | List faxes; filter by direction, status, workStatus, createdAfter |
| GET | /faxes/{id} | faxes:read | Status, AI summary, extracted fields, Smart Fax state |
| PATCH | /faxes/{id} | faxes:write | Update workStatus, assignedTo, dueAt |
| DELETE | /faxes/{id} | faxes:write | Permanently delete document + content (audited) |
| GET | /faxes/{id}/document | faxes:read | Download the PDF |
| GET | /faxes/{id}/certificate | faxes:read | Signed proof of delivery (PDF or JSON) |
| POST | /faxes/{id}/retry | faxes:send | Re-send a failed fax |
| GET | /webhooks | webhooks:manage | List webhook endpoints |
| POST | /webhooks | webhooks:manage | Create an endpoint (secret returned once) |
| DELETE | /webhooks/{id} | webhooks:manage | Delete an endpoint |
Errors, idempotency and limits
HTTP/1.1 403
X-Request-Id: req_4f1c…
{ "error": { "type": "permission_error", "message": "This key is missing the faxes:send permission.", "missingScopes": ["faxes:send"] } }- Error
type: invalid_request, authentication_error, permission_error, not_found, conflict, idempotency_error, rate_limited, quota_exceeded, api_error. Idempotency-KeyonPOST /faxes: a retry with the same key and body within 24 hours returns the original response (headerIdempotent-Replayed: true) instead of faxing twice.- Limits: 120 requests/minute per key; 30 sends/minute per workspace.
429responses includeRetry-After. - Every response includes
X-Request-Id— include it when contacting support.