Send invoices to Chorus Pro
In France, all invoices to public-sector clients must be submitted electronically via Chorus Pro, the government’s official B2G e-invoicing portal (Decree No. 2016-1478). Since April 2020, this applies to every central, regional and local administration—whether you’re a French company or an international supplier.
This guide shows you how to use the B2Brouter API to:
- Set up your company account (staging & production).
- Lookup public entities by SIRET in the B2Brouter Directory.
- Create customer and organizational-unit contacts.
- Generate, send, and track your invoices via Chorus Pro.
- Download the exact XML file submitted and acknowledge.
Prerequisites
Section titled “Prerequisites”- French company with a valid TVA/SIRET number.
- Testing environment (staging)
- Register at app-staging.b2brouter.net to try out the API.
- Once registered, open a Support Ticket in staging to request your API key and permissions.
- Production integration & eDocExchange subscription
- To go live, register at app.b2brouter.net.
- Subscribe to an eDocExchange Product or contact our Sales team at https://www.b2brouter.net/global/contact/ to discuss plans, sign your contract, and receive dedicated integration support.
Obtaining API Credentials
Section titled “Obtaining API Credentials”- Log in to your B2Brouter account.
- Go to the Developers tab.
- Select API Keys.
- Click on the clipboard icon to retrieve your API token.
Required identifier: SIRET, not SIREN
Section titled “Required identifier: SIRET, not SIREN”To invoice via Chorus Pro, both the issuing company and the client (the public entity) must be identified with a SIRET (cin_scheme="0009"), never with a SIREN:
- Issuing company: if the company’s country is
fr,cin_valuemust hold a non-blank SIRET andcin_schememust equal9("0009"). If the SIRET is blank, orcin_schemeis anything other than9, the invoice is not sent. - Client: the recipient must also be identified with a SIRET. Without it, contact creation fails with the error “Chorus needs the SIRET identifier of the client”.
Hierarchical consistency: even though invoicing is always SIRET-to-SIRET, the account or contact shouldn’t be “flat” at SIRET level. Keep the same hierarchy as in the DGFiP circuit: a SIREN parent with the SIRET modeled as an organizational unit (OU) (
parent_id+cin_scheme="0009") under that parent (see Account structure). If your company already has a B2Brouter account with a SIREN parent, create the issuing SIRET as an OU under that parent instead of a separate standalone account.
Retrieve or Create Your Company Account
Section titled “Retrieve or Create Your Company Account”1. Retrieve your Company ID
Section titled “1. Retrieve your Company ID”curl --request GET \ --url 'https://api-staging.b2brouter.net/accounts?offset=0&limit=25' \ --header 'X-B2B-API-Key: {YOUR_API_KEY}' \ --header 'X-B2B-API-Version: {YOUR_API_VERSION}' \ --header 'accept: application/json'2. Create a Company Account (if needed)
Section titled “2. Create a Company Account (if needed)”Provide cin_scheme: "0009" and cin_value with the issuing establishment’s SIRET (14 digits). This is required for Chorus Pro: without a SIRET, or with a cin_scheme other than 9, invoice submission fails.
If your company already has a B2Brouter account at SIREN parent level (for example, for DGFiP), don’t create a new standalone account with this SIRET: create it as an OU with
parent_idpointing to the parent, following the same steps as Create organisational units in the DGFiP guide. The example below is for a company that doesn’t yet have any B2Brouter account.
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": "fr", "rounding_method": "half_up", "tin_value": "FR46458880332", "tin_scheme": 9957, "cin_scheme": "0009", "cin_value": "45888033200017", "name": "Exemplar SAS", "address": "10 Rue Imaginaire", "city": "Paris", "postalcode": "75001", "province": "Île-de-France", "email": "john.doe@example.com" } }'Verify recipient information
Section titled “Verify recipient information”You can check if the recipient exists in our public directory:
curl --request GET \ --url https://api-staging.b2brouter.net/directory/fr/0009/13001533200013 \ --header 'X-B2B-API-Key: {YOUR_API_KEY}' \ --header 'X-B2B-API-Version: {YOUR_API_VERSION}' \ --header 'Content-Type: application/json'This lookup already returns the entity’s existing organizational units (service codes) from the Chorus Pro directory. You don’t need to create them yourself as a contact: use the
cin1_scheme/cin1_valuealready returned by the directory.
Create a Contact
Section titled “Create a Contact”When creating a French customer:
- Use
cin_valuefor SIRET-CODE number. This is required: without a SIRET, Chorus Pro rejects the invoice with the error “Chorus needs the SIRET identifier of the client”. - Use
cin_schemeto identify the Schemes Codelist. SIRET-CODE is 0009; a SIREN (0002) is not accepted. transport_type_codeshould befr.chorus.document_type_codeshould bexml.ubl.invoice.chorus.
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": { "language": "en", "is_client": true, "is_provider": true, "terms": "custom", "public_sector": true, "name": "UNIVERSITE D AIX MARSEILLE", "address": "58 BD CHARLES LIVON", "city": "MARSEILLE 7", "postalcode": "13007", "country": "fr", "currency": "EUR", "transport_type_code": "fr.chorus", "document_type_code": "xml.ubl.invoice.chorus", "cin_value": "13001533200013", "cin_scheme": "0009" } }'Create an Organizational Unit Contact
Section titled “Create an Organizational Unit Contact”To bill a specific department or service, create a sub-contact under the main entity using parent_id and include the Chorus Pro “service code” (cin1_scheme / cin1_value).
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 'Content-Type: application/json' \ --data '{ "contact": { "parent_id": 1313228381, "name": "Factures marché FCM ROP cadre A2", "address": "58 BD CHARLES LIVON", "city": "MARSEILLE 7", "postalcode": "13007", "country": "fr", "cin1_scheme": "8017", "cin1_value": "ESR_MISSION_FACTURES_DEPLACEMENTS" } }'Create and Send an Invoice
Section titled “Create and Send an Invoice”When invoicing a French customer, ensure you provide all required fields including:
number,dateanddue_date- At least one
invoice_lines_attributeswithtaxes_attributes contact_idor a completecontactobject
Depending on the recipient, these fields are also needed:
ponumberorbuyer_reference: only when the public entity requires them in Chorus Pro. Then one of the two is enough. If you send neither, the send is refused with the error “Missing required fields: Entry number or service code”.buyer_referencewith thecin1_value(Code Service) to identify the target department. If the contact has a Code Service and you do not sendbuyer_reference, B2Brouter fills it with that code when the invoice is created. If you send it, B2Brouter uses your value.
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 'content-type: application/json' \ --data '{ "send_after_import": true, "invoice": { "type": "IssuedInvoice", "contact_id": 1313228399, "bank_account": { "type": "iban", "iban": "FR7630006000011234567890189" }, "terms": "custom", "invoice_lines_attributes": [ { "unit": 5, "quantity": 135, "price": 25, "description": "Cocktail Dinatoire", "taxes_attributes": [ { "name": "TVA", "category": "S", "percent": 10 } ], "article_code": "14", "position": 1 } ], "number": "00002", "date": "2025-06-18", "due_date": "2025-07-18", "currency": "EUR", "ponumber": "0123456", "buyer_reference": "ESR_MISSION_FACTURES_DEPLACEMENTS" } }'Check Invoice Status
Section titled “Check Invoice Status”Check Single Invoice Status
Section titled “Check Single Invoice Status”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'Check Multiple Invoices Status
Section titled “Check Multiple Invoices Status”curl --request GET \ --url 'https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/invoices?offset=0&limit=25&state_updated_at_from=2025-06-12' \ --header 'X-B2B-API-Key: {YOUR_API_KEY}' \ --header 'X-B2B-API-Version: {YOUR_API_VERSION}' \ --header 'accept: application/json'Real-Time Status Updates with Webhooks
Section titled “Real-Time Status Updates with Webhooks”Instead of polling, subscribe to push notifications via webhooks. Whenever an invoice state changes, B2Brouter will send an HTTP POST to your endpoint.
Invoice Status WebHooks - API Reference
Download the Original Invoice XML
Section titled “Download the Original Invoice XML”After sending, the GET /invoices/{id} response includes a download_legal_url field. Use it to fetch the exact XML file submitted to Chorus Pro:
curl --request GET \ --url https://api-staging.b2brouter.net{download_legal_url} \ --header 'X-B2B-API-Key: {YOUR_API_KEY}' \ --header 'X-B2B-API-Version: {YOUR_API_VERSION}' \ --header 'Accept: application/xml'As a one-step alternative, you can call GET /invoices/{id}/as/legal directly, without first fetching download_legal_url from the invoice payload. It returns the archived legal document as stored and does not generate a billable transaction — see Download invoices and Transaction: View_as.
Mark Invoice as Acknowledged
Section titled “Mark Invoice as Acknowledged”curl --request POST \ --url https://api-staging.b2brouter.net/invoices/{INVOICE_ID}/ack \ --header 'X-B2B-API-Key: {YOUR_API_KEY}' \ --header 'X-B2B-API-Version: {YOUR_API_VERSION}' \ --header 'accept: application/json'Related guides
Section titled “Related guides”- DGFiP – E-Invoicing and E-Reporting: domestic French B2B circuit, with a different identifier model (SIREN parent + SIRET organizational units).
For further help: