Receiving and statuses
How to track the status of sent invoices (GET /peppol/status), read inbound documents received over Peppol (GET /peppol/received), and how that relates to the peppol.document.received webhook. Both read operations require the invoice:read scope and the X-Organization-Id header.
Sent invoice status
| Method | Path | Scope |
|---|---|---|
| GET | /v1/agent/peppol/status/{invoiceId} | invoice:read |
Returns the latest (most recent) transmission for the given invoice. If no transmission exists yet for the invoice, it returns a synthetic not_sent status with no other fields.
GET /v1/agent/peppol/status/b1f0d7a2-…
X-API-Key: efk_pk_test_...
X-Organization-Id: 0a2c1f3e-…
{
"data": {
"invoice_id": "b1f0d7a2-…",
"state": "SENT",
"error_message": null,
"receiver_identifier": "9915:2010101010",
"document_id": "…",
"updated_at": "2026-06-22T10:00:05.000Z"
}
}| Field | Type | Description |
|---|---|---|
invoice_id | UUID | The invoice's ID. |
state | enum | The transmission status (see the state machine below). |
error_message | string | null | The failure reason for the ERROR state. |
receiver_identifier | string | null | The recipient's Peppol identifier (e.g. 9915:DIČ or 0245:DIČ). |
document_id | string | null | The document identifier within the transmission. |
updated_at | ISO 8601 | Time of the last status change. |
State machine
| State | Meaning | Action / when to retry |
|---|---|---|
not_sent | No transmission exists for the invoice yet: it has not been sent. | Call POST /peppol/send/{invoiceId}. |
QUEUED | The send is queued and waiting for a worker. | Wait and keep polling (or listen for the webhook). |
SENDING | A worker is currently sending the document via the AP. | Wait: this is a transient state. |
SENT | The document was accepted by the Peppol network (AS4 receipt). | Done at the send level. Delivery to the recipient is signaled by the delivered webhook. |
DEFERRED | The send is temporarily deferred (e.g. transient unavailability) and will be retried. | Don't retry the send manually: the system retries on its own. Keep polling. |
ERROR | The send failed permanently (see error_message). | Fix the cause (often a missing address / VAT ID) and send again. |
DELIVERED state (document delivered to the recipient) is carried by a separate peppol.document.delivered webhook event, at the GET /peppol/status level, the terminal successful send state is SENT. In the phoss-ap sandbox, delivery is confirmed right at submit time, so the transition to SENT is fast.While GET /peppol/status gives you one summary state, a detailed layer-by-layer delivery breakdown (AS4 transport / MLS / business response) and the full transmission history for audit and archiving are available via Delivery evidence (GET /v1/agent/peppol/sent/{invoiceId}/evidence).
Inbound documents
| Method | Path | Scope |
|---|---|---|
| GET | /v1/agent/peppol/received | invoice:read |
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | int 1–100 | 50 | Number of records. |
offset | int ≥ 0 | 0 | Pagination offset. |
Records are sorted from newest first.
GET /v1/agent/peppol/received?limit=20&offset=0
X-API-Key: efk_pk_test_...
X-Organization-Id: 0a2c1f3e-…
{
"data": [
{
"id": "f3a1…",
"sender_participant_id": "9915:9999999999",
"sender_name": "Supplier a.s.",
"sender_ico": "11112222",
"document_type": "invoice",
"document_number": "VF2026123",
"total": "240.00",
"vat_total": "40.00",
"currency": "EUR",
"status": "new",
"issue_date": "2026-06-20",
"received_at": "2026-06-20T08:15:00.000Z"
}
]
}| Field | Type | Description |
|---|---|---|
id | UUID | The received document's ID. |
sender_participant_id | string | The sender's Peppol identifier. |
sender_name | string | null | The sender's name. |
sender_ico | string | null | The sender's IČO. |
document_type | string | The document type (e.g. invoice, credit_note). |
document_number | string | The sender's document number. |
total | string | The total amount including VAT. |
vat_total | string | The VAT amount. |
currency | string | The currency. |
status | enum | Processing status: new, reviewed, matched, rejected, partially_paid, paid. |
issue_date | date | The issue date. |
received_at | ISO 8601 | Time the document was received. |
Downloading a received document (PDF / XML)
You can download an individual received document as a PDF (generated from the document's data, including a pay-by-square QR code when there's an IBAN) or as the original UBL XML. Both operations require the invoice:read scope and return the file as an attachment (Content-Disposition: attachment). id is the value from GET /peppol/received.
| Method | Path | Scope | Content-Type |
|---|---|---|---|
| GET | /v1/agent/peppol/received/{id}/pdf | invoice:read | application/pdf |
| GET | /v1/agent/peppol/received/{id}/xml | invoice:read | application/xml |
If the original XML is not available for a document, the /xml endpoint returns 404. A nonexistent id (or a document belonging to another organization) also returns 404.
GET /v1/agent/peppol/received/f3a1…/pdf
X-API-Key: efk_pk_test_...
X-Organization-Id: 0a2c1f3e-…
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="prijata-faktura-VF2026123.pdf"
%PDF-1.7 …Relation to the webhook
When a document arrives for you over Peppol, the system stores it (it appears in GET /peppol/received) and simultaneously fires the peppol.document.received webhook. Polling and the webhook are two views of the same event: the webhook is a push notification, and the received endpoint is the authoritative list.
{
"event": "peppol.document.received",
"timestamp": "2026-06-20T08:15:00.000Z",
"data": {
"senderName": "Supplier a.s.",
"senderParticipantId": "9915:9999999999",
"documentNumber": "VF2026123",
"documentType": "invoice",
"total": "240.00",
"currency": "EUR",
"orgId": "0a2c1f3e-…"
}
}GET /peppol/received. Deduplicate webhooks by X-Webhook-Id: details in Webhooks.