@papierapi/sdk 0.1.0
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/LICENSE +21 -0
- package/README.md +450 -0
- package/dist/chunk-JDUUPLUG.js +984 -0
- package/dist/chunk-JDUUPLUG.js.map +7 -0
- package/dist/client.d.ts +469 -0
- package/dist/errors.d.ts +20 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +343 -0
- package/dist/index.js.map +7 -0
- package/dist/internal/contracts/common.d.ts +108 -0
- package/dist/internal/contracts/dispatch.d.ts +979 -0
- package/dist/internal/contracts/fax.d.ts +49 -0
- package/dist/internal/contracts/index.d.ts +7 -0
- package/dist/internal/contracts/letter.d.ts +292 -0
- package/dist/internal/contracts/mcp.d.ts +395 -0
- package/dist/internal/contracts/platform.d.ts +424 -0
- package/dist/internal/contracts/rest.d.ts +1656 -0
- package/dist/operations.d.ts +1563 -0
- package/dist/operations.js +7 -0
- package/dist/operations.js.map +7 -0
- package/examples/get-dispatch.ts +13 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Papier API
|
|
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
ADDED
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
# @papierapi/sdk
|
|
2
|
+
|
|
3
|
+
The official TypeScript SDK for the Papier API. It provides a typed,
|
|
4
|
+
runtime-validated ESM client for preparing, approving, paying for, dispatching,
|
|
5
|
+
and tracking physical letters and faxes.
|
|
6
|
+
|
|
7
|
+
The SDK is designed for trusted server-side applications. It validates request
|
|
8
|
+
inputs before sending them, validates every API response against the published
|
|
9
|
+
contract, and keeps real dispatch behind an explicit human approval.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Typed letter and fax workflows
|
|
14
|
+
- PDF uploads up to 20 MiB
|
|
15
|
+
- Structured letter content without generating a PDF yourself
|
|
16
|
+
- Human approval links before payment or dispatch
|
|
17
|
+
- Direct-payment and wallet-backed dispatch flows
|
|
18
|
+
- Idempotency keys for retry-safe payment and dispatch creation
|
|
19
|
+
- Dispatch status, event, summary, and proof retrieval
|
|
20
|
+
- Runtime response validation
|
|
21
|
+
- Typed API, transport, and contract errors
|
|
22
|
+
- Machine-readable operation metadata
|
|
23
|
+
- Injectable access-token provider and Fetch implementation
|
|
24
|
+
|
|
25
|
+
## Requirements
|
|
26
|
+
|
|
27
|
+
- Node.js `>=20 <26`
|
|
28
|
+
- An ESM application
|
|
29
|
+
- A Papier API OAuth access token or API key
|
|
30
|
+
- A configured sender profile for letter or fax drafts
|
|
31
|
+
|
|
32
|
+
The package ships ESM JavaScript and TypeScript declarations. CommonJS
|
|
33
|
+
`require()` is not supported.
|
|
34
|
+
|
|
35
|
+
Create API credentials and sender profiles in the
|
|
36
|
+
[Papier API developer area](https://app.papierapi.de/developers).
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install @papierapi/sdk
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Equivalent package-manager commands:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pnpm add @papierapi/sdk
|
|
48
|
+
yarn add @papierapi/sdk
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Client setup
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { PapierApiClient } from "@papierapi/sdk";
|
|
55
|
+
|
|
56
|
+
const api = new PapierApiClient({
|
|
57
|
+
baseUrl: "https://api.papierapi.de",
|
|
58
|
+
accessToken: process.env.PAPIERAPI_TOKEN!,
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Recommended environment variables:
|
|
63
|
+
|
|
64
|
+
```dotenv
|
|
65
|
+
PAPIERAPI_TOKEN=pap_...
|
|
66
|
+
PAPIERAPI_SENDER_PROFILE_ID=snd_...
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Keep credentials in a server-side secret manager. Do not bundle a Papier API
|
|
70
|
+
token into browser JavaScript, mobile applications, source control, logs, or
|
|
71
|
+
prompts.
|
|
72
|
+
|
|
73
|
+
### Rotating or short-lived tokens
|
|
74
|
+
|
|
75
|
+
`accessToken` may be a string or a synchronous or asynchronous provider. The
|
|
76
|
+
provider is called immediately before each request.
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
const api = new PapierApiClient({
|
|
80
|
+
baseUrl: "https://api.papierapi.de",
|
|
81
|
+
accessToken: async () => secretManager.read("PAPIERAPI_TOKEN"),
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Client options
|
|
86
|
+
|
|
87
|
+
| Option | Type | Default | Description |
|
|
88
|
+
| --- | --- | --- | --- |
|
|
89
|
+
| `baseUrl` | `string` | required | Absolute API origin. HTTPS is required except for localhost. Do not include `/v1`, a path, query, or fragment. |
|
|
90
|
+
| `accessToken` | `string \| (() => string \| Promise<string>)` | required | OAuth access token or API key sent as a Bearer token. |
|
|
91
|
+
| `fetcher` | Fetch-compatible function | `globalThis.fetch` | Custom transport for tests, tracing, proxies, or platform integration. |
|
|
92
|
+
| `timeoutMs` | `number` | `30000` | Per-request timeout. Valid range: 1 to 120,000 ms. |
|
|
93
|
+
| `maxResponseBytes` | `number` | `2097152` | Maximum accepted response body. Valid range: 256 bytes to 10 MiB. |
|
|
94
|
+
|
|
95
|
+
## Workflow
|
|
96
|
+
|
|
97
|
+
A real letter or fax is never sent by a draft or review call. The normal flow
|
|
98
|
+
is:
|
|
99
|
+
|
|
100
|
+
1. Upload a PDF or provide structured letter content.
|
|
101
|
+
2. Create a draft.
|
|
102
|
+
3. Quote the immutable draft.
|
|
103
|
+
4. Create a human approval request.
|
|
104
|
+
5. Let a person review the document, recipient, options, and final price.
|
|
105
|
+
6. After approval, create a direct-payment session or a wallet-backed dispatch.
|
|
106
|
+
7. Read the server-confirmed payment and dispatch status.
|
|
107
|
+
|
|
108
|
+
Changing the document, recipient, options, or price requires a new approval.
|
|
109
|
+
|
|
110
|
+
## Prepare a PDF letter for review
|
|
111
|
+
|
|
112
|
+
`prepareLetterForReview()` creates a draft, quotes it, and creates an approval
|
|
113
|
+
link. It does not pay for or send the letter.
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import { readFile } from "node:fs/promises";
|
|
117
|
+
import { PapierApiClient } from "@papierapi/sdk";
|
|
118
|
+
|
|
119
|
+
const api = new PapierApiClient({
|
|
120
|
+
baseUrl: "https://api.papierapi.de",
|
|
121
|
+
accessToken: process.env.PAPIERAPI_TOKEN!,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const pdf = await readFile("./contract.pdf");
|
|
125
|
+
const upload = await api.uploadDocument(pdf);
|
|
126
|
+
|
|
127
|
+
const review = await api.prepareLetterForReview({
|
|
128
|
+
sender_profile_id: process.env.PAPIERAPI_SENDER_PROFILE_ID!,
|
|
129
|
+
recipient: {
|
|
130
|
+
type: "street",
|
|
131
|
+
company: "Example Property Management GmbH",
|
|
132
|
+
name: "Contracts Department",
|
|
133
|
+
street: "Invalidenstrasse",
|
|
134
|
+
house_number: "1",
|
|
135
|
+
postal_code: "10115",
|
|
136
|
+
city: "Berlin",
|
|
137
|
+
country: "DE",
|
|
138
|
+
},
|
|
139
|
+
source: {
|
|
140
|
+
mode: "raw_pdf",
|
|
141
|
+
document_id: upload.data.document.id,
|
|
142
|
+
},
|
|
143
|
+
options: {
|
|
144
|
+
print: "grayscale",
|
|
145
|
+
duplex: true,
|
|
146
|
+
service: "standard",
|
|
147
|
+
},
|
|
148
|
+
metadata: {
|
|
149
|
+
external_reference: "contract-2026-0042",
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
console.log({
|
|
154
|
+
approvalRequestId: review.approval.id,
|
|
155
|
+
draftId: review.draft.id,
|
|
156
|
+
pages: review.draft.page_count,
|
|
157
|
+
totalCents: review.quote.total_cents,
|
|
158
|
+
approvalUrl: review.approval.approval_url,
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Open `approvalUrl` in a user-controlled browser. Preparing a review package is
|
|
163
|
+
not evidence that the document was paid for, submitted to a provider, or sent.
|
|
164
|
+
|
|
165
|
+
### Supported PDF input types
|
|
166
|
+
|
|
167
|
+
`uploadDocument()` accepts:
|
|
168
|
+
|
|
169
|
+
- `Blob`
|
|
170
|
+
- `ArrayBuffer`
|
|
171
|
+
- `Uint8Array`, including Node.js `Buffer`
|
|
172
|
+
|
|
173
|
+
The local size limit is 1 byte through 20 MiB. The API performs additional PDF
|
|
174
|
+
and layout validation.
|
|
175
|
+
|
|
176
|
+
## Prepare a structured letter
|
|
177
|
+
|
|
178
|
+
Use structured content when Papier API should render the document. The same
|
|
179
|
+
draft, quote, and approval model applies.
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
const review = await api.prepareLetterForReview({
|
|
183
|
+
sender_profile_id: process.env.PAPIERAPI_SENDER_PROFILE_ID!,
|
|
184
|
+
recipient: {
|
|
185
|
+
type: "street",
|
|
186
|
+
name: "Max Mustermann",
|
|
187
|
+
street: "Beispielweg",
|
|
188
|
+
house_number: "4",
|
|
189
|
+
postal_code: "10115",
|
|
190
|
+
city: "Berlin",
|
|
191
|
+
country: "DE",
|
|
192
|
+
},
|
|
193
|
+
source: {
|
|
194
|
+
mode: "structured",
|
|
195
|
+
content: {
|
|
196
|
+
locale: "en-DE",
|
|
197
|
+
date: "2026-07-20",
|
|
198
|
+
subject: "Contract notice",
|
|
199
|
+
salutation: "Dear Mr Mustermann,",
|
|
200
|
+
blocks: [
|
|
201
|
+
{
|
|
202
|
+
type: "paragraph",
|
|
203
|
+
text: "This letter confirms the requested contractual notice.",
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
type: "list",
|
|
207
|
+
ordered: false,
|
|
208
|
+
items: ["Reference: 2026-0042", "Effective date: 31 July 2026"],
|
|
209
|
+
},
|
|
210
|
+
],
|
|
211
|
+
closing: "Kind regards",
|
|
212
|
+
signatory: "Example Operations Team",
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
options: {
|
|
216
|
+
print: "grayscale",
|
|
217
|
+
duplex: false,
|
|
218
|
+
service: "registered_insertion",
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
console.log(review.approval.approval_url);
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Structured blocks support paragraphs, headings, ordered or unordered lists,
|
|
226
|
+
tables, spacers, closings, and signature placeholders. TypeScript exposes the
|
|
227
|
+
accepted shapes through `CreateLetterDraftInput` and related exported types.
|
|
228
|
+
|
|
229
|
+
## Prepare a fax for review
|
|
230
|
+
|
|
231
|
+
Fax drafts use an uploaded PDF and an E.164 recipient number.
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
import { readFile } from "node:fs/promises";
|
|
235
|
+
|
|
236
|
+
const upload = await api.uploadDocument(await readFile("./signed-contract.pdf"));
|
|
237
|
+
|
|
238
|
+
const review = await api.prepareFaxForReview({
|
|
239
|
+
sender_profile_id: process.env.PAPIERAPI_SENDER_PROFILE_ID!,
|
|
240
|
+
recipient: {
|
|
241
|
+
fax_number_e164: "+493012345678",
|
|
242
|
+
company: "Example Recipient GmbH",
|
|
243
|
+
name: "Contracts Department",
|
|
244
|
+
recipient_reference: "contract-2026-0042",
|
|
245
|
+
},
|
|
246
|
+
document_id: upload.data.document.id,
|
|
247
|
+
cover: {
|
|
248
|
+
enabled: true,
|
|
249
|
+
subject: "Signed contract",
|
|
250
|
+
note: "Please route this document to the contracts team.",
|
|
251
|
+
},
|
|
252
|
+
options: {
|
|
253
|
+
max_attempts: 2,
|
|
254
|
+
purpose: "contractual",
|
|
255
|
+
},
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
console.log(review.approval.approval_url);
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Fax availability depends on the active Papier API environment and sender
|
|
262
|
+
profile. A prepared fax is not proof of transmission.
|
|
263
|
+
|
|
264
|
+
## Responses
|
|
265
|
+
|
|
266
|
+
Individual client methods return a validated API envelope:
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
const response = await api.getDispatch("dsp_...");
|
|
270
|
+
|
|
271
|
+
console.log(response.request_id);
|
|
272
|
+
console.log(response.data.status);
|
|
273
|
+
console.log(response.next_actions);
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
The concrete `data` type is inferred for every method. Responses that do not
|
|
277
|
+
match the published schema are rejected with `PapierApiContractError` instead
|
|
278
|
+
of being returned as untrusted data.
|
|
279
|
+
|
|
280
|
+
## Client API
|
|
281
|
+
|
|
282
|
+
### Documents, drafts, quotes, and approvals
|
|
283
|
+
|
|
284
|
+
| Method | Purpose |
|
|
285
|
+
| --- | --- |
|
|
286
|
+
| `uploadDocument(document)` | Upload a PDF and return its document ID. |
|
|
287
|
+
| `createLetterDraft(input)` | Create a letter draft from structured content or an uploaded PDF. |
|
|
288
|
+
| `createFaxDraft(input)` | Create a fax draft from an uploaded PDF. |
|
|
289
|
+
| `getDraft(draftId)` | Read a draft and its current verification state. |
|
|
290
|
+
| `quoteDraft(draftId)` | Calculate a time-limited quote for a draft. |
|
|
291
|
+
| `requestApproval(draftId, input)` | Create a human approval request and approval URL. |
|
|
292
|
+
| `prepareLetterForReview(input, expiresInSeconds?)` | Create, quote, and request approval for a letter. Default approval lifetime: 3,600 seconds. |
|
|
293
|
+
| `prepareFaxForReview(input, expiresInSeconds?)` | Create, quote, and request approval for a fax. Default approval lifetime: 3,600 seconds. |
|
|
294
|
+
|
|
295
|
+
### Payment, dispatch, and status
|
|
296
|
+
|
|
297
|
+
| Method | Purpose |
|
|
298
|
+
| --- | --- |
|
|
299
|
+
| `createDirectPaymentSession(draftId, input, idempotencyKey)` | Create user-controlled Checkout after approval. Opening Checkout does not dispatch. |
|
|
300
|
+
| `getDirectPayment(directPaymentId)` | Read server-confirmed payment and resulting dispatch state. |
|
|
301
|
+
| `createDispatch(draftId, input, idempotencyKey)` | Create a wallet-backed dispatch after approval. |
|
|
302
|
+
| `listDispatches(limit?)` | List up to 100 dispatches. Default: 25. |
|
|
303
|
+
| `getDispatch(dispatchId)` | Read the canonical dispatch state. |
|
|
304
|
+
| `getDispatchSummary(dispatchId)` | Read a redacted channel-specific summary. |
|
|
305
|
+
| `getDispatchEvents(dispatchId)` | Read persisted dispatch events. |
|
|
306
|
+
| `getDispatchProof(dispatchId)` | Read the proof bundle and event-chain verification result. |
|
|
307
|
+
| `cancelDispatch(dispatchId)` | Request cancellation of a dispatch. |
|
|
308
|
+
| `getWallet()` | Read the current wallet balance. |
|
|
309
|
+
|
|
310
|
+
The SDK does not automatically approve, pay for, or dispatch a draft.
|
|
311
|
+
|
|
312
|
+
## Idempotency and retries
|
|
313
|
+
|
|
314
|
+
The SDK does not automatically retry requests.
|
|
315
|
+
|
|
316
|
+
`createDispatch()` and `createDirectPaymentSession()` require an idempotency
|
|
317
|
+
key. Reuse a key only when retrying the identical logical operation.
|
|
318
|
+
|
|
319
|
+
```ts
|
|
320
|
+
async function createCheckout(draftId: string, quoteId: string, approvalId: string) {
|
|
321
|
+
const idempotencyKey = `checkout:${draftId}:${approvalId}`;
|
|
322
|
+
|
|
323
|
+
return api.createDirectPaymentSession(
|
|
324
|
+
draftId,
|
|
325
|
+
{
|
|
326
|
+
quote_id: quoteId,
|
|
327
|
+
approval_id: approvalId,
|
|
328
|
+
},
|
|
329
|
+
idempotencyKey,
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
Idempotency keys must contain 8 to 200 letters, digits, dots, underscores,
|
|
335
|
+
colons, or dashes. Consult `papierApiOperations[name].safeToRetry` before adding
|
|
336
|
+
custom retry behavior around another operation.
|
|
337
|
+
|
|
338
|
+
## Error handling
|
|
339
|
+
|
|
340
|
+
```ts
|
|
341
|
+
import {
|
|
342
|
+
PapierApiContractError,
|
|
343
|
+
PapierApiError,
|
|
344
|
+
PapierApiTransportError,
|
|
345
|
+
} from "@papierapi/sdk";
|
|
346
|
+
|
|
347
|
+
try {
|
|
348
|
+
const dispatch = await api.getDispatch("dsp_...");
|
|
349
|
+
console.log(dispatch.data.status);
|
|
350
|
+
} catch (error) {
|
|
351
|
+
if (error instanceof PapierApiError) {
|
|
352
|
+
console.error({
|
|
353
|
+
status: error.status,
|
|
354
|
+
code: error.code,
|
|
355
|
+
requestId: error.requestId,
|
|
356
|
+
retryable: error.retryable,
|
|
357
|
+
fieldPath: error.fieldPath,
|
|
358
|
+
suggestedAction: error.suggestedAction,
|
|
359
|
+
});
|
|
360
|
+
} else if (error instanceof PapierApiTransportError) {
|
|
361
|
+
console.error({ reason: error.reason, retryable: error.retryable });
|
|
362
|
+
} else if (error instanceof PapierApiContractError) {
|
|
363
|
+
console.error({ operationId: error.operationId, status: error.status });
|
|
364
|
+
} else {
|
|
365
|
+
throw error;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
Error categories:
|
|
371
|
+
|
|
372
|
+
| Error | Meaning |
|
|
373
|
+
| --- | --- |
|
|
374
|
+
| `PapierApiError` | The API returned a valid structured error response. |
|
|
375
|
+
| `PapierApiTransportError` | The request timed out or the network was unavailable. |
|
|
376
|
+
| `PapierApiContractError` | A response was malformed, too large, or incompatible with the SDK contract. |
|
|
377
|
+
| `TypeError` | Client configuration, token, timeout, response limit, or PDF bounds are invalid. |
|
|
378
|
+
| `ZodError` | A method input, identifier, query parameter, or idempotency key violates the published schema. |
|
|
379
|
+
|
|
380
|
+
Use `requestId` when contacting support about an API response.
|
|
381
|
+
|
|
382
|
+
## Operation registry
|
|
383
|
+
|
|
384
|
+
The canonical machine-readable operation registry is exported from the
|
|
385
|
+
side-effect-free `@papierapi/sdk/operations` entry point.
|
|
386
|
+
|
|
387
|
+
```ts
|
|
388
|
+
import {
|
|
389
|
+
papierApiOperations,
|
|
390
|
+
type PapierApiOperationName,
|
|
391
|
+
type PapierApiOperationResponse,
|
|
392
|
+
} from "@papierapi/sdk/operations";
|
|
393
|
+
|
|
394
|
+
const operationName = "getDispatch" satisfies PapierApiOperationName;
|
|
395
|
+
const operation = papierApiOperations[operationName];
|
|
396
|
+
|
|
397
|
+
console.log({
|
|
398
|
+
method: operation.method,
|
|
399
|
+
path: operation.path,
|
|
400
|
+
safeToRetry: operation.safeToRetry,
|
|
401
|
+
requiresIdempotencyKey: operation.requiresIdempotencyKey,
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
type GetDispatchResponse = PapierApiOperationResponse<"getDispatch">;
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
Each registry entry includes the HTTP method, path, request kind, path and query
|
|
408
|
+
schemas, response schema, retry classification, and idempotency requirement.
|
|
409
|
+
|
|
410
|
+
## Custom Fetch implementation
|
|
411
|
+
|
|
412
|
+
Inject `fetcher` to integrate tracing, testing, a proxy, or another compatible
|
|
413
|
+
runtime. It must implement the standard Fetch signature and return a standard
|
|
414
|
+
`Response`.
|
|
415
|
+
|
|
416
|
+
```ts
|
|
417
|
+
const api = new PapierApiClient({
|
|
418
|
+
baseUrl: "http://127.0.0.1:8787",
|
|
419
|
+
accessToken: "pap_test_token",
|
|
420
|
+
fetcher: async (input, init) => {
|
|
421
|
+
telemetry.recordRequest(input, init);
|
|
422
|
+
return fetch(input, init);
|
|
423
|
+
},
|
|
424
|
+
timeoutMs: 10_000,
|
|
425
|
+
});
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Plain HTTP is accepted only for `localhost` and `127.0.0.1`. Production origins
|
|
429
|
+
must use HTTPS.
|
|
430
|
+
|
|
431
|
+
## Security and runtime behavior
|
|
432
|
+
|
|
433
|
+
- Bearer tokens are resolved immediately before every request.
|
|
434
|
+
- Request inputs and identifiers are validated before network access.
|
|
435
|
+
- API responses are size-bounded and schema-validated before being returned.
|
|
436
|
+
- Requests time out through `AbortController`.
|
|
437
|
+
- PDF uploads are copied into a request `Blob` where required.
|
|
438
|
+
- The SDK does not persist credentials, documents, responses, or approval data.
|
|
439
|
+
- The SDK does not perform hidden retries or background dispatches.
|
|
440
|
+
|
|
441
|
+
## API contract and support
|
|
442
|
+
|
|
443
|
+
- [OpenAPI 3.1 contract](https://api.papierapi.de/openapi.json)
|
|
444
|
+
- [Developer area](https://app.papierapi.de/developers)
|
|
445
|
+
- [Product documentation](https://papierapi.de/entwickler)
|
|
446
|
+
- Technical support: [support@papierapi.de](mailto:support@papierapi.de)
|
|
447
|
+
|
|
448
|
+
## License
|
|
449
|
+
|
|
450
|
+
MIT. See [LICENSE](LICENSE).
|