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

MethodPathScope
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"
  }
}
FieldTypeDescription
invoice_idUUIDThe invoice's ID.
stateenumThe transmission status (see the state machine below).
error_messagestring | nullThe failure reason for the ERROR state.
receiver_identifierstring | nullThe recipient's Peppol identifier (e.g. 9915:DIČ or 0245:DIČ).
document_idstring | nullThe document identifier within the transmission.
updated_atISO 8601Time of the last status change.

State machine

StateMeaningAction / when to retry
not_sentNo transmission exists for the invoice yet: it has not been sent.Call POST /peppol/send/{invoiceId}.
QUEUEDThe send is queued and waiting for a worker.Wait and keep polling (or listen for the webhook).
SENDINGA worker is currently sending the document via the AP.Wait: this is a transient state.
SENTThe document was accepted by the Peppol network (AS4 receipt).Done at the send level. Delivery to the recipient is signaled by the delivered webhook.
DEFERREDThe 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.
ERRORThe send failed permanently (see error_message).Fix the cause (often a missing address / VAT ID) and send again.
The 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

MethodPathScope
GET/v1/agent/peppol/receivedinvoice:read

Query parameters:

ParameterTypeDefaultDescription
limitint 1–10050Number of records.
offsetint ≥ 00Pagination 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"
    }
  ]
}
FieldTypeDescription
idUUIDThe received document's ID.
sender_participant_idstringThe sender's Peppol identifier.
sender_namestring | nullThe sender's name.
sender_icostring | nullThe sender's IČO.
document_typestringThe document type (e.g. invoice, credit_note).
document_numberstringThe sender's document number.
totalstringThe total amount including VAT.
vat_totalstringThe VAT amount.
currencystringThe currency.
statusenumProcessing status: new, reviewed, matched, rejected, partially_paid, paid.
issue_datedateThe issue date.
received_atISO 8601Time 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.

MethodPathScopeContent-Type
GET/v1/agent/peppol/received/{id}/pdfinvoice:readapplication/pdf
GET/v1/agent/peppol/received/{id}/xmlinvoice:readapplication/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-…"
  }
}
Recommended pattern: listen for the webhook and, upon receiving it (or periodically as a safety net), fetch GET /peppol/received. Deduplicate webhooks by X-Webhook-Id: details in Webhooks.