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 certificates
  • faxes:send — Send faxes
  • faxes:write — Update work status, assignee and due date; delete faxes
  • webhooks: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.pdf

Inbound 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

MethodPathScopeWhat it does
GET/me—Workspace, plan, usage, key scopes
GET/numbersfaxes:readYour fax numbers (use id as fromNumberId)
POST/faxesfaxes:sendSend a fax (JSON + base64, or multipart)
GET/faxesfaxes:readList faxes; filter by direction, status, workStatus, createdAfter
GET/faxes/{id}faxes:readStatus, AI summary, extracted fields, Smart Fax state
PATCH/faxes/{id}faxes:writeUpdate workStatus, assignedTo, dueAt
DELETE/faxes/{id}faxes:writePermanently delete document + content (audited)
GET/faxes/{id}/documentfaxes:readDownload the PDF
GET/faxes/{id}/certificatefaxes:readSigned proof of delivery (PDF or JSON)
POST/faxes/{id}/retryfaxes:sendRe-send a failed fax
GET/webhookswebhooks:manageList webhook endpoints
POST/webhookswebhooks:manageCreate an endpoint (secret returned once)
DELETE/webhooks/{id}webhooks:manageDelete 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-Key on POST /faxes: a retry with the same key and body within 24 hours returns the original response (header Idempotent-Replayed: true) instead of faxing twice.
  • Limits: 120 requests/minute per key; 30 sends/minute per workspace. 429 responses include Retry-After.
  • Every response includes X-Request-Id — include it when contacting support.