TypeScript SDK

Updated

The npm package is named faxforagents and has been on npm since 2026-10-30. Install it with npm install faxforagents. Node 18 or later, Deno, Bun, browsers and edge runtimes, no runtime dependencies. The REST calls further down work with fetch as well, so nothing here depends on the package.

Status

Published. The package is generated from the same OpenAPI document as this site, built with tsup and published with npm provenance. The quickstart below is the one from the package's README. The package page is npmjs.com/package/faxforagents. The MCP bridge for stdio clients will be faxforagents-mcp. The sources are at github.com/faxforagents/sdk-typescript and github.com/faxforagents/mcp.

Install and send with the package

Shell
npm install faxforagents
TypeScript
import { FaxForAgents } from 'faxforagents';

const ffa = new FaxForAgents();                               // reads FAXFORAGENTS_API_KEY

const doc = await ffa.documents.create({ text: 'Hello from an agent.', filename: 'hello' });
console.log(doc.id, doc.page_count, doc.sha256.slice(0, 12));

const quote = await ffa.quotes.create({ document_id: doc.id, to: '+15550000001' });
console.log(quote.amount_micro, 'micro, expires', quote.expires_at);

let fax = await ffa.faxes.create({ quote_id: quote.id });     // Idempotency-Key minted for you
console.log(fax.id, fax.state);                               // queued, never delivered yet

fax = await ffa.faxes.wait(fax.id);                           // polls until a terminal state
console.log(fax.state, fax.pages_sent, fax.evidence);         // delivered, 1, {...}

for await (const job of ffa.faxes.iter({ state: 'failed' })) {  // follows next_cursor
  console.log(job.id, job.failure_code);
}

A test key is tied to the sandbox, where the destination number picks the outcome. ESM and CommonJS builds, types included.

Send a fax with fetch

TypeScript
const API = 'https://api.faxforagents.com/v1'
const KEY = process.env.FFA_KEY! // ffa_test_..., never in source control

async function call<T>(path: string, init: RequestInit = {}): Promise<T> {
  const r = await fetch(API + path, { ...init, headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json', ...init.headers } })
  if (!r.ok) throw new Error(`${r.status} ${await r.text()}`)
  return r.json() as Promise<T>
}

const doc = await call<{ id: string }>('/documents', { method: 'POST', body: JSON.stringify({ markdown: '# PO 4411\n\nPlease confirm.' }) })
const quote = await call<{ id: string }>('/fax-quotes', { method: 'POST', body: JSON.stringify({ document_id: doc.id, to: '+15550000001' }) })
const job = await call<{ id: string; state: string }>('/faxes', { method: 'POST', headers: { 'Idempotency-Key': 'po-4411' }, body: JSON.stringify({ quote_id: quote.id }) })
console.log(job.id, job.state) // fax_..., queued

Upload a PDF

TypeScript
import { readFile, stat } from 'node:fs/promises'

const size = (await stat(file)).size
const up = await call<{ id: string; upload_url: string }>('/uploads', { method: 'POST', body: JSON.stringify({ filename: 'contract.pdf', size_bytes: size }) })
await fetch(up.upload_url, { method: 'PUT', body: await readFile(file) })
await call(`/uploads/${up.id}/complete`, { method: 'POST' })
const doc = await call<{ id: string }>('/documents', { method: 'POST', body: JSON.stringify({ upload_id: up.id }) })

How do I page through jobs?

TypeScript
let cursor: string | undefined
do {
  const page = await call<{ items: { id: string; state: string }[]; next_cursor?: string }>(`/faxes?limit=50${cursor ? `&cursor=${cursor}` : ''}`)
  for (const job of page.items) console.log(job.id, job.state)
  cursor = page.next_cursor
} while (cursor)

How do I verify a webhook?

The reference verifier is on the webhooks page. The package ships the same function as verifyWebhook.

Errors

Every non-2xx body is the error envelope. Read error.code and error.retryable. Retry a retryable call with the same Idempotency-Key. The errors page lists every code.