Receive, integrate and manage received invoices
Overview
This guide explains how to:
- Receive invoices through different channels (Peppol, email, b2brouter, uploads).
- Integrate received invoices in your system (JSON, PDF, original file).
- Manage invoice lifecycle (acknowledge, accept/refuse/paid, etc.).
Prerequisites
- A company with a valid Taxcode Identifier (TIN) or Company Identifier (CIN).
- A registered account on B2Brouter’s test environment: Register Here
- API permissions (Request via a support ticket: Open a Ticket)
- In case of doubt about the registration process, please refer to the User Guide.
If you still need to create the account or enable reception transports, follow:
- Getting started (account setup): https://developer.b2brouter.net/docs/setting_up_guide#/
- Transports guide: https://developer.b2brouter.net/docs/transports_guide/
Key concepts (avoid ID confusion)
ACCOUNT_IDis used only in/accounts/{ACCOUNT_ID}/...endpoints.INVOICE_IDis the invoice identifier used in/invoices/{INVOICE_ID}...endpoints.- In a received invoice,
invoice.contactis the issuer/supplier (not your own account).
1) Ingest received invoices
1.1 Import a received invoice file (XML) (optional)
If you already have the received invoice file (for example, for testing, migrations, or backfills), you can import it with Import an invoice from a file.
Use the query param issued=false to import it as a ReceivedInvoice.
Example request:
curl --request POST
--url https://api-staging.b2brouter.net/accounts
--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 '{
"account": {
"country": "de",
"rounding_method": "half_up",
"round_before_sum": false,
"apply_taxes_per_line": false,
"tin_value": "DE123456789",
"name": "Muster GmbH",
"address": "Musterstraße 45",
"city": "Berlin",
"postalcode": "10115",
"province": "Berlin",
"email": "[email protected]"
}
}'Sample response (excerpt):
{
"invoice": {
"id": 105337,
"type": "ReceivedInvoice",
"state": "new",
"date": "2025-02-10",
"due_date": "2025-03-12",
"ponumber": null,
"file_reference": null,
"payment_method_info": "Cash payment",
"is_credit_note": false,
"adjustment_in_cents": 0,
"charge_reason": null,
"charge_amount": 0,
"charge_percent": 0,
"discount_text": null,
"discount_percent": 0,
"discount_amount": 0,
"subtotal": 90,
"taxes": [
{
"name": "VAT 19,00%",
"percent": 19,
"base": 90,
"amount": 17.1
}
],
"total": 107.1,
"currency": "EUR",
"amounts_withheld_reason": null,
"withheld_percent": 0,
"amounts_withheld": 0,
"payable_amount": 107.1,
"extra_info": "Test note information",
"attachments": [],
"created_at": "2025-02-10T08:57:40Z",
"updated_at": "2025-02-10T08:57:40Z",
"state_updated_at": "2025-02-10T08:57:40Z",
"ack_at": null
}
}It is also possible to generate a received invoice with JSON using the call Create an invoice, remember to inform "type": "ReceivedInvoice" when doing so.
1.2 Receive invoices through transports
Once transports are enabled for the account, invoices will arrive automatically (for example from Peppol or email).
2) List received invoices
Example request:
curl --request GET \
--url https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/invoices?type=ReceivedInvoice \
--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": "2",
"file_reference": null,
"date": "2025-02-10",
"due_date": "2025-03-12",
"account": {
"id": 73509,
"name": "Muster GmbH"
},
"contact": {
"id": 1313198550,
"name": "Ejemplo S.L.",
"tin_value": "B12345678"
"tin_scheme": "9920"
},
"state": "new",
"total": 107.1,
"currency": "EUR",
"created_at": "2025-02-10T08:57:40Z",
"updated_at": "2025-02-10T08:57:40Z",
"state_updated_at": "2025-02-10T08:57:40Z",
"from_net_id": null
},
{
"id": 105332,
"number": "1",
"file_reference": null,
"date": "2025-02-10",
"due_date": "2025-03-12",
"account": {
"id": 73509,
"name": "Muster GmbH"
},
"contact": {
"id": 1313198550,
"name": "Ejemplo S.L.",
"tin_value": "B12345678"
"tin_scheme": "9920"
},
"state": "received",
"total": 178.5,
"currency": "EUR",
"created_at": "2025-02-10T08:50:14Z",
"updated_at": "2025-02-10T08:50:14Z",
"state_updated_at": "2025-02-10T08:50:14Z",
"from_net_id": "105331"
}
],
"total_count": 2,
"offset": 0,
"limit": 25
}Consider that the received invoices may have different status as you can see on the previous call, invoices imported will appear in state "new" and the ones received trough different transports will normally appear in state "received".They could also have "invalid" state if there is any validation issue on the invoice.
To check all the available invoice states you can use the endpoint List of available invoice status
To get back the information of the invoice on JSON we can use the Get an invoice endpoint. Add a Query Param to include lines information or detailed lines information, depending on how much information from the invoice we need.
Example request:
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'Sample response (excerpt):
{
"invoice": {
"id": 105332,
"type": "ReceivedInvoice",
"state": "received",
"date": "2025-02-10",
"due_date": "2025-03-12",
"ponumber": null,
"file_reference": null,
"payment_method_info": "Cash payment",
"is_credit_note": false,
"adjustment_in_cents": 0,
"charge_reason": null,
"charge_amount": 0,
"charge_percent": 0,
"discount_text": null,
"discount_percent": 0,
"discount_amount": 0,
"subtotal": 150,
"taxes": [
{
"name": "USt 19,00%",
"percent": 19,
"base": 150,
"amount": 28.5
}
],
"total": 178.5,
"currency": "EUR",
"amounts_withheld_reason": null,
"withheld_percent": 0,
"amounts_withheld": 0,
"payable_amount": 178.5,
"extra_info": "Test note information",
"public_url": null,
"attachments": [
{
"link": "/attachments/download/253526/2025-02-10_1_original.pdf",
"content_type": "application/pdf"
}
],
"created_at": "2025-02-10T08:50:14Z",
"updated_at": "2025-02-10T09:50:36Z",
"state_updated_at": "2025-02-10T08:50:14Z",
"ack_at": null,
"lines": [
{
"quantity": 5,
"price": 10,
"description": "Test Line 1",
"total_cost": 50,
"extension_amount": 0
},
{
"quantity": 10,
"price": 10,
"description": "Test Line 2",
"total_cost": 100,
"extension_amount": 0
}
]
}
}You could also want to download the original legal invoice that has been received, and you can do so using the endpoint Get an invoice with a specific document type informing the id of the invoice and the document_type_code param as 'original'.
Example request:
curl --request GET \
--url https://api-staging.b2brouter.net/invoices/{INVOICE_ID}/as/original \
--header 'X-B2B-API-Key: {YOUR_API_KEY}' \
--header 'X-B2B-API-Version: {YOUR_API_VERSION}'Sample Response:
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ccts="urn:un:unece:uncefact:documentation:2" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:qdt="urn:oasis:names:specification:ubl:schema:xsd:QualifiedDatatypes-2" xmlns:udt="urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2">
<cbc:UBLVersionID>2.1</cbc:UBLVersionID>
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0</cbc:CustomizationID>
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
<cbc:ID>2</cbc:ID>
<cbc:IssueDate>2025-02-10</cbc:IssueDate>
<cbc:DueDate>2025-03-12</cbc:DueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:Note>Test note information</cbc:Note>
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
<cbc:BuyerReference>123</cbc:BuyerReference>
<cac:AccountingSupplierParty>
<cac:Party>
<cbc:EndpointID schemeID="EM">[email protected]</cbc:EndpointID>
<cac:PartyName>
<cbc:Name>Ejemplo S.L.</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Calle Falsa 123, 3ºA</cbc:StreetName>
<cbc:CityName>Madrid</cbc:CityName>
<cbc:PostalZone>28001</cbc:PostalZone>
<cbc:CountrySubentity>Madrid</cbc:CountrySubentity>
<cac:Country>
<cbc:IdentificationCode>ES</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>B12345678</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Ejemplo S.L.</cbc:RegistrationName>
<cbc:CompanyID>B12345678</cbc:CompanyID>
</cac:PartyLegalEntity>
<cac:Contact>
<cbc:ElectronicMail>[email protected]</cbc:ElectronicMail>
</cac:Contact>
</cac:Party>
</cac:AccountingSupplierParty>
<cac:AccountingCustomerParty>
<cac:Party>
<cbc:EndpointID schemeID="EM">[email protected]</cbc:EndpointID>
<cac:PartyName>
<cbc:Name>Muster GmbH</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Musterstraße 45</cbc:StreetName>
<cbc:CityName>Berlin</cbc:CityName>
<cbc:PostalZone>10115</cbc:PostalZone>
<cbc:CountrySubentity>Berlin</cbc:CountrySubentity>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>DE123456789</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Muster GmbH</cbc:RegistrationName>
<cbc:CompanyID>DE123456789</cbc:CompanyID>
</cac:PartyLegalEntity>
<cac:Contact>
<cbc:ElectronicMail>[email protected]</cbc:ElectronicMail>
</cac:Contact>
</cac:Party>
</cac:AccountingCustomerParty>
<cac:PaymentMeans>
<cbc:PaymentMeansCode>10</cbc:PaymentMeansCode>
</cac:PaymentMeans>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="EUR">17.10</cbc:TaxAmount>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">90.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">17.10</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19.00</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
</cac:TaxTotal>
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount currencyID="EUR">90.00</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount currencyID="EUR">90.00</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount currencyID="EUR">107.10</cbc:TaxInclusiveAmount>
<cbc:PayableAmount currencyID="EUR">107.10</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:InvoicedQuantity unitCode="EA">4.0</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">20.00</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Test line 1</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19.00</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">5.0</cbc:PriceAmount>
</cac:Price>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>2</cbc:ID>
<cbc:InvoicedQuantity unitCode="EA">6.0</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">30.00</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Test line 2</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19.00</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">5.0</cbc:PriceAmount>
</cac:Price>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>3</cbc:ID>
<cbc:InvoicedQuantity unitCode="EA">8.0</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">40.00</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Test line 1</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19.00</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">5.0</cbc:PriceAmount>
</cac:Price>
</cac:InvoiceLine>
</Invoice>You can also use the document_type_code param as 'pdf.invoice' to generate a pdf view of the invoice, or any other document_type_code displayed at Get document types to get back the invoice transformed into any other electronic invoice format.
Now that the invoice is on your end in the format/s that you want, you can use the endpoint Mark an invoice as acknowledged to prevent the invoice from being listed when getting the list of received invoices.
Finally, you can switch the invoice state to inform the sender that you have "accepted", "refused", or "paid" the invoice. You can also mark the invoice as "annotated" for internal tracking purposes, but note that this status does not trigger any notification to the sender. To do so, we will use the Switch invoice state endpoint. You can add the Body Param reason to specify the reason of the rejection. Consider that if the invoice came from any network, B2Brouter will be able to send the status change notification to sender through that network, but if the invoice came from mail, you will have to add the body param "commit": "with_mail" to be able to inform the sender.
Example request:
curl --request POST \
--url https://api-staging.b2brouter.net/invoices/{INVOICE_ID}/mark_as \
--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 '{
"state": "refused",
"reason": "Missing PO number"
}'Sample Response:
204 code
No Content
Conclusion
This guide covers the key steps to handle received invoices through B2Brouter’s API.
For more details, consult the API Reference.
Updated 20 days ago