@getpeppr/sdk 0.2.0 → 1.0.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/README.md +114 -325
- package/dist/core/client.d.ts +37 -7
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/client.js +69 -7
- package/dist/core/client.js.map +1 -1
- package/dist/core/validator.d.ts.map +1 -1
- package/dist/core/validator.js +15 -0
- package/dist/core/validator.js.map +1 -1
- package/dist/index.d.ts +10 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -1
- package/dist/types/invoice.d.ts +64 -3
- package/dist/types/invoice.d.ts.map +1 -1
- package/package.json +10 -8
package/README.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# @getpeppr/sdk
|
|
2
2
|
|
|
3
|
-
Send Peppol e-invoices in
|
|
3
|
+
Send Peppol e-invoices in under 20 lines of code.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@getpeppr/sdk)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
[](https://www.typescriptlang.org/)
|
|
8
|
+
[](https://nodejs.org/)
|
|
8
9
|
|
|
9
10
|
```typescript
|
|
10
11
|
import { Peppol } from "@getpeppr/sdk";
|
|
@@ -13,13 +14,20 @@ const peppol = new Peppol({ apiKey: "sk_live_..." });
|
|
|
13
14
|
|
|
14
15
|
const result = await peppol.invoices.send({
|
|
15
16
|
number: "INV-2026-001",
|
|
16
|
-
to: {
|
|
17
|
+
to: {
|
|
18
|
+
name: "Acme Corp",
|
|
19
|
+
peppolId: "0208:BE9876543210",
|
|
20
|
+
street: "123 Business Ave",
|
|
21
|
+
city: "Brussels",
|
|
22
|
+
postalCode: "1000",
|
|
23
|
+
country: "BE",
|
|
24
|
+
},
|
|
17
25
|
lines: [
|
|
18
26
|
{ description: "Consulting services", quantity: 10, unitPrice: 150, vatRate: 21 },
|
|
19
27
|
],
|
|
20
28
|
});
|
|
21
29
|
|
|
22
|
-
console.log(`Invoice sent!
|
|
30
|
+
console.log(`Invoice sent! ID: ${result.id}`);
|
|
23
31
|
```
|
|
24
32
|
|
|
25
33
|
## Installation
|
|
@@ -30,402 +38,163 @@ npm install @getpeppr/sdk
|
|
|
30
38
|
|
|
31
39
|
## Features
|
|
32
40
|
|
|
33
|
-
- **Stripe-like
|
|
41
|
+
- **Stripe-like DX** -- JSON in, Peppol out
|
|
34
42
|
- **Full Peppol BIS 3.0 compliance** -- UBL 2.1 XML generation handled for you
|
|
35
|
-
- **
|
|
36
|
-
- **
|
|
37
|
-
- **Credit notes** with automatic UBL CreditNote generation
|
|
38
|
-
- **PDF and XML export** -- download invoices in any format
|
|
43
|
+
- **All invoice types** -- standard (380), credit note (381), debit (383), prepayment (386), self-billed (389)
|
|
44
|
+
- **Client-side + server-side validation** -- XSD and Schematron rules
|
|
39
45
|
- **Peppol Directory lookup** -- verify participants before sending
|
|
40
|
-
- **Events API** with async pagination
|
|
41
|
-
- **Batch send** with concurrency control
|
|
42
46
|
- **Webhook signature verification** -- HMAC-SHA256 with replay protection
|
|
43
|
-
- **
|
|
44
|
-
- **
|
|
45
|
-
- **
|
|
46
|
-
|
|
47
|
-
## Configuration
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
import { Peppol } from "@getpeppr/sdk";
|
|
51
|
-
|
|
52
|
-
const peppol = new Peppol({
|
|
53
|
-
apiKey: "sk_live_...", // Required. Starts with sk_sandbox_ or sk_live_
|
|
54
|
-
baseUrl: "https://...", // Custom gateway URL (default: https://api.getpeppr.dev/v1)
|
|
55
|
-
timeout: 30000, // Request timeout in ms (default: 30s)
|
|
56
|
-
retry: {
|
|
57
|
-
maxRetries: 3, // Max retry attempts (default: 3)
|
|
58
|
-
initialDelayMs: 500, // Initial retry delay (default: 500ms)
|
|
59
|
-
maxDelayMs: 30000, // Max retry delay (default: 30s)
|
|
60
|
-
},
|
|
61
|
-
});
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
## Sending Invoices
|
|
65
|
-
|
|
66
|
-
### Basic invoice
|
|
67
|
-
|
|
68
|
-
```typescript
|
|
69
|
-
const result = await peppol.invoices.send({
|
|
70
|
-
number: "INV-2026-001",
|
|
71
|
-
to: {
|
|
72
|
-
name: "Acme Corp",
|
|
73
|
-
peppolId: "0208:BE9876543210",
|
|
74
|
-
country: "BE",
|
|
75
|
-
},
|
|
76
|
-
lines: [
|
|
77
|
-
{ description: "Consulting services", quantity: 10, unitPrice: 150, vatRate: 21 },
|
|
78
|
-
],
|
|
79
|
-
});
|
|
47
|
+
- **Batch send** with concurrency control
|
|
48
|
+
- **Built-in retry** with exponential backoff and rate limit handling
|
|
49
|
+
- **Async pagination** -- iterate over all invoices, events, contacts
|
|
50
|
+
- **TypeScript-first**, zero dependencies
|
|
80
51
|
|
|
81
|
-
|
|
82
|
-
console.log(result.status); // "new" | "sent" | ...
|
|
83
|
-
```
|
|
52
|
+
## Quick Examples
|
|
84
53
|
|
|
85
|
-
###
|
|
54
|
+
### Create draft + send later
|
|
86
55
|
|
|
87
56
|
```typescript
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
number: "INV-2026-001",
|
|
57
|
+
const draft = await peppol.invoices.create({
|
|
58
|
+
number: "INV-2026-002",
|
|
91
59
|
to: {
|
|
92
60
|
name: "Acme Corp",
|
|
93
61
|
peppolId: "0208:BE9876543210",
|
|
94
|
-
vatNumber: "BE9876543210",
|
|
95
62
|
street: "123 Business Ave",
|
|
96
63
|
city: "Brussels",
|
|
97
64
|
postalCode: "1000",
|
|
98
65
|
country: "BE",
|
|
99
|
-
companyId: "0876543210",
|
|
100
|
-
contactName: "Jane Doe",
|
|
101
|
-
phone: "+32 2 123 4567",
|
|
102
|
-
email: "invoices@acme.be",
|
|
103
|
-
},
|
|
104
|
-
lines: [
|
|
105
|
-
{
|
|
106
|
-
description: "Consulting services",
|
|
107
|
-
quantity: 10,
|
|
108
|
-
unit: "hours", // Human-readable: "hours", "days", "kg", or UN/ECE: "HUR", "DAY"
|
|
109
|
-
unitPrice: 150,
|
|
110
|
-
vatRate: 21,
|
|
111
|
-
vatCategory: "S", // S=standard, Z=zero-rated, E=exempt, AE=reverse charge
|
|
112
|
-
itemId: "SRV-001",
|
|
113
|
-
allowances: [{ reason: "Loyalty discount", amount: 50 }],
|
|
114
|
-
charges: [{ reason: "Express delivery", amount: 25 }],
|
|
115
|
-
},
|
|
116
|
-
],
|
|
117
|
-
|
|
118
|
-
// Optional
|
|
119
|
-
date: "2026-01-15", // Invoice date (default: today)
|
|
120
|
-
dueDate: "2026-02-15", // Due date
|
|
121
|
-
currency: "EUR", // ISO 4217 (default: EUR)
|
|
122
|
-
taxCurrency: "GBP", // Tax reporting currency if different
|
|
123
|
-
taxCurrencyRate: 0.86, // Exchange rate to tax currency
|
|
124
|
-
buyerReference: "PO-2026-042", // Buyer reference (BT-10)
|
|
125
|
-
orderReference: "ORD-789", // Purchase order number
|
|
126
|
-
note: "Thank you for your business",
|
|
127
|
-
paymentTerms: "Net 30 days",
|
|
128
|
-
paymentMeans: 30, // 30=credit transfer, 58=SEPA
|
|
129
|
-
paymentIban: "BE68539007547034",
|
|
130
|
-
paymentBic: "BBRUBEBB",
|
|
131
|
-
paymentReference: "+++090/9337/55493+++",
|
|
132
|
-
|
|
133
|
-
payeeParty: { // When payment recipient differs from seller
|
|
134
|
-
name: "Factoring Co",
|
|
135
|
-
peppolId: "0208:BE1111111111",
|
|
136
|
-
country: "BE",
|
|
137
66
|
},
|
|
138
|
-
|
|
139
|
-
invoicePeriod: { // Billing period (common for SaaS)
|
|
140
|
-
startDate: "2026-01-01",
|
|
141
|
-
endDate: "2026-01-31",
|
|
142
|
-
},
|
|
143
|
-
|
|
144
|
-
delivery: { // Delivery information
|
|
145
|
-
date: "2026-01-20",
|
|
146
|
-
locationId: "LOC-001",
|
|
147
|
-
address: { street: "456 Warehouse Rd", city: "Antwerp", postalCode: "2000", country: "BE" },
|
|
148
|
-
},
|
|
149
|
-
|
|
150
|
-
allowances: [{ reason: "Volume discount", amount: 100, vatRate: 21 }],
|
|
151
|
-
charges: [{ reason: "Handling fee", amount: 25, vatRate: 21 }],
|
|
152
|
-
|
|
153
|
-
attachments: [
|
|
154
|
-
{
|
|
155
|
-
id: "ATT-001",
|
|
156
|
-
description: "Timesheet",
|
|
157
|
-
filename: "timesheet.pdf",
|
|
158
|
-
mimeType: "application/pdf",
|
|
159
|
-
content: "base64-encoded-content...", // Or use `url` for external reference
|
|
160
|
-
},
|
|
161
|
-
],
|
|
162
|
-
});
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
### Create draft + send later
|
|
166
|
-
|
|
167
|
-
```typescript
|
|
168
|
-
const draft = await peppol.invoices.create({
|
|
169
|
-
number: "INV-2026-002",
|
|
170
|
-
to: { name: "Acme Corp", peppolId: "0208:BE9876543210", country: "BE" },
|
|
171
67
|
lines: [{ description: "Consulting", quantity: 5, unitPrice: 200, vatRate: 21 }],
|
|
172
68
|
});
|
|
173
69
|
|
|
174
|
-
console.log(draft.id); // "inv-xyz456"
|
|
175
|
-
console.log(draft.status); // "new"
|
|
176
|
-
|
|
177
70
|
// Send when ready
|
|
178
71
|
await peppol.invoices.sendById(draft.id);
|
|
179
72
|
```
|
|
180
73
|
|
|
181
|
-
### Credit
|
|
74
|
+
### Credit note
|
|
182
75
|
|
|
183
76
|
```typescript
|
|
184
|
-
const
|
|
77
|
+
const creditNote = await peppol.invoices.send({
|
|
185
78
|
number: "CN-2026-001",
|
|
186
79
|
isCreditNote: true,
|
|
187
|
-
invoiceReference: "INV-2026-001",
|
|
188
|
-
to: {
|
|
80
|
+
invoiceReference: "INV-2026-001",
|
|
81
|
+
to: {
|
|
82
|
+
name: "Acme Corp",
|
|
83
|
+
peppolId: "0208:BE9876543210",
|
|
84
|
+
street: "123 Business Ave",
|
|
85
|
+
city: "Brussels",
|
|
86
|
+
postalCode: "1000",
|
|
87
|
+
country: "BE",
|
|
88
|
+
},
|
|
189
89
|
lines: [
|
|
190
90
|
{ description: "Refund for consulting services", quantity: 2, unitPrice: 150, vatRate: 21 },
|
|
191
91
|
],
|
|
192
92
|
});
|
|
193
93
|
```
|
|
194
94
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
### Single page
|
|
95
|
+
### Webhook verification
|
|
198
96
|
|
|
199
97
|
```typescript
|
|
200
|
-
|
|
201
|
-
limit: 25,
|
|
202
|
-
offset: 0,
|
|
203
|
-
type: "issued", // "issued" | "received"
|
|
204
|
-
includeLines: true, // Include line item details
|
|
205
|
-
});
|
|
98
|
+
import { webhooks } from "@getpeppr/sdk";
|
|
206
99
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
for await (const invoice of peppol.invoices.listAll({ type: "issued" })) {
|
|
215
|
-
console.log(invoice.id, invoice.number, invoice.status);
|
|
216
|
-
}
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
## Invoice Status
|
|
220
|
-
|
|
221
|
-
### Get current status
|
|
222
|
-
|
|
223
|
-
```typescript
|
|
224
|
-
const result = await peppol.invoices.getStatus("inv-abc123");
|
|
225
|
-
console.log(result.status); // "sent", "accepted", etc.
|
|
226
|
-
```
|
|
100
|
+
app.post("/webhooks/peppol", async (req, res) => {
|
|
101
|
+
try {
|
|
102
|
+
const event = await webhooks.constructEvent(
|
|
103
|
+
req.body, // Raw body string (NOT parsed JSON)
|
|
104
|
+
req.headers["getpeppr-signature"], // Getpeppr-Signature header
|
|
105
|
+
"whsec_your_webhook_secret", // Your webhook secret
|
|
106
|
+
);
|
|
227
107
|
|
|
228
|
-
|
|
108
|
+
switch (event.type) {
|
|
109
|
+
case "invoice.accepted":
|
|
110
|
+
console.log("Invoice accepted:", event.data);
|
|
111
|
+
break;
|
|
112
|
+
case "invoice.received":
|
|
113
|
+
console.log("New invoice received:", event.data);
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
229
116
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
117
|
+
res.sendStatus(200);
|
|
118
|
+
} catch (err) {
|
|
119
|
+
res.status(400).send("Webhook verification failed");
|
|
120
|
+
}
|
|
234
121
|
});
|
|
235
122
|
```
|
|
236
123
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
```typescript
|
|
240
|
-
const result = await peppol.invoices.waitFor("inv-abc123", ["accepted", "paid"]);
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
Terminal failure statuses (`error`, `refused`, `invalid`) throw immediately without waiting for timeout.
|
|
244
|
-
|
|
245
|
-
### Document status lifecycle
|
|
246
|
-
|
|
247
|
-
```
|
|
248
|
-
new --> sent --> downloaded --> registered --> accepted --> paid --> closed
|
|
249
|
-
\-> refused
|
|
250
|
-
\-> error
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
## Export PDF / XML
|
|
254
|
-
|
|
255
|
-
```typescript
|
|
256
|
-
import { writeFileSync } from "fs";
|
|
257
|
-
|
|
258
|
-
// Export as PDF
|
|
259
|
-
const pdf = await peppol.invoices.getAs("inv-abc123", "pdf");
|
|
260
|
-
writeFileSync("invoice.pdf", Buffer.from(pdf));
|
|
261
|
-
|
|
262
|
-
// Export as UBL XML
|
|
263
|
-
const xml = await peppol.invoices.getAs("inv-abc123", "xml.ubl.invoice.bis3");
|
|
264
|
-
writeFileSync("invoice.xml", Buffer.from(xml));
|
|
265
|
-
|
|
266
|
-
// Available formats: "pdf" | "xml.ubl.invoice.bis3" | "xml.facturae.3.2" | "original"
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
## Acknowledge Received Invoice
|
|
124
|
+
### Directory lookup
|
|
270
125
|
|
|
271
126
|
```typescript
|
|
272
|
-
const
|
|
273
|
-
console.log(
|
|
127
|
+
const entry = await peppol.directory.lookup("0208:BE0123456789");
|
|
128
|
+
console.log(entry.name); // "My Company NV"
|
|
129
|
+
console.log(entry.country); // "BE"
|
|
130
|
+
console.log(entry.capabilities); // ["invoice", "credit_note"]
|
|
274
131
|
```
|
|
275
132
|
|
|
276
|
-
|
|
133
|
+
### Batch send
|
|
277
134
|
|
|
278
135
|
```typescript
|
|
279
|
-
const invoices = [invoice1, invoice2, invoice3
|
|
136
|
+
const invoices = [invoice1, invoice2, invoice3];
|
|
280
137
|
|
|
281
138
|
const result = await peppol.invoices.sendBatch(invoices, {
|
|
282
|
-
concurrency: 5,
|
|
283
|
-
stopOnError: false,
|
|
139
|
+
concurrency: 5,
|
|
140
|
+
stopOnError: false,
|
|
284
141
|
});
|
|
285
142
|
|
|
286
143
|
console.log(`${result.succeeded.length} sent, ${result.failed.length} failed`);
|
|
287
|
-
|
|
288
|
-
for (const failure of result.failed) {
|
|
289
|
-
console.error(`Invoice #${failure.index} (${failure.input.number}): ${failure.error.message}`);
|
|
290
|
-
}
|
|
291
144
|
```
|
|
292
145
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
```typescript
|
|
296
|
-
const entry = await peppol.directory.lookup("0208:BE0123456789");
|
|
297
|
-
|
|
298
|
-
console.log(entry.name); // "My Company NV"
|
|
299
|
-
console.log(entry.country); // "BE"
|
|
300
|
-
console.log(entry.capabilities); // ["invoice", "credit_note"]
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
## Validation
|
|
304
|
-
|
|
305
|
-
### Client-side validation (instant, offline)
|
|
146
|
+
### Client-side validation
|
|
306
147
|
|
|
307
148
|
```typescript
|
|
308
149
|
const result = peppol.validate({
|
|
309
150
|
number: "INV-001",
|
|
310
|
-
to: {
|
|
151
|
+
to: {
|
|
152
|
+
name: "Acme",
|
|
153
|
+
peppolId: "0208:BE9876543210",
|
|
154
|
+
street: "123 Business Ave",
|
|
155
|
+
city: "Brussels",
|
|
156
|
+
postalCode: "1000",
|
|
157
|
+
country: "BE",
|
|
158
|
+
},
|
|
311
159
|
lines: [{ description: "Item", quantity: 1, unitPrice: 100, vatRate: 21 }],
|
|
312
160
|
});
|
|
313
161
|
|
|
314
162
|
if (!result.valid) {
|
|
315
163
|
for (const err of result.errors) {
|
|
316
164
|
console.log(`${err.field}: ${err.message}`);
|
|
317
|
-
if (err.suggestion) console.log(` Fix: ${err.suggestion}`);
|
|
318
165
|
}
|
|
319
166
|
}
|
|
320
|
-
|
|
321
|
-
for (const warn of result.warnings) {
|
|
322
|
-
console.log(`Warning: ${warn.field}: ${warn.message}`);
|
|
323
|
-
}
|
|
324
167
|
```
|
|
325
168
|
|
|
326
|
-
###
|
|
169
|
+
### Export PDF / XML
|
|
327
170
|
|
|
328
171
|
```typescript
|
|
329
|
-
|
|
330
|
-
number: "INV-001",
|
|
331
|
-
to: { name: "Acme", peppolId: "0208:BE9876543210", country: "BE" },
|
|
332
|
-
lines: [{ description: "Item", quantity: 1, unitPrice: 100, vatRate: 21 }],
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
console.log(result.valid); // true/false
|
|
336
|
-
console.log(result.xsd.errors); // XSD schema errors
|
|
337
|
-
console.log(result.schematron.errors); // Peppol business rule errors
|
|
338
|
-
console.log(result.schematron.warnings); // Non-blocking warnings
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
## Events
|
|
342
|
-
|
|
343
|
-
### List events
|
|
344
|
-
|
|
345
|
-
```typescript
|
|
346
|
-
const result = await peppol.events.list({
|
|
347
|
-
limit: 10,
|
|
348
|
-
invoiceId: "inv-abc123", // Filter by invoice
|
|
349
|
-
dateFrom: "2026-01-01", // Filter by date range
|
|
350
|
-
dateTo: "2026-01-31",
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
for (const event of result.data) {
|
|
354
|
-
console.log(event.name, event.text, event.createdAt);
|
|
355
|
-
}
|
|
356
|
-
```
|
|
172
|
+
import { writeFileSync } from "fs";
|
|
357
173
|
|
|
358
|
-
|
|
174
|
+
const pdf = await peppol.invoices.getAs("inv-abc123", "pdf");
|
|
175
|
+
writeFileSync("invoice.pdf", Buffer.from(pdf));
|
|
359
176
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
console.log(event.name, event.createdAt);
|
|
363
|
-
}
|
|
177
|
+
const xml = await peppol.invoices.getAs("inv-abc123", "xml.ubl.invoice.bis3");
|
|
178
|
+
writeFileSync("invoice.xml", Buffer.from(xml));
|
|
364
179
|
```
|
|
365
180
|
|
|
366
|
-
##
|
|
367
|
-
|
|
368
|
-
Verify and parse incoming webhook payloads with HMAC-SHA256 signature verification and replay protection.
|
|
181
|
+
## Configuration
|
|
369
182
|
|
|
370
183
|
```typescript
|
|
371
|
-
import { Peppol
|
|
372
|
-
|
|
373
|
-
// Express example
|
|
374
|
-
app.post("/webhooks/peppol", async (req, res) => {
|
|
375
|
-
try {
|
|
376
|
-
const event = await webhooks.constructEvent(
|
|
377
|
-
req.body, // Raw body string (NOT parsed JSON)
|
|
378
|
-
req.headers["x-b2brouter-signature"], // Signature header
|
|
379
|
-
"whsec_your_webhook_secret", // Your webhook secret
|
|
380
|
-
);
|
|
381
|
-
|
|
382
|
-
switch (event.type) {
|
|
383
|
-
case "invoice.accepted":
|
|
384
|
-
console.log("Invoice accepted:", event.data);
|
|
385
|
-
break;
|
|
386
|
-
case "invoice.refused":
|
|
387
|
-
console.log("Invoice refused:", event.data);
|
|
388
|
-
break;
|
|
389
|
-
case "invoice.received":
|
|
390
|
-
console.log("New invoice received:", event.data);
|
|
391
|
-
break;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
res.sendStatus(200);
|
|
395
|
-
} catch (err) {
|
|
396
|
-
console.error("Webhook verification failed:", err.message);
|
|
397
|
-
res.status(400).send("Webhook verification failed");
|
|
398
|
-
}
|
|
399
|
-
});
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
Supported event types:
|
|
403
|
-
|
|
404
|
-
| Event | Description |
|
|
405
|
-
|-------|-------------|
|
|
406
|
-
| `invoice.sent` | Invoice sent to Peppol network |
|
|
407
|
-
| `invoice.accepted` | Recipient accepted the invoice |
|
|
408
|
-
| `invoice.refused` | Recipient refused the invoice |
|
|
409
|
-
| `invoice.error` | Delivery error |
|
|
410
|
-
| `invoice.registered` | Invoice registered by recipient |
|
|
411
|
-
| `invoice.paid` | Invoice marked as paid |
|
|
412
|
-
| `invoice.closed` | Invoice closed |
|
|
413
|
-
| `invoice.received` | New invoice received |
|
|
414
|
-
| `creditnote.sent` | Credit note sent |
|
|
415
|
-
| `creditnote.received` | Credit note received |
|
|
416
|
-
|
|
417
|
-
## UBL XML Generation
|
|
418
|
-
|
|
419
|
-
Generate UBL 2.1 XML without sending (useful for debugging or manual submission):
|
|
184
|
+
import { Peppol } from "@getpeppr/sdk";
|
|
420
185
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
186
|
+
const peppol = new Peppol({
|
|
187
|
+
apiKey: "sk_live_...", // Required. Starts with sk_sandbox_ or sk_live_
|
|
188
|
+
baseUrl: "https://...", // Default: https://api.getpeppr.dev/v1
|
|
189
|
+
timeout: 30000, // Request timeout in ms (default: 30s)
|
|
190
|
+
retry: {
|
|
191
|
+
maxRetries: 3, // Max retry attempts (default: 3)
|
|
192
|
+
initialDelayMs: 500, // Initial retry delay (default: 500ms)
|
|
193
|
+
maxDelayMs: 30000, // Max retry delay (default: 30s)
|
|
194
|
+
},
|
|
195
|
+
onRequest: (entry) => {}, // Optional request hook
|
|
196
|
+
onResponse: (entry) => {}, // Optional response hook
|
|
426
197
|
});
|
|
427
|
-
|
|
428
|
-
console.log(xml); // Full UBL 2.1 Invoice XML
|
|
429
198
|
```
|
|
430
199
|
|
|
431
200
|
## Error Handling
|
|
@@ -440,7 +209,7 @@ try {
|
|
|
440
209
|
} catch (err) {
|
|
441
210
|
if (err instanceof PeppolValidationError) {
|
|
442
211
|
// Client-side validation failed
|
|
443
|
-
console.log(err.validation.errors);
|
|
212
|
+
console.log(err.validation.errors); // ValidationError[]
|
|
444
213
|
console.log(err.validation.warnings); // ValidationWarning[]
|
|
445
214
|
} else if (err instanceof PeppolApiError) {
|
|
446
215
|
// API returned an error
|
|
@@ -454,9 +223,29 @@ try {
|
|
|
454
223
|
}
|
|
455
224
|
```
|
|
456
225
|
|
|
457
|
-
|
|
226
|
+
Transient errors (429, 500, 502, 503, 504) are automatically retried with exponential backoff and jitter. Rate limit responses (429) respect the `Retry-After` header.
|
|
227
|
+
|
|
228
|
+
## Webhook Events
|
|
229
|
+
|
|
230
|
+
| Event | Description |
|
|
231
|
+
|-------|-------------|
|
|
232
|
+
| `invoice.sent` | Invoice sent to the Peppol network |
|
|
233
|
+
| `invoice.accepted` | Recipient accepted the invoice |
|
|
234
|
+
| `invoice.refused` | Recipient refused the invoice |
|
|
235
|
+
| `invoice.error` | Delivery error |
|
|
236
|
+
| `invoice.registered` | Invoice registered by recipient |
|
|
237
|
+
| `invoice.paid` | Invoice marked as paid |
|
|
238
|
+
| `invoice.closed` | Invoice closed |
|
|
239
|
+
| `invoice.received` | New invoice received from the network |
|
|
240
|
+
| `creditnote.sent` | Credit note sent |
|
|
241
|
+
| `creditnote.received` | Credit note received |
|
|
242
|
+
| `test.ping` | Test event for endpoint verification |
|
|
243
|
+
|
|
244
|
+
## Links
|
|
458
245
|
|
|
459
|
-
|
|
246
|
+
- [Documentation](https://getpeppr.dev/docs)
|
|
247
|
+
- [Website](https://getpeppr.dev)
|
|
248
|
+
- [GitHub](https://github.com/zerolooplabs/getpeppr)
|
|
460
249
|
|
|
461
250
|
## License
|
|
462
251
|
|