Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
# Changelog

## 0.6.1 (2026-11-15)

Follows API 1.20.5. The saved spec has 147 operations and the models are regenerated from it.

New: `billing.get_invoice_receipt(invoice_id)` and `billing.get_topup_receipt(topup_session_id)`, on both clients.
Each returns the new model `PaymentReceipt`. `url` is the hosted receipt and `pdf_url` the same receipt as a PDF.
Both need the scope `billing:read`. A payment that was not made raises `ConflictError`.

Changed: `documents.create_upload` no longer needs `content_type`. Its default was `application/pdf`. It is now `None`, and the field is left out of the request.
The API then reads the type from the filename. `scan.png` opens as `image/png`, and 0.6.0 opened it as a PDF.
A filename of an unsupported format, such as `letter.docx`, raises `InvalidRequestError` with the code `unsupported_format` on this call.
`UploadCreate.content_type` is `str | None` with the default `None`. `documents.upload` names the type itself, as before.

New: `NotFoundError.field` is `details["field"]`. On `quotes.create` it is `document_id` or `from`, the id that was not found.
New: `ConflictError.state` is `details["state"]`. `faxes.get_receipt` on a fax that has not ended carries the fax state there.
Both are `None` when the server sent no such detail.

The API now refuses an auto top-up threshold above 1000 USD and an agent `contact_email` that is not an address. Both raise `InvalidRequestError`.
`Capabilities.scopes` is described as every scope the platform defines. `me()` returns the scopes of the API key.
Other model names, fields and optionality are kept.

## 0.6.0 (2026-11-13)

Follows API 1.20.0. The saved spec has 145 operations and the models are regenerated from it.
Expand Down
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ The same in async form, with `AsyncClient` and `await` on every call.
- `documents.upload(path)` runs the whole upload path for a PDF or an image (PNG, JPG, TIFF): the
upload session, the signed PUT with the content type read from the filename, the sha256 check, the
document. An image becomes gray letter pages.
- `documents.create_upload(filename=..., size_bytes=...)` needs no `content_type`. The API reads the
type from the filename and refuses a filename of another format at once with `unsupported_format`.
- `faxes.wait(fax_id)` and `approvals.wait(approval_id)` poll with a timeout.
- `verify_webhook(secret, headers, body)` checks the Standard Webhooks signature on a delivery.
- Models are pydantic v2, generated from the public OpenAPI document. Money is an integer count of
Expand Down Expand Up @@ -108,7 +110,7 @@ each call needs.
| `ffa.faxes` | `create`, `list`, `iter`, `get`, `wait`, `list_events`, `list_attempts`, `get_receipt`, `get_receipt_pdf`, `cancel` |
| `ffa.webhooks` | `list`, `create`, `update`, `delete`, `rotate_secret`, `test`, `list_deliveries`, `replay_delivery` |
| `ffa.events` | `list`, `iter` |
| `ffa.billing` | `balance`, `list_ledger`, `iter_ledger`, `iter_topup_sessions`, `iter_invoices`, settings, top-ups, auto top-ups, budgets, `usage`, exports, invoices, subscriptions, `create_portal_session` |
| `ffa.billing` | `balance`, `list_ledger`, `iter_ledger`, `iter_topup_sessions`, `iter_invoices`, settings, top-ups, auto top-ups, budgets, `usage`, exports, invoices, `get_invoice_receipt`, `get_topup_receipt`, subscriptions, `create_portal_session` |
| `ffa.platform` | `capabilities`, `service_status` |
| `ffa.sandbox` | `list_scenarios`, `create_scenario`, `create_inbound_fax`, `reset` |
| `ffa.approvals` | `request`, `request_help`, `list`, `iter`, `get`, `wait`, `approve`, `reject`, `revoke` |
Expand Down Expand Up @@ -152,6 +154,10 @@ except APIError as exc:
`ServerError` (5xx) are all `APIError`. `APIConnectionError` and `APITimeoutError` mean the API was
not reached.

`NotFoundError.field` names the id that was not found when the API says which: on a quote it is
`document_id` or `from`. `ConflictError.state` is the state of a fax whose receipt was asked for
before the fax ended. Both are `None` when the API sent no such detail.

Every refusal is the same envelope, a 422 for a field that fails validation included. A 413
`payload_too_large` is a plain `APIError`: the body is over the limit of its route. The published
limits are in one table at <https://faxforagents.com/docs/limits/>.
Expand Down Expand Up @@ -299,7 +305,7 @@ ruff check src tests && mypy src
sh scripts/truthcheck.sh
```

`spec/openapi.yaml` follows the public document at API version 1.20.0 and keeps the schemas of the earlier live documents.
`spec/openapi.yaml` follows the public document at API version 1.20.5 and keeps the schemas of the earlier live documents.
The two validation error schemas are the exception. 0.5.0 removed them because the server never sent that shape.
0.6.0 removed two cost fields of an extraction, because the server stopped sending them.
It also retains earlier public model names and route-documented response additions.
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "faxforagents"
version = "0.6.0"
version = "0.6.1"
description = "Python client for Fax for Agents: a fax API, a hosted MCP server and SDKs built so AI agents can send and receive faxes."
readme = "README.md"
requires-python = ">=3.10"
Expand Down
Loading
Loading