faxforagents 0.0.0-stage → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/LICENSE +21 -0
- package/README.md +173 -2
- package/dist/index.cjs +1138 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +13363 -0
- package/dist/index.d.ts +13363 -0
- package/dist/index.js +1069 -0
- package/dist/index.js.map +1 -0
- package/package.json +75 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.1 (2026-10-29)
|
|
4
|
+
|
|
5
|
+
API version 1.2.3. The generated types document `503 live_provider_unavailable` on the eight operations
|
|
6
|
+
that reach the carrier with a live key (`createFaxQuote`, `createFax`, `cancelFax`, `getNumberInventory`,
|
|
7
|
+
`createNumberOrder`, `createReleaseRequest`, `createPortabilityCheck`, `createPortOrder`). A production
|
|
8
|
+
server with no carrier configured refuses them before any hold or approval is consumed, with `retryable`
|
|
9
|
+
false. No client code changed.
|
|
10
|
+
|
|
11
|
+
## 0.2.0 (2026-10-28)
|
|
12
|
+
|
|
13
|
+
API version 1.1.0: HTML rendering and image uploads.
|
|
14
|
+
|
|
15
|
+
- `documents.create({ html })` renders HTML on the server, scripts off and no network.
|
|
16
|
+
- `documents.upload` takes a PNG, JPG or TIFF beside a PDF and reads the content type from the
|
|
17
|
+
filename (`guessContentType`, `CONTENT_TYPES`). `createUpload` documents the four content types.
|
|
18
|
+
- New resources, every operation of the document: `numbers` (coverage, inventory, orders, porting,
|
|
19
|
+
sender verification), `extractions` (OCR, fields, classification, summaries, saved schemas),
|
|
20
|
+
`organizations` and `members`. The inbox gains `update`, `delete`, `getDownload` and `download`.
|
|
21
|
+
- `sandbox.createInboundFax` returns `InboxItemSummary`. `InboxItem` carries the number, project,
|
|
22
|
+
media status and read state of a received fax. `Quote` carries `per_page_micro` and `route_label`.
|
|
23
|
+
- A `prepare` script builds the package on a git install.
|
|
24
|
+
|
|
25
|
+
## 0.1.0 (2026-10-28)
|
|
26
|
+
|
|
27
|
+
First release.
|
|
28
|
+
|
|
29
|
+
- `FaxForAgents` client over `fetch`, every `/v1` operation of API version 0.1.0, ESM and CommonJS.
|
|
30
|
+
- Types generated from the public OpenAPI document with openapi-typescript (`npm run gen:types`).
|
|
31
|
+
- `Idempotency-Key` on every mutating call, retries for 429 and 5xx with `Retry-After`.
|
|
32
|
+
- `iter` helpers on every list, `faxes.wait` and `approvals.wait`.
|
|
33
|
+
- `verifyWebhook` for the Standard Webhooks signature, with rotation support, on Web Crypto.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 JSB Holdings LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,174 @@
|
|
|
1
|
-
#
|
|
1
|
+
# faxforagents
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The TypeScript and JavaScript client for Fax for Agents, <https://faxforagents.com>.
|
|
4
|
+
|
|
5
|
+
Fax for Agents is a fax API, a hosted MCP server and SDKs built so AI agents can send and receive
|
|
6
|
+
faxes. It is made by JSB Holdings LLC.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install faxforagents
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Node 18 or later, Deno, Bun, browsers and edge runtimes. Zero runtime dependencies. The client uses
|
|
13
|
+
`fetch` and Web Crypto. ESM and CommonJS builds, types included.
|
|
14
|
+
|
|
15
|
+
## Quickstart, against the sandbox
|
|
16
|
+
|
|
17
|
+
A test key (`ffa_test_...`) reaches the sandbox provider only. No carrier, no cost, nothing leaves the
|
|
18
|
+
box. The destination number picks the outcome. Keys are created in the dashboard at
|
|
19
|
+
<https://app.faxforagents.com> or with `POST /v1/api-keys`.
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { FaxForAgents } from 'faxforagents';
|
|
23
|
+
|
|
24
|
+
const ffa = new FaxForAgents(); // reads FAXFORAGENTS_API_KEY
|
|
25
|
+
|
|
26
|
+
const doc = await ffa.documents.create({ text: 'Hello from an agent.', filename: 'hello' });
|
|
27
|
+
console.log(doc.id, doc.page_count, doc.sha256.slice(0, 12));
|
|
28
|
+
|
|
29
|
+
const quote = await ffa.quotes.create({ document_id: doc.id, to: '+15550000001' });
|
|
30
|
+
console.log(quote.amount_micro, 'micro, expires', quote.expires_at);
|
|
31
|
+
|
|
32
|
+
let fax = await ffa.faxes.create({ quote_id: quote.id }); // Idempotency-Key minted for you
|
|
33
|
+
console.log(fax.id, fax.state); // queued, never delivered yet
|
|
34
|
+
|
|
35
|
+
fax = await ffa.faxes.wait(fax.id); // polls until a terminal state
|
|
36
|
+
console.log(fax.state, fax.pages_sent, fax.evidence); // delivered, 1, {...}
|
|
37
|
+
|
|
38
|
+
for await (const job of ffa.faxes.iter({ state: 'failed' })) { // follows next_cursor
|
|
39
|
+
console.log(job.id, job.failure_code);
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## What the client does for you
|
|
44
|
+
|
|
45
|
+
- Every mutating call carries an `Idempotency-Key`. When you pass none, a UUID is minted once per call
|
|
46
|
+
and reused on every retry, so a retried send never creates a second fax. Pass
|
|
47
|
+
`{ idempotencyKey }` as the last argument to pick your own.
|
|
48
|
+
- 429 and 5xx answers are retried up to three times. `Retry-After` is honoured. Network errors and
|
|
49
|
+
timeouts are retried the same way.
|
|
50
|
+
- Every list has an `iter` twin that follows `next_cursor`, as an async iterator.
|
|
51
|
+
- `documents.create({ text })`, `{ markdown }` or `{ html }` renders on the server. HTML prints with
|
|
52
|
+
scripts off and no network, inline CSS and `data:` images only, at most 2 MiB.
|
|
53
|
+
- `documents.upload(bytes, { filename })` runs the whole upload path for a PDF or an image (PNG, JPG,
|
|
54
|
+
TIFF): the upload session, the signed PUT with the content type read from the filename, the sha256
|
|
55
|
+
check, the document. An image becomes gray letter pages.
|
|
56
|
+
- `faxes.wait(faxId)` and `approvals.wait(approvalId)` poll with a timeout.
|
|
57
|
+
- `verifyWebhook(secret, headers, body)` checks the Standard Webhooks signature on a delivery.
|
|
58
|
+
- Types are generated from the public OpenAPI document with openapi-typescript. Money is an integer
|
|
59
|
+
count of USD micro-units (`39000` is $0.039). Timestamps are UTC strings.
|
|
60
|
+
|
|
61
|
+
## Resources
|
|
62
|
+
|
|
63
|
+
Method names are the operationIds of the [OpenAPI document](https://github.com/faxforagents/openapi)
|
|
64
|
+
in camel case, shortened by their resource. The reference at <https://faxforagents.github.io/openapi/>
|
|
65
|
+
names the scope each call needs.
|
|
66
|
+
|
|
67
|
+
| Resource | Calls |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `ffa.identity` | `me`, `listApiKeys`, `createApiKey`, `rotateApiKey`, `revokeApiKey` |
|
|
70
|
+
| `ffa.documents` | `create`, `upload`, `createUpload`, `putUploadContent`, `completeUpload`, `cancelUpload`, `list`, `iter`, `get`, `delete`, `getValidation`, `getDownload`, `download`, `listPages` |
|
|
71
|
+
| `ffa.quotes` | `create`, `get` |
|
|
72
|
+
| `ffa.faxes` | `create`, `list`, `iter`, `get`, `wait`, `listEvents`, `listAttempts`, `getReceipt`, `cancel` |
|
|
73
|
+
| `ffa.webhooks` | `list`, `create`, `update`, `delete`, `rotateSecret`, `test`, `listDeliveries`, `replayDelivery` |
|
|
74
|
+
| `ffa.events` | `list`, `iter` |
|
|
75
|
+
| `ffa.billing` | `balance`, `listLedger`, settings, top-ups, auto top-ups, budgets, `usage`, exports, invoices, subscriptions, `createPortalSession` |
|
|
76
|
+
| `ffa.platform` | `capabilities`, `serviceStatus` |
|
|
77
|
+
| `ffa.sandbox` | `listScenarios`, `createScenario`, `createInboundFax`, `reset` |
|
|
78
|
+
| `ffa.approvals` | `request`, `requestHelp`, `list`, `iter`, `get`, `wait`, `approve`, `reject`, `revoke` |
|
|
79
|
+
| `ffa.policies` | `list`, `create`, `effective`, `get`, `update`, `listVersions`, `evaluate` |
|
|
80
|
+
| `ffa.agents` | `list`, `create`, `get`, `update`, `createKey`, `activity` |
|
|
81
|
+
| `ffa.inbox` | `list`, `iter`, `get`, `update`, `delete`, `getDownload`, `download` |
|
|
82
|
+
| `ffa.numbers` | `coverage`, `inventory`, `createOrder`, `getOrder`, `list`, `get`, `update`, `release`, `checkPortability`, `listPortOrders`, `createPortOrder`, `getPortOrder`, `createPortOutRequest`, `verifySender` |
|
|
83
|
+
| `ffa.extractions` | `create`, `list`, `iter`, `get`, `correct`, `classify`, `listClassifications`, `iterClassifications`, `getClassification`, `summarize`, `listSummaries`, `iterSummaries`, `getSummary`, `listSchemas`, `createSchema`, `getSchema` |
|
|
84
|
+
| `ffa.organizations` | `list`, `current`, `updateCurrent`, `requestDataExport`, `requestDataDeletion` |
|
|
85
|
+
| `ffa.members` | `list`, `update`, `remove`, `listInvitations`, `invite`, `revokeInvitation` |
|
|
86
|
+
|
|
87
|
+
`ffa.request('GET', '/v1/anything')` reaches an operation the resources do not cover yet.
|
|
88
|
+
|
|
89
|
+
## States
|
|
90
|
+
|
|
91
|
+
A fax job is `queued`, `active`, `partial`, `failed`, `unknown` or `delivered`. `delivered` is written
|
|
92
|
+
only when the carrier's evidence is on the attempt, and `fax.evidence` holds it. `partial` and
|
|
93
|
+
`unknown` never retransmit on their own. Whether to resend is a human decision.
|
|
94
|
+
|
|
95
|
+
Sandbox destinations: `+15550000001` delivered, `+15550000002` busy then delivered, `+15550000003`
|
|
96
|
+
partial, `+15550000004` no answer, `+15550000005` unknown, `+15550000006` provider timeout,
|
|
97
|
+
`+15550000007` invalid number. Any other `+1` number is delivered.
|
|
98
|
+
|
|
99
|
+
## Errors
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
import { APIError, RateLimitedError } from 'faxforagents';
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
await ffa.faxes.create({ quote_id: quote.id });
|
|
106
|
+
} catch (err) {
|
|
107
|
+
if (err instanceof RateLimitedError) console.log('retry in', err.retryAfter);
|
|
108
|
+
else if (err instanceof APIError) console.log(err.code, err.message, err.correlationId);
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`AuthenticationError` (401), `ScopeError` (403), `NotFoundError` (404), `ConflictError` (409),
|
|
113
|
+
`PaymentRequiredError` (402), `InvalidRequestError` (400, 422), `RateLimitedError` (429) and
|
|
114
|
+
`ServerError` (5xx) all extend `APIError`. `APIConnectionError` and `APITimeoutError` mean the API was
|
|
115
|
+
not reached.
|
|
116
|
+
|
|
117
|
+
## Approvals
|
|
118
|
+
|
|
119
|
+
A live send needs either a human approval bound to the quote or a delegated policy that allows it.
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
let req = await ffa.approvals.request(quote.id); // a person is mailed
|
|
123
|
+
req = await ffa.approvals.wait(req.id); // pending until they decide
|
|
124
|
+
if (req.status === 'approved') {
|
|
125
|
+
await ffa.faxes.create({ quote_id: quote.id, approval_id: req.id });
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
An agent's own API key can never approve. `ffa.policies.evaluate({ quote_id })` is a dry run that
|
|
130
|
+
says whether a policy would allow the send.
|
|
131
|
+
|
|
132
|
+
## Webhooks
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import { verifyWebhook, parseEvent, SignatureError } from 'faxforagents';
|
|
136
|
+
|
|
137
|
+
// Express: app.post('/hooks/fax', express.raw({ type: '*/*' }), async (req, res) => { ... })
|
|
138
|
+
try {
|
|
139
|
+
const eventId = await verifyWebhook(secret, req.headers, req.body); // raw bytes
|
|
140
|
+
const event = parseEvent(req.body); // event.type: fax.delivered...
|
|
141
|
+
res.sendStatus(200);
|
|
142
|
+
} catch (err) {
|
|
143
|
+
if (err instanceof SignatureError) res.sendStatus(400);
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Verify on the raw bytes. `verifyWebhook` is async because it uses Web Crypto. Store the event id to
|
|
148
|
+
drop a redelivery you already handled. During a secret rotation two signatures arrive for 24 hours and
|
|
149
|
+
either one verifies.
|
|
150
|
+
|
|
151
|
+
## Prices
|
|
152
|
+
|
|
153
|
+
Price card launch-v1 is effective from 2026-10-28. $0.039 per page sent, $0.019 per page received.
|
|
154
|
+
$2 per number per month, $19 per month for the Agent workspace. Sandbox pages cost 0.
|
|
155
|
+
`ffa.platform.capabilities()` returns the card in force.
|
|
156
|
+
|
|
157
|
+
## Working on this repository
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
npm ci
|
|
161
|
+
npm test # vitest with msw, no network
|
|
162
|
+
FAXFORAGENTS_API_KEY=ffa_test_... npm run test:live # one real sandbox send
|
|
163
|
+
npm run gen:types # src/schema.d.ts from spec/openapi.yaml
|
|
164
|
+
npm run typecheck && npm run build
|
|
165
|
+
sh scripts/truthcheck.sh
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`spec/openapi.yaml` is a copy of the public document. To take a new one, copy it over and run
|
|
169
|
+
`npm run gen:types`. `npm install` from a git URL builds the package on install (the `prepare` script),
|
|
170
|
+
so `npm install github:faxforagents/sdk-typescript` works before the package is on npm.
|
|
171
|
+
|
|
172
|
+
## Licence
|
|
173
|
+
|
|
174
|
+
MIT. See [LICENSE](LICENSE). Security reports go to hello@faxforagents.com, see [SECURITY.md](SECURITY.md).
|