Peppol e-invoicing for developers. Send compliant invoices with one API call.
getpeppr is a developer-first API gateway for the Peppol e-invoicing network. You send JSON — we handle UBL XML, BIS 3.0 validation, and network delivery.
npm install @getpeppr/sdkimport { Peppol } from "@getpeppr/sdk";
const peppol = new Peppol({ apiKey: "sk_sandbox_..." });
const invoice = await peppol.invoices.send({
number: "INV-2026-001",
to: { name: "Globex NV", peppolId: "0208:BE0987654321", street: "Rue de la Loi 200", city: "Brussels", postalCode: "1000", country: "BE" },
lines: [{ description: "Consulting", quantity: 1, unitPrice: 1000, vatRate: 21 }],
});
console.log(invoice.status); // "submitted"curl -X POST https://api.getpeppr.dev/v1/invoices/send \
-H "Authorization: Bearer sk_sandbox_abc123..." \
-H "Content-Type: application/json" \
-d '{
"number": "INV-2026-001",
"to": {
"name": "Globex NV",
"peppolId": "0208:BE0987654321",
"street": "Rue de la Loi 200",
"city": "Brussels",
"postalCode": "1000",
"country": "BE"
},
"lines": [{
"description": "Consulting",
"quantity": 1,
"unitPrice": 1000,
"vatRate": 21
}]
}'# Install once
npm install -g @getpeppr/cli
# Authenticate (sandbox by default)
getpeppr login --key sk_sandbox_abc123... --sandbox
# Send a JSON file and watch delivery status
getpeppr send invoice.json --watch
# Or synthesize a quick test invoice from flags
getpeppr send --to 0208:BE0987654321 --amount 1000 --desc "Consulting"The CLI also handles offline validation (getpeppr validate), scaffolding (getpeppr init), UBL conversion (getpeppr convert), and Peppol Directory lookups (getpeppr lookup).
Full documentation is available at getpeppr.dev/docs.
| Guide | Description |
|---|---|
| Quick Start | Installation, first invoice, configuration |
| Onboarding Setup | Legal entity and Peppol identity setup |
| Authentication | API keys, environments, rate limits |
| Sandbox | Sandbox limitations, quotas, and going to production |
| Send an Invoice | Sending, attachments, allowances, delivery |
| Credit Notes | Correcting and cancelling invoices |
| Listing Invoices | Browsing your sent invoices |
| Validation | Client-side validation before sending |
| Contacts & Directory | Contact management and Peppol Directory lookup |
| Document Status | Tracking delivery lifecycle |
| Webhooks | Real-time event notifications |
| Error Handling | Error types, status codes, retries |
| CLI | Send invoices, manage credentials, validate, scaffold, convert, and lookup — all from the terminal |
| Type Definitions | TypeScript interface reference |
Import the collection into Postman for interactive API exploration.
- Open Postman → Import → select
postman/getpeppr.postman_collection.json - Set collection variables:
base_url→https://api.getpeppr.devapi_key→ your API key (e.g.sk_sandbox_abc123...)
| Language | Directory | Description |
|---|---|---|
| TypeScript | examples/typescript/ |
Full SDK examples |
| Python | examples/python/ |
HTTP examples with requests |
| cURL | examples/curl/ |
Command-line examples |
Send an invoice, track its delivery, and export it:
send → track status → export (PDF, XML, JSON)
| Method | Endpoint | SDK Method | Description |
|---|---|---|---|
POST |
/v1/invoices/send |
invoices.send() |
Validate, create, and send in one step |
GET |
/v1/invoices |
invoices.list() |
List invoices (paginated) |
GET |
/v1/invoices/:id |
invoices.getStatus() |
Get invoice details and delivery status |
GET |
/v1/invoices/:id/as/:format |
invoices.getAs() |
Export as PDF, XML, or JSON |
Invoices are immutable after submission — there are no drafts, updates, or deletes. To correct an invoice, send a credit note.
"submitted" → "delivered" → "accepted" → "paid"
→ "rejected"
→ "failed"
| Method | Endpoint | SDK Method | Description |
|---|---|---|---|
POST |
/v1/invoices/send |
invoices.send() |
Send a credit note (isCreditNote: true, must include invoiceReference) |
| Method | Endpoint | SDK Method | Description |
|---|---|---|---|
GET |
/v1/contacts |
contacts.list() |
List contacts (paginated) |
GET |
/v1/contacts/:id |
contacts.get() |
Get contact details |
POST |
/v1/contacts |
contacts.create() |
Create a contact |
PUT |
/v1/contacts/:id |
contacts.update() |
Update a contact |
DELETE |
/v1/contacts/:id |
contacts.delete() |
Delete a contact |
| Method | Endpoint | SDK Method | Description |
|---|---|---|---|
GET |
/v1/bank-accounts |
bankAccounts.list() |
List bank accounts (paginated) |
GET |
/v1/bank-accounts/:id |
bankAccounts.get() |
Get bank account details |
POST |
/v1/bank-accounts |
bankAccounts.create() |
Create a bank account |
PUT |
/v1/bank-accounts/:id |
bankAccounts.update() |
Update a bank account |
DELETE |
/v1/bank-accounts/:id |
bankAccounts.delete() |
Delete a bank account |
| Method | Endpoint | SDK Method | Description |
|---|---|---|---|
GET |
/v1/transports/types |
transports.listTypes() |
List available transport types |
GET |
/v1/transports |
transports.list() |
List configured transports |
GET |
/v1/transports/:code |
transports.get() |
Get transport details |
POST |
/v1/transports |
transports.create() |
Create a transport |
PUT |
/v1/transports/:code |
transports.update() |
Update a transport |
DELETE |
/v1/transports/:code |
transports.delete() |
Delete a transport |
Note: Transports are managed automatically by the Peppol network. These endpoints return static transport configurations — creating, updating, or deleting transports has no effect on invoice delivery routing.
| Method | Endpoint | SDK Method | Description |
|---|---|---|---|
GET |
/v1/directory/:scheme/:id |
directory.lookup() |
Lookup Peppol participant (enriched: name, country, capabilities, VAT, contacts, website) |
GET |
/v1/directory/search |
directory.search() |
Search Peppol Directory by name, country, or VAT |
Convenience method: directory.searchByVat(vatNumber) — searches by VAT number (country prefix stripped server-side).
| Method | Endpoint | SDK Method | Description |
|---|---|---|---|
POST |
/v1/validate |
peppol.validate() |
Validate invoice (client-side rules, BIS 3.0 + country-specific) |
| Method | Endpoint | SDK Method | Description |
|---|---|---|---|
GET |
/v1/events |
events.list() |
List usage events (paginated) |
Verify incoming webhook signatures using HMAC-SHA256:
import { webhooks } from "@getpeppr/sdk";
const event = await webhooks.constructEvent(
rawBody, // raw request body string
req.headers["getpeppr-signature"],
process.env.WEBHOOK_SECRET
);
console.log(event.type); // e.g. "invoice.delivered"Verify that a recipient is registered on the Peppol network before sending:
// Non-blocking mode — sends even if recipient not found (omit for no validation)
const invoice = await peppol.invoices.send(data, { validateRecipient: "warn" });
// Strict mode — rejects with 422 if recipient not found
const invoice = await peppol.invoices.send(data, { validateRecipient: "strict" });Also available via the x-validate-recipient header in REST calls.
Automatically paginate through all results:
for await (const invoice of peppol.invoices.listAll()) {
console.log(invoice.number);
}Also available on contacts.listAll(), bankAccounts.listAll(), and events.listAll().
Note:
invoices.list()returns outbound invoice submissions (invoices you sent). There is currently no endpoint for received invoices.
Send multiple invoices concurrently:
const result = await peppol.invoices.sendBatch(invoices, {
concurrency: 5,
stopOnError: false,
});
console.log(`${result.succeeded.length} sent, ${result.failed.length} failed`);Wait for an invoice to reach a target status:
const final = await peppol.invoices.waitFor(invoice.id, "accepted", {
interval: 2000, // poll every 2s
timeout: 60_000, // give up after 60s
});MIT — see LICENSE.
Built by Zero Loop Labs.