Aller au contenu
Log in

Send invoices (end-to-end)

Ce contenu n’est pas encore disponible dans votre langue.

This guide shows a clean API flow to send invoices: create or reuse a contact, create or import an invoice, send it, and retrieve the final files.

  • API Key: X-B2B-API-Key
  • API Version: X-B2B-API-Version
  • ACCOUNT_ID: the account that issues the invoice.

Important IDs:

  • ACCOUNT_ID: owner account (path param in /accounts/{ACCOUNT_ID}/...).
  • CONTACT_ID: recipient contact (stored inside the account).
  • INVOICE_ID: invoice identifier (used in /invoices/{INVOICE_ID}... endpoints).
Terminal window
curl --request GET \
--url 'https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/contacts?offset=0&limit=25&name=Example%20Customer' \
--header 'X-B2B-API-Key: {YOUR_API_KEY}' \
--header 'X-B2B-API-Version: {YOUR_API_VERSION}' \
--header 'accept: application/json'

If you know the recipient’s identifier and country, you can retrieve public information from the directory and use it to build the contact.

Terminal window
curl --request GET \
--url https://api-staging.b2brouter.net/directory/es/ESB63276174 \
--header 'X-B2B-API-Key: {YOUR_API_KEY}' \
--header 'X-B2B-API-Version: {YOUR_API_VERSION}' \
--header 'accept: application/json'

1.3 Create a contact (if you don’t have one)

Section titled “1.3 Create a contact (if you don’t have one)”
Terminal window
curl --request POST \
--url https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/contacts \
--header 'X-B2B-API-Key: {YOUR_API_KEY}' \
--header 'X-B2B-API-Version: {YOUR_API_VERSION}' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"contact": {
"name": "Example Customer",
"country": "es",
"is_client": true,
"email": "billing@example.com",
"tin_scheme": "9920",
"tin_value": "ESB00000000",
"transport_type_code": "b2brouter",
"document_type_code": "json"
}
}'

Note: CONTACT_ID is returned in the response. Do not confuse it with ACCOUNT_ID.

2 Create (JSON) or import (XML) the invoice

Section titled “2 Create (JSON) or import (XML) the invoice”
Terminal window
curl --request POST \
--url https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/invoices \
--header 'X-B2B-API-Key: {YOUR_API_KEY}' \
--header 'X-B2B-API-Version: {YOUR_API_VERSION}' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"send_after_import": false,
"invoice": {
"type": "IssuedInvoice",
"contact_id": {CONTACT_ID},
"number": "INV-0001",
"date": "2026-01-21",
"terms": "custom",
"due_date": "2026-02-21",
"currency": "EUR",
"invoice_lines_attributes": [
{
"quantity": 1,
"price": 10,
"description": "Example service",
"taxes_attributes": [
{ "name": "VAT", "category": "S", "percent": 21 }
]
}
]
}
}'

2.2 Import invoice from a file (when you already generate XML)

Section titled “2.2 Import invoice from a file (when you already generate XML)”
Terminal window
curl --request POST \
--url 'https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/invoices/import?send_after_import=false' \
--header 'X-B2B-API-Key: {YOUR_API_KEY}' \
--header 'X-B2B-API-Version: {YOUR_API_VERSION}' \
--header 'content-type: application/octet-stream' \
--data 'data:text/xml;name=invoice.xml;base64,PD94bWw+Li4u'

2.3 What the import does with the contact data on the invoice (update_contact)

Section titled “2.3 What the import does with the contact data on the invoice (update_contact)”

When you import a file, or create an invoice with a contact block instead of contact_id, B2Brouter looks up the buyer among the contacts of the account by its identifiers and uses the contact it finds. By default, an import never modifies an existing contact:

  • If some data on the file (address, routing codes, sending method) does not match the contact, the invoice is assigned to an organizational unit of that contact carrying the file’s data. The contact does not change.
  • If only the name differs, nothing happens: no organizational unit is created, no field is written, and the invoice goes out with the name stored on the contact.

The update_contact parameter is optional, off by default, and exists on every API version. Send update_contact=true (as a query parameter on the import call, or as a top-level field of the JSON body on the create call, like send_after_import) so that the import updates the contact instead of creating an organizational unit. If an organizational unit with that data already exists, it is used.

  • The descriptive data on the file (the name included, the address and the other non-identifier fields) replaces the contact’s.
  • Identifiers (tax identifier, company identifier, Peppol identifier and routing codes) are only filled when they were blank on the contact. An identifier that already has a value is never overwritten, even if the file carries a different one.
  • A blank value on the file never clears a stored value.
  • On received invoices the parameter is ignored: a received document never updates the supplier’s contact.
  • The bulk import endpoint /invoices/imports does not accept this parameter.

Decide which side owns the contact data. With update_contact=true on every call, the invoice you send is the reference: any change in the file propagates to the contact record and to later invoices. Without the parameter, the contact record in B2Brouter is the reference, and you correct it through the contacts API or from the web application.

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

4 Retrieve the invoice and download final files

Section titled “4 Retrieve the invoice and download final files”
Terminal window
curl --request GET \
--url 'https://api-staging.b2brouter.net/invoices/{INVOICE_ID}?include=lines' \
--header 'X-B2B-API-Key: {YOUR_API_KEY}' \
--header 'X-B2B-API-Version: {YOUR_API_VERSION}' \
--header 'accept: application/json'

See the Download invoices guide.