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.
Prerequisites
Section titled “Prerequisites”- An API key with access to every account you want to export.
- The
ACCOUNT_IDof each account — see Account identifiers.
Step 1: List the invoices of an account
Section titled “Step 1: List the invoices of an account”Use List of invoices:
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.
Step 2: Repeat for every document type
Section titled “Step 2: Repeat for every document type”type defaults to IssuedInvoice, so a call that omits it returns issued invoices only. A complete export needs one pass per type:
IssuedInvoiceIssuedSelfInvoiceIssuedSimplifiedInvoiceReceivedInvoiceReceivedSelfInvoice
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'Step 3: Include the acknowledged invoices
Section titled “Step 3: Include the acknowledged invoices”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:
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.
Step 4: Split a long history into windows
Section titled “Step 4: Split a long history into windows”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_fromanddate_to— the invoice date.due_date_fromanddue_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:
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.
Step 6: Response documents and events
Section titled “Step 6: Response documents and events”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.
Pace the export
Section titled “Pace the export”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 sameoffset. 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.