Document Status
Track the delivery lifecycle of sent invoices and credit notes on the Peppol network.
Track the lifecycle of sent documents. After calling send(), use getStatus() to check delivery progress at any time.
import { Peppol } from "@getpeppr/sdk";
const peppol = new Peppol({ apiKey: "sk_live_..." });
// Send an invoice
const result = await peppol.invoices.send(invoiceData);
console.log(result.status); // "submitted"
// Check status later
const status = await peppol.invoices.getStatus(result.id);
console.log(status.status);
// Status flow:
// "submitted" → "delivered" → "accepted" → "paid"
// → "rejected"
// → "failed"
// The Peppol AS4 message ID is read from the network on demand, so ask for it
// explicitly. Without ?include=evidence the field is simply absent.
const withEvidence = await peppol.invoices.getStatus(result.id, { includeEvidence: true });
if (withEvidence.peppolMessageId) {
console.log(`Peppol AS4 ID: ${withEvidence.peppolMessageId}`);
}Example Response
200 OK
{
"id": "inv_abc123",
"submissionId": "8b3f2c1d-4a5e-4f6b-9c8d-7e6f5a4b3c2d",
"providerDocumentId": "inv_abc123",
"number": "INV-2026-001",
"status": "delivered",
"currency": "EUR",
"totalAmount": 12100,
"createdAt": "2026-03-01T10:00:00Z",
"updatedAt": "2026-03-01T10:04:12Z"
}Peppol AS4 message ID
The AS4 message ID is the receipt the receiving access point signed for your document. getpeppr reads it from the network on request rather than storing it, so it is opt-in: pass include=evidence (or { includeEvidence: true } with the SDK). If the document has not gone out yet, the field is simply absent — the rest of the response is unchanged.
200 OK — ?include=evidence
{
"id": "inv_abc123",
"status": "delivered",
"peppolMessageId": "4381dde6-28b7-4d7b-a728-2148e1d470c9@phase4",
"createdAt": "2026-03-01T10:00:00Z"
}Status Flow
Every document follows a linear progression through these states:
submitted→delivered→accepted→paidAfter delivered, a document can also transition to:
rejectedAt any point after submitted, delivery failures result in:
failedno_actionStatus Details
submitted— document submitted to the Peppol networkdelivered— confirmed received by buyer's access pointaccepted— buyer accepted the documentrejected— buyer rejected the documentpaid— buyer marked the invoice as paidfailed— delivery failed (network/protocol error)no_action— not deliverable: no receiving capability found for the recipient on the Peppol network. Terminal forwaitFor()and the CLI--watch— nothing ever follows it; register or correct the recipient, then send again
Use Webhooks for real-time status updates instead of polling
getStatus().Raw status and structured detail (SDK 2.2.0, required since 4.0.0)
rawStatus— the raw status string exactly as the gateway sent it, before any SDK coercion. When the gateway emits a status the SDK doesn't recognize,statusfalls back tounknownbutrawStatuspreserves the original value. Available onSendResult(e.g.getStatus()) and oninvoices.list()rows. Since SDK 4.0.0 it is required on both, not optional: the one case where it used to be missing — a 2xx response carrying no status at all — is now refused outright.detail— structured national status detail, one entry per axis (platformFiscal,delivery,businessDisposition,settlement), each carrying the native code and label of the jurisdiction (e.g. a French DGFiP lifecycle code) plus itscodeSystem/codeVersion. Present when the jurisdiction provides one; exposed as thedetailfield onGET /api/v1/invoiceslist items and parsed by the SDK.
waitFor() terminal semantics
failed,rejected,no_action— terminal failures:waitFor()throws immediately instead of polling until the timeout (unless the terminal itself is the awaited target).paid— terminal success. Since SDK 2.2.0, if the document reachespaidwhile you are waiting for an earlier progress status (e.g.delivered),waitFor()resolves with the real result (result.status === "paid") — the target was passed, not missed. Previously this path ended in a timeout error.