Receive, integrate and manage received invoices

Receive, integrate and manage received invoices

Introduction

This guide explains how to start receiving invoices through B2Brouter with different methods, how to integrate them on your end with different formats, and also how to manage status of these received invoices.

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.

Obtaining API Credentials

Once permissions are granted:

  1. Log in to your B2Brouter account.
  2. Navigate to the Integration menu (lightning bolt icon).
  3. Select B2Brouter API.
  4. Click Show API Key to retrieve your API key.

Creating a new Company Account

If you already have an API key, you can directly create a Company using the API:

Request Example:

curl --request POST
--url https://app-staging.b2brouter.net/accounts
--header 'X-B2B-API-Key: YOUR_API_KEY'
--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": "jane.doe@example.com"
  }
}'

Sample Response:

{
  "account": {
    "id": 73509,
    "tin_value": "DE123456789",
    "tin_scheme": 9930,
    "cin_value": null,
    "cin_scheme": null,
    "name": "Muster GmbH",
    "address": "Musterstraße 45",
    "address2": null,
    "city": "Berlin",
    "postalcode": "10115",
    "province": "Berlin",
    "country": "de",
    "currency": "EUR",
    "contact_person": null,
    "phone": null,
    "email": "jane.doe@example.com",
    "rounding_method": "half_up",
    "round_before_sum": false,
    "apply_taxes_per_line": false,
    "archived": false,
    "created_at": "2025-02-10T08:28:02.000Z",
    "updated_at": "2025-02-10T08:28:02.000Z",
    "transactions_count": 0,
    "transactions_count_previous_period": 0,
    "transactions_limit": 0
  }
}

Once we got our company created, we can start by creating some transport configurations to enable reception through different methods like b2brouter internal channel, email or Peppol Network:

Request Example:

curl --request POST
--url https://app-staging.b2brouter.net/accounts/YOUR_PROJECT_ID/transports
--header 'X-B2B-API-Key: YOUR_API_KEY'
--header 'accept: application/json'
--header 'content-type: application/json'
--data '{
  "transport": {
    "code": "b2brouter",
    "enabled": true,
    "reception": true
  }
}'

Sample Response:

{
  "transport": {
    "code": "b2brouter",
    "enabled": true,
    "reception": true,
    "created_at": "2025-02-10T08:32:18.822Z",
    "updated_at": "2025-02-10T08:32:18.822Z"
  }
}

If you have the received invoice in XML format, and you want to upload it to B2Brouter it is also possible with the call Import an invoice from a file, we recommend to use the Query Param "issued" = false when importing a received invoice.

Request Example:

curl --request POST
--url 'https://app-staging.b2brouter.net/projects/YOUR_PROJECT_ID/invoices/import.json?send_after_import=false&issued=false'
--header 'X-B2B-API-Key: YOUR_API_KEY'
--header 'content-type: application/octet-stream'
--data 'data:text/xml;name=Invoice-2.xml;base64,PD94bWwZvaWNlPgo='

Sample Response:

{
  "invoice": {
    "id": 105337,
    "type": "ReceivedInvoice",
    "number": "2",
    "to_net": null,
    "to_net_id": null,
    "from_net": "uploaded",
    "from_net_id": null,
    "project": {
      "id": 73509,
      "name": "Muster GmbH"
    },
    "company": {
      "id": 4206,
      "name": "Muster GmbH",
      "taxcode": "DE123456789",
      "address": "Musterstraße 45",
      "address2": null,
      "postalcode": "10115",
      "city": "Berlin",
      "province": "Berlin",
      "country": "DE"
    },
    "client": {
      "id": 1313198550,
      "name": "Ejemplo S.L.",
      "taxcode": "B12345678",
      "address": "Calle Falsa 123, 3ºA",
      "address2": null,
      "postalcode": "28001",
      "city": "Madrid",
      "province": "Madrid",
      "country": "ES",
      "party_identification": null
    },
    "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.

Once we already set up the transports that we want to start receiving invoices we just need to wait to receive some invoices or import/create them to be able to list them and start the receiving flow, you can also filter with different Query Params.

Request Example:

curl --request GET
--url https://app-staging.b2brouter.net/projects/YOUR_PROJECT_ID/received.json
--header 'X-B2B-API-Key: YOUR_API_KEY'
--header 'accept: application/json'

Sample response:

{
  "invoices": [ 
    {
      "id": 105337,
      "number": "2",
      "file_reference": null,
      "date": "2025-02-10",
      "due_date": "2025-03-12",
      "project": {
        "id": 73509,
        "name": "Muster GmbH"
      },
      "client": {
        "id": 1313198550,
        "name": "Ejemplo S.L.",
        "taxcode": "B12345678"
      },
      "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",
      "project": {
        "id": 73509,
        "name": "Muster GmbH"
      },
      "client": {
        "id": 1313198550,
        "name": "Ejemplo S.L.",
        "taxcode": "B12345678"
      },
      "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

Now that we listed the current received invoices, we will save their unique id to be able to get back the information of this invoices in different formats.

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.

Request Example:

curl --request GET
--url 'https://app-staging.b2brouter.net/invoices/YOUR_INVOICE_ID.json?include=lines'
--header 'X-B2B-API-Key: YOUR_API_KEY'
--header 'accept: application/json'

Sample Response:

{
  "invoice": {
    "id": 105332,
    "type": "ReceivedInvoice",
    "number": "1",
    "to_net": null,
    "to_net_id": null,
    "from_net": "from_issued",
    "from_net_id": "105331",
    "project": {
      "id": 73509,
      "name": "Muster GmbH"
    },
    "company": {
      "id": 4206,
      "name": "Muster GmbH",
      "taxcode": "DE123456789",
      "address": "Musterstraße 45",
      "address2": null,
      "postalcode": "10115",
      "city": "Berlin",
      "province": "Berlin",
      "country": "de"
    },
    "client": {
      "id": 1313198550,
      "name": "Ejemplo S.L.",
      "taxcode": "B12345678",
      "address": "Calle Falsa 123, 3ºA",
      "address2": null,
      "postalcode": "28001",
      "city": "Madrid",
      "province": "Madrid",
      "country": "es",
      "party_identification": null
    },
    "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'.

Request Example:

curl --request GET
--url https://app-staging.b2brouter.net/invoices/YOUR_INVOICE_ID/as/original
--header 'X-B2B-API-Key: YOUR_API_KEY'

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">john.doe@example.com</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>john.doe@example.com</cbc:ElectronicMail>
      </cac:Contact>
    </cac:Party>
  </cac:AccountingSupplierParty>
  <cac:AccountingCustomerParty>
    <cac:Party>
      <cbc:EndpointID schemeID="EM">jane.doe@example.com</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>jane.doe@example.com</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", "annotated" or "paid" the invoice. 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.

Request Example:

curl --request POST
--url https://app-staging.b2brouter.net/invoices/YOUR_INVOICE_ID/mark_as.json
--header 'X-B2B-API-Key: YOUR_API_KEY'
--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.