Skip to content
Log in

Export your invoice history

This guide shows how to export a complete invoice history through the API: every invoice of an account, with its documents. It answers the same question asked at both ends of a contract — can we take our whole history with us before we close the account? and can an API key read everything we already have before we sign? The procedure is the same in both cases.

  • An API key with access to every account you want to export.
  • The ACCOUNT_ID of each account — see Account identifiers.

Use List of invoices:

Terminal window
curl --request GET \
--url 'https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/invoices?limit=500&offset=0' \
--header 'X-B2B-API-Key: {YOUR_API_KEY}' \
--header 'X-B2B-API-Version: {YOUR_API_VERSION}' \
--header 'accept: application/json'

Sample response (excerpt):

{
"invoices": [
{
"id": 105337,
"number": "F-2025-1",
"state": "sent",
"total": 107.1,
"currency": "EUR"
}
],
"total_count": 1840,
"offset": 0,
"limit": 500
}

The response echoes the pagination it applied:

  • limit — items per page. The default is 25 and the maximum is 500. A larger value is reduced to 500.
  • offset — the first item to return. The default is 0.
  • total_count — how many invoices match the filters.

Increase offset by limit and call again, until offset reaches total_count.

type defaults to IssuedInvoice, so a call that omits it returns issued invoices only. A complete export needs one pass per type:

  • IssuedInvoice
  • IssuedSelfInvoice
  • IssuedSimplifiedInvoice
  • ReceivedInvoice
  • ReceivedSelfInvoice
Terminal window
curl --request GET \
--url 'https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/invoices?type=ReceivedInvoice&limit=500&offset=0' \
--header 'X-B2B-API-Key: {YOUR_API_KEY}' \
--header 'X-B2B-API-Version: {YOUR_API_VERSION}' \
--header 'accept: application/json'

By default the list hides the invoices marked as acknowledged. That is intended for day-to-day work, where acknowledging an invoice takes it out of the pending list. For an export it is a silent omission: the pages look complete, and part of the history is missing.

Add ack=true to list the acknowledged invoices together with the rest:

Terminal window
curl --request GET \
--url 'https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/invoices?type=ReceivedInvoice&ack=true&limit=500&offset=0' \
--header 'X-B2B-API-Key: {YOUR_API_KEY}' \
--header 'X-B2B-API-Version: {YOUR_API_VERSION}' \
--header 'accept: application/json'

The list also includes the invoices of the organisational units under the account. Add exclude_offices=1 when you want the invoices of the account itself only.

A single sweep over offset is fragile: invoices created while it runs shift the pages under it. Filtering by date gives you fixed windows that you can repeat and restart one by one.

  • date_from and date_to — the invoice date.
  • due_date_from and due_date_to — the due date.
  • updated_at_from — invoices modified after a date. This is the filter for the incremental passes that follow a first full export.
  • state_updated_at_from — invoices whose state changed after a date.

Month by month, each window is a short sweep, and a window that fails can be retried on its own.

Step 5: Download the documents of each invoice

Section titled “Step 5: Download the documents of each invoice”

The steps above give you ids and metadata, not files. Documents are downloaded one invoice at a time. Download invoices explains every route in full; in an unattended loop the one to reach for is /as/legal:

Terminal window
curl --request GET \
--url https://api-staging.b2brouter.net/invoices/{INVOICE_ID}/as/legal \
--header 'X-B2B-API-Key: {YOUR_API_KEY}' \
--header 'X-B2B-API-Version: {YOUR_API_VERSION}'

It returns the archived legal document as stored, for issued and for received invoices, from the invoice id alone. Use /as/original for the source file the invoice was created from, and attachments[].link for the files attached to the invoice, which are not the invoice document itself.

Neither /as/legal nor /as/original regenerates anything, so neither one generates a billable transaction — see Transaction: View_as. The size of an export is a question of pacing, not of your transaction counter.

Two collections sit outside the invoice payload. Add them when the export has to stand as a record of what happened, not only of what was issued and received.

GET /accounts/{ACCOUNT_ID}/events returns the account’s event trail — see List of events. It paginates with the same limit and offset, and it filters on date_from, date_to, invoice_id and tax_report_id.

An export is usually the heaviest thing an integration does, so the rate limits decide how long it takes. API rate limiting gives the published figures and the 429 Too Many Requests response.

Two points matter for a full sweep:

  • The limit counts every request from the same client IP address, not the requests of one API key or one account. An export that runs from the host that carries the rest of your traffic shares one budget with it.
  • On a 429, back off exponentially and resume from the same offset. Nothing is lost.

Run the export before the account is closed

Section titled “Run the export before the account is closed”

Once an account is archived, its invoice endpoints answer 403, and the API route described here is no longer available. Run the export while the account is still active, and treat it as a step before closing rather than after.