Getting Started
Send your first invoice through the Peppol network in under 5 minutes.
Prerequisites
- An Invostaq account with a tenant (sign up at invostaq.com)
- An API key (starts with
sk_test_for sandbox orsk_live_for production)
Generate an API key from the Invostaq dashboard at Settings > API Keys. See the Authentication guide for details.
Step 1: Look up the recipient
Before sending an invoice, verify the recipient is registered on the Peppol network and get their routing info.
curl https://api.invostaq.com/api/v2/lookup?participantId=0196:971501234567 \
-H "x-api-key: sk_test_dGVzdGtleS0xMjM0NTY3ODkwYWJjZGVm"
{
"participantId": "0196:971501234567",
"isRegistered": true,
"accessPointRef": "AP-0196-971501234567",
"supportedDocTypes": [
"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
],
"provider": "Invostaq"
}
The response tells you:
isRegistered— whether the recipient can receive Peppol documentsaccessPointRef— the routing reference you need in Step 2supportedDocTypes— which document types the recipient accepts
If isRegistered is false, the recipient isn't on the Peppol network yet.
Step 2: Send the invoice
Post your invoice data with the routing information from Step 1. v2 is the recommended contract for new integrations.
curl -X POST https://api.invostaq.com/api/v2/invoices/send \
-H "x-api-key: sk_test_dGVzdGtleS0xMjM0NTY3ODkwYWJjZGVm" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: inv-2024-001-first-attempt" \
-d '{
"invoice": {
"number": "INV-2024-001",
"issueDate": "2024-06-15",
"currency": "EUR",
"supplier": {
"name": "Acme Trading NV",
"taxId": "BE0417497106",
"address": {
"line1": "Rue de la Loi 1",
"city": "Brussels",
"postalCode": "1000",
"countryCode": "BE"
}
},
"buyer": {
"name": "Gulf Imports Co",
"taxId": "971501234567",
"address": {
"line1": "Sheikh Zayed Road",
"city": "Dubai",
"countryCode": "AE"
}
},
"lineItems": [
{
"description": "Consulting services — June 2024",
"quantity": 1,
"unitPrice": 1000.00,
"taxRate": 21.0
}
],
"totals": {
"subtotal": 1000.00,
"taxAmount": 210.00,
"grandTotal": 1210.00
}
},
"routing": {
"senderParticipantId": "0208:0417497106",
"receiverParticipantId": "0196:971501234567",
"accessPointRef": "AP-0196-971501234567"
}
}'
{
"invoiceId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"transactionId": "txn_abc123def456",
"status": "success",
"networkStatus": "Processing",
"idempotencyKeyEcho": "inv-2024-001-first-attempt",
"provider": "Invostaq"
}
Your invoice is now being routed through the Peppol network. The initial networkStatus is Processing — it updates to Delivered or Failed once the recipient's Access Point responds.
About the Idempotency-Key: If your request times out or you're unsure whether it succeeded, retry with the same key. The API returns the original result without resubmitting to Peppol. Keys can be any string up to 128 characters — invoice numbers, UUIDs, or any value unique to this submission.
Note on
taxRate: Tax rates are specified as percentages. Use21.0for 21%, not0.21.
Step 3: Track delivery via webhooks
Set up a webhook to receive delivery status updates in real time. Register your endpoint from the Invostaq dashboard under Settings > Webhooks.
When the invoice is delivered, you receive:
{
"transactionId": "txn_abc123def456",
"eventType": "transaction.sent",
"status": "Delivered"
}
If delivery fails:
{
"transactionId": "txn_abc123def456",
"eventType": "transaction.failed",
"status": "Failed",
"reason": "Recipient Access Point unreachable"
}
Always respond with 200 OK. See the Webhooks guide for the full event reference and retry behavior.
Common mistakes
| Mistake | What happens | Fix |
|---|---|---|
Missing x-api-key header | 401 api-key-required | Add your API key to the header |
| Wrong participant ID format | 400 invalid-sender-id | Use ISO 6523 format: 0196:971501234567 |
| Declared totals inconsistent (v2) | 400 declared-totals-mismatch | grandTotal must equal subtotal + taxAmount; subtotal must equal sum of line extensions |
| Line totals don't add up (v1) | 400 totals-mismatch | Recalculate: sum(qty * price + tax) must match totalAmount within ±0.02 |
No Idempotency-Key on retry | Duplicate invoice sent | Always include an idempotency key |
What's next
| Guide | When you need it |
|---|---|
| API Overview | Invoice lifecycle, all endpoints at a glance |
| Authentication | Key management, sandbox vs. live, rate limits |
| Errors | Every error type with full JSON examples |
| Webhooks | Event types, security, retry behavior |
| curl Examples | Lookup, send, idempotency, error handling |
| TypeScript Examples | Full client with retry logic |