# peppol.sh

> Peppol e-invoicing API for developers. JSON in, e-invoice out, delivered via Peppol.

## What is peppol.sh?

peppol.sh is a REST API that lets you send e-invoices, credit notes, and other business documents via the Peppol network. You send simple JSON, we convert it to compliant Peppol BIS 3.0 UBL XML and deliver it to the recipient via Peppol.

## When to use peppol.sh

Use peppol.sh when you need to:
- Send e-invoices to businesses or governments in the EU via Peppol
- Validate UBL XML documents against Peppol BIS 3.0 and EN16931 rules
- Look up whether a business is registered on the Peppol network
- Generate valid e-invoices from structured JSON data
- Automate invoicing workflows without learning UBL/Peppol standards

## When NOT to use peppol.sh

- You need to receive invoices (peppol.sh sends documents, it does not receive them)
- You need non-Peppol delivery channels (e.g. email-only invoicing)
- You operate outside the Peppol network coverage

## Authentication

API key via Bearer header. No OAuth required.

    Authorization: Bearer ps_test_...   (sandbox)
    Authorization: Bearer ps_live_...   (production)

Create an account with one request. The response has a sandbox key (ps_test_...) that works immediately, with no email verification:

    curl -X POST https://api.peppol.sh/v1/signup \
      -H "Content-Type: application/json" \
      -d '{"email": "agent@example.com"}'

## Environments

| Environment | Base URL                  | Keys     | Delivery                                 |
|-------------|---------------------------|----------|------------------------------------------|
| Sandbox     | https://sandbox.peppol.sh | ps_test_ | Simulated, no live Peppol network (free) |
| Production  | https://api.peppol.sh     | ps_live_ | The live Peppol network                  |

A key works on one host only. A key on the other host returns 403 with code wrong_environment.

## Key endpoints

| Method | Path                     | Description                           | API key  |
|--------|--------------------------|---------------------------------------|----------|
| POST   | /v1/signup               | Create account, get sandbox key       | None     |
| GET    | /v1/health               | Health check                          | None     |
| GET    | /v1/openapi.json         | OpenAPI 3.1 spec                      | None     |
| GET    | /v1/lookup/{peppol_id}   | Look up a Peppol participant          | Optional |
| POST   | /v1/ubl/xml              | Generate UBL XML from UBL-shaped JSON | None     |
| POST   | /v1/companies            | Create a company                      | Required |
| POST   | /v1/documents            | Send an invoice or credit note        | Required |
| GET    | /v1/documents            | List sent documents                   | Required |
| POST   | /v1/validate             | Validate an invoice (JSON or UBL XML) | Required |
| POST   | /v1/webhooks             | Register a webhook endpoint           | Required |

## Pricing

Credit-based. One credit = one document sent.

| Top-up   | Rate    | Credits | Mode               |
|----------|---------|---------|--------------------|
| €25      | €0.20   | 125     | Personal           |
| €100     | €0.18   | 555     | Personal           |
| €250     | €0.16   | 1,562   | Personal + Connect |
| €500     | €0.14   | 3,571   | Personal + Connect |
| €1,000   | €0.12   | 8,333   | Personal + Connect |
| €2,500+  | €0.10   | 25,000+ | Personal + Connect |

Sandbox is free forever. Credits never expire.

## Bootstrap flow

1. POST /v1/signup → account + sandbox API key (instant)
2. POST /v1/companies → create a company to send from
3. POST /v1/documents → send test invoices in sandbox
4. Verify the workspace (KYC), then create a live key with POST /v1/account/keys → send on the live Peppol network

## Rate limits

- Sandbox keys: 60 requests/minute
- Live keys: 120 requests/minute
- Lookup without a key: 60 requests/hour for each IP address
- Each response has RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset headers. A 429 response has a Retry-After header in seconds.

## Section documentation

- [API reference](https://peppol.sh/api/llms.txt)
- [Integrations](https://peppol.sh/for/llms.txt)
- [Documentation](https://peppol.sh/docs/llms.txt)
- [Full documentation (single file)](https://peppol.sh/llms-full.txt)

## Resources

- [OpenAPI spec](https://api.peppol.sh/v1/openapi.json)
- [Interactive docs](https://api.peppol.sh/)
- [Website](https://peppol.sh)
- [Developers](https://peppol.sh/developers.md): quickstart, base URLs, SDK and rate limits
- [Deprecation policy](https://peppol.sh/deprecation.md)
- [Contact](https://peppol.sh/contact.md)
- [Dashboard](https://app.peppol.sh)
- [TypeScript SDK](https://github.com/peppol-sh/peppol-sh-ts): `npm i @peppol-sh/sdk`
- [GitHub](https://github.com/peppol-sh)
- [SKILL.md](https://peppol.sh/.well-known/agent-skills/peppol-api/SKILL.md)
- [Agent card](https://peppol.sh/.well-known/agent.json)
- [Auth guide](https://peppol.sh/auth.md)
