Counting and listing sent documents
Two calls answer the questions a dashboard asks. One counts your documents over a period. The other lists the documents you sent, page by page, and can attach the invoice you originally submitted.
All paths below are relative to https://app.goroute.ai/peppol-api. Both calls need the
transactions:read permission and read only your own organisation, unless you ask for
the whole group with scope=group.
| Method and path | What it does |
|---|---|
GET /api/v1/transactions/stats | Counts by direction and by status over a date range |
GET /api/v1/transactions/history | Your sent documents, paged, optionally with the original invoice |
/history is sent documents onlyThe name does not say so, but the endpoint fixes the direction to sent and there is no
parameter to change it. Received documents never appear in its results. To read what you
received, use GET /api/v1/inbound-documents or GET /api/v1/transactions without a
direction filter.
Count documents by statusโ
GET /api/v1/transactions/stats
| Parameter | Type | What it does |
|---|---|---|
date_from | date-time | Start of the period. Defaults to 30 days before date_to |
date_to | date-time | End of the period. Defaults to now |
exclude_reporting_legs | boolean, default false | Leaves out the extra copies GoRoute sends to a tax authority, so the counts match the documents you recognise |
scope | string | group counts the caller's organisation and every active entity beneath it, at any depth. Any other value, or none, counts your own organisation only |
curl -H "X-API-Key: your_api_key" \
"https://app.goroute.ai/peppol-api/api/v1/transactions/stats?date_from=2026-08-01T00:00:00&date_to=2026-08-31T23:59:59&exclude_reporting_legs=true"
{
"total": 0,
"sent": 0,
"received": 0,
"delivered": 0,
"failed": 0,
"pending": 0,
"period_start": "2026-08-01T00:00:00Z",
"period_end": "2026-08-31T23:59:59Z",
"by_entity": null
}
Reading the numbersโ
period_start and period_end are the window actually used, so you can see what the
defaults resolved to.
The six counts are two different cuts of the same documents, not one list of six parts:
sentandreceivedsplit the documents by direction. Together they maketotal.delivered,failedandpendingcount by status.pendingmeans queued, submitted, accepted or retrying.
So sent + received equals total, but delivered + failed + pending usually does not.
Two more statuses exist and sit in none of the three buckets: held, a document prepared
and deliberately not yet transmitted because the tax authority's endpoint is not live, and
issued, a document delivered to the buyer by email as a PDF/A-3 hybrid because they are
not on the network. Neither is a failure and neither is counted as one.
One document type is counted in a way worth knowing: an Oman export reported under the
substitute participant is stored as failed but counts as delivered here, because
nothing about it is outstanding. The same rule is applied by the status filter on
GET /api/v1/transactions, so the counts and the rows agree.
Soft-deleted documents are left out of every count.
Group totalsโ
With scope=group, the six counts cover the whole subtree and by_entity fills in โ one
row per entity that has at least one matching document, sorted by name:
{
"by_entity": [
{
"org_id": "3f2b9c10-6d44-4c1e-9a8a-5b7e3f0a1d22",
"name": "Nordlys Retail AS",
"sent": 0,
"received": 0,
"delivered": 0,
"failed": 0,
"total": 0
}
]
}
Outside group scope by_entity is null. scope=group is refused with 400 and
NOT_A_GROUP when nothing sits beneath you or you are acting as another organisation
read-only, and with 400 and GROUP_VIEW_DISABLED where the operator has switched the
group view off.
List sent documentsโ
GET /api/v1/transactions/history
| Parameter | Type | What it does |
|---|---|---|
page | integer, default 1 | Which page to return |
page_size | integer, default 20, maximum 100 | Rows per page |
status | string | Return only documents with this status |
date_from, date_to | date-time | Restrict to documents created in this window |
document_number | string | Read the caveat below before using this |
include_invoice_data | boolean, default false | Attach the invoice as originally submitted to each row |
scope | string | group reads the same series across the caller's whole subtree. Rows keep their shape; there is no per-entity split |
curl -H "X-API-Key: your_api_key" \
"https://app.goroute.ai/peppol-api/api/v1/transactions/history?page=1&page_size=50&status=failed"
{
"items": [
{
"transaction_id": "7c1f7d54-2a3f-4a51-9a2f-1c9d0a6b5e21",
"status": "failed",
"document_number": "INV-2026-000417",
"receiver_peppol_id": "0192:910000047",
"created_at": "2026-08-14T09:12:44Z",
"has_invoice_data": true,
"can_resend": true,
"invoice_data": null
}
],
"total": 0,
"page": 1,
"page_size": 50,
"total_pages": 0
}
has_invoice_data says whether the original invoice was kept for that document.
can_resend is true only when the document failed or is retrying and the original
invoice is still there โ the two conditions for
POST /api/v1/transactions/{transaction_id}/resend to have anything to send.
invoice_data stays null until you ask for it with include_invoice_data=true.
document_number filters one page, not the whole historyGoRoute fetches the page first and then keeps the rows on that page whose document number contains what you asked for. Two things follow, and neither is reported in the response:
- A page can come back with fewer rows than
page_sizeโ sometimes none at all โ whiletotalandtotal_pagesstill describe the unfiltered series. - A matching document that sits on another page is never found.
To search reliably, use GET /api/v1/transactions, whose invoice_number filter is applied
to the whole series before paging. Note the difference in behaviour as well as in
reliability: invoice_number there is an exact match, because an invoice number is an
identifier and a partial match would hand back the wrong document; document_number here
matches any row containing the text.
/history has no exclude_reporting_legs parameter, so reporting legs are included in its
rows and in its total. If you are comparing counts with rows, compare
GET /api/v1/transactions/stats against GET /api/v1/transactions with the same
exclude_reporting_legs value, not against this endpoint.
Relatedโ
- Transactions in the API reference โ the full list endpoint, filters and resend
- Accounts Payable โ the documents you receive
- Audit Log API โ who did what, rather than how many