# Python SDK

> The faxforagents package for Python, on PyPI since 2026-10-30: upload, quote, send, wait for the receipt, page through jobs. The REST calls work without it.

Page: https://faxforagents.com/docs/sdks/python/
Last changed: 2026-10-30

Updated Oct 30, 2026

The Python package is named `faxforagents` and has been on PyPI since 2026-10-30. Install it with `pip install faxforagents`. Python 3.10 or later, two dependencies, `httpx` and `pydantic`. The REST calls further down work with `httpx` or `requests` as well, so nothing here depends on the package.

## Status

Published. The package is built from the same OpenAPI document as this site and released through PyPI trusted publishing. The quickstart below is the one from the package's README. The source is at [github.com/faxforagents/sdk-python](https://github.com/faxforagents/sdk-python) and the package page is [pypi.org/project/faxforagents](https://pypi.org/project/faxforagents/).

## Install and send with the package

Shell

```
`pip install faxforagents # the client pip install "faxforagents[cli]" # plus the faxforagents command`
```

Python

```
`import os from faxforagents import Client os.environ["FAXFORAGENTS_API_KEY"] = "ffa_test_..." # or export it in the shell with Client() as ffa: doc = ffa.documents.create(text="Hello from an agent.", filename="hello") print(doc.id, doc.page_count, doc.sha256[:12]) quote = ffa.quotes.create(document_id=doc.id, to="+15550000001") print(quote.amount_micro, "micro, expires", quote.expires_at) fax = ffa.faxes.create(quote_id=quote.id) # Idempotency-Key minted for you print(fax.id, fax.state) # queued, never delivered yet fax = ffa.faxes.wait(fax.id) # polls until a terminal state print(fax.state, fax.pages_sent, fax.evidence) # delivered, 1, {...} for job in ffa.faxes.iter(state="failed"): # follows next_cursor print(job.id, job.failure_code)`
```

A test key is tied to the sandbox, where the destination number picks the outcome. The same calls exist in async form, with `AsyncClient` and `await` on every call.

## Send a fax with httpx

Python

```
`import httpx API = "https://api.faxforagents.com/v1" KEY = "ffa_test_..." # from the dashboard, never in source control h = {"Authorization": f"Bearer {KEY}"} with httpx.Client(base_url=API, headers=h, timeout=30) as c: doc = c.post("/documents", json={"markdown": "# PO 4411\n\nPlease confirm."}).raise_for_status().json() quote = c.post("/fax-quotes", json={"document_id": doc["id"], "to": "+15550000001"}).raise_for_status().json() job = c.post("/faxes", json={"quote_id": quote["id"]}, headers={"Idempotency-Key": "po-4411"}).raise_for_status().json() print(job["id"], job["state"]) # fax_..., queued`
```

## Upload a PDF

Python

```
`size = path.stat().st_size up = c.post("/uploads", json={"filename": path.name, "size_bytes": size}).raise_for_status().json() httpx.put(up["upload_url"], content=path.read_bytes(), timeout=120).raise_for_status() c.post(f"/uploads/{up['id']}/complete").raise_for_status() doc = c.post("/documents", json={"upload_id": up["id"]}).raise_for_status().json()`
```

## How do I page through jobs?

Python

```
`cursor = None while True: page = c.get("/faxes", params={"limit": 50, "cursor": cursor}).raise_for_status().json() for job in page["items"]: print(job["id"], job["state"]) cursor = page.get("next_cursor") if not cursor: break`
```

## How do I verify a webhook?

The reference verifier is on the [webhooks page](https://faxforagents.com/docs/webhooks/). The package ships the same function as `faxforagents.webhooks.verify`.

## 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](https://faxforagents.com/docs/errors/) lists every code.
