# Sending Peppol documents in Belgium for the companies you onboard (/getting-started/belgium/platform/sending) This guide walks through everything needed to exchange Peppol documents for a company registered in Belgium, assuming you are integrating Recommand into your own product and onboarding Belgian companies as your users, and that the company only sends documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are building [#what-you-are-building] You are onboarding companies that are not your own: one Recommand team, and a company inside it for every customer you put on the network. Your customers never need a Recommand account. They see your interface, and Recommand stays behind your API calls. That shape has a few consequences worth knowing before you write code: * **One team, many companies.** There is no limit on companies per team, and billing is per team with the document volume of all companies pooled together, so the more companies you onboard the lower your price per document. See [pricing per team](/faq/general-usage/is-pricing-per-company-or-per-team). * **Every company is registered and verified individually.** Peppol identifies companies, not platforms. Each company gets its own Peppol address and its own authorisation record. * **Verification is taken care of.** Recommand hands you a URL that the company's authorised representative opens to confirm their identity. You present or forward that link; you never need to handle identity documents yourself. If you prefer to handle verification yourself, reach out to us at [support@recommand.eu](mailto:support@recommand.eu), we have a few other flows we can set up for you. * **You can run the whole flow under your own brand.** The API is designed for white-label use, see [can I whitelabel Recommand](/faq/general-usage/can-i-whitelabel-integrate-recommand). The [Recommand dashboard](https://app.recommand.eu) shows the same teams, companies and documents your API calls produce, which is the quickest way to see what a customer is looking at while you are debugging. If the only company you will register is your own, switch the first answer above to **One company** for the shorter version of this guide. The endpoints are the same; there is simply less to organise. Peppol in Belgium [#peppol-in-belgium] Belgium runs on the standard European Peppol stack, which makes it the simplest of all countries to start in. Documents are exchanged as **Peppol BIS 3 UBL**, over the standard Peppol billing process, and Recommand's own access point and SMP handle both directions. What is specific to Belgium: * **The B2B mandate is already in force.** Since 1 January 2026 Belgian companies must be able to send and receive structured electronic invoices for domestic B2B transactions. See [what if I don't switch to Peppol](/faq/sending-and-error-handling/what-if-i-dont-switch-to-peppol-by-2026) for what non-compliance means in practice. * **Enterprise numbers are the Peppol address.** Belgian companies are published under scheme `0208` (enterprise number), which is why a Belgian Peppol address looks like `0208:0123456789`. Sometimes, scheme `9925` is used as well, which is followed by a Belgian VAT number, like this: `9925:BE0123456789`. * **Representatives are checked against the CBE.** During verification, the name given for the representative is matched against the company's registered representatives in the Crossroads Bank for Enterprises, so a name that is not authorised is refused up front. Create your team and API credentials [#create-your-team-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). The team you get is the container for every company you will onboard. 2. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 3. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Try it safely first [#try-it-safely-first] Build the whole flow against a **playground team** before you touch production. Playgrounds look and behave like production teams, but nothing is delivered over the real Peppol network, there are no SMP registrations, no subscription checks and no billing. Create one from the team switcher at the top of the [dashboard](https://app.recommand.eu): **Add playground**, give it a name, and you are switched into it. There is no limit on how many you create. Everything that follows in this guide is identical there: same endpoints, same validation, same webhooks (triggered by simulated inbound delivery). Register a company in the playground and use it as both sender and recipient to see a document arrive. Three things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`, which is the quickest way to check that your country-specific fields map to the format and process you expect. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. * **The Peppol Test Network.** For genuine end-to-end tests with real counterparties, tick **Use Peppol Test Network** when you create the playground. It then uses dedicated test access point and SMP endpoints while staying fully separated from production. The setting cannot be changed after creation, so make a second playground if you want both. More detail in the [getting started guide](/docs) and [how do I use the playground environment](/faq/api-and-development/how-do-i-use-the-playground-environment). Register the company [#register-the-company] Create one company per customer with the [create company endpoint](/reference/companies/create-company). Registration on the Peppol network happens as part of this call: identifiers and document types are set up for you, based on the company's country. ```javascript const auth = "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"); const response = await fetch("https://app.recommand.eu/api/v1/companies", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(company), }); const result = await response.json(); if (!result.success) throw new Error(JSON.stringify(result.errors)); const companyId = result.company.id; const verificationUrl = result.verificationUrl; // hand this to your user ``` ```bash curl -X POST https://app.recommand.eu/api/v1/companies \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @company.json ``` The response carries a `verificationUrl` straight away. Keep it: the next step is to put it in front of the company's representative. Register the companies that use your platform, not the companies they invoice. Customers and suppliers manage their own Peppol registration; adding them causes registration conflicts. See [managing companies](/docs/managing-companies). The exact identifier fields to send depend on the country, which is what the next section covers. If you would rather create identifiers and document types yourself instead of accepting the country defaults, pass `skipDefaultCompanySetup: true` and use the [company identifiers](/reference/company-identifiers/create-company-identifier) and [company document types](/reference/company-document-types/get-company-document-types) endpoints. Belgian identifiers and Peppol address [#belgian-identifiers-and-peppol-address] | Field | Belgian value | | ------------------------ | ----------------------------------------------------------- | | `country` | `"BE"` | | `enterpriseNumber` | 10 digits, starting with `0` or `1` (modulo-97 check digit) | | `enterpriseNumberScheme` | `"0208"` | | `vatNumber` | `BE` + the same 10 digits | ```json title="company.json" { "name": "ACME Corporation", "address": "123 Main Street", "postalCode": "1000", "city": "Brussels", "country": "BE", "enterpriseNumber": "0123456789", "enterpriseNumberScheme": "0208", "vatNumber": "BE0123456789" } ``` Both numbers are validated against the national rules, including the modulo-97 check digit, and a mismatch is rejected instead of silently registered. For Belgian companies the enterprise number is derived from the VAT number when you leave it out. Two Peppol identifiers are then registered for the company: * `0208:0123456789` is the enterprise number, and the address others will use * `9925:BE0123456789` is the VAT number The company's Peppol address is the first one: **`0208:` followed by the enterprise number**. Registering for sending only [#registering-for-sending-only] Because you are only looking to send invoices or other documents, register the company **without** recipient registration: set `isSmpRecipient` to `false` (or leave the checkbox unticked in the dashboard). ```json { "isSmpRecipient": false } ``` What that means: * The company is not published as a recipient on an SMP, so nothing is delivered to it over Peppol through your integration. * Registration succeeds even when the company already receives its documents through another Peppol provider. The other Peppol provider will remain in charge for processing received documents for this company. * Nothing changes for sending: outgoing documents leave through the access point as normal. You can flip `isSmpRecipient` to `true` on an existing company at any time. Recommand then publishes it as a recipient and registers the document types for its country. That registration is exclusive, so the company has to be deregistered at its current provider first. Verify the company [#verify-the-company] A company cannot exchange documents on Peppol until an authorised representative has confirmed their identity. The company object exposes this as `isVerified`, and it stays `false` until the check is done. For Belgian companies the flow is short: 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. Fill in the representative's first and last name. That name is checked against the **Crossroads Bank for Enterprises** before the identity check starts: a name that matches none of the company's registered representatives is refused. 3. Complete the identity check. `isVerified` flips to `true` and the company is published on the Peppol network. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. Building verification into your onboarding [#building-verification-into-your-onboarding] With one company you would click through this once. With many, verification is part of the flow you build: every company you register needs its own, and it is the step most likely to leave a customer stuck halfway. **Show the URL immediately.** The create-company response already carries `verificationUrl`, so no extra call is needed. Put it in front of the user while they are still in your onboarding. **Ask for a fresh one when the moment has passed.** Links get lost, and companies you created earlier never had one shown. The [verify company endpoint](/reference/companies/verify-company) starts a new verification session: ```bash curl -X POST https://app.recommand.eu/api/v1/companies/{companyId}/verify \ -u key_xxx:secret_xxx ``` The `company.verification` webhook fires when verification reaches a final state: `verified`, `rejected` or `error`. A company that comes back `rejected` or `error` and is not surfaced anywhere sits silently unusable. See [working with webhooks](/docs/working-with-webhooks). **Respect `isVerified` in your own UI.** Do not let a user press send for a company that is not verified yet; this will result in an error. You should inform the user what is missing instead. **Re-verify after identifier changes.** Updating a company's `vatNumber` or `enterpriseNumber` resets `isVerified` to `false`. Check the field after an update and present a new `verificationUrl` if it flipped. The full mechanics are in the [company verification guide](/docs/company-verification). The document format [#the-document-format] For Belgium there is nothing to pick: leave the format alone and you send **Peppol BIS 3 UBL**, over the standard Peppol billing process. That is what Belgian recipients register, and what the Belgian B2B mandate expects. Two things are still worth checking before a first send to a new recipient: * **Is the recipient on the network?** The [verify endpoint](/reference/recipients/verify-recipient) answers that, and sending performs the same check automatically. * **Does the recipient accept this document type?** The [verify document support endpoint](/reference/recipients/verify-document-support) answers that. Most Belgian recipients accept invoices and credit notes; not all accept every other type. This is also checked automatically when sending. See [verifying recipients](/docs/verifying-recipients) for the full flow, including what to do when a recipient cannot be reached. Send a document [#send-a-document] One endpoint sends everything: [`POST /:companyId/send`](/reference/sending/send-document). The `companyId` is the sender, `recipient` is the Peppol address of the receiver, and `document` is the invoice or credit note as JSON. Recommand will validate the document and generate the XML. Raw XML sending is supported as well: set `documentType` to `xml` and pass the document string in `document`, along with the correct `doctypeId`. See [working with raw UBL](/docs/ubl-format-guide#working-with-raw-ubl). ```javascript const response = await fetch( `https://app.recommand.eu/api/v1/${companyId}/send`, { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, // The body below, with doctypeId and countrySpecific where the country // needs them. body: JSON.stringify(sendRequest), } ); const result = await response.json(); if (!result.success) { // result.errors is keyed by field path, e.g. { "buyer.vatNumber": [...] } } ``` ```bash curl -X POST https://app.recommand.eu/api/v1/{companyId}/send \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @send-invoice.json ``` ```json title="send-invoice.json" { "recipient": "0208:0123456789", "documentType": "invoice", "document": { "invoiceNumber": "INV-2026-001", "issueDate": "2026-08-17", "dueDate": "2026-09-16", "currency": "EUR", "buyer": { "name": "Customer Company", "street": "Customer Street 1", "city": "Antwerp", "postalZone": "2000", "country": "BE", "vatNumber": "BE0987654321" }, "paymentMeans": [{ "iban": "BE68539007547034" }], "lines": [ { "name": "Consulting Services", "quantity": "10.00", "unitCode": "HUR", "netPriceAmount": "100.00", "vat": { "category": "S", "percentage": "21.00" } } ] } } ``` The seller block is filled in from the company when you leave it out, which is usually what you want: it keeps the company's registered identifiers and the document in agreement. Things worth wiring up while you are here: * **Validation errors.** Outgoing documents are always validated. A `success: false` response with `errors` keyed by field path is a document your recipient would have rejected, so surface it to the user who typed the data. * **Email fallback.** Pass `email.to` with `when: "on_peppol_failure"` to fall back to email when a recipient turns out not to be reachable over Peppol, or send with `recipient: null` for email-only delivery. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **PDFs.** `pdfGeneration.enabled` attaches a generated PDF of the document. You can also attach an existing PDF (or other files) via `attachments`; see [adding attachments](/docs/sending-invoices#adding-attachments). For a full field reference, see [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Going live [#going-live] Before you switch your first real customer over, walk this list: * **A valid subscription in production.** Playgrounds skip the subscription check; production does not. * **Verification handled in your UI.** Show the `verificationUrl` at the right moment, make it forwardable, and handle the `company.verification` webhook so a company that comes back `rejected` or `error` does not sit silently unusable. * **`isVerified` respected.** Do not let a user press send for a company that is not verified yet; explain what is missing instead. * **Webhook endpoint hardened.** Signature verification, a fast 200, retries and idempotency on your side. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of the person who can fix it. * **One real document, end to end.** Send an invoice between two companies you control on production before letting customers in. Documents are counted per team, with the volume of all your companies pooled, so onboarding more companies lowers your price per document rather than adding per-company fees. Received documents count towards the quota as well as sent ones, so budget for both sides of the exchange. Generated XML through `generate` is not billed; emails and submitted reports are. Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Receiving Peppol documents in Belgium for the companies you onboard (/getting-started/belgium/platform/receiving) This guide walks through everything needed to exchange Peppol documents for a company registered in Belgium, assuming you are integrating Recommand into your own product and onboarding Belgian companies as your users, and that the company only receives documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are building [#what-you-are-building] You are onboarding companies that are not your own: one Recommand team, and a company inside it for every customer you put on the network. Your customers never need a Recommand account. They see your interface, and Recommand stays behind your API calls. That shape has a few consequences worth knowing before you write code: * **One team, many companies.** There is no limit on companies per team, and billing is per team with the document volume of all companies pooled together, so the more companies you onboard the lower your price per document. See [pricing per team](/faq/general-usage/is-pricing-per-company-or-per-team). * **Every company is registered and verified individually.** Peppol identifies companies, not platforms. Each company gets its own Peppol address and its own authorisation record. * **Verification is taken care of.** Recommand hands you a URL that the company's authorised representative opens to confirm their identity. You present or forward that link; you never need to handle identity documents yourself. If you prefer to handle verification yourself, reach out to us at [support@recommand.eu](mailto:support@recommand.eu), we have a few other flows we can set up for you. * **You can run the whole flow under your own brand.** The API is designed for white-label use, see [can I whitelabel Recommand](/faq/general-usage/can-i-whitelabel-integrate-recommand). The [Recommand dashboard](https://app.recommand.eu) shows the same teams, companies and documents your API calls produce, which is the quickest way to see what a customer is looking at while you are debugging. If the only company you will register is your own, switch the first answer above to **One company** for the shorter version of this guide. The endpoints are the same; there is simply less to organise. Peppol in Belgium [#peppol-in-belgium] Belgium runs on the standard European Peppol stack, which makes it the simplest of all countries to start in. Documents are exchanged as **Peppol BIS 3 UBL**, over the standard Peppol billing process, and Recommand's own access point and SMP handle both directions. What is specific to Belgium: * **The B2B mandate is already in force.** Since 1 January 2026 Belgian companies must be able to send and receive structured electronic invoices for domestic B2B transactions. See [what if I don't switch to Peppol](/faq/sending-and-error-handling/what-if-i-dont-switch-to-peppol-by-2026) for what non-compliance means in practice. * **Enterprise numbers are the Peppol address.** Belgian companies are published under scheme `0208` (enterprise number), which is why a Belgian Peppol address looks like `0208:0123456789`. Sometimes, scheme `9925` is used as well, which is followed by a Belgian VAT number, like this: `9925:BE0123456789`. * **Representatives are checked against the CBE.** During verification, the name given for the representative is matched against the company's registered representatives in the Crossroads Bank for Enterprises, so a name that is not authorised is refused up front. Create your team and API credentials [#create-your-team-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). The team you get is the container for every company you will onboard. 2. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 3. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Try it safely first [#try-it-safely-first] Build the whole flow against a **playground team** before you touch production. Playgrounds look and behave like production teams, but nothing is delivered over the real Peppol network, there are no SMP registrations, no subscription checks and no billing. Create one from the team switcher at the top of the [dashboard](https://app.recommand.eu): **Add playground**, give it a name, and you are switched into it. There is no limit on how many you create. Everything that follows in this guide is identical there: same endpoints, same validation, same webhooks (triggered by simulated inbound delivery). Register a company in the playground and use it as both sender and recipient to see a document arrive. Three things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`, which is the quickest way to check that your country-specific fields map to the format and process you expect. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. * **The Peppol Test Network.** For genuine end-to-end tests with real counterparties, tick **Use Peppol Test Network** when you create the playground. It then uses dedicated test access point and SMP endpoints while staying fully separated from production. The setting cannot be changed after creation, so make a second playground if you want both. More detail in the [getting started guide](/docs) and [how do I use the playground environment](/faq/api-and-development/how-do-i-use-the-playground-environment). Register the company [#register-the-company] Create one company per customer with the [create company endpoint](/reference/companies/create-company). Registration on the Peppol network happens as part of this call: identifiers and document types are set up for you, based on the company's country. ```javascript const auth = "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"); const response = await fetch("https://app.recommand.eu/api/v1/companies", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(company), }); const result = await response.json(); if (!result.success) throw new Error(JSON.stringify(result.errors)); const companyId = result.company.id; const verificationUrl = result.verificationUrl; // hand this to your user ``` ```bash curl -X POST https://app.recommand.eu/api/v1/companies \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @company.json ``` The response carries a `verificationUrl` straight away. Keep it: the next step is to put it in front of the company's representative. Register the companies that use your platform, not the companies they invoice. Customers and suppliers manage their own Peppol registration; adding them causes registration conflicts. See [managing companies](/docs/managing-companies). The exact identifier fields to send depend on the country, which is what the next section covers. If you would rather create identifiers and document types yourself instead of accepting the country defaults, pass `skipDefaultCompanySetup: true` and use the [company identifiers](/reference/company-identifiers/create-company-identifier) and [company document types](/reference/company-document-types/get-company-document-types) endpoints. Belgian identifiers and Peppol address [#belgian-identifiers-and-peppol-address] | Field | Belgian value | | ------------------------ | ----------------------------------------------------------- | | `country` | `"BE"` | | `enterpriseNumber` | 10 digits, starting with `0` or `1` (modulo-97 check digit) | | `enterpriseNumberScheme` | `"0208"` | | `vatNumber` | `BE` + the same 10 digits | ```json title="company.json" { "name": "ACME Corporation", "address": "123 Main Street", "postalCode": "1000", "city": "Brussels", "country": "BE", "enterpriseNumber": "0123456789", "enterpriseNumberScheme": "0208", "vatNumber": "BE0123456789" } ``` Both numbers are validated against the national rules, including the modulo-97 check digit, and a mismatch is rejected instead of silently registered. For Belgian companies the enterprise number is derived from the VAT number when you leave it out. Two Peppol identifiers are then registered for the company: * `0208:0123456789` is the enterprise number, and the address others will use * `9925:BE0123456789` is the VAT number The company's Peppol address is the first one: **`0208:` followed by the enterprise number**. Registering as a recipient [#registering-as-a-recipient] To receive documents, the company must be published as a recipient on an SMP (Service Metadata Publisher). That is what `isSmpRecipient` does, and it is the default: ```json { "isSmpRecipient": true } ``` What that means: * The company becomes findable on the Peppol network: any sender can look it up and deliver to it via the Peppol network. * Recipient registration is **exclusive**. If the company is already registered for receiving through another Peppol provider, registration fails until it is deregistered there. * The document types the company accepts are registered along with it, based on its country. Which ones those are is covered further down. * The company is only published once it is verified. Moving an existing Belgian registration [#moving-an-existing-belgian-registration] Since the B2B mandate came into force, most Belgian companies are already reachable over Peppol through a provider of their own. Recipient registration is exclusive, so registering the enterprise number under scheme `0208` fails while the company is still published somewhere else: it has to be deregistered at its current provider first. If this is the case, we will let you know which SMP the company is published on. You can also look the enterprise number up ahead of time with the [verify endpoint](/reference/recipients/verify-recipient), which returns the same thing. Mail [support@recommand.eu](mailto:support@recommand.eu) with the enterprise number and we will work out where the company is registered. Verify the company [#verify-the-company] A company cannot exchange documents on Peppol until an authorised representative has confirmed their identity. The company object exposes this as `isVerified`, and it stays `false` until the check is done. For Belgian companies the flow is short: 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. Fill in the representative's first and last name. That name is checked against the **Crossroads Bank for Enterprises** before the identity check starts: a name that matches none of the company's registered representatives is refused. 3. Complete the identity check. `isVerified` flips to `true` and the company is published on the Peppol network. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. Building verification into your onboarding [#building-verification-into-your-onboarding] With one company you would click through this once. With many, verification is part of the flow you build: every company you register needs its own, and it is the step most likely to leave a customer stuck halfway. **Show the URL immediately.** The create-company response already carries `verificationUrl`, so no extra call is needed. Put it in front of the user while they are still in your onboarding. **Ask for a fresh one when the moment has passed.** Links get lost, and companies you created earlier never had one shown. The [verify company endpoint](/reference/companies/verify-company) starts a new verification session: ```bash curl -X POST https://app.recommand.eu/api/v1/companies/{companyId}/verify \ -u key_xxx:secret_xxx ``` The `company.verification` webhook fires when verification reaches a final state: `verified`, `rejected` or `error`. A company that comes back `rejected` or `error` and is not surfaced anywhere sits silently unusable. See [working with webhooks](/docs/working-with-webhooks). **Respect `isVerified` in your own UI.** Do not let a user press send for a company that is not verified yet; this will result in an error. You should inform the user what is missing instead. **Re-verify after identifier changes.** Updating a company's `vatNumber` or `enterpriseNumber` resets `isVerified` to `false`. Check the field after an update and present a new `verificationUrl` if it flipped. The full mechanics are in the [company verification guide](/docs/company-verification). Document types registered for you [#document-types-registered-for-you] When you register a Belgian company as a recipient, it is published for the two document types that cover almost all Belgian traffic: | Document type | Process | | ------------------------------ | --------------------------------------------- | | Invoice (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Credit note (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | Anything sent to the company in one of these formats is accepted, validated, stored and handed to you. A sender who tries a document type the company is not published for gets an error before delivery, which is exactly the point of the registration. Need more document types, such as self-billing, message level responses, invoice responses? Register the combinations you want with the [create company document type endpoint](/reference/company-document-types/create-company-document-type). Get incoming documents into your product [#get-incoming-documents-into-your-product] Recommand receives, validates and stores incoming documents for every company in your team. You pick them up in one of two ways. Webhooks (recommended) [#webhooks-recommended] Register an endpoint once with the [create webhook endpoint](/reference/webhooks/create-webhook) or through the dashboard and events are pushed to you as they happen, `document.received` among them: ```javascript await fetch("https://app.recommand.eu/api/v1/webhooks", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(webhook), // the body below }); ``` ```bash curl -X POST https://app.recommand.eu/api/v1/webhooks \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @create-webhook.json ``` ```json title="create-webhook.json" { "url": "https://your-app.example/webhooks/recommand", "companyId": null, "secret": "your_webhook_signing_secret" } ``` `companyId: null` covers every company in the team. Pass a `secret` and verify the HMAC SHA-256 signature on every delivery before you trust the payload. Switch on `event.eventType`, and acknowledge with a 200 before doing the heavy processing. Both are covered in [working with webhooks](/docs/working-with-webhooks). Polling the inbox [#polling-the-inbox] If you would rather pull, the [inbox endpoint](/reference/documents/get-inbox) lists unread documents: ```javascript const inbox = await fetch("https://app.recommand.eu/api/v1/inbox", { headers: { Authorization: auth }, }).then((r) => r.json()); ``` Mark each document as read with the [mark as read endpoint](/reference/documents/mark-as-read) once your system has it, so it drops off the list. After you have the document [#after-you-have-the-document] * Fetch details, the original XML or a rendered PDF from the [documents endpoints](/reference/documents/get-document). * Route documents to the right customer with [labels and suppliers](/docs/suppliers-and-labels), and automate that routing with [rules](/docs/rules). * Let Recommand mail incoming documents on to an address of your choosing when that is easier than an API call, see [email delivery and notifications](/docs/email-delivery-and-notifications). For the full picture, including retries and idempotency, see [receiving documents](/docs/receiving-documents). Going live [#going-live] Before you switch your first real customer over, walk this list: * **A valid subscription in production.** Playgrounds skip the subscription check; production does not. * **Verification handled in your UI.** Show the `verificationUrl` at the right moment, make it forwardable, and handle the `company.verification` webhook so a company that comes back `rejected` or `error` does not sit silently unusable. * **`isVerified` respected.** Do not let a user press send for a company that is not verified yet; explain what is missing instead. * **Webhook endpoint hardened.** Signature verification, a fast 200, retries and idempotency on your side. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of the person who can fix it. * **One real document, end to end.** Send an invoice between two companies you control on production before letting customers in. Documents are counted per team, with the volume of all your companies pooled, so onboarding more companies lowers your price per document rather than adding per-company fees. Received documents count towards the quota as well as sent ones, so budget for both sides of the exchange. Generated XML through `generate` is not billed; emails and submitted reports are. Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Sending and receiving Peppol documents in Belgium for the companies you onboard (/getting-started/belgium/platform/sending-and-receiving) This guide walks through everything needed to exchange Peppol documents for a company registered in Belgium, assuming you are integrating Recommand into your own product and onboarding Belgian companies as your users, and that the company sends and receives documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are building [#what-you-are-building] You are onboarding companies that are not your own: one Recommand team, and a company inside it for every customer you put on the network. Your customers never need a Recommand account. They see your interface, and Recommand stays behind your API calls. That shape has a few consequences worth knowing before you write code: * **One team, many companies.** There is no limit on companies per team, and billing is per team with the document volume of all companies pooled together, so the more companies you onboard the lower your price per document. See [pricing per team](/faq/general-usage/is-pricing-per-company-or-per-team). * **Every company is registered and verified individually.** Peppol identifies companies, not platforms. Each company gets its own Peppol address and its own authorisation record. * **Verification is taken care of.** Recommand hands you a URL that the company's authorised representative opens to confirm their identity. You present or forward that link; you never need to handle identity documents yourself. If you prefer to handle verification yourself, reach out to us at [support@recommand.eu](mailto:support@recommand.eu), we have a few other flows we can set up for you. * **You can run the whole flow under your own brand.** The API is designed for white-label use, see [can I whitelabel Recommand](/faq/general-usage/can-i-whitelabel-integrate-recommand). The [Recommand dashboard](https://app.recommand.eu) shows the same teams, companies and documents your API calls produce, which is the quickest way to see what a customer is looking at while you are debugging. If the only company you will register is your own, switch the first answer above to **One company** for the shorter version of this guide. The endpoints are the same; there is simply less to organise. Peppol in Belgium [#peppol-in-belgium] Belgium runs on the standard European Peppol stack, which makes it the simplest of all countries to start in. Documents are exchanged as **Peppol BIS 3 UBL**, over the standard Peppol billing process, and Recommand's own access point and SMP handle both directions. What is specific to Belgium: * **The B2B mandate is already in force.** Since 1 January 2026 Belgian companies must be able to send and receive structured electronic invoices for domestic B2B transactions. See [what if I don't switch to Peppol](/faq/sending-and-error-handling/what-if-i-dont-switch-to-peppol-by-2026) for what non-compliance means in practice. * **Enterprise numbers are the Peppol address.** Belgian companies are published under scheme `0208` (enterprise number), which is why a Belgian Peppol address looks like `0208:0123456789`. Sometimes, scheme `9925` is used as well, which is followed by a Belgian VAT number, like this: `9925:BE0123456789`. * **Representatives are checked against the CBE.** During verification, the name given for the representative is matched against the company's registered representatives in the Crossroads Bank for Enterprises, so a name that is not authorised is refused up front. Create your team and API credentials [#create-your-team-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). The team you get is the container for every company you will onboard. 2. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 3. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Try it safely first [#try-it-safely-first] Build the whole flow against a **playground team** before you touch production. Playgrounds look and behave like production teams, but nothing is delivered over the real Peppol network, there are no SMP registrations, no subscription checks and no billing. Create one from the team switcher at the top of the [dashboard](https://app.recommand.eu): **Add playground**, give it a name, and you are switched into it. There is no limit on how many you create. Everything that follows in this guide is identical there: same endpoints, same validation, same webhooks (triggered by simulated inbound delivery). Register a company in the playground and use it as both sender and recipient to see a document arrive. Three things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`, which is the quickest way to check that your country-specific fields map to the format and process you expect. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. * **The Peppol Test Network.** For genuine end-to-end tests with real counterparties, tick **Use Peppol Test Network** when you create the playground. It then uses dedicated test access point and SMP endpoints while staying fully separated from production. The setting cannot be changed after creation, so make a second playground if you want both. More detail in the [getting started guide](/docs) and [how do I use the playground environment](/faq/api-and-development/how-do-i-use-the-playground-environment). Register the company [#register-the-company] Create one company per customer with the [create company endpoint](/reference/companies/create-company). Registration on the Peppol network happens as part of this call: identifiers and document types are set up for you, based on the company's country. ```javascript const auth = "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"); const response = await fetch("https://app.recommand.eu/api/v1/companies", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(company), }); const result = await response.json(); if (!result.success) throw new Error(JSON.stringify(result.errors)); const companyId = result.company.id; const verificationUrl = result.verificationUrl; // hand this to your user ``` ```bash curl -X POST https://app.recommand.eu/api/v1/companies \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @company.json ``` The response carries a `verificationUrl` straight away. Keep it: the next step is to put it in front of the company's representative. Register the companies that use your platform, not the companies they invoice. Customers and suppliers manage their own Peppol registration; adding them causes registration conflicts. See [managing companies](/docs/managing-companies). The exact identifier fields to send depend on the country, which is what the next section covers. If you would rather create identifiers and document types yourself instead of accepting the country defaults, pass `skipDefaultCompanySetup: true` and use the [company identifiers](/reference/company-identifiers/create-company-identifier) and [company document types](/reference/company-document-types/get-company-document-types) endpoints. Belgian identifiers and Peppol address [#belgian-identifiers-and-peppol-address] | Field | Belgian value | | ------------------------ | ----------------------------------------------------------- | | `country` | `"BE"` | | `enterpriseNumber` | 10 digits, starting with `0` or `1` (modulo-97 check digit) | | `enterpriseNumberScheme` | `"0208"` | | `vatNumber` | `BE` + the same 10 digits | ```json title="company.json" { "name": "ACME Corporation", "address": "123 Main Street", "postalCode": "1000", "city": "Brussels", "country": "BE", "enterpriseNumber": "0123456789", "enterpriseNumberScheme": "0208", "vatNumber": "BE0123456789" } ``` Both numbers are validated against the national rules, including the modulo-97 check digit, and a mismatch is rejected instead of silently registered. For Belgian companies the enterprise number is derived from the VAT number when you leave it out. Two Peppol identifiers are then registered for the company: * `0208:0123456789` is the enterprise number, and the address others will use * `9925:BE0123456789` is the VAT number The company's Peppol address is the first one: **`0208:` followed by the enterprise number**. Registering for both directions [#registering-for-both-directions] Sending needs no registration of its own; receiving does. So register the company as a recipient, which is the default: ```json { "isSmpRecipient": true } ``` What that means: * The company becomes findable on the Peppol network and can be delivered to through Recommand's access point, while sending its own documents out through the same access point. * Recipient registration is **exclusive**. If the company already receives through another Peppol provider, registration fails until it is deregistered there. What that takes depends on the country, which the next section covers. * The document types the company accepts are registered along with it, based on its country. Which ones those are is covered further down. * The company is only published once it is verified. If the company still receives elsewhere and you do not want to move that yet, register it with `isSmpRecipient: false` and start with sending only. Flipping the field later publishes it as a recipient. Moving an existing Belgian registration [#moving-an-existing-belgian-registration] Since the B2B mandate came into force, most Belgian companies are already reachable over Peppol through a provider of their own. Recipient registration is exclusive, so registering the enterprise number under scheme `0208` fails while the company is still published somewhere else: it has to be deregistered at its current provider first. If this is the case, we will let you know which SMP the company is published on. You can also look the enterprise number up ahead of time with the [verify endpoint](/reference/recipients/verify-recipient), which returns the same thing. Mail [support@recommand.eu](mailto:support@recommand.eu) with the enterprise number and we will work out where the company is registered. Verify the company [#verify-the-company] A company cannot exchange documents on Peppol until an authorised representative has confirmed their identity. The company object exposes this as `isVerified`, and it stays `false` until the check is done. For Belgian companies the flow is short: 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. Fill in the representative's first and last name. That name is checked against the **Crossroads Bank for Enterprises** before the identity check starts: a name that matches none of the company's registered representatives is refused. 3. Complete the identity check. `isVerified` flips to `true` and the company is published on the Peppol network. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. Building verification into your onboarding [#building-verification-into-your-onboarding] With one company you would click through this once. With many, verification is part of the flow you build: every company you register needs its own, and it is the step most likely to leave a customer stuck halfway. **Show the URL immediately.** The create-company response already carries `verificationUrl`, so no extra call is needed. Put it in front of the user while they are still in your onboarding. **Ask for a fresh one when the moment has passed.** Links get lost, and companies you created earlier never had one shown. The [verify company endpoint](/reference/companies/verify-company) starts a new verification session: ```bash curl -X POST https://app.recommand.eu/api/v1/companies/{companyId}/verify \ -u key_xxx:secret_xxx ``` The `company.verification` webhook fires when verification reaches a final state: `verified`, `rejected` or `error`. A company that comes back `rejected` or `error` and is not surfaced anywhere sits silently unusable. See [working with webhooks](/docs/working-with-webhooks). **Respect `isVerified` in your own UI.** Do not let a user press send for a company that is not verified yet; this will result in an error. You should inform the user what is missing instead. **Re-verify after identifier changes.** Updating a company's `vatNumber` or `enterpriseNumber` resets `isVerified` to `false`. Check the field after an update and present a new `verificationUrl` if it flipped. The full mechanics are in the [company verification guide](/docs/company-verification). The document format [#the-document-format] For Belgium there is nothing to pick: leave the format alone and you send **Peppol BIS 3 UBL**, over the standard Peppol billing process. That is what Belgian recipients register, and what the Belgian B2B mandate expects. Two things are still worth checking before a first send to a new recipient: * **Is the recipient on the network?** The [verify endpoint](/reference/recipients/verify-recipient) answers that, and sending performs the same check automatically. * **Does the recipient accept this document type?** The [verify document support endpoint](/reference/recipients/verify-document-support) answers that. Most Belgian recipients accept invoices and credit notes; not all accept every other type. This is also checked automatically when sending. See [verifying recipients](/docs/verifying-recipients) for the full flow, including what to do when a recipient cannot be reached. Send a document [#send-a-document] One endpoint sends everything: [`POST /:companyId/send`](/reference/sending/send-document). The `companyId` is the sender, `recipient` is the Peppol address of the receiver, and `document` is the invoice or credit note as JSON. Recommand will validate the document and generate the XML. Raw XML sending is supported as well: set `documentType` to `xml` and pass the document string in `document`, along with the correct `doctypeId`. See [working with raw UBL](/docs/ubl-format-guide#working-with-raw-ubl). ```javascript const response = await fetch( `https://app.recommand.eu/api/v1/${companyId}/send`, { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, // The body below, with doctypeId and countrySpecific where the country // needs them. body: JSON.stringify(sendRequest), } ); const result = await response.json(); if (!result.success) { // result.errors is keyed by field path, e.g. { "buyer.vatNumber": [...] } } ``` ```bash curl -X POST https://app.recommand.eu/api/v1/{companyId}/send \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @send-invoice.json ``` ```json title="send-invoice.json" { "recipient": "0208:0123456789", "documentType": "invoice", "document": { "invoiceNumber": "INV-2026-001", "issueDate": "2026-08-17", "dueDate": "2026-09-16", "currency": "EUR", "buyer": { "name": "Customer Company", "street": "Customer Street 1", "city": "Antwerp", "postalZone": "2000", "country": "BE", "vatNumber": "BE0987654321" }, "paymentMeans": [{ "iban": "BE68539007547034" }], "lines": [ { "name": "Consulting Services", "quantity": "10.00", "unitCode": "HUR", "netPriceAmount": "100.00", "vat": { "category": "S", "percentage": "21.00" } } ] } } ``` The seller block is filled in from the company when you leave it out, which is usually what you want: it keeps the company's registered identifiers and the document in agreement. Things worth wiring up while you are here: * **Validation errors.** Outgoing documents are always validated. A `success: false` response with `errors` keyed by field path is a document your recipient would have rejected, so surface it to the user who typed the data. * **Email fallback.** Pass `email.to` with `when: "on_peppol_failure"` to fall back to email when a recipient turns out not to be reachable over Peppol, or send with `recipient: null` for email-only delivery. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **PDFs.** `pdfGeneration.enabled` attaches a generated PDF of the document. You can also attach an existing PDF (or other files) via `attachments`; see [adding attachments](/docs/sending-invoices#adding-attachments). For a full field reference, see [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Document types registered for you [#document-types-registered-for-you] When you register a Belgian company as a recipient, it is published for the two document types that cover almost all Belgian traffic: | Document type | Process | | ------------------------------ | --------------------------------------------- | | Invoice (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Credit note (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | Anything sent to the company in one of these formats is accepted, validated, stored and handed to you. A sender who tries a document type the company is not published for gets an error before delivery, which is exactly the point of the registration. Need more document types, such as self-billing, message level responses, invoice responses? Register the combinations you want with the [create company document type endpoint](/reference/company-document-types/create-company-document-type). Get incoming documents into your product [#get-incoming-documents-into-your-product] Recommand receives, validates and stores incoming documents for every company in your team. You pick them up in one of two ways. Webhooks (recommended) [#webhooks-recommended] Register an endpoint once with the [create webhook endpoint](/reference/webhooks/create-webhook) or through the dashboard and events are pushed to you as they happen, `document.received` among them: ```javascript await fetch("https://app.recommand.eu/api/v1/webhooks", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(webhook), // the body below }); ``` ```bash curl -X POST https://app.recommand.eu/api/v1/webhooks \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @create-webhook.json ``` ```json title="create-webhook.json" { "url": "https://your-app.example/webhooks/recommand", "companyId": null, "secret": "your_webhook_signing_secret" } ``` `companyId: null` covers every company in the team. Pass a `secret` and verify the HMAC SHA-256 signature on every delivery before you trust the payload. Switch on `event.eventType`, and acknowledge with a 200 before doing the heavy processing. Both are covered in [working with webhooks](/docs/working-with-webhooks). Polling the inbox [#polling-the-inbox] If you would rather pull, the [inbox endpoint](/reference/documents/get-inbox) lists unread documents: ```javascript const inbox = await fetch("https://app.recommand.eu/api/v1/inbox", { headers: { Authorization: auth }, }).then((r) => r.json()); ``` Mark each document as read with the [mark as read endpoint](/reference/documents/mark-as-read) once your system has it, so it drops off the list. After you have the document [#after-you-have-the-document] * Fetch details, the original XML or a rendered PDF from the [documents endpoints](/reference/documents/get-document). * Route documents to the right customer with [labels and suppliers](/docs/suppliers-and-labels), and automate that routing with [rules](/docs/rules). * Let Recommand mail incoming documents on to an address of your choosing when that is easier than an API call, see [email delivery and notifications](/docs/email-delivery-and-notifications). For the full picture, including retries and idempotency, see [receiving documents](/docs/receiving-documents). Going live [#going-live] Before you switch your first real customer over, walk this list: * **A valid subscription in production.** Playgrounds skip the subscription check; production does not. * **Verification handled in your UI.** Show the `verificationUrl` at the right moment, make it forwardable, and handle the `company.verification` webhook so a company that comes back `rejected` or `error` does not sit silently unusable. * **`isVerified` respected.** Do not let a user press send for a company that is not verified yet; explain what is missing instead. * **Webhook endpoint hardened.** Signature verification, a fast 200, retries and idempotency on your side. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of the person who can fix it. * **One real document, end to end.** Send an invoice between two companies you control on production before letting customers in. Documents are counted per team, with the volume of all your companies pooled, so onboarding more companies lowers your price per document rather than adding per-company fees. Received documents count towards the quota as well as sent ones, so budget for both sides of the exchange. Generated XML through `generate` is not billed; emails and submitted reports are. Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Sending Peppol documents in Belgium for your own company (/getting-started/belgium/business/sending) This guide walks through everything needed to exchange Peppol documents for a company registered in Belgium, assuming you are setting up your own Belgian company, and that the company only sends documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are setting up [#what-you-are-setting-up] You are putting one company, your own or one you represent, on the Peppol network, so it can exchange invoices electronically with its customers and suppliers. The setup is a one-time affair: registering the company and getting it verified takes a few minutes in the [Recommand dashboard](https://app.recommand.eu), and there is nothing to gain from automating something you do once. What you do integrate is the part that repeats: sending and receiving documents. Our existing [integrations](/integrations) can also connect Recommand to accounting or invoicing software you already use, with no code at all. A single team can hold several companies at no extra cost, useful if you run more than one legal entity, and the document volume of all of them counts towards one plan. If you are building e-invoicing or Peppol integration into a product for your own customers, and will be registering their companies rather than only your own, switch the first answer above to **Many companies**. The API is the same; what changes is how companies, verification and billing are organised. Peppol in Belgium [#peppol-in-belgium] Belgium runs on the standard European Peppol stack, which makes it the simplest of all countries to start in. Documents are exchanged as **Peppol BIS 3 UBL**, over the standard Peppol billing process, and Recommand's own access point and SMP handle both directions. What is specific to Belgium: * **The B2B mandate is already in force.** Since 1 January 2026 Belgian companies must be able to send and receive structured electronic invoices for domestic B2B transactions. See [what if I don't switch to Peppol](/faq/sending-and-error-handling/what-if-i-dont-switch-to-peppol-by-2026) for what non-compliance means in practice. * **Enterprise numbers are the Peppol address.** Belgian companies are published under scheme `0208` (enterprise number), which is why a Belgian Peppol address looks like `0208:0123456789`. Sometimes, scheme `9925` is used as well, which is followed by a Belgian VAT number, like this: `9925:BE0123456789`. * **Representatives are checked against the CBE.** During verification, the name given for the representative is matched against the company's registered representatives in the Crossroads Bank for Enterprises, so a name that is not authorised is refused up front. Create your account and API credentials [#create-your-account-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). 2. Your account starts with a **team**. The team holds your company, your subscription and your document history, and you can invite colleagues to it. 3. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 4. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Sending and receiving can also be driven entirely from the dashboard or through an [integration](/integrations), and each section below says how. The dashboard is available in English, Dutch, French and German; pick your language on the [account page](https://app.recommand.eu/account). Try it safely first [#try-it-safely-first] You do not have to get anything right the first time. Everything below, adding the company, registering it, sending and receiving, can be done in a **playground team** first, where nothing is delivered over the real Peppol network, nothing is registered on it, and nothing is billed. Open the team switcher at the top of the [dashboard](https://app.recommand.eu) and pick **Add playground**. Give it a name, leave the Peppol Test Network box unticked, and you are switched into the new team straight away. There is nothing to set up beyond that. Add a company to that team and use it as both sender and recipient to watch a document travel end to end. When the flow does what you want, repeat it once in your real team. Two things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. A playground stays useful after you are live, too: it is the safest place to try a new invoice layout or a new integration. See [how can I test without sending real invoices](/faq/api-and-development/how-can-i-test-without-sending-real-invoices). Playground companies are not registered on the Peppol network and playground documents never leave it, so nothing you do there affects your real company. Register the company [#register-the-company] You are registering one company, once, so the dashboard is the shortest path. 1. Open [Companies](https://app.recommand.eu/companies) and start the company wizard. 2. Fill in the legal name, address and country, plus the identifiers described in the next section. 3. Choose whether the company should also **receive** documents over Peppol, or only send them. 4. Save. The company is registered on the Peppol network as part of this step: its identifiers and the document types for its country are set up for you. Right after saving, the dashboard offers the verification step, which the section below covers. Note the company's ID from its detail page. Every API call for sending and receiving takes it in the path. The [create company endpoint](/reference/companies/create-company) does exactly the same thing, and returns the company `id` and a `verificationUrl` in one response. It is worth using when company creation is part of a flow you are automating, which is likely the case if you are registering many companies. Switch the first answer above to **Many companies** for that version. Add each legal entity as its own company: run the wizard again. There is no per-company fee, and all of them share your document volume. Belgian identifiers and Peppol address [#belgian-identifiers-and-peppol-address] | Field | Belgian value | | ------------------------ | ----------------------------------------------------------- | | `country` | `"BE"` | | `enterpriseNumber` | 10 digits, starting with `0` or `1` (modulo-97 check digit) | | `enterpriseNumberScheme` | `"0208"` | | `vatNumber` | `BE` + the same 10 digits | ```json title="company.json" { "name": "ACME Corporation", "address": "123 Main Street", "postalCode": "1000", "city": "Brussels", "country": "BE", "enterpriseNumber": "0123456789", "enterpriseNumberScheme": "0208", "vatNumber": "BE0123456789" } ``` Both numbers are validated against the national rules, including the modulo-97 check digit, and a mismatch is rejected instead of silently registered. For Belgian companies the enterprise number is derived from the VAT number when you leave it out. Two Peppol identifiers are then registered for the company: * `0208:0123456789` is the enterprise number, and the address others will use * `9925:BE0123456789` is the VAT number The company's Peppol address is the first one: **`0208:` followed by the enterprise number**. Registering for sending only [#registering-for-sending-only] Because you are only looking to send invoices or other documents, register the company **without** recipient registration: set `isSmpRecipient` to `false` (or leave the checkbox unticked in the dashboard). ```json { "isSmpRecipient": false } ``` What that means: * The company is not published as a recipient on an SMP, so nothing is delivered to it over Peppol through your integration. * Registration succeeds even when the company already receives its documents through another Peppol provider. The other Peppol provider will remain in charge for processing received documents for this company. * Nothing changes for sending: outgoing documents leave through the access point as normal. You can flip `isSmpRecipient` to `true` on an existing company at any time. Recommand then publishes it as a recipient and registers the document types for its country. That registration is exclusive, so the company has to be deregistered at its current provider first. Verify the company [#verify-the-company] A company cannot exchange documents on Peppol until an authorised representative has confirmed their identity. The company object exposes this as `isVerified`, and it stays `false` until the check is done. For Belgian companies the flow is short: 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. Fill in the representative's first and last name. That name is checked against the **Crossroads Bank for Enterprises** before the identity check starts: a name that matches none of the company's registered representatives is refused. 3. Complete the identity check. `isVerified` flips to `true` and the company is published on the Peppol network. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. Verifying once, in the dashboard [#verifying-once-in-the-dashboard] You have one company, and it is verified once. There is nothing here worth automating: open [Companies](https://app.recommand.eu/companies) in the dashboard, pick the company and start verification. If you are authorised to act for the company, complete the check yourself; otherwise use the button to forward the link to whoever is. The page is self-contained and works in any browser. The person completing it does not need a Recommand account. That is the whole step. From here on the API takes over: sending and receiving documents is what you actually integrate. Updating the company's `vatNumber` or `enterpriseNumber` sets `isVerified` back to `false`, and the company has to be verified again before it can exchange documents. The document format [#the-document-format] For Belgium there is nothing to pick: leave the format alone and you send **Peppol BIS 3 UBL**, over the standard Peppol billing process. That is what Belgian recipients register, and what the Belgian B2B mandate expects. Two things are still worth checking before a first send to a new recipient: * **Is the recipient on the network?** The [verify endpoint](/reference/recipients/verify-recipient) answers that, and sending performs the same check automatically. * **Does the recipient accept this document type?** The [verify document support endpoint](/reference/recipients/verify-document-support) answers that. Most Belgian recipients accept invoices and credit notes; not all accept every other type. This is also checked automatically when sending. See [verifying recipients](/docs/verifying-recipients) for the full flow, including what to do when a recipient cannot be reached. Send a document [#send-a-document] One endpoint sends everything: [`POST /:companyId/send`](/reference/sending/send-document). The `companyId` is the sender, `recipient` is the Peppol address of the receiver, and `document` is the invoice or credit note as JSON. Recommand will validate the document and generate the XML. Raw XML sending is supported as well: set `documentType` to `xml` and pass the document string in `document`, along with the correct `doctypeId`. See [working with raw UBL](/docs/ubl-format-guide#working-with-raw-ubl). ```bash curl -X POST https://app.recommand.eu/api/v1/{companyId}/send \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @send-invoice.json ``` ```json title="send-invoice.json" { "recipient": "0208:0123456789", "documentType": "invoice", "document": { "invoiceNumber": "INV-2026-001", "issueDate": "2026-08-17", "dueDate": "2026-09-16", "currency": "EUR", "buyer": { "name": "Customer Company", "street": "Customer Street 1", "city": "Antwerp", "postalZone": "2000", "country": "BE", "vatNumber": "BE0987654321" }, "paymentMeans": [{ "iban": "BE68539007547034" }], "lines": [ { "name": "Consulting Services", "quantity": "10.00", "unitCode": "HUR", "netPriceAmount": "100.00", "vat": { "category": "S", "percentage": "21.00" } } ] } } ``` The seller block is filled in from your company when you leave it out, which is usually what you want: it keeps your registered identifiers and the document in agreement. The full field reference lives in [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Worth wiring up while you are here: * **Validation errors.** Outgoing documents are always validated. A `success: false` response with `errors` keyed by field path is a document the recipient would have rejected. Surface it wherever the data was typed. * **Email fallback.** Pass `email.to` with `when: "on_peppol_failure"` to fall back to email when a recipient turns out not to be reachable over Peppol, or send with `recipient: null` for email-only delivery. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **PDFs.** `pdfGeneration.enabled` attaches a generated PDF of the document. You can also attach an existing PDF (or other files) via `attachments`; see [adding attachments](/docs/sending-invoices#adding-attachments). For a full field reference, see [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Sending without writing code [#sending-without-writing-code] The same send is available two other ways, and they mix freely with the API: * **From the dashboard.** [Send document](https://app.recommand.eu/send-document) takes the recipient and the invoice lines, previews what the recipient will get, and remembers your usual settings. You can also drop an existing UBL or CII XML file into the upload zone if your software already produces one. * **From your accounting or invoicing software.** If you use one of the supported tools, let it do the work: your invoices flow to Recommand and out over Peppol without retyping. See [integrations](/integrations) for the current list, including Microsoft Business Central, Exact Online, Yuki, ClearFacts, ERPNext and Harvest. Whichever route you use, Recommand validates a document before it leaves. If a field is missing or malformed you get a clear error instead of a rejection from the recipient days later. See the [troubleshooting guide](/docs/troubleshooting-guide) for the errors you are most likely to run into. Going live [#going-live] A short list before you start sending or receiving real invoices: * **A valid subscription**, so sending is not blocked. Playgrounds skip that check; production does not. * **The company verified**, with `isVerified` true. Until then it cannot exchange documents. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of whoever can fix it rather than logging it. * **Webhook endpoint hardened**, if you took that route: signature verification, a fast 200, retries and idempotency on your side. * **One real document sent and received**, ideally between two companies you control, so you have seen both ends. * **Notification addresses set**, so incoming documents also reach a mailbox somebody reads. Once you are live, your Peppol address is public on the network: suppliers can find and reach you without any action from you. Ask customers who still email PDFs to switch, and let your accountant know where the documents now land. Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Receiving Peppol documents in Belgium for your own company (/getting-started/belgium/business/receiving) This guide walks through everything needed to exchange Peppol documents for a company registered in Belgium, assuming you are setting up your own Belgian company, and that the company only receives documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are setting up [#what-you-are-setting-up] You are putting one company, your own or one you represent, on the Peppol network, so it can exchange invoices electronically with its customers and suppliers. The setup is a one-time affair: registering the company and getting it verified takes a few minutes in the [Recommand dashboard](https://app.recommand.eu), and there is nothing to gain from automating something you do once. What you do integrate is the part that repeats: sending and receiving documents. Our existing [integrations](/integrations) can also connect Recommand to accounting or invoicing software you already use, with no code at all. A single team can hold several companies at no extra cost, useful if you run more than one legal entity, and the document volume of all of them counts towards one plan. If you are building e-invoicing or Peppol integration into a product for your own customers, and will be registering their companies rather than only your own, switch the first answer above to **Many companies**. The API is the same; what changes is how companies, verification and billing are organised. Peppol in Belgium [#peppol-in-belgium] Belgium runs on the standard European Peppol stack, which makes it the simplest of all countries to start in. Documents are exchanged as **Peppol BIS 3 UBL**, over the standard Peppol billing process, and Recommand's own access point and SMP handle both directions. What is specific to Belgium: * **The B2B mandate is already in force.** Since 1 January 2026 Belgian companies must be able to send and receive structured electronic invoices for domestic B2B transactions. See [what if I don't switch to Peppol](/faq/sending-and-error-handling/what-if-i-dont-switch-to-peppol-by-2026) for what non-compliance means in practice. * **Enterprise numbers are the Peppol address.** Belgian companies are published under scheme `0208` (enterprise number), which is why a Belgian Peppol address looks like `0208:0123456789`. Sometimes, scheme `9925` is used as well, which is followed by a Belgian VAT number, like this: `9925:BE0123456789`. * **Representatives are checked against the CBE.** During verification, the name given for the representative is matched against the company's registered representatives in the Crossroads Bank for Enterprises, so a name that is not authorised is refused up front. Create your account and API credentials [#create-your-account-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). 2. Your account starts with a **team**. The team holds your company, your subscription and your document history, and you can invite colleagues to it. 3. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 4. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Sending and receiving can also be driven entirely from the dashboard or through an [integration](/integrations), and each section below says how. The dashboard is available in English, Dutch, French and German; pick your language on the [account page](https://app.recommand.eu/account). Try it safely first [#try-it-safely-first] You do not have to get anything right the first time. Everything below, adding the company, registering it, sending and receiving, can be done in a **playground team** first, where nothing is delivered over the real Peppol network, nothing is registered on it, and nothing is billed. Open the team switcher at the top of the [dashboard](https://app.recommand.eu) and pick **Add playground**. Give it a name, leave the Peppol Test Network box unticked, and you are switched into the new team straight away. There is nothing to set up beyond that. Add a company to that team and use it as both sender and recipient to watch a document travel end to end. When the flow does what you want, repeat it once in your real team. Two things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. A playground stays useful after you are live, too: it is the safest place to try a new invoice layout or a new integration. See [how can I test without sending real invoices](/faq/api-and-development/how-can-i-test-without-sending-real-invoices). Playground companies are not registered on the Peppol network and playground documents never leave it, so nothing you do there affects your real company. Register the company [#register-the-company] You are registering one company, once, so the dashboard is the shortest path. 1. Open [Companies](https://app.recommand.eu/companies) and start the company wizard. 2. Fill in the legal name, address and country, plus the identifiers described in the next section. 3. Choose whether the company should also **receive** documents over Peppol, or only send them. 4. Save. The company is registered on the Peppol network as part of this step: its identifiers and the document types for its country are set up for you. Right after saving, the dashboard offers the verification step, which the section below covers. Note the company's ID from its detail page. Every API call for sending and receiving takes it in the path. The [create company endpoint](/reference/companies/create-company) does exactly the same thing, and returns the company `id` and a `verificationUrl` in one response. It is worth using when company creation is part of a flow you are automating, which is likely the case if you are registering many companies. Switch the first answer above to **Many companies** for that version. Add each legal entity as its own company: run the wizard again. There is no per-company fee, and all of them share your document volume. Belgian identifiers and Peppol address [#belgian-identifiers-and-peppol-address] | Field | Belgian value | | ------------------------ | ----------------------------------------------------------- | | `country` | `"BE"` | | `enterpriseNumber` | 10 digits, starting with `0` or `1` (modulo-97 check digit) | | `enterpriseNumberScheme` | `"0208"` | | `vatNumber` | `BE` + the same 10 digits | ```json title="company.json" { "name": "ACME Corporation", "address": "123 Main Street", "postalCode": "1000", "city": "Brussels", "country": "BE", "enterpriseNumber": "0123456789", "enterpriseNumberScheme": "0208", "vatNumber": "BE0123456789" } ``` Both numbers are validated against the national rules, including the modulo-97 check digit, and a mismatch is rejected instead of silently registered. For Belgian companies the enterprise number is derived from the VAT number when you leave it out. Two Peppol identifiers are then registered for the company: * `0208:0123456789` is the enterprise number, and the address others will use * `9925:BE0123456789` is the VAT number The company's Peppol address is the first one: **`0208:` followed by the enterprise number**. Registering as a recipient [#registering-as-a-recipient] To receive documents, the company must be published as a recipient on an SMP (Service Metadata Publisher). That is what `isSmpRecipient` does, and it is the default: ```json { "isSmpRecipient": true } ``` What that means: * The company becomes findable on the Peppol network: any sender can look it up and deliver to it via the Peppol network. * Recipient registration is **exclusive**. If the company is already registered for receiving through another Peppol provider, registration fails until it is deregistered there. * The document types the company accepts are registered along with it, based on its country. Which ones those are is covered further down. * The company is only published once it is verified. Moving an existing Belgian registration [#moving-an-existing-belgian-registration] Since the B2B mandate came into force, most Belgian companies are already reachable over Peppol through a provider of their own. Recipient registration is exclusive, so registering the enterprise number under scheme `0208` fails while the company is still published somewhere else: it has to be deregistered at its current provider first. If this is the case, we will let you know which SMP the company is published on. You can also look the enterprise number up ahead of time with the [verify endpoint](/reference/recipients/verify-recipient), which returns the same thing. Mail [support@recommand.eu](mailto:support@recommand.eu) with the enterprise number and we will work out where the company is registered. Verify the company [#verify-the-company] A company cannot exchange documents on Peppol until an authorised representative has confirmed their identity. The company object exposes this as `isVerified`, and it stays `false` until the check is done. For Belgian companies the flow is short: 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. Fill in the representative's first and last name. That name is checked against the **Crossroads Bank for Enterprises** before the identity check starts: a name that matches none of the company's registered representatives is refused. 3. Complete the identity check. `isVerified` flips to `true` and the company is published on the Peppol network. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. Verifying once, in the dashboard [#verifying-once-in-the-dashboard] You have one company, and it is verified once. There is nothing here worth automating: open [Companies](https://app.recommand.eu/companies) in the dashboard, pick the company and start verification. If you are authorised to act for the company, complete the check yourself; otherwise use the button to forward the link to whoever is. The page is self-contained and works in any browser. The person completing it does not need a Recommand account. That is the whole step. From here on the API takes over: sending and receiving documents is what you actually integrate. Updating the company's `vatNumber` or `enterpriseNumber` sets `isVerified` back to `false`, and the company has to be verified again before it can exchange documents. Document types registered for you [#document-types-registered-for-you] When you register a Belgian company as a recipient, it is published for the two document types that cover almost all Belgian traffic: | Document type | Process | | ------------------------------ | --------------------------------------------- | | Invoice (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Credit note (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | Anything sent to the company in one of these formats is accepted, validated, stored and handed to you. A sender who tries a document type the company is not published for gets an error before delivery, which is exactly the point of the registration. Need more document types, such as self-billing, message level responses, invoice responses? Register the combinations you want with the [create company document type endpoint](/reference/company-document-types/create-company-document-type). Pick up incoming documents [#pick-up-incoming-documents] Once the company is published as a recipient, everything sent to it arrives in Recommand automatically. There are two ways to get the documents into your own systems. Webhooks (recommended) [#webhooks-recommended] Register an endpoint once with the [create webhook endpoint](/reference/webhooks/create-webhook) and events are pushed to you as they happen, `document.received` among them: ```bash curl -X POST https://app.recommand.eu/api/v1/webhooks \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @create-webhook.json ``` ```json title="create-webhook.json" { "url": "https://your-app.example/webhooks/recommand", "companyId": null, "secret": "your_webhook_signing_secret" } ``` Pass a `secret` and verify the HMAC SHA-256 signature on every delivery before you trust the payload, then acknowledge with a 200 before doing the heavy processing. Both are covered in [working with webhooks](/docs/working-with-webhooks). Polling the inbox [#polling-the-inbox] If you would rather pull, the [inbox endpoint](/reference/documents/get-inbox) lists unread documents, and [mark as read](/reference/documents/mark-as-read) drops one off the list once your system has it. Fetch details, the original XML or a rendered PDF from the [documents endpoints](/reference/documents/get-document). Receiving without writing code [#receiving-without-writing-code] * **In the dashboard.** Incoming invoices appear under [Sent and received](https://app.recommand.eu/transmitted-documents), with the original XML, a readable rendering, attachments and the delivery history. * **By email.** Add notification email addresses per company so incoming documents land in the mailbox your bookkeeping already watches, attachments included. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **In your accounting software.** Forward incoming documents straight to Exact Online, Yuki, ClearFacts or another supported tool, see [integrations](/integrations). Two things worth setting up early, whichever route you take: * **Labels and suppliers** to keep documents organised as volume grows, see [suppliers and labels](/docs/suppliers-and-labels). * **Rules** to act on incoming documents automatically: forwarding, labelling, notifying, see [rules](/docs/rules). The full picture, including retries and idempotency, is in [receiving documents](/docs/receiving-documents). Going live [#going-live] A short list before you start sending or receiving real invoices: * **A valid subscription**, so sending is not blocked. Playgrounds skip that check; production does not. * **The company verified**, with `isVerified` true. Until then it cannot exchange documents. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of whoever can fix it rather than logging it. * **Webhook endpoint hardened**, if you took that route: signature verification, a fast 200, retries and idempotency on your side. * **One real document sent and received**, ideally between two companies you control, so you have seen both ends. * **Notification addresses set**, so incoming documents also reach a mailbox somebody reads. Once you are live, your Peppol address is public on the network: suppliers can find and reach you without any action from you. Ask customers who still email PDFs to switch, and let your accountant know where the documents now land. Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Sending and receiving Peppol documents in Belgium for your own company (/getting-started/belgium/business/sending-and-receiving) This guide walks through everything needed to exchange Peppol documents for a company registered in Belgium, assuming you are setting up your own Belgian company, and that the company sends and receives documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are setting up [#what-you-are-setting-up] You are putting one company, your own or one you represent, on the Peppol network, so it can exchange invoices electronically with its customers and suppliers. The setup is a one-time affair: registering the company and getting it verified takes a few minutes in the [Recommand dashboard](https://app.recommand.eu), and there is nothing to gain from automating something you do once. What you do integrate is the part that repeats: sending and receiving documents. Our existing [integrations](/integrations) can also connect Recommand to accounting or invoicing software you already use, with no code at all. A single team can hold several companies at no extra cost, useful if you run more than one legal entity, and the document volume of all of them counts towards one plan. If you are building e-invoicing or Peppol integration into a product for your own customers, and will be registering their companies rather than only your own, switch the first answer above to **Many companies**. The API is the same; what changes is how companies, verification and billing are organised. Peppol in Belgium [#peppol-in-belgium] Belgium runs on the standard European Peppol stack, which makes it the simplest of all countries to start in. Documents are exchanged as **Peppol BIS 3 UBL**, over the standard Peppol billing process, and Recommand's own access point and SMP handle both directions. What is specific to Belgium: * **The B2B mandate is already in force.** Since 1 January 2026 Belgian companies must be able to send and receive structured electronic invoices for domestic B2B transactions. See [what if I don't switch to Peppol](/faq/sending-and-error-handling/what-if-i-dont-switch-to-peppol-by-2026) for what non-compliance means in practice. * **Enterprise numbers are the Peppol address.** Belgian companies are published under scheme `0208` (enterprise number), which is why a Belgian Peppol address looks like `0208:0123456789`. Sometimes, scheme `9925` is used as well, which is followed by a Belgian VAT number, like this: `9925:BE0123456789`. * **Representatives are checked against the CBE.** During verification, the name given for the representative is matched against the company's registered representatives in the Crossroads Bank for Enterprises, so a name that is not authorised is refused up front. Create your account and API credentials [#create-your-account-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). 2. Your account starts with a **team**. The team holds your company, your subscription and your document history, and you can invite colleagues to it. 3. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 4. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Sending and receiving can also be driven entirely from the dashboard or through an [integration](/integrations), and each section below says how. The dashboard is available in English, Dutch, French and German; pick your language on the [account page](https://app.recommand.eu/account). Try it safely first [#try-it-safely-first] You do not have to get anything right the first time. Everything below, adding the company, registering it, sending and receiving, can be done in a **playground team** first, where nothing is delivered over the real Peppol network, nothing is registered on it, and nothing is billed. Open the team switcher at the top of the [dashboard](https://app.recommand.eu) and pick **Add playground**. Give it a name, leave the Peppol Test Network box unticked, and you are switched into the new team straight away. There is nothing to set up beyond that. Add a company to that team and use it as both sender and recipient to watch a document travel end to end. When the flow does what you want, repeat it once in your real team. Two things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. A playground stays useful after you are live, too: it is the safest place to try a new invoice layout or a new integration. See [how can I test without sending real invoices](/faq/api-and-development/how-can-i-test-without-sending-real-invoices). Playground companies are not registered on the Peppol network and playground documents never leave it, so nothing you do there affects your real company. Register the company [#register-the-company] You are registering one company, once, so the dashboard is the shortest path. 1. Open [Companies](https://app.recommand.eu/companies) and start the company wizard. 2. Fill in the legal name, address and country, plus the identifiers described in the next section. 3. Choose whether the company should also **receive** documents over Peppol, or only send them. 4. Save. The company is registered on the Peppol network as part of this step: its identifiers and the document types for its country are set up for you. Right after saving, the dashboard offers the verification step, which the section below covers. Note the company's ID from its detail page. Every API call for sending and receiving takes it in the path. The [create company endpoint](/reference/companies/create-company) does exactly the same thing, and returns the company `id` and a `verificationUrl` in one response. It is worth using when company creation is part of a flow you are automating, which is likely the case if you are registering many companies. Switch the first answer above to **Many companies** for that version. Add each legal entity as its own company: run the wizard again. There is no per-company fee, and all of them share your document volume. Belgian identifiers and Peppol address [#belgian-identifiers-and-peppol-address] | Field | Belgian value | | ------------------------ | ----------------------------------------------------------- | | `country` | `"BE"` | | `enterpriseNumber` | 10 digits, starting with `0` or `1` (modulo-97 check digit) | | `enterpriseNumberScheme` | `"0208"` | | `vatNumber` | `BE` + the same 10 digits | ```json title="company.json" { "name": "ACME Corporation", "address": "123 Main Street", "postalCode": "1000", "city": "Brussels", "country": "BE", "enterpriseNumber": "0123456789", "enterpriseNumberScheme": "0208", "vatNumber": "BE0123456789" } ``` Both numbers are validated against the national rules, including the modulo-97 check digit, and a mismatch is rejected instead of silently registered. For Belgian companies the enterprise number is derived from the VAT number when you leave it out. Two Peppol identifiers are then registered for the company: * `0208:0123456789` is the enterprise number, and the address others will use * `9925:BE0123456789` is the VAT number The company's Peppol address is the first one: **`0208:` followed by the enterprise number**. Registering for both directions [#registering-for-both-directions] Sending needs no registration of its own; receiving does. So register the company as a recipient, which is the default: ```json { "isSmpRecipient": true } ``` What that means: * The company becomes findable on the Peppol network and can be delivered to through Recommand's access point, while sending its own documents out through the same access point. * Recipient registration is **exclusive**. If the company already receives through another Peppol provider, registration fails until it is deregistered there. What that takes depends on the country, which the next section covers. * The document types the company accepts are registered along with it, based on its country. Which ones those are is covered further down. * The company is only published once it is verified. If the company still receives elsewhere and you do not want to move that yet, register it with `isSmpRecipient: false` and start with sending only. Flipping the field later publishes it as a recipient. Moving an existing Belgian registration [#moving-an-existing-belgian-registration] Since the B2B mandate came into force, most Belgian companies are already reachable over Peppol through a provider of their own. Recipient registration is exclusive, so registering the enterprise number under scheme `0208` fails while the company is still published somewhere else: it has to be deregistered at its current provider first. If this is the case, we will let you know which SMP the company is published on. You can also look the enterprise number up ahead of time with the [verify endpoint](/reference/recipients/verify-recipient), which returns the same thing. Mail [support@recommand.eu](mailto:support@recommand.eu) with the enterprise number and we will work out where the company is registered. Verify the company [#verify-the-company] A company cannot exchange documents on Peppol until an authorised representative has confirmed their identity. The company object exposes this as `isVerified`, and it stays `false` until the check is done. For Belgian companies the flow is short: 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. Fill in the representative's first and last name. That name is checked against the **Crossroads Bank for Enterprises** before the identity check starts: a name that matches none of the company's registered representatives is refused. 3. Complete the identity check. `isVerified` flips to `true` and the company is published on the Peppol network. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. Verifying once, in the dashboard [#verifying-once-in-the-dashboard] You have one company, and it is verified once. There is nothing here worth automating: open [Companies](https://app.recommand.eu/companies) in the dashboard, pick the company and start verification. If you are authorised to act for the company, complete the check yourself; otherwise use the button to forward the link to whoever is. The page is self-contained and works in any browser. The person completing it does not need a Recommand account. That is the whole step. From here on the API takes over: sending and receiving documents is what you actually integrate. Updating the company's `vatNumber` or `enterpriseNumber` sets `isVerified` back to `false`, and the company has to be verified again before it can exchange documents. The document format [#the-document-format] For Belgium there is nothing to pick: leave the format alone and you send **Peppol BIS 3 UBL**, over the standard Peppol billing process. That is what Belgian recipients register, and what the Belgian B2B mandate expects. Two things are still worth checking before a first send to a new recipient: * **Is the recipient on the network?** The [verify endpoint](/reference/recipients/verify-recipient) answers that, and sending performs the same check automatically. * **Does the recipient accept this document type?** The [verify document support endpoint](/reference/recipients/verify-document-support) answers that. Most Belgian recipients accept invoices and credit notes; not all accept every other type. This is also checked automatically when sending. See [verifying recipients](/docs/verifying-recipients) for the full flow, including what to do when a recipient cannot be reached. Send a document [#send-a-document] One endpoint sends everything: [`POST /:companyId/send`](/reference/sending/send-document). The `companyId` is the sender, `recipient` is the Peppol address of the receiver, and `document` is the invoice or credit note as JSON. Recommand will validate the document and generate the XML. Raw XML sending is supported as well: set `documentType` to `xml` and pass the document string in `document`, along with the correct `doctypeId`. See [working with raw UBL](/docs/ubl-format-guide#working-with-raw-ubl). ```bash curl -X POST https://app.recommand.eu/api/v1/{companyId}/send \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @send-invoice.json ``` ```json title="send-invoice.json" { "recipient": "0208:0123456789", "documentType": "invoice", "document": { "invoiceNumber": "INV-2026-001", "issueDate": "2026-08-17", "dueDate": "2026-09-16", "currency": "EUR", "buyer": { "name": "Customer Company", "street": "Customer Street 1", "city": "Antwerp", "postalZone": "2000", "country": "BE", "vatNumber": "BE0987654321" }, "paymentMeans": [{ "iban": "BE68539007547034" }], "lines": [ { "name": "Consulting Services", "quantity": "10.00", "unitCode": "HUR", "netPriceAmount": "100.00", "vat": { "category": "S", "percentage": "21.00" } } ] } } ``` The seller block is filled in from your company when you leave it out, which is usually what you want: it keeps your registered identifiers and the document in agreement. The full field reference lives in [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Worth wiring up while you are here: * **Validation errors.** Outgoing documents are always validated. A `success: false` response with `errors` keyed by field path is a document the recipient would have rejected. Surface it wherever the data was typed. * **Email fallback.** Pass `email.to` with `when: "on_peppol_failure"` to fall back to email when a recipient turns out not to be reachable over Peppol, or send with `recipient: null` for email-only delivery. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **PDFs.** `pdfGeneration.enabled` attaches a generated PDF of the document. You can also attach an existing PDF (or other files) via `attachments`; see [adding attachments](/docs/sending-invoices#adding-attachments). For a full field reference, see [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Sending without writing code [#sending-without-writing-code] The same send is available two other ways, and they mix freely with the API: * **From the dashboard.** [Send document](https://app.recommand.eu/send-document) takes the recipient and the invoice lines, previews what the recipient will get, and remembers your usual settings. You can also drop an existing UBL or CII XML file into the upload zone if your software already produces one. * **From your accounting or invoicing software.** If you use one of the supported tools, let it do the work: your invoices flow to Recommand and out over Peppol without retyping. See [integrations](/integrations) for the current list, including Microsoft Business Central, Exact Online, Yuki, ClearFacts, ERPNext and Harvest. Whichever route you use, Recommand validates a document before it leaves. If a field is missing or malformed you get a clear error instead of a rejection from the recipient days later. See the [troubleshooting guide](/docs/troubleshooting-guide) for the errors you are most likely to run into. Document types registered for you [#document-types-registered-for-you] When you register a Belgian company as a recipient, it is published for the two document types that cover almost all Belgian traffic: | Document type | Process | | ------------------------------ | --------------------------------------------- | | Invoice (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Credit note (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | Anything sent to the company in one of these formats is accepted, validated, stored and handed to you. A sender who tries a document type the company is not published for gets an error before delivery, which is exactly the point of the registration. Need more document types, such as self-billing, message level responses, invoice responses? Register the combinations you want with the [create company document type endpoint](/reference/company-document-types/create-company-document-type). Pick up incoming documents [#pick-up-incoming-documents] Once the company is published as a recipient, everything sent to it arrives in Recommand automatically. There are two ways to get the documents into your own systems. Webhooks (recommended) [#webhooks-recommended] Register an endpoint once with the [create webhook endpoint](/reference/webhooks/create-webhook) and events are pushed to you as they happen, `document.received` among them: ```bash curl -X POST https://app.recommand.eu/api/v1/webhooks \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @create-webhook.json ``` ```json title="create-webhook.json" { "url": "https://your-app.example/webhooks/recommand", "companyId": null, "secret": "your_webhook_signing_secret" } ``` Pass a `secret` and verify the HMAC SHA-256 signature on every delivery before you trust the payload, then acknowledge with a 200 before doing the heavy processing. Both are covered in [working with webhooks](/docs/working-with-webhooks). Polling the inbox [#polling-the-inbox] If you would rather pull, the [inbox endpoint](/reference/documents/get-inbox) lists unread documents, and [mark as read](/reference/documents/mark-as-read) drops one off the list once your system has it. Fetch details, the original XML or a rendered PDF from the [documents endpoints](/reference/documents/get-document). Receiving without writing code [#receiving-without-writing-code] * **In the dashboard.** Incoming invoices appear under [Sent and received](https://app.recommand.eu/transmitted-documents), with the original XML, a readable rendering, attachments and the delivery history. * **By email.** Add notification email addresses per company so incoming documents land in the mailbox your bookkeeping already watches, attachments included. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **In your accounting software.** Forward incoming documents straight to Exact Online, Yuki, ClearFacts or another supported tool, see [integrations](/integrations). Two things worth setting up early, whichever route you take: * **Labels and suppliers** to keep documents organised as volume grows, see [suppliers and labels](/docs/suppliers-and-labels). * **Rules** to act on incoming documents automatically: forwarding, labelling, notifying, see [rules](/docs/rules). The full picture, including retries and idempotency, is in [receiving documents](/docs/receiving-documents). Going live [#going-live] A short list before you start sending or receiving real invoices: * **A valid subscription**, so sending is not blocked. Playgrounds skip that check; production does not. * **The company verified**, with `isVerified` true. Until then it cannot exchange documents. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of whoever can fix it rather than logging it. * **Webhook endpoint hardened**, if you took that route: signature verification, a fast 200, retries and idempotency on your side. * **One real document sent and received**, ideally between two companies you control, so you have seen both ends. * **Notification addresses set**, so incoming documents also reach a mailbox somebody reads. Once you are live, your Peppol address is public on the network: suppliers can find and reach you without any action from you. Ask customers who still email PDFs to switch, and let your accountant know where the documents now land. Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Sending Peppol documents in France for the companies you onboard (/getting-started/france/platform/sending) This guide walks through everything needed to exchange Peppol documents for a company registered in France, assuming you are integrating Recommand into your own product and onboarding French companies as your users, and that the company only sends documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are building [#what-you-are-building] You are onboarding companies that are not your own: one Recommand team, and a company inside it for every customer you put on the network. Your customers never need a Recommand account. They see your interface, and Recommand stays behind your API calls. That shape has a few consequences worth knowing before you write code: * **One team, many companies.** There is no limit on companies per team, and billing is per team with the document volume of all companies pooled together, so the more companies you onboard the lower your price per document. See [pricing per team](/faq/general-usage/is-pricing-per-company-or-per-team). * **Every company is registered and verified individually.** Peppol identifies companies, not platforms. Each company gets its own Peppol address and its own authorisation record. * **Verification is taken care of.** Recommand hands you a URL that the company's authorised representative opens to confirm their identity. You present or forward that link; you never need to handle identity documents yourself. If you prefer to handle verification yourself, reach out to us at [support@recommand.eu](mailto:support@recommand.eu), we have a few other flows we can set up for you. * **You can run the whole flow under your own brand.** The API is designed for white-label use, see [can I whitelabel Recommand](/faq/general-usage/can-i-whitelabel-integrate-recommand). The [Recommand dashboard](https://app.recommand.eu) shows the same teams, companies and documents your API calls produce, which is the quickest way to see what a customer is looking at while you are debugging. If the only company you will register is your own, switch the first answer above to **One company** for the shorter version of this guide. The endpoints are the same; there is simply less to organise. Peppol in France [#peppol-in-france] French domestic e-invoicing follows the French e-invoicing reform rather than plain Peppol BIS 3. Recommand covers the French specifics for you, but they do change what you send and how a company is onboarded. What is specific to France: * **A French-accredited access point and SMP.** Companies you register with country `FR` are automatically published on a French-accredited SMP and exchange documents through the matching access point. You do not choose or configure this: it follows from the company's country. * **A signed mandate.** Before a French company can operate, its authorised representative signs a mandate that lets that accredited platform act for the company, and the file is reviewed before the company goes live. This is the one step in this guide that is not instant, so start it early. * **French document formats.** Invoices and credit notes travel as French CIUS or Extended UBL, CII D22B (CIUS or Extended), or Factur-X (a PDF/A-3 with the CII XML embedded), next to plain Peppol BIS 3 UBL. * **Two processes.** The same document types are published for a **regulated** process (`urn:peppol:france:billing:regulated`, transactions inside the French e-invoicing perimeter) and a **non-regulated** one (`urn:peppol:france:billing:non-regulated`, transactions outside it). * **Mandatory content.** French invoices carry a billing mode and three statements (recovery costs, late-payment penalties, early-payment discount) that plain EN 16931 does not require. They go in a `countrySpecific` block. * **Lifecycle statuses.** Inside the perimeter, receivers report back on the invoices they receive with an invoice lifecycle status. * **E-reporting.** What falls outside the e-invoicing perimeter is reported instead: B2C sales as daily totals, and invoices to businesses abroad one by one. Recommand files both report types on the company's behalf. * **Identifiers are SIREN-based.** French companies are published under scheme `0225`. The reform phases the obligations in over time: from **1 September 2026** every company must be able to receive electronic invoices, with issuance starting for large and mid-size companies, and from **1 September 2027** issuance applies to small and micro companies as well. Confirm the schedule and what falls inside the perimeter with your accountant or legal advisor. This documentation describes what the API does, not what your obligations are. Create your team and API credentials [#create-your-team-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). The team you get is the container for every company you will onboard. 2. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 3. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Try it safely first [#try-it-safely-first] Build the whole flow against a **playground team** before you touch production. Playgrounds look and behave like production teams, but nothing is delivered over the real Peppol network, there are no SMP registrations, no subscription checks and no billing. Create one from the team switcher at the top of the [dashboard](https://app.recommand.eu): **Add playground**, give it a name, and you are switched into it. There is no limit on how many you create. Everything that follows in this guide is identical there: same endpoints, same validation, same webhooks (triggered by simulated inbound delivery). Register a company in the playground and use it as both sender and recipient to see a document arrive. Three things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`, which is the quickest way to check that your country-specific fields map to the format and process you expect. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. * **The Peppol Test Network.** For genuine end-to-end tests with real counterparties, tick **Use Peppol Test Network** when you create the playground. It then uses dedicated test access point and SMP endpoints while staying fully separated from production. The setting cannot be changed after creation, so make a second playground if you want both. More detail in the [getting started guide](/docs) and [how do I use the playground environment](/faq/api-and-development/how-do-i-use-the-playground-environment). Register the company [#register-the-company] Create one company per customer with the [create company endpoint](/reference/companies/create-company). Registration on the Peppol network happens as part of this call: identifiers and document types are set up for you, based on the company's country. ```javascript const auth = "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"); const response = await fetch("https://app.recommand.eu/api/v1/companies", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(company), }); const result = await response.json(); if (!result.success) throw new Error(JSON.stringify(result.errors)); const companyId = result.company.id; const verificationUrl = result.verificationUrl; // hand this to your user ``` ```bash curl -X POST https://app.recommand.eu/api/v1/companies \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @company.json ``` The response carries a `verificationUrl` straight away. Keep it: the next step is to put it in front of the company's representative. Register the companies that use your platform, not the companies they invoice. Customers and suppliers manage their own Peppol registration; adding them causes registration conflicts. See [managing companies](/docs/managing-companies). The exact identifier fields to send depend on the country, which is what the next section covers. If you would rather create identifiers and document types yourself instead of accepting the country defaults, pass `skipDefaultCompanySetup: true` and use the [company identifiers](/reference/company-identifiers/create-company-identifier) and [company document types](/reference/company-document-types/get-company-document-types) endpoints. French identifiers and Peppol address [#french-identifiers-and-peppol-address] In France the identifier you register decides whether your documents will pass validation later, so it is worth getting exactly right. | Field | French value | | ------------------------ | --------------------------------------- | | `country` | `"FR"` | | `enterpriseNumber` | The nine-digit **SIREN** of the company | | `enterpriseNumberScheme` | `"0002"` | | `vatNumber` | `FR` + the French VAT number | ```json title="company.json" { "name": "Société de Test SAS", "address": "10 rue de la Paix", "postalCode": "75002", "city": "Paris", "country": "FR", "enterpriseNumber": "133512194", "enterpriseNumberScheme": "0002", "vatNumber": "FR23133512194" } ``` French regulated invoices must carry the seller's nine-digit SIREN as `enterpriseNumber` with `enterpriseNumberScheme` `"0002"`. Because the seller block of a document defaults to the company's own details, a company registered with a SIRET or without the scheme produces invoices that are rejected at validation time. Register the SIREN, and name a specific establishment through the document's `delivery.locationIdentifier` (scheme `0009`) when you need to. One Peppol identifier is registered for the company: * `0225:133512194` is the French electronic address The company's Peppol address is therefore **`0225:` followed by the SIREN**. French addresses may also carry a routing suffix, as in `0225:987654321_STATUTS`; treat the whole string after the scheme as the identifier when a recipient gives you one. Both SIREN (9 digits) and SIRET (14 digits) are checked with the Luhn algorithm before they are filed, and numbers that disagree with each other are refused rather than guessed at. Registering for sending only [#registering-for-sending-only] Because you are only looking to send invoices or other documents, register the company **without** recipient registration: set `isSmpRecipient` to `false` (or leave the checkbox unticked in the dashboard). ```json { "isSmpRecipient": false } ``` What that means: * The company is not published as a recipient on an SMP, so nothing is delivered to it over Peppol through your integration. * Registration succeeds even when the company already receives its documents through another Peppol provider. The other Peppol provider will remain in charge for processing received documents for this company. * Nothing changes for sending: outgoing documents leave through the access point as normal. You can flip `isSmpRecipient` to `true` on an existing company at any time. Recommand then publishes it as a recipient and registers the document types for its country. That registration is exclusive, so the company has to be deregistered at its current provider first. Sign the mandate and verify the company [#sign-the-mandate-and-verify-the-company] French companies go through the same identity check as everyone else, plus two steps that are specific to France: the representative signs a mandate, and the resulting file is reviewed before the company goes live. 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. **Read and sign the mandate.** The verification page shows the mandate that authorises the French-accredited platform to act for the company on the Peppol network, naming the company by its SIREN and the establishment it is filed under. The representative accepts it before the identity check starts. 3. **Complete the identity check.** The identity verification is what signs the mandate: the proof reference is recorded on it. 4. **Wait for the review.** The signed mandate and the company's details are filed with the accredited platform, and the verification sits in review until that file is accepted. Only then does `isVerified` become `true` and the company start operating. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. This is the one step of French onboarding that is not immediate. Start verification as soon as the company is created, and do not promise your users a same-minute go-live for France. If a file seems stuck, mail [support@recommand.eu](mailto:support@recommand.eu) with the company ID. Companies in a playground team are never filed with the accredited platform, so there is no mandate and no review. Test the French flow in a playground first, then run the real thing once. Building verification into your onboarding [#building-verification-into-your-onboarding] With one company you would click through this once. With many, verification is part of the flow you build: every company you register needs its own, and it is the step most likely to leave a customer stuck halfway. **Show the URL immediately.** The create-company response already carries `verificationUrl`, so no extra call is needed. Put it in front of the user while they are still in your onboarding. **Ask for a fresh one when the moment has passed.** Links get lost, and companies you created earlier never had one shown. The [verify company endpoint](/reference/companies/verify-company) starts a new verification session: ```bash curl -X POST https://app.recommand.eu/api/v1/companies/{companyId}/verify \ -u key_xxx:secret_xxx ``` The `company.verification` webhook fires when verification reaches a final state: `verified`, `rejected` or `error`. A company that comes back `rejected` or `error` and is not surfaced anywhere sits silently unusable. See [working with webhooks](/docs/working-with-webhooks). **Respect `isVerified` in your own UI.** Do not let a user press send for a company that is not verified yet; this will result in an error. You should inform the user what is missing instead. **Re-verify after identifier changes.** Updating a company's `vatNumber` or `enterpriseNumber` resets `isVerified` to `false`. Check the field after an update and present a new `verificationUrl` if it flipped. The full mechanics are in the [company verification guide](/docs/company-verification). Pick the French document format and process [#pick-the-french-document-format-and-process] A French invoice needs three decisions: the format, the process, and the mandatory French content. The format [#the-format] Name the format with `doctypeId` on the send request. Leave it off and the recipient is looked up and the document written in the first format, in [our order of preference](/changelog/2026-08-28-automatic-document-format-routing), they are registered to receive. Peppol BIS 3 UBL comes first in that order, so a French recipient who publishes it as well receives plain BIS 3: valid on the network, but not what the French reform asks for inside its perimeter. Name the French format you want for transactions inside the perimeter. | Format | `doctypeId` | | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | France UBL CIUS invoice | `urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:peppol:france:billing:cius:1.0::2.1` | | France UBL CIUS credit note | `urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2::CreditNote##urn:cen.eu:en16931:2017#compliant#urn:peppol:france:billing:cius:1.0::2.1` | | France UBL Extended invoice | `urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#conformant#urn:peppol:france:billing:extended:1.0::2.1` | | France CII CIUS | `urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100::CrossIndustryInvoice##urn:cen.eu:en16931:2017#compliant#urn:peppol:france:billing:cius:1.0::D22B` | | France CII Extended | `urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100::CrossIndustryInvoice##urn:cen.eu:en16931:2017#conformant#urn:peppol:france:billing:extended:1.0::D22B` | | France Factur-X | `urn:peppol:doctype:pdf+xml##urn:cen.eu:en16931:2017#conformant#urn:peppol:france:billing:Factur-X:1.0::D22B` | The CII and Factur-X document types carry both invoices and credit notes; the `documentType` field of your request decides which one it is. Start with **France UBL CIUS** unless you have a reason not to. Extended is for data the CIUS does not carry, and Factur-X is for recipients who want a human-readable PDF as the carrier. The process [#the-process] Set `countrySpecific.businessProcess` to say which side of the French perimeter the transaction is on. The document is then sent over the matching process: | `businessProcess` | Process identifier | Use for | | --------------------- | ----------------------------------------- | ---------------------------------------- | | `REGULATED` (default) | `urn:peppol:france:billing:regulated` | Transactions inside the French perimeter | | `NON_REGULATED` | `urn:peppol:france:billing:non-regulated` | Transactions outside it | The recipient must have registered the document type **for that process**. Pass the `processId` to the [verify document support endpoint](/reference/recipients/verify-document-support) to check exactly that combination rather than "any process". The mandatory French content [#the-mandatory-french-content] French UBL, CII and Factur-X require a `countrySpecific` block with the billing mode and the three statements French invoices must carry. It is required for those document types and must be omitted for plain EN 16931 documents. ```json { "countrySpecific": { "country": "FR", "billingMode": "S1", "businessProcess": "REGULATED", "recoveryCostsNote": "Indemnité forfaitaire de 40 EUR pour frais de recouvrement.", "latePaymentPenaltiesNote": "Pénalités de retard exigibles au taux prévu dans les conditions générales de vente.", "earlyPaymentDiscountNote": "Aucun escompte accordé pour paiement anticipé." } } ``` `billingMode` follows AFNOR XP Z12-012. The common ones are `B1` (goods), `S1` (services) and `M1` (mixed); the full list, including already-paid, advance payment, subcontracting and multi-seller variants, is documented on the [send document endpoint](/reference/sending/send-document). Invoicing outside France [#invoicing-outside-france] The French formats and processes are for the French perimeter. A counterparty in another country is registered for the **standard** Peppol billing process, so a regulated document does not match anything they published. For those invoices, send plain Peppol BIS 3 UBL and leave the `countrySpecific` block out with it, it belongs to the French document types only. The rest of the invoice is unchanged. * The seller's `enterpriseNumber` must be the nine-digit SIREN with `enterpriseNumberScheme` `"0002"`. * The currency must be `EUR`. * Factur-X needs a compliant PDF/A-3 to embed the XML in: either attach one as an embedded attachment, or let Recommand generate it with `pdfGeneration.enabled`. Send a document [#send-a-document] One endpoint sends everything: [`POST /:companyId/send`](/reference/sending/send-document). The `companyId` is the sender, `recipient` is the Peppol address of the receiver, and `document` is the invoice or credit note as JSON. Recommand will validate the document and generate the XML. Raw XML sending is supported as well: set `documentType` to `xml` and pass the document string in `document`, along with the correct `doctypeId`. See [working with raw UBL](/docs/ubl-format-guide#working-with-raw-ubl). ```javascript const response = await fetch( `https://app.recommand.eu/api/v1/${companyId}/send`, { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, // The body below, with doctypeId and countrySpecific where the country // needs them. body: JSON.stringify(sendRequest), } ); const result = await response.json(); if (!result.success) { // result.errors is keyed by field path, e.g. { "buyer.vatNumber": [...] } } ``` ```bash curl -X POST https://app.recommand.eu/api/v1/{companyId}/send \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @send-invoice.json ``` ```json title="send-invoice.json" { "recipient": "0208:0123456789", "documentType": "invoice", "document": { "invoiceNumber": "INV-2026-001", "issueDate": "2026-08-17", "dueDate": "2026-09-16", "currency": "EUR", "buyer": { "name": "Customer Company", "street": "Customer Street 1", "city": "Antwerp", "postalZone": "2000", "country": "BE", "vatNumber": "BE0987654321" }, "paymentMeans": [{ "iban": "BE68539007547034" }], "lines": [ { "name": "Consulting Services", "quantity": "10.00", "unitCode": "HUR", "netPriceAmount": "100.00", "vat": { "category": "S", "percentage": "21.00" } } ] } } ``` The seller block is filled in from the company when you leave it out, which is usually what you want: it keeps the company's registered identifiers and the document in agreement. Things worth wiring up while you are here: * **Validation errors.** Outgoing documents are always validated. A `success: false` response with `errors` keyed by field path is a document your recipient would have rejected, so surface it to the user who typed the data. * **Email fallback.** Pass `email.to` with `when: "on_peppol_failure"` to fall back to email when a recipient turns out not to be reachable over Peppol, or send with `recipient: null` for email-only delivery. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **PDFs.** `pdfGeneration.enabled` attaches a generated PDF of the document. You can also attach an existing PDF (or other files) via `attachments`; see [adding attachments](/docs/sending-invoices#adding-attachments). For a full field reference, see [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). French e-reporting [#french-e-reporting] French e-invoicing covers invoices between businesses established in France. Everything else a French company sells still has to reach the tax administration: sales to private individuals, and invoices to businesses outside France. That is e-reporting. You send Recommand the figures, and Recommand files them on the company's behalf. You never build a regulatory file yourself. B2C reports contain daily totals. Cross-border reports describe an individual invoice or credit note, or a payment received on an invoice. | Report | Endpoint (under `/api/v1`) | `type` | Scope | | -------------------- | ------------------------------------ | ---------- | --------------------------------------------------------------- | | B2C sales | `POST /:companyId/reporting/fr/b2c` | `sales` | Sales for one day, category and currency | | B2C payments | `POST /:companyId/reporting/fr/b2c` | `payments` | Payments received for one day and currency, grouped by VAT rate | | Cross-border invoice | `POST /:companyId/reporting/fr/b2bi` | `invoice` | One invoice or credit note issued to a business outside France | | Cross-border payment | `POST /:companyId/reporting/fr/b2bi` | `payment` | A payment received on a previously reported invoice | All reports are submitted per company, through the API only. Every accepted report is stored with the company's other documents and counts towards the document quota. Register the company first [#register-the-company-first] E-reporting has to be switched on per company, because the tax administration needs to know two things about the taxpayer before its first report: its VAT regime, which sets how often reports are filed, and whether its VAT becomes due on invoicing or on payment. Register the company once through [`PUT /:companyId/reporting/fr/declarant`](/reference/reporting/register-french-reporting-declarant), or from the company page in the dashboard. ```json { "vatRegime": "REEL_NORMAL_MENSUEL", "vatExigibility": "DEBITS" } ``` | Field | Values | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `vatRegime` | `REEL_NORMAL_MENSUEL` (régime réel normal), `REEL_SIMPLIFIE` (régime réel simplifié), `FRANCHISE_EN_BASE` (franchise en base de TVA) | | `vatExigibility` | `DEBITS` (VAT due on invoicing, typical for goods), `ENCAISSEMENTS` (VAT due on payment, typical for services) | The company must be registered in France with a valid SIREN or SIRET, and it must be verified with a signed French mandate whose annex covers e-reporting. That annex is what entitles Recommand to report for the SIREN. A company that was verified without one is refused with a 400; contact [support@recommand.eu](mailto:support@recommand.eu) to have e-reporting enabled for it. The response carries a `state`. Reports are accepted once it is `registered`; `pending` means the registration is still being completed in the background, and `blocked` means support has to intervene, for example because the company is already registered for e-reporting through another platform. It also carries `enabled`. A suspended registration keeps its `registered` state but refuses every report with a 400 until support switches it back on, so check both fields when reports start being refused. Registering makes the company's reporting periods due. Only register companies that will submit reports, and submit each day's figures promptly rather than at month end. Changing the VAT regime later can leave the open period unfiled, so coordinate such a change with support. Report B2C sales [#report-b2c-sales] Submit one sales report per day, per category and per currency through [`POST /:companyId/reporting/fr/b2c`](/reference/reporting/submit-french-b2creport), regardless of when customers pay. ```json { "reference": "B2C-SALES-2026-08-17-GOODS", "type": "sales", "date": "2026-08-17", "category": "goods", "currency": "EUR", "taxExclusiveAmount": "10000.00", "taxAmount": "2000.00", "transactionCount": 42, "vatBreakdown": [ { "percentage": "20.00", "taxableAmount": "10000.00", "taxAmount": "2000.00" } ] } ``` * `category` is `goods` or `services`; use a separate report when both were sold on the same day. Only taxable goods and taxable services are supported today, so exempt B2C sales have no report type yet. * Amounts are strings with two decimals and are never negative. VAT amounts are always in EUR, even when the sales currency is different. * `transactionCount` is the number of individual sales in the total. It is at least 1: a day without sales is not reported at all. Report B2C payments [#report-b2c-payments] For service payments where VAT becomes due on payment, submit the daily amounts received through the same B2C endpoint with `type: "payments"`. Group the amounts including VAT by VAT rate. Submit the sales report as usual as well. ```json { "reference": "B2C-PAYMENTS-2026-08-17-EUR", "type": "payments", "date": "2026-08-17", "currency": "EUR", "vatBreakdown": [ { "percentage": "20.00", "amount": "1200.00" } ] } ``` Payment reports are only accepted for companies registered with VAT due on payment (`ENCAISSEMENTS`). Report cross-border invoices [#report-cross-border-invoices] Submit every invoice or credit note issued to a business outside France through [`POST /:companyId/reporting/fr/b2bi`](/reference/reporting/submit-french-b2bi-report). An invoice to a French buyer is exchanged over the e-invoicing network instead and is refused here. Set `documentType` to `invoice` or `creditNote` to say which of the two you are reporting. It defaults to `invoice`, so you only have to name it for credit notes. The reporting company must carry its own French VAT number as well as its SIREN: a cross-border report identifies the seller by both. Add the VAT number to the company before its first cross-border report. ```json { "reference": "EREPORT-INV-2026-000431", "type": "invoice", "documentNumber": "INV-2026-000431", "issueDate": "2026-01-15", "currency": "EUR", "buyer": { "name": "Rossi Forniture S.r.l.", "country": "IT", "vatNumber": "IT00987654321" }, "taxExclusiveAmount": "10000.00", "taxAmount": "0.00", "vatBreakdown": [ { "percentage": "0.00", "taxableAmount": "10000.00", "taxAmount": "0.00", "category": "K", "exemptionReasonCode": "VATEX-EU-IC" } ] } ``` The buyer is identified the way the tax administration identifies foreign businesses: * **In the European Union**: by its intra-community VAT number, which is required. * **Outside the European Union**: by its country and name; no VAT number is needed. * **In Nouvelle-Calédonie or Polynésie française**: by its local registration number (RIDET or TAHITI), in `enterpriseNumber`. Cross-border operations are usually exempt or reverse charged rather than taxed. When a VAT breakdown entry uses an exempt category, name why: give `exemptionReason`, `exemptionReasonCode`, or both. A breakdown that leaves both off on an exempt category is refused. Report a cross-border payment [#report-a-cross-border-payment] Submit a payment received on a previously reported invoice through the same cross-border endpoint with `type: "payment"`. Set `invoiceNumber` to the original report's `documentNumber` and `issueDate` to the invoice date. The `date` field is the day the payment was received. For a payment of EUR 10,000 on the invoice above: ```json { "reference": "EREPORT-PAYMENT-2026-000431-1", "type": "payment", "invoiceNumber": "INV-2026-000431", "issueDate": "2026-01-15", "date": "2026-02-10", "currency": "EUR", "vatBreakdown": [ { "percentage": "0.00", "amount": "10000.00" } ] } ``` Amounts include VAT and are grouped by VAT rate. As with B2C payments, payment reports are only accepted for companies registered with VAT due on payment (`ENCAISSEMENTS`). References, retries, corrections [#references-retries-corrections] Every report needs its own `reference`, at most 128 characters. It is your idempotency key: retrying the exact same request with the same reference returns the report filed the first time, with `duplicate: true`, and files nothing again. Use this after a timeout or a `502`. To change a report you already filed, send a new report with a **new reference** and the `action` field: * `action: "correct"` replaces the earlier report. It is matched on the data that identifies the report: the day, category and currency of a B2C sales report, the day of a B2C payment report, or the document number of a cross-border invoice. * `action: "cancel"` withdraws it, matched the same way. Reusing the original reference for a correction would be treated as a retry of the original report, and nothing would change. When a report is refused [#when-a-report-is-refused] Submitting a report can fail for reasons that have nothing to do with the figures, so handle each status separately rather than treating any non-200 as bad data. | Status | What happened | What to do | | ------ | -------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | 400 | The company is not registered for e-reporting, its registration is still `pending` or `blocked`, or it is suspended (`enabled: false`) | Register it, or wait for the state to become `registered`. A `blocked` or suspended registration needs support | | 400 | The reporting service refused the report; the reason is in the message | Fix what the message names and submit again under a new reference | | 400 | A payment report was sent for a company whose VAT is due on invoicing (`DEBITS`), or a cross-border report named a French buyer | Neither is reportable. A French buyer is invoiced over the e-invoicing network instead | | 409 | The report conflicts with what was already filed, for example a correction of something that was never reported | Look at what is on file before resubmitting | | 502 | The reporting service could not be reached | Retry later with the **same** reference. The reference is the idempotency key, so a retry cannot file the report twice | The 502 case is the one worth building for: it is the only status where reusing the reference is right. Every other failure needs a fresh reference once you have fixed the cause. Follow the report until it is filed [#follow-the-report-until-it-is-filed] Accepting a report is not filing it. The tax administration receives a filing per reporting period, assembled after the period ends, and can still reject it. Every report you submit therefore carries a `reporting` block in the [documents API](/reference/documents/get-document), which Recommand keeps up to date: | `reportingStatus` | Meaning | | ----------------------- | -------------------------------------------------------------------------------------- | | `accepted` | On file, inside its reporting period. Not yet filed. | | `pending_rectificative` | Arrived after its period was already filed; it will be carried by a corrective filing. | | `filed` | Reported to the tax administration within its own period. | | `filed_rectificative` | Reported by a corrective filing, because it arrived late. | | `superseded` | Replaced by a later correction, or cancelled. | | `rejected` | The tax administration rejected the filing carrying it; see `outcomeCode`. | The block also names the reporting period (`periodStart`, `periodEnd`), the filing the report was carried on (`submissionId`) and when the status was last checked. Every change fires a `document.reporting_status_changed` webhook event, so you can route rejections to whoever handles them. Reports from playground teams and teams on the test network are validated, recorded and shown exactly like real ones, but they are never filed with the tax administration. Their status stays `accepted` and is marked as simulated. Use them to build the integration; use a production team to file. Registration is immediate there: it comes back `registered` straight away rather than going through `pending`, so you can submit reports as soon as you have registered. Registrations are also kept per environment. A team on the test network registers in `TEST`, a production team in `PROD`, and the two are separate registrations for the same company. The `environment` field on the registration response says which one you are looking at. Going live [#going-live] Before you switch your first real customer over, walk this list: * **A valid subscription in production.** Playgrounds skip the subscription check; production does not. * **Verification handled in your UI.** Show the `verificationUrl` at the right moment, make it forwardable, and handle the `company.verification` webhook so a company that comes back `rejected` or `error` does not sit silently unusable. * **`isVerified` respected.** Do not let a user press send for a company that is not verified yet; explain what is missing instead. * **Webhook endpoint hardened.** Signature verification, a fast 200, retries and idempotency on your side. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of the person who can fix it. * **One real document, end to end.** Send an invoice between two companies you control on production before letting customers in. Documents are counted per team, with the volume of all your companies pooled, so onboarding more companies lowers your price per document rather than adding per-company fees. Received documents count towards the quota as well as sent ones, so budget for both sides of the exchange. Generated XML through `generate` is not billed; emails and submitted reports are. Before you go live in France [#before-you-go-live-in-france] France adds a few checks to the list above, all of them things that only show up once real documents move: * **The mandate is accepted.** `isVerified` is `true`, which for a French company means the signed mandate cleared its review. Plan this in: it is the one step that is not instant. * **The company carries the SIREN under scheme `0002`.** Both the documents you send and the mandate itself are built from the company's own identifiers, so a SIRET or a missing scheme surfaces as rejected documents rather than as a registration error. * **You know which side of the perimeter you are on.** Regulated is the default; transactions outside it have to say so explicitly, and the counterparty has to be registered for the process you use. If the company sends documents, two more: * **The format and process are what you meant.** Check one document before the first real send: the preview in the dashboard, or `generate` from the API, shows the resolved `doctypeId` and `processId`. * **Invoices are in EUR**, with the billing mode and the three mandatory statements filled in. B2B invoices are only half of the French obligation. If the company also sells to private individuals, or invoices businesses outside France, those operations have to be reported to the tax administration separately. Register the company for e-reporting and submit the reports through the API, as described in the e-reporting section of the [French sending guides](/getting-started/france). Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Receiving Peppol documents in France for the companies you onboard (/getting-started/france/platform/receiving) This guide walks through everything needed to exchange Peppol documents for a company registered in France, assuming you are integrating Recommand into your own product and onboarding French companies as your users, and that the company only receives documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are building [#what-you-are-building] You are onboarding companies that are not your own: one Recommand team, and a company inside it for every customer you put on the network. Your customers never need a Recommand account. They see your interface, and Recommand stays behind your API calls. That shape has a few consequences worth knowing before you write code: * **One team, many companies.** There is no limit on companies per team, and billing is per team with the document volume of all companies pooled together, so the more companies you onboard the lower your price per document. See [pricing per team](/faq/general-usage/is-pricing-per-company-or-per-team). * **Every company is registered and verified individually.** Peppol identifies companies, not platforms. Each company gets its own Peppol address and its own authorisation record. * **Verification is taken care of.** Recommand hands you a URL that the company's authorised representative opens to confirm their identity. You present or forward that link; you never need to handle identity documents yourself. If you prefer to handle verification yourself, reach out to us at [support@recommand.eu](mailto:support@recommand.eu), we have a few other flows we can set up for you. * **You can run the whole flow under your own brand.** The API is designed for white-label use, see [can I whitelabel Recommand](/faq/general-usage/can-i-whitelabel-integrate-recommand). The [Recommand dashboard](https://app.recommand.eu) shows the same teams, companies and documents your API calls produce, which is the quickest way to see what a customer is looking at while you are debugging. If the only company you will register is your own, switch the first answer above to **One company** for the shorter version of this guide. The endpoints are the same; there is simply less to organise. Peppol in France [#peppol-in-france] French domestic e-invoicing follows the French e-invoicing reform rather than plain Peppol BIS 3. Recommand covers the French specifics for you, but they do change what you send and how a company is onboarded. What is specific to France: * **A French-accredited access point and SMP.** Companies you register with country `FR` are automatically published on a French-accredited SMP and exchange documents through the matching access point. You do not choose or configure this: it follows from the company's country. * **A signed mandate.** Before a French company can operate, its authorised representative signs a mandate that lets that accredited platform act for the company, and the file is reviewed before the company goes live. This is the one step in this guide that is not instant, so start it early. * **French document formats.** Invoices and credit notes travel as French CIUS or Extended UBL, CII D22B (CIUS or Extended), or Factur-X (a PDF/A-3 with the CII XML embedded), next to plain Peppol BIS 3 UBL. * **Two processes.** The same document types are published for a **regulated** process (`urn:peppol:france:billing:regulated`, transactions inside the French e-invoicing perimeter) and a **non-regulated** one (`urn:peppol:france:billing:non-regulated`, transactions outside it). * **Mandatory content.** French invoices carry a billing mode and three statements (recovery costs, late-payment penalties, early-payment discount) that plain EN 16931 does not require. They go in a `countrySpecific` block. * **Lifecycle statuses.** Inside the perimeter, receivers report back on the invoices they receive with an invoice lifecycle status. * **E-reporting.** What falls outside the e-invoicing perimeter is reported instead: B2C sales as daily totals, and invoices to businesses abroad one by one. Recommand files both report types on the company's behalf. * **Identifiers are SIREN-based.** French companies are published under scheme `0225`. The reform phases the obligations in over time: from **1 September 2026** every company must be able to receive electronic invoices, with issuance starting for large and mid-size companies, and from **1 September 2027** issuance applies to small and micro companies as well. Confirm the schedule and what falls inside the perimeter with your accountant or legal advisor. This documentation describes what the API does, not what your obligations are. Create your team and API credentials [#create-your-team-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). The team you get is the container for every company you will onboard. 2. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 3. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Try it safely first [#try-it-safely-first] Build the whole flow against a **playground team** before you touch production. Playgrounds look and behave like production teams, but nothing is delivered over the real Peppol network, there are no SMP registrations, no subscription checks and no billing. Create one from the team switcher at the top of the [dashboard](https://app.recommand.eu): **Add playground**, give it a name, and you are switched into it. There is no limit on how many you create. Everything that follows in this guide is identical there: same endpoints, same validation, same webhooks (triggered by simulated inbound delivery). Register a company in the playground and use it as both sender and recipient to see a document arrive. Three things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`, which is the quickest way to check that your country-specific fields map to the format and process you expect. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. * **The Peppol Test Network.** For genuine end-to-end tests with real counterparties, tick **Use Peppol Test Network** when you create the playground. It then uses dedicated test access point and SMP endpoints while staying fully separated from production. The setting cannot be changed after creation, so make a second playground if you want both. More detail in the [getting started guide](/docs) and [how do I use the playground environment](/faq/api-and-development/how-do-i-use-the-playground-environment). Register the company [#register-the-company] Create one company per customer with the [create company endpoint](/reference/companies/create-company). Registration on the Peppol network happens as part of this call: identifiers and document types are set up for you, based on the company's country. ```javascript const auth = "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"); const response = await fetch("https://app.recommand.eu/api/v1/companies", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(company), }); const result = await response.json(); if (!result.success) throw new Error(JSON.stringify(result.errors)); const companyId = result.company.id; const verificationUrl = result.verificationUrl; // hand this to your user ``` ```bash curl -X POST https://app.recommand.eu/api/v1/companies \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @company.json ``` The response carries a `verificationUrl` straight away. Keep it: the next step is to put it in front of the company's representative. Register the companies that use your platform, not the companies they invoice. Customers and suppliers manage their own Peppol registration; adding them causes registration conflicts. See [managing companies](/docs/managing-companies). The exact identifier fields to send depend on the country, which is what the next section covers. If you would rather create identifiers and document types yourself instead of accepting the country defaults, pass `skipDefaultCompanySetup: true` and use the [company identifiers](/reference/company-identifiers/create-company-identifier) and [company document types](/reference/company-document-types/get-company-document-types) endpoints. French identifiers and Peppol address [#french-identifiers-and-peppol-address] In France the identifier you register decides whether your documents will pass validation later, so it is worth getting exactly right. | Field | French value | | ------------------------ | --------------------------------------- | | `country` | `"FR"` | | `enterpriseNumber` | The nine-digit **SIREN** of the company | | `enterpriseNumberScheme` | `"0002"` | | `vatNumber` | `FR` + the French VAT number | ```json title="company.json" { "name": "Société de Test SAS", "address": "10 rue de la Paix", "postalCode": "75002", "city": "Paris", "country": "FR", "enterpriseNumber": "133512194", "enterpriseNumberScheme": "0002", "vatNumber": "FR23133512194" } ``` French regulated invoices must carry the seller's nine-digit SIREN as `enterpriseNumber` with `enterpriseNumberScheme` `"0002"`. Because the seller block of a document defaults to the company's own details, a company registered with a SIRET or without the scheme produces invoices that are rejected at validation time. Register the SIREN, and name a specific establishment through the document's `delivery.locationIdentifier` (scheme `0009`) when you need to. One Peppol identifier is registered for the company: * `0225:133512194` is the French electronic address The company's Peppol address is therefore **`0225:` followed by the SIREN**. French addresses may also carry a routing suffix, as in `0225:987654321_STATUTS`; treat the whole string after the scheme as the identifier when a recipient gives you one. Both SIREN (9 digits) and SIRET (14 digits) are checked with the Luhn algorithm before they are filed, and numbers that disagree with each other are refused rather than guessed at. Registering as a recipient [#registering-as-a-recipient] To receive documents, the company must be published as a recipient on an SMP (Service Metadata Publisher). That is what `isSmpRecipient` does, and it is the default: ```json { "isSmpRecipient": true } ``` What that means: * The company becomes findable on the Peppol network: any sender can look it up and deliver to it via the Peppol network. * Recipient registration is **exclusive**. If the company is already registered for receiving through another Peppol provider, registration fails until it is deregistered there. * The document types the company accepts are registered along with it, based on its country. Which ones those are is covered further down. * The company is only published once it is verified. Where a French company is published [#where-a-french-company-is-published] A French company is published on the **French-accredited SMP**, and it exchanges documents through the matching access point. This follows from the company's country: there is nothing to choose or configure. Two consequences for the order of your onboarding: * **The mandate gates the go-live.** The accredited platform only acts for the company once the signed mandate has been accepted, so the company is not operational the minute it is created. The verification section below covers that step; start it early. * **Deregister elsewhere first.** Recipient registration is exclusive here as well, and France has no automatic migration path. A company that currently receives through another platform has to be deregistered there before it can be registered with Recommand. Sign the mandate and verify the company [#sign-the-mandate-and-verify-the-company] French companies go through the same identity check as everyone else, plus two steps that are specific to France: the representative signs a mandate, and the resulting file is reviewed before the company goes live. 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. **Read and sign the mandate.** The verification page shows the mandate that authorises the French-accredited platform to act for the company on the Peppol network, naming the company by its SIREN and the establishment it is filed under. The representative accepts it before the identity check starts. 3. **Complete the identity check.** The identity verification is what signs the mandate: the proof reference is recorded on it. 4. **Wait for the review.** The signed mandate and the company's details are filed with the accredited platform, and the verification sits in review until that file is accepted. Only then does `isVerified` become `true` and the company start operating. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. This is the one step of French onboarding that is not immediate. Start verification as soon as the company is created, and do not promise your users a same-minute go-live for France. If a file seems stuck, mail [support@recommand.eu](mailto:support@recommand.eu) with the company ID. Companies in a playground team are never filed with the accredited platform, so there is no mandate and no review. Test the French flow in a playground first, then run the real thing once. Building verification into your onboarding [#building-verification-into-your-onboarding] With one company you would click through this once. With many, verification is part of the flow you build: every company you register needs its own, and it is the step most likely to leave a customer stuck halfway. **Show the URL immediately.** The create-company response already carries `verificationUrl`, so no extra call is needed. Put it in front of the user while they are still in your onboarding. **Ask for a fresh one when the moment has passed.** Links get lost, and companies you created earlier never had one shown. The [verify company endpoint](/reference/companies/verify-company) starts a new verification session: ```bash curl -X POST https://app.recommand.eu/api/v1/companies/{companyId}/verify \ -u key_xxx:secret_xxx ``` The `company.verification` webhook fires when verification reaches a final state: `verified`, `rejected` or `error`. A company that comes back `rejected` or `error` and is not surfaced anywhere sits silently unusable. See [working with webhooks](/docs/working-with-webhooks). **Respect `isVerified` in your own UI.** Do not let a user press send for a company that is not verified yet; this will result in an error. You should inform the user what is missing instead. **Re-verify after identifier changes.** Updating a company's `vatNumber` or `enterpriseNumber` resets `isVerified` to `false`. Check the field after an update and present a new `verificationUrl` if it flipped. The full mechanics are in the [company verification guide](/docs/company-verification). Document types registered for you [#document-types-registered-for-you] A French company is published for the whole French set, all on the **regulated** process, so any sender inside the perimeter can reach it in the format they prefer: | Document type | Registered process | | ------------------------------------------- | ------------------------------------- | | Invoice + credit note (Peppol BIS 3 UBL) | `urn:peppol:france:billing:regulated` | | Invoice + credit note (France UBL CIUS) | `urn:peppol:france:billing:regulated` | | Invoice + credit note (France UBL Extended) | `urn:peppol:france:billing:regulated` | | Invoice + credit note (France CII CIUS) | `urn:peppol:france:billing:regulated` | | Invoice + credit note (France CII Extended) | `urn:peppol:france:billing:regulated` | | Factur-X invoice + credit note | `urn:peppol:france:billing:regulated` | | Invoice lifecycle status (CDAR) | `urn:peppol:france:billing:regulated` | Whichever format arrives, you read the same parsed document out of the API. For Factur-X, the CII XML is extracted from the PDF/A-3 and parsed like any other document, and the original PDF is kept and included in the document's [download package](/reference/documents/download-package). The defaults cover the regulated process. If counterparties will send you documents over `urn:peppol:france:billing:non-regulated`, register the same document types for that process as well with the [create company document type endpoint](/reference/company-document-types/create-company-document-type). Get incoming documents into your product [#get-incoming-documents-into-your-product] Recommand receives, validates and stores incoming documents for every company in your team. You pick them up in one of two ways. Webhooks (recommended) [#webhooks-recommended] Register an endpoint once with the [create webhook endpoint](/reference/webhooks/create-webhook) or through the dashboard and events are pushed to you as they happen, `document.received` among them: ```javascript await fetch("https://app.recommand.eu/api/v1/webhooks", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(webhook), // the body below }); ``` ```bash curl -X POST https://app.recommand.eu/api/v1/webhooks \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @create-webhook.json ``` ```json title="create-webhook.json" { "url": "https://your-app.example/webhooks/recommand", "companyId": null, "secret": "your_webhook_signing_secret" } ``` `companyId: null` covers every company in the team. Pass a `secret` and verify the HMAC SHA-256 signature on every delivery before you trust the payload. Switch on `event.eventType`, and acknowledge with a 200 before doing the heavy processing. Both are covered in [working with webhooks](/docs/working-with-webhooks). Polling the inbox [#polling-the-inbox] If you would rather pull, the [inbox endpoint](/reference/documents/get-inbox) lists unread documents: ```javascript const inbox = await fetch("https://app.recommand.eu/api/v1/inbox", { headers: { Authorization: auth }, }).then((r) => r.json()); ``` Mark each document as read with the [mark as read endpoint](/reference/documents/mark-as-read) once your system has it, so it drops off the list. After you have the document [#after-you-have-the-document] * Fetch details, the original XML or a rendered PDF from the [documents endpoints](/reference/documents/get-document). * Route documents to the right customer with [labels and suppliers](/docs/suppliers-and-labels), and automate that routing with [rules](/docs/rules). * Let Recommand mail incoming documents on to an address of your choosing when that is easier than an API call, see [email delivery and notifications](/docs/email-delivery-and-notifications). For the full picture, including retries and idempotency, see [receiving documents](/docs/receiving-documents). Report back on the invoices you receive [#report-back-on-the-invoices-you-receive] Inside the French perimeter, receiving an invoice comes with an obligation the other two countries do not have: you report its lifecycle back to the sender. Recommand models those status messages as a document type of their own, `frenchInvoicingCdar`, so you send them the same way you send anything else. When an invoice arrives, Recommand automatically sends the transmission statuses back to the sender: `202` (received) when the document reaches the access point, and `203` (made available) when it is delivered to you. You only send the later processing statuses. ```javascript await fetch(`https://app.recommand.eu/api/v1/${companyId}/send`, { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify({ recipient: "0225:987654321", documentType: "frenchInvoicingCdar", document: { businessProcess: "REGULATED", senderRole: "WK", issuerRole: "BY", issuerLegalId: "123456789", issuerLegalIdScheme: "0002", recipientRole: "SE", statusCode: "205", statusDate: "2026-08-17T14:05:09", invoiceId: "INV-2026-001", invoiceTypeCode: "380", invoiceIssueDate: "2026-08-17", sellerLegalId: "987654321", sellerLegalIdScheme: "0002", }, }), }); ``` The processing statuses that matter most on the receiving side: | Status | Meaning | | ------ | ------------------------------------ | | `204` | Taken in charge (processing started) | | `205` | Approved | | `206` | Partially approved | | `207` | In dispute | | `210` | Refused | | `211` | Payment sent | A refusal, partial approval or dispute carries a coded reason (`DOUBLON`, `TX_TVA_ERR`, `NON_CONFORME`, …) and an optional free-text note, so the sender knows what to fix. The full status and reason lists are on the [send document endpoint](/reference/sending/send-document). Report collection on the invoices you sent [#report-collection-on-the-invoices-you-sent] `212` (collected) runs the other way: it is the seller who reports that a payment came in. It carries `collectedAmounts`, at least one entry naming an `amount`, its `currency` and the `vatPercent` it falls under. A disbursement is expressed as a negative amount. `212` is not a terminal status. An invoice settled in several instalments gets one `212` per payment received, each carrying only the amount of that payment rather than the running total. Successive messages are told apart by the CDAR's own `id`, generated for you when you leave it off, with `statusDate` naming the moment of collection and `issueDate` the moment the message was written. Incoming CDAR messages are parsed, stored and shown next to your other documents, and delivered through your existing webhooks and notifications, so this is also how you learn what your customers did with the invoices you sent them, including the `202` and `203` their access point sent when they received yours. What counts towards your document quota [#what-counts-towards-your-document-quota] You pay for documents and for the business answers to them, not for the messages platforms exchange to move them. Transmission statuses (`200`, `201`, `202`, `203`, `213` and `501`) never count, whether you receive them or Recommand sends them for you. Processing statuses (`204` to `212` and `214`) count as one document each, in both directions, exactly like an invoice: the party sending the decision and the party receiving it are treated alike. Going live [#going-live] Before you switch your first real customer over, walk this list: * **A valid subscription in production.** Playgrounds skip the subscription check; production does not. * **Verification handled in your UI.** Show the `verificationUrl` at the right moment, make it forwardable, and handle the `company.verification` webhook so a company that comes back `rejected` or `error` does not sit silently unusable. * **`isVerified` respected.** Do not let a user press send for a company that is not verified yet; explain what is missing instead. * **Webhook endpoint hardened.** Signature verification, a fast 200, retries and idempotency on your side. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of the person who can fix it. * **One real document, end to end.** Send an invoice between two companies you control on production before letting customers in. Documents are counted per team, with the volume of all your companies pooled, so onboarding more companies lowers your price per document rather than adding per-company fees. Received documents count towards the quota as well as sent ones, so budget for both sides of the exchange. Generated XML through `generate` is not billed; emails and submitted reports are. Before you go live in France [#before-you-go-live-in-france] France adds a few checks to the list above, all of them things that only show up once real documents move: * **The mandate is accepted.** `isVerified` is `true`, which for a French company means the signed mandate cleared its review. Plan this in: it is the one step that is not instant. * **The company carries the SIREN under scheme `0002`.** Both the documents you send and the mandate itself are built from the company's own identifiers, so a SIRET or a missing scheme surfaces as rejected documents rather than as a registration error. * **You know which side of the perimeter you are on.** Regulated is the default; transactions outside it have to say so explicitly, and the counterparty has to be registered for the process you use. If the company sends documents, two more: * **The format and process are what you meant.** Check one document before the first real send: the preview in the dashboard, or `generate` from the API, shows the resolved `doctypeId` and `processId`. * **Invoices are in EUR**, with the billing mode and the three mandatory statements filled in. B2B invoices are only half of the French obligation. If the company also sells to private individuals, or invoices businesses outside France, those operations have to be reported to the tax administration separately. Register the company for e-reporting and submit the reports through the API, as described in the e-reporting section of the [French sending guides](/getting-started/france). Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Sending and receiving Peppol documents in France for the companies you onboard (/getting-started/france/platform/sending-and-receiving) This guide walks through everything needed to exchange Peppol documents for a company registered in France, assuming you are integrating Recommand into your own product and onboarding French companies as your users, and that the company sends and receives documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are building [#what-you-are-building] You are onboarding companies that are not your own: one Recommand team, and a company inside it for every customer you put on the network. Your customers never need a Recommand account. They see your interface, and Recommand stays behind your API calls. That shape has a few consequences worth knowing before you write code: * **One team, many companies.** There is no limit on companies per team, and billing is per team with the document volume of all companies pooled together, so the more companies you onboard the lower your price per document. See [pricing per team](/faq/general-usage/is-pricing-per-company-or-per-team). * **Every company is registered and verified individually.** Peppol identifies companies, not platforms. Each company gets its own Peppol address and its own authorisation record. * **Verification is taken care of.** Recommand hands you a URL that the company's authorised representative opens to confirm their identity. You present or forward that link; you never need to handle identity documents yourself. If you prefer to handle verification yourself, reach out to us at [support@recommand.eu](mailto:support@recommand.eu), we have a few other flows we can set up for you. * **You can run the whole flow under your own brand.** The API is designed for white-label use, see [can I whitelabel Recommand](/faq/general-usage/can-i-whitelabel-integrate-recommand). The [Recommand dashboard](https://app.recommand.eu) shows the same teams, companies and documents your API calls produce, which is the quickest way to see what a customer is looking at while you are debugging. If the only company you will register is your own, switch the first answer above to **One company** for the shorter version of this guide. The endpoints are the same; there is simply less to organise. Peppol in France [#peppol-in-france] French domestic e-invoicing follows the French e-invoicing reform rather than plain Peppol BIS 3. Recommand covers the French specifics for you, but they do change what you send and how a company is onboarded. What is specific to France: * **A French-accredited access point and SMP.** Companies you register with country `FR` are automatically published on a French-accredited SMP and exchange documents through the matching access point. You do not choose or configure this: it follows from the company's country. * **A signed mandate.** Before a French company can operate, its authorised representative signs a mandate that lets that accredited platform act for the company, and the file is reviewed before the company goes live. This is the one step in this guide that is not instant, so start it early. * **French document formats.** Invoices and credit notes travel as French CIUS or Extended UBL, CII D22B (CIUS or Extended), or Factur-X (a PDF/A-3 with the CII XML embedded), next to plain Peppol BIS 3 UBL. * **Two processes.** The same document types are published for a **regulated** process (`urn:peppol:france:billing:regulated`, transactions inside the French e-invoicing perimeter) and a **non-regulated** one (`urn:peppol:france:billing:non-regulated`, transactions outside it). * **Mandatory content.** French invoices carry a billing mode and three statements (recovery costs, late-payment penalties, early-payment discount) that plain EN 16931 does not require. They go in a `countrySpecific` block. * **Lifecycle statuses.** Inside the perimeter, receivers report back on the invoices they receive with an invoice lifecycle status. * **E-reporting.** What falls outside the e-invoicing perimeter is reported instead: B2C sales as daily totals, and invoices to businesses abroad one by one. Recommand files both report types on the company's behalf. * **Identifiers are SIREN-based.** French companies are published under scheme `0225`. The reform phases the obligations in over time: from **1 September 2026** every company must be able to receive electronic invoices, with issuance starting for large and mid-size companies, and from **1 September 2027** issuance applies to small and micro companies as well. Confirm the schedule and what falls inside the perimeter with your accountant or legal advisor. This documentation describes what the API does, not what your obligations are. Create your team and API credentials [#create-your-team-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). The team you get is the container for every company you will onboard. 2. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 3. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Try it safely first [#try-it-safely-first] Build the whole flow against a **playground team** before you touch production. Playgrounds look and behave like production teams, but nothing is delivered over the real Peppol network, there are no SMP registrations, no subscription checks and no billing. Create one from the team switcher at the top of the [dashboard](https://app.recommand.eu): **Add playground**, give it a name, and you are switched into it. There is no limit on how many you create. Everything that follows in this guide is identical there: same endpoints, same validation, same webhooks (triggered by simulated inbound delivery). Register a company in the playground and use it as both sender and recipient to see a document arrive. Three things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`, which is the quickest way to check that your country-specific fields map to the format and process you expect. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. * **The Peppol Test Network.** For genuine end-to-end tests with real counterparties, tick **Use Peppol Test Network** when you create the playground. It then uses dedicated test access point and SMP endpoints while staying fully separated from production. The setting cannot be changed after creation, so make a second playground if you want both. More detail in the [getting started guide](/docs) and [how do I use the playground environment](/faq/api-and-development/how-do-i-use-the-playground-environment). Register the company [#register-the-company] Create one company per customer with the [create company endpoint](/reference/companies/create-company). Registration on the Peppol network happens as part of this call: identifiers and document types are set up for you, based on the company's country. ```javascript const auth = "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"); const response = await fetch("https://app.recommand.eu/api/v1/companies", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(company), }); const result = await response.json(); if (!result.success) throw new Error(JSON.stringify(result.errors)); const companyId = result.company.id; const verificationUrl = result.verificationUrl; // hand this to your user ``` ```bash curl -X POST https://app.recommand.eu/api/v1/companies \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @company.json ``` The response carries a `verificationUrl` straight away. Keep it: the next step is to put it in front of the company's representative. Register the companies that use your platform, not the companies they invoice. Customers and suppliers manage their own Peppol registration; adding them causes registration conflicts. See [managing companies](/docs/managing-companies). The exact identifier fields to send depend on the country, which is what the next section covers. If you would rather create identifiers and document types yourself instead of accepting the country defaults, pass `skipDefaultCompanySetup: true` and use the [company identifiers](/reference/company-identifiers/create-company-identifier) and [company document types](/reference/company-document-types/get-company-document-types) endpoints. French identifiers and Peppol address [#french-identifiers-and-peppol-address] In France the identifier you register decides whether your documents will pass validation later, so it is worth getting exactly right. | Field | French value | | ------------------------ | --------------------------------------- | | `country` | `"FR"` | | `enterpriseNumber` | The nine-digit **SIREN** of the company | | `enterpriseNumberScheme` | `"0002"` | | `vatNumber` | `FR` + the French VAT number | ```json title="company.json" { "name": "Société de Test SAS", "address": "10 rue de la Paix", "postalCode": "75002", "city": "Paris", "country": "FR", "enterpriseNumber": "133512194", "enterpriseNumberScheme": "0002", "vatNumber": "FR23133512194" } ``` French regulated invoices must carry the seller's nine-digit SIREN as `enterpriseNumber` with `enterpriseNumberScheme` `"0002"`. Because the seller block of a document defaults to the company's own details, a company registered with a SIRET or without the scheme produces invoices that are rejected at validation time. Register the SIREN, and name a specific establishment through the document's `delivery.locationIdentifier` (scheme `0009`) when you need to. One Peppol identifier is registered for the company: * `0225:133512194` is the French electronic address The company's Peppol address is therefore **`0225:` followed by the SIREN**. French addresses may also carry a routing suffix, as in `0225:987654321_STATUTS`; treat the whole string after the scheme as the identifier when a recipient gives you one. Both SIREN (9 digits) and SIRET (14 digits) are checked with the Luhn algorithm before they are filed, and numbers that disagree with each other are refused rather than guessed at. Registering for both directions [#registering-for-both-directions] Sending needs no registration of its own; receiving does. So register the company as a recipient, which is the default: ```json { "isSmpRecipient": true } ``` What that means: * The company becomes findable on the Peppol network and can be delivered to through Recommand's access point, while sending its own documents out through the same access point. * Recipient registration is **exclusive**. If the company already receives through another Peppol provider, registration fails until it is deregistered there. What that takes depends on the country, which the next section covers. * The document types the company accepts are registered along with it, based on its country. Which ones those are is covered further down. * The company is only published once it is verified. If the company still receives elsewhere and you do not want to move that yet, register it with `isSmpRecipient: false` and start with sending only. Flipping the field later publishes it as a recipient. Where a French company is published [#where-a-french-company-is-published] A French company is published on the **French-accredited SMP**, and it exchanges documents through the matching access point. This follows from the company's country: there is nothing to choose or configure. Two consequences for the order of your onboarding: * **The mandate gates the go-live.** The accredited platform only acts for the company once the signed mandate has been accepted, so the company is not operational the minute it is created. The verification section below covers that step; start it early. * **Deregister elsewhere first.** Recipient registration is exclusive here as well, and France has no automatic migration path. A company that currently receives through another platform has to be deregistered there before it can be registered with Recommand. Sign the mandate and verify the company [#sign-the-mandate-and-verify-the-company] French companies go through the same identity check as everyone else, plus two steps that are specific to France: the representative signs a mandate, and the resulting file is reviewed before the company goes live. 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. **Read and sign the mandate.** The verification page shows the mandate that authorises the French-accredited platform to act for the company on the Peppol network, naming the company by its SIREN and the establishment it is filed under. The representative accepts it before the identity check starts. 3. **Complete the identity check.** The identity verification is what signs the mandate: the proof reference is recorded on it. 4. **Wait for the review.** The signed mandate and the company's details are filed with the accredited platform, and the verification sits in review until that file is accepted. Only then does `isVerified` become `true` and the company start operating. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. This is the one step of French onboarding that is not immediate. Start verification as soon as the company is created, and do not promise your users a same-minute go-live for France. If a file seems stuck, mail [support@recommand.eu](mailto:support@recommand.eu) with the company ID. Companies in a playground team are never filed with the accredited platform, so there is no mandate and no review. Test the French flow in a playground first, then run the real thing once. Building verification into your onboarding [#building-verification-into-your-onboarding] With one company you would click through this once. With many, verification is part of the flow you build: every company you register needs its own, and it is the step most likely to leave a customer stuck halfway. **Show the URL immediately.** The create-company response already carries `verificationUrl`, so no extra call is needed. Put it in front of the user while they are still in your onboarding. **Ask for a fresh one when the moment has passed.** Links get lost, and companies you created earlier never had one shown. The [verify company endpoint](/reference/companies/verify-company) starts a new verification session: ```bash curl -X POST https://app.recommand.eu/api/v1/companies/{companyId}/verify \ -u key_xxx:secret_xxx ``` The `company.verification` webhook fires when verification reaches a final state: `verified`, `rejected` or `error`. A company that comes back `rejected` or `error` and is not surfaced anywhere sits silently unusable. See [working with webhooks](/docs/working-with-webhooks). **Respect `isVerified` in your own UI.** Do not let a user press send for a company that is not verified yet; this will result in an error. You should inform the user what is missing instead. **Re-verify after identifier changes.** Updating a company's `vatNumber` or `enterpriseNumber` resets `isVerified` to `false`. Check the field after an update and present a new `verificationUrl` if it flipped. The full mechanics are in the [company verification guide](/docs/company-verification). Pick the French document format and process [#pick-the-french-document-format-and-process] A French invoice needs three decisions: the format, the process, and the mandatory French content. The format [#the-format] Name the format with `doctypeId` on the send request. Leave it off and the recipient is looked up and the document written in the first format, in [our order of preference](/changelog/2026-08-28-automatic-document-format-routing), they are registered to receive. Peppol BIS 3 UBL comes first in that order, so a French recipient who publishes it as well receives plain BIS 3: valid on the network, but not what the French reform asks for inside its perimeter. Name the French format you want for transactions inside the perimeter. | Format | `doctypeId` | | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | France UBL CIUS invoice | `urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:peppol:france:billing:cius:1.0::2.1` | | France UBL CIUS credit note | `urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2::CreditNote##urn:cen.eu:en16931:2017#compliant#urn:peppol:france:billing:cius:1.0::2.1` | | France UBL Extended invoice | `urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#conformant#urn:peppol:france:billing:extended:1.0::2.1` | | France CII CIUS | `urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100::CrossIndustryInvoice##urn:cen.eu:en16931:2017#compliant#urn:peppol:france:billing:cius:1.0::D22B` | | France CII Extended | `urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100::CrossIndustryInvoice##urn:cen.eu:en16931:2017#conformant#urn:peppol:france:billing:extended:1.0::D22B` | | France Factur-X | `urn:peppol:doctype:pdf+xml##urn:cen.eu:en16931:2017#conformant#urn:peppol:france:billing:Factur-X:1.0::D22B` | The CII and Factur-X document types carry both invoices and credit notes; the `documentType` field of your request decides which one it is. Start with **France UBL CIUS** unless you have a reason not to. Extended is for data the CIUS does not carry, and Factur-X is for recipients who want a human-readable PDF as the carrier. The process [#the-process] Set `countrySpecific.businessProcess` to say which side of the French perimeter the transaction is on. The document is then sent over the matching process: | `businessProcess` | Process identifier | Use for | | --------------------- | ----------------------------------------- | ---------------------------------------- | | `REGULATED` (default) | `urn:peppol:france:billing:regulated` | Transactions inside the French perimeter | | `NON_REGULATED` | `urn:peppol:france:billing:non-regulated` | Transactions outside it | The recipient must have registered the document type **for that process**. Pass the `processId` to the [verify document support endpoint](/reference/recipients/verify-document-support) to check exactly that combination rather than "any process". The mandatory French content [#the-mandatory-french-content] French UBL, CII and Factur-X require a `countrySpecific` block with the billing mode and the three statements French invoices must carry. It is required for those document types and must be omitted for plain EN 16931 documents. ```json { "countrySpecific": { "country": "FR", "billingMode": "S1", "businessProcess": "REGULATED", "recoveryCostsNote": "Indemnité forfaitaire de 40 EUR pour frais de recouvrement.", "latePaymentPenaltiesNote": "Pénalités de retard exigibles au taux prévu dans les conditions générales de vente.", "earlyPaymentDiscountNote": "Aucun escompte accordé pour paiement anticipé." } } ``` `billingMode` follows AFNOR XP Z12-012. The common ones are `B1` (goods), `S1` (services) and `M1` (mixed); the full list, including already-paid, advance payment, subcontracting and multi-seller variants, is documented on the [send document endpoint](/reference/sending/send-document). Invoicing outside France [#invoicing-outside-france] The French formats and processes are for the French perimeter. A counterparty in another country is registered for the **standard** Peppol billing process, so a regulated document does not match anything they published. For those invoices, send plain Peppol BIS 3 UBL and leave the `countrySpecific` block out with it, it belongs to the French document types only. The rest of the invoice is unchanged. * The seller's `enterpriseNumber` must be the nine-digit SIREN with `enterpriseNumberScheme` `"0002"`. * The currency must be `EUR`. * Factur-X needs a compliant PDF/A-3 to embed the XML in: either attach one as an embedded attachment, or let Recommand generate it with `pdfGeneration.enabled`. Send a document [#send-a-document] One endpoint sends everything: [`POST /:companyId/send`](/reference/sending/send-document). The `companyId` is the sender, `recipient` is the Peppol address of the receiver, and `document` is the invoice or credit note as JSON. Recommand will validate the document and generate the XML. Raw XML sending is supported as well: set `documentType` to `xml` and pass the document string in `document`, along with the correct `doctypeId`. See [working with raw UBL](/docs/ubl-format-guide#working-with-raw-ubl). ```javascript const response = await fetch( `https://app.recommand.eu/api/v1/${companyId}/send`, { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, // The body below, with doctypeId and countrySpecific where the country // needs them. body: JSON.stringify(sendRequest), } ); const result = await response.json(); if (!result.success) { // result.errors is keyed by field path, e.g. { "buyer.vatNumber": [...] } } ``` ```bash curl -X POST https://app.recommand.eu/api/v1/{companyId}/send \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @send-invoice.json ``` ```json title="send-invoice.json" { "recipient": "0208:0123456789", "documentType": "invoice", "document": { "invoiceNumber": "INV-2026-001", "issueDate": "2026-08-17", "dueDate": "2026-09-16", "currency": "EUR", "buyer": { "name": "Customer Company", "street": "Customer Street 1", "city": "Antwerp", "postalZone": "2000", "country": "BE", "vatNumber": "BE0987654321" }, "paymentMeans": [{ "iban": "BE68539007547034" }], "lines": [ { "name": "Consulting Services", "quantity": "10.00", "unitCode": "HUR", "netPriceAmount": "100.00", "vat": { "category": "S", "percentage": "21.00" } } ] } } ``` The seller block is filled in from the company when you leave it out, which is usually what you want: it keeps the company's registered identifiers and the document in agreement. Things worth wiring up while you are here: * **Validation errors.** Outgoing documents are always validated. A `success: false` response with `errors` keyed by field path is a document your recipient would have rejected, so surface it to the user who typed the data. * **Email fallback.** Pass `email.to` with `when: "on_peppol_failure"` to fall back to email when a recipient turns out not to be reachable over Peppol, or send with `recipient: null` for email-only delivery. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **PDFs.** `pdfGeneration.enabled` attaches a generated PDF of the document. You can also attach an existing PDF (or other files) via `attachments`; see [adding attachments](/docs/sending-invoices#adding-attachments). For a full field reference, see [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). French e-reporting [#french-e-reporting] French e-invoicing covers invoices between businesses established in France. Everything else a French company sells still has to reach the tax administration: sales to private individuals, and invoices to businesses outside France. That is e-reporting. You send Recommand the figures, and Recommand files them on the company's behalf. You never build a regulatory file yourself. B2C reports contain daily totals. Cross-border reports describe an individual invoice or credit note, or a payment received on an invoice. | Report | Endpoint (under `/api/v1`) | `type` | Scope | | -------------------- | ------------------------------------ | ---------- | --------------------------------------------------------------- | | B2C sales | `POST /:companyId/reporting/fr/b2c` | `sales` | Sales for one day, category and currency | | B2C payments | `POST /:companyId/reporting/fr/b2c` | `payments` | Payments received for one day and currency, grouped by VAT rate | | Cross-border invoice | `POST /:companyId/reporting/fr/b2bi` | `invoice` | One invoice or credit note issued to a business outside France | | Cross-border payment | `POST /:companyId/reporting/fr/b2bi` | `payment` | A payment received on a previously reported invoice | All reports are submitted per company, through the API only. Every accepted report is stored with the company's other documents and counts towards the document quota. Register the company first [#register-the-company-first] E-reporting has to be switched on per company, because the tax administration needs to know two things about the taxpayer before its first report: its VAT regime, which sets how often reports are filed, and whether its VAT becomes due on invoicing or on payment. Register the company once through [`PUT /:companyId/reporting/fr/declarant`](/reference/reporting/register-french-reporting-declarant), or from the company page in the dashboard. ```json { "vatRegime": "REEL_NORMAL_MENSUEL", "vatExigibility": "DEBITS" } ``` | Field | Values | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `vatRegime` | `REEL_NORMAL_MENSUEL` (régime réel normal), `REEL_SIMPLIFIE` (régime réel simplifié), `FRANCHISE_EN_BASE` (franchise en base de TVA) | | `vatExigibility` | `DEBITS` (VAT due on invoicing, typical for goods), `ENCAISSEMENTS` (VAT due on payment, typical for services) | The company must be registered in France with a valid SIREN or SIRET, and it must be verified with a signed French mandate whose annex covers e-reporting. That annex is what entitles Recommand to report for the SIREN. A company that was verified without one is refused with a 400; contact [support@recommand.eu](mailto:support@recommand.eu) to have e-reporting enabled for it. The response carries a `state`. Reports are accepted once it is `registered`; `pending` means the registration is still being completed in the background, and `blocked` means support has to intervene, for example because the company is already registered for e-reporting through another platform. It also carries `enabled`. A suspended registration keeps its `registered` state but refuses every report with a 400 until support switches it back on, so check both fields when reports start being refused. Registering makes the company's reporting periods due. Only register companies that will submit reports, and submit each day's figures promptly rather than at month end. Changing the VAT regime later can leave the open period unfiled, so coordinate such a change with support. Report B2C sales [#report-b2c-sales] Submit one sales report per day, per category and per currency through [`POST /:companyId/reporting/fr/b2c`](/reference/reporting/submit-french-b2creport), regardless of when customers pay. ```json { "reference": "B2C-SALES-2026-08-17-GOODS", "type": "sales", "date": "2026-08-17", "category": "goods", "currency": "EUR", "taxExclusiveAmount": "10000.00", "taxAmount": "2000.00", "transactionCount": 42, "vatBreakdown": [ { "percentage": "20.00", "taxableAmount": "10000.00", "taxAmount": "2000.00" } ] } ``` * `category` is `goods` or `services`; use a separate report when both were sold on the same day. Only taxable goods and taxable services are supported today, so exempt B2C sales have no report type yet. * Amounts are strings with two decimals and are never negative. VAT amounts are always in EUR, even when the sales currency is different. * `transactionCount` is the number of individual sales in the total. It is at least 1: a day without sales is not reported at all. Report B2C payments [#report-b2c-payments] For service payments where VAT becomes due on payment, submit the daily amounts received through the same B2C endpoint with `type: "payments"`. Group the amounts including VAT by VAT rate. Submit the sales report as usual as well. ```json { "reference": "B2C-PAYMENTS-2026-08-17-EUR", "type": "payments", "date": "2026-08-17", "currency": "EUR", "vatBreakdown": [ { "percentage": "20.00", "amount": "1200.00" } ] } ``` Payment reports are only accepted for companies registered with VAT due on payment (`ENCAISSEMENTS`). Report cross-border invoices [#report-cross-border-invoices] Submit every invoice or credit note issued to a business outside France through [`POST /:companyId/reporting/fr/b2bi`](/reference/reporting/submit-french-b2bi-report). An invoice to a French buyer is exchanged over the e-invoicing network instead and is refused here. Set `documentType` to `invoice` or `creditNote` to say which of the two you are reporting. It defaults to `invoice`, so you only have to name it for credit notes. The reporting company must carry its own French VAT number as well as its SIREN: a cross-border report identifies the seller by both. Add the VAT number to the company before its first cross-border report. ```json { "reference": "EREPORT-INV-2026-000431", "type": "invoice", "documentNumber": "INV-2026-000431", "issueDate": "2026-01-15", "currency": "EUR", "buyer": { "name": "Rossi Forniture S.r.l.", "country": "IT", "vatNumber": "IT00987654321" }, "taxExclusiveAmount": "10000.00", "taxAmount": "0.00", "vatBreakdown": [ { "percentage": "0.00", "taxableAmount": "10000.00", "taxAmount": "0.00", "category": "K", "exemptionReasonCode": "VATEX-EU-IC" } ] } ``` The buyer is identified the way the tax administration identifies foreign businesses: * **In the European Union**: by its intra-community VAT number, which is required. * **Outside the European Union**: by its country and name; no VAT number is needed. * **In Nouvelle-Calédonie or Polynésie française**: by its local registration number (RIDET or TAHITI), in `enterpriseNumber`. Cross-border operations are usually exempt or reverse charged rather than taxed. When a VAT breakdown entry uses an exempt category, name why: give `exemptionReason`, `exemptionReasonCode`, or both. A breakdown that leaves both off on an exempt category is refused. Report a cross-border payment [#report-a-cross-border-payment] Submit a payment received on a previously reported invoice through the same cross-border endpoint with `type: "payment"`. Set `invoiceNumber` to the original report's `documentNumber` and `issueDate` to the invoice date. The `date` field is the day the payment was received. For a payment of EUR 10,000 on the invoice above: ```json { "reference": "EREPORT-PAYMENT-2026-000431-1", "type": "payment", "invoiceNumber": "INV-2026-000431", "issueDate": "2026-01-15", "date": "2026-02-10", "currency": "EUR", "vatBreakdown": [ { "percentage": "0.00", "amount": "10000.00" } ] } ``` Amounts include VAT and are grouped by VAT rate. As with B2C payments, payment reports are only accepted for companies registered with VAT due on payment (`ENCAISSEMENTS`). References, retries, corrections [#references-retries-corrections] Every report needs its own `reference`, at most 128 characters. It is your idempotency key: retrying the exact same request with the same reference returns the report filed the first time, with `duplicate: true`, and files nothing again. Use this after a timeout or a `502`. To change a report you already filed, send a new report with a **new reference** and the `action` field: * `action: "correct"` replaces the earlier report. It is matched on the data that identifies the report: the day, category and currency of a B2C sales report, the day of a B2C payment report, or the document number of a cross-border invoice. * `action: "cancel"` withdraws it, matched the same way. Reusing the original reference for a correction would be treated as a retry of the original report, and nothing would change. When a report is refused [#when-a-report-is-refused] Submitting a report can fail for reasons that have nothing to do with the figures, so handle each status separately rather than treating any non-200 as bad data. | Status | What happened | What to do | | ------ | -------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | 400 | The company is not registered for e-reporting, its registration is still `pending` or `blocked`, or it is suspended (`enabled: false`) | Register it, or wait for the state to become `registered`. A `blocked` or suspended registration needs support | | 400 | The reporting service refused the report; the reason is in the message | Fix what the message names and submit again under a new reference | | 400 | A payment report was sent for a company whose VAT is due on invoicing (`DEBITS`), or a cross-border report named a French buyer | Neither is reportable. A French buyer is invoiced over the e-invoicing network instead | | 409 | The report conflicts with what was already filed, for example a correction of something that was never reported | Look at what is on file before resubmitting | | 502 | The reporting service could not be reached | Retry later with the **same** reference. The reference is the idempotency key, so a retry cannot file the report twice | The 502 case is the one worth building for: it is the only status where reusing the reference is right. Every other failure needs a fresh reference once you have fixed the cause. Follow the report until it is filed [#follow-the-report-until-it-is-filed] Accepting a report is not filing it. The tax administration receives a filing per reporting period, assembled after the period ends, and can still reject it. Every report you submit therefore carries a `reporting` block in the [documents API](/reference/documents/get-document), which Recommand keeps up to date: | `reportingStatus` | Meaning | | ----------------------- | -------------------------------------------------------------------------------------- | | `accepted` | On file, inside its reporting period. Not yet filed. | | `pending_rectificative` | Arrived after its period was already filed; it will be carried by a corrective filing. | | `filed` | Reported to the tax administration within its own period. | | `filed_rectificative` | Reported by a corrective filing, because it arrived late. | | `superseded` | Replaced by a later correction, or cancelled. | | `rejected` | The tax administration rejected the filing carrying it; see `outcomeCode`. | The block also names the reporting period (`periodStart`, `periodEnd`), the filing the report was carried on (`submissionId`) and when the status was last checked. Every change fires a `document.reporting_status_changed` webhook event, so you can route rejections to whoever handles them. Reports from playground teams and teams on the test network are validated, recorded and shown exactly like real ones, but they are never filed with the tax administration. Their status stays `accepted` and is marked as simulated. Use them to build the integration; use a production team to file. Registration is immediate there: it comes back `registered` straight away rather than going through `pending`, so you can submit reports as soon as you have registered. Registrations are also kept per environment. A team on the test network registers in `TEST`, a production team in `PROD`, and the two are separate registrations for the same company. The `environment` field on the registration response says which one you are looking at. Document types registered for you [#document-types-registered-for-you] A French company is published for the whole French set, all on the **regulated** process, so any sender inside the perimeter can reach it in the format they prefer: | Document type | Registered process | | ------------------------------------------- | ------------------------------------- | | Invoice + credit note (Peppol BIS 3 UBL) | `urn:peppol:france:billing:regulated` | | Invoice + credit note (France UBL CIUS) | `urn:peppol:france:billing:regulated` | | Invoice + credit note (France UBL Extended) | `urn:peppol:france:billing:regulated` | | Invoice + credit note (France CII CIUS) | `urn:peppol:france:billing:regulated` | | Invoice + credit note (France CII Extended) | `urn:peppol:france:billing:regulated` | | Factur-X invoice + credit note | `urn:peppol:france:billing:regulated` | | Invoice lifecycle status (CDAR) | `urn:peppol:france:billing:regulated` | Whichever format arrives, you read the same parsed document out of the API. For Factur-X, the CII XML is extracted from the PDF/A-3 and parsed like any other document, and the original PDF is kept and included in the document's [download package](/reference/documents/download-package). The defaults cover the regulated process. If counterparties will send you documents over `urn:peppol:france:billing:non-regulated`, register the same document types for that process as well with the [create company document type endpoint](/reference/company-document-types/create-company-document-type). Get incoming documents into your product [#get-incoming-documents-into-your-product] Recommand receives, validates and stores incoming documents for every company in your team. You pick them up in one of two ways. Webhooks (recommended) [#webhooks-recommended] Register an endpoint once with the [create webhook endpoint](/reference/webhooks/create-webhook) or through the dashboard and events are pushed to you as they happen, `document.received` among them: ```javascript await fetch("https://app.recommand.eu/api/v1/webhooks", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(webhook), // the body below }); ``` ```bash curl -X POST https://app.recommand.eu/api/v1/webhooks \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @create-webhook.json ``` ```json title="create-webhook.json" { "url": "https://your-app.example/webhooks/recommand", "companyId": null, "secret": "your_webhook_signing_secret" } ``` `companyId: null` covers every company in the team. Pass a `secret` and verify the HMAC SHA-256 signature on every delivery before you trust the payload. Switch on `event.eventType`, and acknowledge with a 200 before doing the heavy processing. Both are covered in [working with webhooks](/docs/working-with-webhooks). Polling the inbox [#polling-the-inbox] If you would rather pull, the [inbox endpoint](/reference/documents/get-inbox) lists unread documents: ```javascript const inbox = await fetch("https://app.recommand.eu/api/v1/inbox", { headers: { Authorization: auth }, }).then((r) => r.json()); ``` Mark each document as read with the [mark as read endpoint](/reference/documents/mark-as-read) once your system has it, so it drops off the list. After you have the document [#after-you-have-the-document] * Fetch details, the original XML or a rendered PDF from the [documents endpoints](/reference/documents/get-document). * Route documents to the right customer with [labels and suppliers](/docs/suppliers-and-labels), and automate that routing with [rules](/docs/rules). * Let Recommand mail incoming documents on to an address of your choosing when that is easier than an API call, see [email delivery and notifications](/docs/email-delivery-and-notifications). For the full picture, including retries and idempotency, see [receiving documents](/docs/receiving-documents). Report back on the invoices you receive [#report-back-on-the-invoices-you-receive] Inside the French perimeter, receiving an invoice comes with an obligation the other two countries do not have: you report its lifecycle back to the sender. Recommand models those status messages as a document type of their own, `frenchInvoicingCdar`, so you send them the same way you send anything else. When an invoice arrives, Recommand automatically sends the transmission statuses back to the sender: `202` (received) when the document reaches the access point, and `203` (made available) when it is delivered to you. You only send the later processing statuses. ```javascript await fetch(`https://app.recommand.eu/api/v1/${companyId}/send`, { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify({ recipient: "0225:987654321", documentType: "frenchInvoicingCdar", document: { businessProcess: "REGULATED", senderRole: "WK", issuerRole: "BY", issuerLegalId: "123456789", issuerLegalIdScheme: "0002", recipientRole: "SE", statusCode: "205", statusDate: "2026-08-17T14:05:09", invoiceId: "INV-2026-001", invoiceTypeCode: "380", invoiceIssueDate: "2026-08-17", sellerLegalId: "987654321", sellerLegalIdScheme: "0002", }, }), }); ``` The processing statuses that matter most on the receiving side: | Status | Meaning | | ------ | ------------------------------------ | | `204` | Taken in charge (processing started) | | `205` | Approved | | `206` | Partially approved | | `207` | In dispute | | `210` | Refused | | `211` | Payment sent | A refusal, partial approval or dispute carries a coded reason (`DOUBLON`, `TX_TVA_ERR`, `NON_CONFORME`, …) and an optional free-text note, so the sender knows what to fix. The full status and reason lists are on the [send document endpoint](/reference/sending/send-document). Report collection on the invoices you sent [#report-collection-on-the-invoices-you-sent] `212` (collected) runs the other way: it is the seller who reports that a payment came in. It carries `collectedAmounts`, at least one entry naming an `amount`, its `currency` and the `vatPercent` it falls under. A disbursement is expressed as a negative amount. `212` is not a terminal status. An invoice settled in several instalments gets one `212` per payment received, each carrying only the amount of that payment rather than the running total. Successive messages are told apart by the CDAR's own `id`, generated for you when you leave it off, with `statusDate` naming the moment of collection and `issueDate` the moment the message was written. Incoming CDAR messages are parsed, stored and shown next to your other documents, and delivered through your existing webhooks and notifications, so this is also how you learn what your customers did with the invoices you sent them, including the `202` and `203` their access point sent when they received yours. What counts towards your document quota [#what-counts-towards-your-document-quota] You pay for documents and for the business answers to them, not for the messages platforms exchange to move them. Transmission statuses (`200`, `201`, `202`, `203`, `213` and `501`) never count, whether you receive them or Recommand sends them for you. Processing statuses (`204` to `212` and `214`) count as one document each, in both directions, exactly like an invoice: the party sending the decision and the party receiving it are treated alike. Going live [#going-live] Before you switch your first real customer over, walk this list: * **A valid subscription in production.** Playgrounds skip the subscription check; production does not. * **Verification handled in your UI.** Show the `verificationUrl` at the right moment, make it forwardable, and handle the `company.verification` webhook so a company that comes back `rejected` or `error` does not sit silently unusable. * **`isVerified` respected.** Do not let a user press send for a company that is not verified yet; explain what is missing instead. * **Webhook endpoint hardened.** Signature verification, a fast 200, retries and idempotency on your side. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of the person who can fix it. * **One real document, end to end.** Send an invoice between two companies you control on production before letting customers in. Documents are counted per team, with the volume of all your companies pooled, so onboarding more companies lowers your price per document rather than adding per-company fees. Received documents count towards the quota as well as sent ones, so budget for both sides of the exchange. Generated XML through `generate` is not billed; emails and submitted reports are. Before you go live in France [#before-you-go-live-in-france] France adds a few checks to the list above, all of them things that only show up once real documents move: * **The mandate is accepted.** `isVerified` is `true`, which for a French company means the signed mandate cleared its review. Plan this in: it is the one step that is not instant. * **The company carries the SIREN under scheme `0002`.** Both the documents you send and the mandate itself are built from the company's own identifiers, so a SIRET or a missing scheme surfaces as rejected documents rather than as a registration error. * **You know which side of the perimeter you are on.** Regulated is the default; transactions outside it have to say so explicitly, and the counterparty has to be registered for the process you use. If the company sends documents, two more: * **The format and process are what you meant.** Check one document before the first real send: the preview in the dashboard, or `generate` from the API, shows the resolved `doctypeId` and `processId`. * **Invoices are in EUR**, with the billing mode and the three mandatory statements filled in. B2B invoices are only half of the French obligation. If the company also sells to private individuals, or invoices businesses outside France, those operations have to be reported to the tax administration separately. Register the company for e-reporting and submit the reports through the API, as described in the e-reporting section of the [French sending guides](/getting-started/france). Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Sending Peppol documents in France for your own company (/getting-started/france/business/sending) This guide walks through everything needed to exchange Peppol documents for a company registered in France, assuming you are setting up your own French company, and that the company only sends documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are setting up [#what-you-are-setting-up] You are putting one company, your own or one you represent, on the Peppol network, so it can exchange invoices electronically with its customers and suppliers. The setup is a one-time affair: registering the company and getting it verified takes a few minutes in the [Recommand dashboard](https://app.recommand.eu), and there is nothing to gain from automating something you do once. What you do integrate is the part that repeats: sending and receiving documents. Our existing [integrations](/integrations) can also connect Recommand to accounting or invoicing software you already use, with no code at all. A single team can hold several companies at no extra cost, useful if you run more than one legal entity, and the document volume of all of them counts towards one plan. If you are building e-invoicing or Peppol integration into a product for your own customers, and will be registering their companies rather than only your own, switch the first answer above to **Many companies**. The API is the same; what changes is how companies, verification and billing are organised. Peppol in France [#peppol-in-france] French domestic e-invoicing follows the French e-invoicing reform rather than plain Peppol BIS 3. Recommand covers the French specifics for you, but they do change what you send and how a company is onboarded. What is specific to France: * **A French-accredited access point and SMP.** Companies you register with country `FR` are automatically published on a French-accredited SMP and exchange documents through the matching access point. You do not choose or configure this: it follows from the company's country. * **A signed mandate.** Before a French company can operate, its authorised representative signs a mandate that lets that accredited platform act for the company, and the file is reviewed before the company goes live. This is the one step in this guide that is not instant, so start it early. * **French document formats.** Invoices and credit notes travel as French CIUS or Extended UBL, CII D22B (CIUS or Extended), or Factur-X (a PDF/A-3 with the CII XML embedded), next to plain Peppol BIS 3 UBL. * **Two processes.** The same document types are published for a **regulated** process (`urn:peppol:france:billing:regulated`, transactions inside the French e-invoicing perimeter) and a **non-regulated** one (`urn:peppol:france:billing:non-regulated`, transactions outside it). * **Mandatory content.** French invoices carry a billing mode and three statements (recovery costs, late-payment penalties, early-payment discount) that plain EN 16931 does not require. They go in a `countrySpecific` block. * **Lifecycle statuses.** Inside the perimeter, receivers report back on the invoices they receive with an invoice lifecycle status. * **E-reporting.** What falls outside the e-invoicing perimeter is reported instead: B2C sales as daily totals, and invoices to businesses abroad one by one. Recommand files both report types on the company's behalf. * **Identifiers are SIREN-based.** French companies are published under scheme `0225`. The reform phases the obligations in over time: from **1 September 2026** every company must be able to receive electronic invoices, with issuance starting for large and mid-size companies, and from **1 September 2027** issuance applies to small and micro companies as well. Confirm the schedule and what falls inside the perimeter with your accountant or legal advisor. This documentation describes what the API does, not what your obligations are. Create your account and API credentials [#create-your-account-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). 2. Your account starts with a **team**. The team holds your company, your subscription and your document history, and you can invite colleagues to it. 3. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 4. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Sending and receiving can also be driven entirely from the dashboard or through an [integration](/integrations), and each section below says how. The dashboard is available in English, Dutch, French and German; pick your language on the [account page](https://app.recommand.eu/account). Try it safely first [#try-it-safely-first] You do not have to get anything right the first time. Everything below, adding the company, registering it, sending and receiving, can be done in a **playground team** first, where nothing is delivered over the real Peppol network, nothing is registered on it, and nothing is billed. Open the team switcher at the top of the [dashboard](https://app.recommand.eu) and pick **Add playground**. Give it a name, leave the Peppol Test Network box unticked, and you are switched into the new team straight away. There is nothing to set up beyond that. Add a company to that team and use it as both sender and recipient to watch a document travel end to end. When the flow does what you want, repeat it once in your real team. Two things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. A playground stays useful after you are live, too: it is the safest place to try a new invoice layout or a new integration. See [how can I test without sending real invoices](/faq/api-and-development/how-can-i-test-without-sending-real-invoices). Playground companies are not registered on the Peppol network and playground documents never leave it, so nothing you do there affects your real company. Register the company [#register-the-company] You are registering one company, once, so the dashboard is the shortest path. 1. Open [Companies](https://app.recommand.eu/companies) and start the company wizard. 2. Fill in the legal name, address and country, plus the identifiers described in the next section. 3. Choose whether the company should also **receive** documents over Peppol, or only send them. 4. Save. The company is registered on the Peppol network as part of this step: its identifiers and the document types for its country are set up for you. Right after saving, the dashboard offers the verification step, which the section below covers. Note the company's ID from its detail page. Every API call for sending and receiving takes it in the path. The [create company endpoint](/reference/companies/create-company) does exactly the same thing, and returns the company `id` and a `verificationUrl` in one response. It is worth using when company creation is part of a flow you are automating, which is likely the case if you are registering many companies. Switch the first answer above to **Many companies** for that version. Add each legal entity as its own company: run the wizard again. There is no per-company fee, and all of them share your document volume. French identifiers and Peppol address [#french-identifiers-and-peppol-address] In France the identifier you register decides whether your documents will pass validation later, so it is worth getting exactly right. | Field | French value | | ------------------------ | --------------------------------------- | | `country` | `"FR"` | | `enterpriseNumber` | The nine-digit **SIREN** of the company | | `enterpriseNumberScheme` | `"0002"` | | `vatNumber` | `FR` + the French VAT number | ```json title="company.json" { "name": "Société de Test SAS", "address": "10 rue de la Paix", "postalCode": "75002", "city": "Paris", "country": "FR", "enterpriseNumber": "133512194", "enterpriseNumberScheme": "0002", "vatNumber": "FR23133512194" } ``` French regulated invoices must carry the seller's nine-digit SIREN as `enterpriseNumber` with `enterpriseNumberScheme` `"0002"`. Because the seller block of a document defaults to the company's own details, a company registered with a SIRET or without the scheme produces invoices that are rejected at validation time. Register the SIREN, and name a specific establishment through the document's `delivery.locationIdentifier` (scheme `0009`) when you need to. One Peppol identifier is registered for the company: * `0225:133512194` is the French electronic address The company's Peppol address is therefore **`0225:` followed by the SIREN**. French addresses may also carry a routing suffix, as in `0225:987654321_STATUTS`; treat the whole string after the scheme as the identifier when a recipient gives you one. Both SIREN (9 digits) and SIRET (14 digits) are checked with the Luhn algorithm before they are filed, and numbers that disagree with each other are refused rather than guessed at. Registering for sending only [#registering-for-sending-only] Because you are only looking to send invoices or other documents, register the company **without** recipient registration: set `isSmpRecipient` to `false` (or leave the checkbox unticked in the dashboard). ```json { "isSmpRecipient": false } ``` What that means: * The company is not published as a recipient on an SMP, so nothing is delivered to it over Peppol through your integration. * Registration succeeds even when the company already receives its documents through another Peppol provider. The other Peppol provider will remain in charge for processing received documents for this company. * Nothing changes for sending: outgoing documents leave through the access point as normal. You can flip `isSmpRecipient` to `true` on an existing company at any time. Recommand then publishes it as a recipient and registers the document types for its country. That registration is exclusive, so the company has to be deregistered at its current provider first. Sign the mandate and verify the company [#sign-the-mandate-and-verify-the-company] French companies go through the same identity check as everyone else, plus two steps that are specific to France: the representative signs a mandate, and the resulting file is reviewed before the company goes live. 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. **Read and sign the mandate.** The verification page shows the mandate that authorises the French-accredited platform to act for the company on the Peppol network, naming the company by its SIREN and the establishment it is filed under. The representative accepts it before the identity check starts. 3. **Complete the identity check.** The identity verification is what signs the mandate: the proof reference is recorded on it. 4. **Wait for the review.** The signed mandate and the company's details are filed with the accredited platform, and the verification sits in review until that file is accepted. Only then does `isVerified` become `true` and the company start operating. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. This is the one step of French onboarding that is not immediate. Start verification as soon as the company is created, and do not promise your users a same-minute go-live for France. If a file seems stuck, mail [support@recommand.eu](mailto:support@recommand.eu) with the company ID. Companies in a playground team are never filed with the accredited platform, so there is no mandate and no review. Test the French flow in a playground first, then run the real thing once. Verifying once, in the dashboard [#verifying-once-in-the-dashboard] You have one company, and it is verified once. There is nothing here worth automating: open [Companies](https://app.recommand.eu/companies) in the dashboard, pick the company and start verification. If you are authorised to act for the company, complete the check yourself; otherwise use the button to forward the link to whoever is. The page is self-contained and works in any browser. The person completing it does not need a Recommand account. That is the whole step. From here on the API takes over: sending and receiving documents is what you actually integrate. Updating the company's `vatNumber` or `enterpriseNumber` sets `isVerified` back to `false`, and the company has to be verified again before it can exchange documents. Pick the French document format and process [#pick-the-french-document-format-and-process] A French invoice needs three decisions: the format, the process, and the mandatory French content. The format [#the-format] Name the format with `doctypeId` on the send request. Leave it off and the recipient is looked up and the document written in the first format, in [our order of preference](/changelog/2026-08-28-automatic-document-format-routing), they are registered to receive. Peppol BIS 3 UBL comes first in that order, so a French recipient who publishes it as well receives plain BIS 3: valid on the network, but not what the French reform asks for inside its perimeter. Name the French format you want for transactions inside the perimeter. | Format | `doctypeId` | | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | France UBL CIUS invoice | `urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:peppol:france:billing:cius:1.0::2.1` | | France UBL CIUS credit note | `urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2::CreditNote##urn:cen.eu:en16931:2017#compliant#urn:peppol:france:billing:cius:1.0::2.1` | | France UBL Extended invoice | `urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#conformant#urn:peppol:france:billing:extended:1.0::2.1` | | France CII CIUS | `urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100::CrossIndustryInvoice##urn:cen.eu:en16931:2017#compliant#urn:peppol:france:billing:cius:1.0::D22B` | | France CII Extended | `urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100::CrossIndustryInvoice##urn:cen.eu:en16931:2017#conformant#urn:peppol:france:billing:extended:1.0::D22B` | | France Factur-X | `urn:peppol:doctype:pdf+xml##urn:cen.eu:en16931:2017#conformant#urn:peppol:france:billing:Factur-X:1.0::D22B` | The CII and Factur-X document types carry both invoices and credit notes; the `documentType` field of your request decides which one it is. Start with **France UBL CIUS** unless you have a reason not to. Extended is for data the CIUS does not carry, and Factur-X is for recipients who want a human-readable PDF as the carrier. The process [#the-process] Set `countrySpecific.businessProcess` to say which side of the French perimeter the transaction is on. The document is then sent over the matching process: | `businessProcess` | Process identifier | Use for | | --------------------- | ----------------------------------------- | ---------------------------------------- | | `REGULATED` (default) | `urn:peppol:france:billing:regulated` | Transactions inside the French perimeter | | `NON_REGULATED` | `urn:peppol:france:billing:non-regulated` | Transactions outside it | The recipient must have registered the document type **for that process**. Pass the `processId` to the [verify document support endpoint](/reference/recipients/verify-document-support) to check exactly that combination rather than "any process". The mandatory French content [#the-mandatory-french-content] French UBL, CII and Factur-X require a `countrySpecific` block with the billing mode and the three statements French invoices must carry. It is required for those document types and must be omitted for plain EN 16931 documents. ```json { "countrySpecific": { "country": "FR", "billingMode": "S1", "businessProcess": "REGULATED", "recoveryCostsNote": "Indemnité forfaitaire de 40 EUR pour frais de recouvrement.", "latePaymentPenaltiesNote": "Pénalités de retard exigibles au taux prévu dans les conditions générales de vente.", "earlyPaymentDiscountNote": "Aucun escompte accordé pour paiement anticipé." } } ``` `billingMode` follows AFNOR XP Z12-012. The common ones are `B1` (goods), `S1` (services) and `M1` (mixed); the full list, including already-paid, advance payment, subcontracting and multi-seller variants, is documented on the [send document endpoint](/reference/sending/send-document). Invoicing outside France [#invoicing-outside-france] The French formats and processes are for the French perimeter. A counterparty in another country is registered for the **standard** Peppol billing process, so a regulated document does not match anything they published. For those invoices, send plain Peppol BIS 3 UBL and leave the `countrySpecific` block out with it, it belongs to the French document types only. The rest of the invoice is unchanged. * The seller's `enterpriseNumber` must be the nine-digit SIREN with `enterpriseNumberScheme` `"0002"`. * The currency must be `EUR`. * Factur-X needs a compliant PDF/A-3 to embed the XML in: either attach one as an embedded attachment, or let Recommand generate it with `pdfGeneration.enabled`. Send a document [#send-a-document] One endpoint sends everything: [`POST /:companyId/send`](/reference/sending/send-document). The `companyId` is the sender, `recipient` is the Peppol address of the receiver, and `document` is the invoice or credit note as JSON. Recommand will validate the document and generate the XML. Raw XML sending is supported as well: set `documentType` to `xml` and pass the document string in `document`, along with the correct `doctypeId`. See [working with raw UBL](/docs/ubl-format-guide#working-with-raw-ubl). ```bash curl -X POST https://app.recommand.eu/api/v1/{companyId}/send \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @send-invoice.json ``` ```json title="send-invoice.json" { "recipient": "0208:0123456789", "documentType": "invoice", "document": { "invoiceNumber": "INV-2026-001", "issueDate": "2026-08-17", "dueDate": "2026-09-16", "currency": "EUR", "buyer": { "name": "Customer Company", "street": "Customer Street 1", "city": "Antwerp", "postalZone": "2000", "country": "BE", "vatNumber": "BE0987654321" }, "paymentMeans": [{ "iban": "BE68539007547034" }], "lines": [ { "name": "Consulting Services", "quantity": "10.00", "unitCode": "HUR", "netPriceAmount": "100.00", "vat": { "category": "S", "percentage": "21.00" } } ] } } ``` The seller block is filled in from your company when you leave it out, which is usually what you want: it keeps your registered identifiers and the document in agreement. The full field reference lives in [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Worth wiring up while you are here: * **Validation errors.** Outgoing documents are always validated. A `success: false` response with `errors` keyed by field path is a document the recipient would have rejected. Surface it wherever the data was typed. * **Email fallback.** Pass `email.to` with `when: "on_peppol_failure"` to fall back to email when a recipient turns out not to be reachable over Peppol, or send with `recipient: null` for email-only delivery. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **PDFs.** `pdfGeneration.enabled` attaches a generated PDF of the document. You can also attach an existing PDF (or other files) via `attachments`; see [adding attachments](/docs/sending-invoices#adding-attachments). For a full field reference, see [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Sending without writing code [#sending-without-writing-code] The same send is available two other ways, and they mix freely with the API: * **From the dashboard.** [Send document](https://app.recommand.eu/send-document) takes the recipient and the invoice lines, previews what the recipient will get, and remembers your usual settings. You can also drop an existing UBL or CII XML file into the upload zone if your software already produces one. * **From your accounting or invoicing software.** If you use one of the supported tools, let it do the work: your invoices flow to Recommand and out over Peppol without retyping. See [integrations](/integrations) for the current list, including Microsoft Business Central, Exact Online, Yuki, ClearFacts, ERPNext and Harvest. Whichever route you use, Recommand validates a document before it leaves. If a field is missing or malformed you get a clear error instead of a rejection from the recipient days later. See the [troubleshooting guide](/docs/troubleshooting-guide) for the errors you are most likely to run into. French e-reporting [#french-e-reporting] French e-invoicing covers invoices between businesses established in France. Everything else a French company sells still has to reach the tax administration: sales to private individuals, and invoices to businesses outside France. That is e-reporting. You send Recommand the figures, and Recommand files them on the company's behalf. You never build a regulatory file yourself. B2C reports contain daily totals. Cross-border reports describe an individual invoice or credit note, or a payment received on an invoice. | Report | Endpoint (under `/api/v1`) | `type` | Scope | | -------------------- | ------------------------------------ | ---------- | --------------------------------------------------------------- | | B2C sales | `POST /:companyId/reporting/fr/b2c` | `sales` | Sales for one day, category and currency | | B2C payments | `POST /:companyId/reporting/fr/b2c` | `payments` | Payments received for one day and currency, grouped by VAT rate | | Cross-border invoice | `POST /:companyId/reporting/fr/b2bi` | `invoice` | One invoice or credit note issued to a business outside France | | Cross-border payment | `POST /:companyId/reporting/fr/b2bi` | `payment` | A payment received on a previously reported invoice | All reports are submitted per company, through the API only. Every accepted report is stored with the company's other documents and counts towards the document quota. Register the company first [#register-the-company-first] E-reporting has to be switched on per company, because the tax administration needs to know two things about the taxpayer before its first report: its VAT regime, which sets how often reports are filed, and whether its VAT becomes due on invoicing or on payment. Register the company once through [`PUT /:companyId/reporting/fr/declarant`](/reference/reporting/register-french-reporting-declarant), or from the company page in the dashboard. ```json { "vatRegime": "REEL_NORMAL_MENSUEL", "vatExigibility": "DEBITS" } ``` | Field | Values | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `vatRegime` | `REEL_NORMAL_MENSUEL` (régime réel normal), `REEL_SIMPLIFIE` (régime réel simplifié), `FRANCHISE_EN_BASE` (franchise en base de TVA) | | `vatExigibility` | `DEBITS` (VAT due on invoicing, typical for goods), `ENCAISSEMENTS` (VAT due on payment, typical for services) | The company must be registered in France with a valid SIREN or SIRET, and it must be verified with a signed French mandate whose annex covers e-reporting. That annex is what entitles Recommand to report for the SIREN. A company that was verified without one is refused with a 400; contact [support@recommand.eu](mailto:support@recommand.eu) to have e-reporting enabled for it. The response carries a `state`. Reports are accepted once it is `registered`; `pending` means the registration is still being completed in the background, and `blocked` means support has to intervene, for example because the company is already registered for e-reporting through another platform. It also carries `enabled`. A suspended registration keeps its `registered` state but refuses every report with a 400 until support switches it back on, so check both fields when reports start being refused. Registering makes the company's reporting periods due. Only register companies that will submit reports, and submit each day's figures promptly rather than at month end. Changing the VAT regime later can leave the open period unfiled, so coordinate such a change with support. Report B2C sales [#report-b2c-sales] Submit one sales report per day, per category and per currency through [`POST /:companyId/reporting/fr/b2c`](/reference/reporting/submit-french-b2creport), regardless of when customers pay. ```json { "reference": "B2C-SALES-2026-08-17-GOODS", "type": "sales", "date": "2026-08-17", "category": "goods", "currency": "EUR", "taxExclusiveAmount": "10000.00", "taxAmount": "2000.00", "transactionCount": 42, "vatBreakdown": [ { "percentage": "20.00", "taxableAmount": "10000.00", "taxAmount": "2000.00" } ] } ``` * `category` is `goods` or `services`; use a separate report when both were sold on the same day. Only taxable goods and taxable services are supported today, so exempt B2C sales have no report type yet. * Amounts are strings with two decimals and are never negative. VAT amounts are always in EUR, even when the sales currency is different. * `transactionCount` is the number of individual sales in the total. It is at least 1: a day without sales is not reported at all. Report B2C payments [#report-b2c-payments] For service payments where VAT becomes due on payment, submit the daily amounts received through the same B2C endpoint with `type: "payments"`. Group the amounts including VAT by VAT rate. Submit the sales report as usual as well. ```json { "reference": "B2C-PAYMENTS-2026-08-17-EUR", "type": "payments", "date": "2026-08-17", "currency": "EUR", "vatBreakdown": [ { "percentage": "20.00", "amount": "1200.00" } ] } ``` Payment reports are only accepted for companies registered with VAT due on payment (`ENCAISSEMENTS`). Report cross-border invoices [#report-cross-border-invoices] Submit every invoice or credit note issued to a business outside France through [`POST /:companyId/reporting/fr/b2bi`](/reference/reporting/submit-french-b2bi-report). An invoice to a French buyer is exchanged over the e-invoicing network instead and is refused here. Set `documentType` to `invoice` or `creditNote` to say which of the two you are reporting. It defaults to `invoice`, so you only have to name it for credit notes. The reporting company must carry its own French VAT number as well as its SIREN: a cross-border report identifies the seller by both. Add the VAT number to the company before its first cross-border report. ```json { "reference": "EREPORT-INV-2026-000431", "type": "invoice", "documentNumber": "INV-2026-000431", "issueDate": "2026-01-15", "currency": "EUR", "buyer": { "name": "Rossi Forniture S.r.l.", "country": "IT", "vatNumber": "IT00987654321" }, "taxExclusiveAmount": "10000.00", "taxAmount": "0.00", "vatBreakdown": [ { "percentage": "0.00", "taxableAmount": "10000.00", "taxAmount": "0.00", "category": "K", "exemptionReasonCode": "VATEX-EU-IC" } ] } ``` The buyer is identified the way the tax administration identifies foreign businesses: * **In the European Union**: by its intra-community VAT number, which is required. * **Outside the European Union**: by its country and name; no VAT number is needed. * **In Nouvelle-Calédonie or Polynésie française**: by its local registration number (RIDET or TAHITI), in `enterpriseNumber`. Cross-border operations are usually exempt or reverse charged rather than taxed. When a VAT breakdown entry uses an exempt category, name why: give `exemptionReason`, `exemptionReasonCode`, or both. A breakdown that leaves both off on an exempt category is refused. Report a cross-border payment [#report-a-cross-border-payment] Submit a payment received on a previously reported invoice through the same cross-border endpoint with `type: "payment"`. Set `invoiceNumber` to the original report's `documentNumber` and `issueDate` to the invoice date. The `date` field is the day the payment was received. For a payment of EUR 10,000 on the invoice above: ```json { "reference": "EREPORT-PAYMENT-2026-000431-1", "type": "payment", "invoiceNumber": "INV-2026-000431", "issueDate": "2026-01-15", "date": "2026-02-10", "currency": "EUR", "vatBreakdown": [ { "percentage": "0.00", "amount": "10000.00" } ] } ``` Amounts include VAT and are grouped by VAT rate. As with B2C payments, payment reports are only accepted for companies registered with VAT due on payment (`ENCAISSEMENTS`). References, retries, corrections [#references-retries-corrections] Every report needs its own `reference`, at most 128 characters. It is your idempotency key: retrying the exact same request with the same reference returns the report filed the first time, with `duplicate: true`, and files nothing again. Use this after a timeout or a `502`. To change a report you already filed, send a new report with a **new reference** and the `action` field: * `action: "correct"` replaces the earlier report. It is matched on the data that identifies the report: the day, category and currency of a B2C sales report, the day of a B2C payment report, or the document number of a cross-border invoice. * `action: "cancel"` withdraws it, matched the same way. Reusing the original reference for a correction would be treated as a retry of the original report, and nothing would change. When a report is refused [#when-a-report-is-refused] Submitting a report can fail for reasons that have nothing to do with the figures, so handle each status separately rather than treating any non-200 as bad data. | Status | What happened | What to do | | ------ | -------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | 400 | The company is not registered for e-reporting, its registration is still `pending` or `blocked`, or it is suspended (`enabled: false`) | Register it, or wait for the state to become `registered`. A `blocked` or suspended registration needs support | | 400 | The reporting service refused the report; the reason is in the message | Fix what the message names and submit again under a new reference | | 400 | A payment report was sent for a company whose VAT is due on invoicing (`DEBITS`), or a cross-border report named a French buyer | Neither is reportable. A French buyer is invoiced over the e-invoicing network instead | | 409 | The report conflicts with what was already filed, for example a correction of something that was never reported | Look at what is on file before resubmitting | | 502 | The reporting service could not be reached | Retry later with the **same** reference. The reference is the idempotency key, so a retry cannot file the report twice | The 502 case is the one worth building for: it is the only status where reusing the reference is right. Every other failure needs a fresh reference once you have fixed the cause. Follow the report until it is filed [#follow-the-report-until-it-is-filed] Accepting a report is not filing it. The tax administration receives a filing per reporting period, assembled after the period ends, and can still reject it. Every report you submit therefore carries a `reporting` block in the [documents API](/reference/documents/get-document), which Recommand keeps up to date: | `reportingStatus` | Meaning | | ----------------------- | -------------------------------------------------------------------------------------- | | `accepted` | On file, inside its reporting period. Not yet filed. | | `pending_rectificative` | Arrived after its period was already filed; it will be carried by a corrective filing. | | `filed` | Reported to the tax administration within its own period. | | `filed_rectificative` | Reported by a corrective filing, because it arrived late. | | `superseded` | Replaced by a later correction, or cancelled. | | `rejected` | The tax administration rejected the filing carrying it; see `outcomeCode`. | The block also names the reporting period (`periodStart`, `periodEnd`), the filing the report was carried on (`submissionId`) and when the status was last checked. Every change fires a `document.reporting_status_changed` webhook event, so you can route rejections to whoever handles them. Reports from playground teams and teams on the test network are validated, recorded and shown exactly like real ones, but they are never filed with the tax administration. Their status stays `accepted` and is marked as simulated. Use them to build the integration; use a production team to file. Registration is immediate there: it comes back `registered` straight away rather than going through `pending`, so you can submit reports as soon as you have registered. Registrations are also kept per environment. A team on the test network registers in `TEST`, a production team in `PROD`, and the two are separate registrations for the same company. The `environment` field on the registration response says which one you are looking at. Going live [#going-live] A short list before you start sending or receiving real invoices: * **A valid subscription**, so sending is not blocked. Playgrounds skip that check; production does not. * **The company verified**, with `isVerified` true. Until then it cannot exchange documents. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of whoever can fix it rather than logging it. * **Webhook endpoint hardened**, if you took that route: signature verification, a fast 200, retries and idempotency on your side. * **One real document sent and received**, ideally between two companies you control, so you have seen both ends. * **Notification addresses set**, so incoming documents also reach a mailbox somebody reads. Once you are live, your Peppol address is public on the network: suppliers can find and reach you without any action from you. Ask customers who still email PDFs to switch, and let your accountant know where the documents now land. Before you go live in France [#before-you-go-live-in-france] France adds a few checks to the list above, all of them things that only show up once real documents move: * **The mandate is accepted.** `isVerified` is `true`, which for a French company means the signed mandate cleared its review. Plan this in: it is the one step that is not instant. * **The company carries the SIREN under scheme `0002`.** Both the documents you send and the mandate itself are built from the company's own identifiers, so a SIRET or a missing scheme surfaces as rejected documents rather than as a registration error. * **You know which side of the perimeter you are on.** Regulated is the default; transactions outside it have to say so explicitly, and the counterparty has to be registered for the process you use. If the company sends documents, two more: * **The format and process are what you meant.** Check one document before the first real send: the preview in the dashboard, or `generate` from the API, shows the resolved `doctypeId` and `processId`. * **Invoices are in EUR**, with the billing mode and the three mandatory statements filled in. B2B invoices are only half of the French obligation. If the company also sells to private individuals, or invoices businesses outside France, those operations have to be reported to the tax administration separately. Register the company for e-reporting and submit the reports through the API, as described in the e-reporting section of the [French sending guides](/getting-started/france). Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Receiving Peppol documents in France for your own company (/getting-started/france/business/receiving) This guide walks through everything needed to exchange Peppol documents for a company registered in France, assuming you are setting up your own French company, and that the company only receives documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are setting up [#what-you-are-setting-up] You are putting one company, your own or one you represent, on the Peppol network, so it can exchange invoices electronically with its customers and suppliers. The setup is a one-time affair: registering the company and getting it verified takes a few minutes in the [Recommand dashboard](https://app.recommand.eu), and there is nothing to gain from automating something you do once. What you do integrate is the part that repeats: sending and receiving documents. Our existing [integrations](/integrations) can also connect Recommand to accounting or invoicing software you already use, with no code at all. A single team can hold several companies at no extra cost, useful if you run more than one legal entity, and the document volume of all of them counts towards one plan. If you are building e-invoicing or Peppol integration into a product for your own customers, and will be registering their companies rather than only your own, switch the first answer above to **Many companies**. The API is the same; what changes is how companies, verification and billing are organised. Peppol in France [#peppol-in-france] French domestic e-invoicing follows the French e-invoicing reform rather than plain Peppol BIS 3. Recommand covers the French specifics for you, but they do change what you send and how a company is onboarded. What is specific to France: * **A French-accredited access point and SMP.** Companies you register with country `FR` are automatically published on a French-accredited SMP and exchange documents through the matching access point. You do not choose or configure this: it follows from the company's country. * **A signed mandate.** Before a French company can operate, its authorised representative signs a mandate that lets that accredited platform act for the company, and the file is reviewed before the company goes live. This is the one step in this guide that is not instant, so start it early. * **French document formats.** Invoices and credit notes travel as French CIUS or Extended UBL, CII D22B (CIUS or Extended), or Factur-X (a PDF/A-3 with the CII XML embedded), next to plain Peppol BIS 3 UBL. * **Two processes.** The same document types are published for a **regulated** process (`urn:peppol:france:billing:regulated`, transactions inside the French e-invoicing perimeter) and a **non-regulated** one (`urn:peppol:france:billing:non-regulated`, transactions outside it). * **Mandatory content.** French invoices carry a billing mode and three statements (recovery costs, late-payment penalties, early-payment discount) that plain EN 16931 does not require. They go in a `countrySpecific` block. * **Lifecycle statuses.** Inside the perimeter, receivers report back on the invoices they receive with an invoice lifecycle status. * **E-reporting.** What falls outside the e-invoicing perimeter is reported instead: B2C sales as daily totals, and invoices to businesses abroad one by one. Recommand files both report types on the company's behalf. * **Identifiers are SIREN-based.** French companies are published under scheme `0225`. The reform phases the obligations in over time: from **1 September 2026** every company must be able to receive electronic invoices, with issuance starting for large and mid-size companies, and from **1 September 2027** issuance applies to small and micro companies as well. Confirm the schedule and what falls inside the perimeter with your accountant or legal advisor. This documentation describes what the API does, not what your obligations are. Create your account and API credentials [#create-your-account-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). 2. Your account starts with a **team**. The team holds your company, your subscription and your document history, and you can invite colleagues to it. 3. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 4. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Sending and receiving can also be driven entirely from the dashboard or through an [integration](/integrations), and each section below says how. The dashboard is available in English, Dutch, French and German; pick your language on the [account page](https://app.recommand.eu/account). Try it safely first [#try-it-safely-first] You do not have to get anything right the first time. Everything below, adding the company, registering it, sending and receiving, can be done in a **playground team** first, where nothing is delivered over the real Peppol network, nothing is registered on it, and nothing is billed. Open the team switcher at the top of the [dashboard](https://app.recommand.eu) and pick **Add playground**. Give it a name, leave the Peppol Test Network box unticked, and you are switched into the new team straight away. There is nothing to set up beyond that. Add a company to that team and use it as both sender and recipient to watch a document travel end to end. When the flow does what you want, repeat it once in your real team. Two things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. A playground stays useful after you are live, too: it is the safest place to try a new invoice layout or a new integration. See [how can I test without sending real invoices](/faq/api-and-development/how-can-i-test-without-sending-real-invoices). Playground companies are not registered on the Peppol network and playground documents never leave it, so nothing you do there affects your real company. Register the company [#register-the-company] You are registering one company, once, so the dashboard is the shortest path. 1. Open [Companies](https://app.recommand.eu/companies) and start the company wizard. 2. Fill in the legal name, address and country, plus the identifiers described in the next section. 3. Choose whether the company should also **receive** documents over Peppol, or only send them. 4. Save. The company is registered on the Peppol network as part of this step: its identifiers and the document types for its country are set up for you. Right after saving, the dashboard offers the verification step, which the section below covers. Note the company's ID from its detail page. Every API call for sending and receiving takes it in the path. The [create company endpoint](/reference/companies/create-company) does exactly the same thing, and returns the company `id` and a `verificationUrl` in one response. It is worth using when company creation is part of a flow you are automating, which is likely the case if you are registering many companies. Switch the first answer above to **Many companies** for that version. Add each legal entity as its own company: run the wizard again. There is no per-company fee, and all of them share your document volume. French identifiers and Peppol address [#french-identifiers-and-peppol-address] In France the identifier you register decides whether your documents will pass validation later, so it is worth getting exactly right. | Field | French value | | ------------------------ | --------------------------------------- | | `country` | `"FR"` | | `enterpriseNumber` | The nine-digit **SIREN** of the company | | `enterpriseNumberScheme` | `"0002"` | | `vatNumber` | `FR` + the French VAT number | ```json title="company.json" { "name": "Société de Test SAS", "address": "10 rue de la Paix", "postalCode": "75002", "city": "Paris", "country": "FR", "enterpriseNumber": "133512194", "enterpriseNumberScheme": "0002", "vatNumber": "FR23133512194" } ``` French regulated invoices must carry the seller's nine-digit SIREN as `enterpriseNumber` with `enterpriseNumberScheme` `"0002"`. Because the seller block of a document defaults to the company's own details, a company registered with a SIRET or without the scheme produces invoices that are rejected at validation time. Register the SIREN, and name a specific establishment through the document's `delivery.locationIdentifier` (scheme `0009`) when you need to. One Peppol identifier is registered for the company: * `0225:133512194` is the French electronic address The company's Peppol address is therefore **`0225:` followed by the SIREN**. French addresses may also carry a routing suffix, as in `0225:987654321_STATUTS`; treat the whole string after the scheme as the identifier when a recipient gives you one. Both SIREN (9 digits) and SIRET (14 digits) are checked with the Luhn algorithm before they are filed, and numbers that disagree with each other are refused rather than guessed at. Registering as a recipient [#registering-as-a-recipient] To receive documents, the company must be published as a recipient on an SMP (Service Metadata Publisher). That is what `isSmpRecipient` does, and it is the default: ```json { "isSmpRecipient": true } ``` What that means: * The company becomes findable on the Peppol network: any sender can look it up and deliver to it via the Peppol network. * Recipient registration is **exclusive**. If the company is already registered for receiving through another Peppol provider, registration fails until it is deregistered there. * The document types the company accepts are registered along with it, based on its country. Which ones those are is covered further down. * The company is only published once it is verified. Where a French company is published [#where-a-french-company-is-published] A French company is published on the **French-accredited SMP**, and it exchanges documents through the matching access point. This follows from the company's country: there is nothing to choose or configure. Two consequences for the order of your onboarding: * **The mandate gates the go-live.** The accredited platform only acts for the company once the signed mandate has been accepted, so the company is not operational the minute it is created. The verification section below covers that step; start it early. * **Deregister elsewhere first.** Recipient registration is exclusive here as well, and France has no automatic migration path. A company that currently receives through another platform has to be deregistered there before it can be registered with Recommand. Sign the mandate and verify the company [#sign-the-mandate-and-verify-the-company] French companies go through the same identity check as everyone else, plus two steps that are specific to France: the representative signs a mandate, and the resulting file is reviewed before the company goes live. 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. **Read and sign the mandate.** The verification page shows the mandate that authorises the French-accredited platform to act for the company on the Peppol network, naming the company by its SIREN and the establishment it is filed under. The representative accepts it before the identity check starts. 3. **Complete the identity check.** The identity verification is what signs the mandate: the proof reference is recorded on it. 4. **Wait for the review.** The signed mandate and the company's details are filed with the accredited platform, and the verification sits in review until that file is accepted. Only then does `isVerified` become `true` and the company start operating. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. This is the one step of French onboarding that is not immediate. Start verification as soon as the company is created, and do not promise your users a same-minute go-live for France. If a file seems stuck, mail [support@recommand.eu](mailto:support@recommand.eu) with the company ID. Companies in a playground team are never filed with the accredited platform, so there is no mandate and no review. Test the French flow in a playground first, then run the real thing once. Verifying once, in the dashboard [#verifying-once-in-the-dashboard] You have one company, and it is verified once. There is nothing here worth automating: open [Companies](https://app.recommand.eu/companies) in the dashboard, pick the company and start verification. If you are authorised to act for the company, complete the check yourself; otherwise use the button to forward the link to whoever is. The page is self-contained and works in any browser. The person completing it does not need a Recommand account. That is the whole step. From here on the API takes over: sending and receiving documents is what you actually integrate. Updating the company's `vatNumber` or `enterpriseNumber` sets `isVerified` back to `false`, and the company has to be verified again before it can exchange documents. Document types registered for you [#document-types-registered-for-you] A French company is published for the whole French set, all on the **regulated** process, so any sender inside the perimeter can reach it in the format they prefer: | Document type | Registered process | | ------------------------------------------- | ------------------------------------- | | Invoice + credit note (Peppol BIS 3 UBL) | `urn:peppol:france:billing:regulated` | | Invoice + credit note (France UBL CIUS) | `urn:peppol:france:billing:regulated` | | Invoice + credit note (France UBL Extended) | `urn:peppol:france:billing:regulated` | | Invoice + credit note (France CII CIUS) | `urn:peppol:france:billing:regulated` | | Invoice + credit note (France CII Extended) | `urn:peppol:france:billing:regulated` | | Factur-X invoice + credit note | `urn:peppol:france:billing:regulated` | | Invoice lifecycle status (CDAR) | `urn:peppol:france:billing:regulated` | Whichever format arrives, you read the same parsed document out of the API. For Factur-X, the CII XML is extracted from the PDF/A-3 and parsed like any other document, and the original PDF is kept and included in the document's [download package](/reference/documents/download-package). The defaults cover the regulated process. If counterparties will send you documents over `urn:peppol:france:billing:non-regulated`, register the same document types for that process as well with the [create company document type endpoint](/reference/company-document-types/create-company-document-type). Pick up incoming documents [#pick-up-incoming-documents] Once the company is published as a recipient, everything sent to it arrives in Recommand automatically. There are two ways to get the documents into your own systems. Webhooks (recommended) [#webhooks-recommended] Register an endpoint once with the [create webhook endpoint](/reference/webhooks/create-webhook) and events are pushed to you as they happen, `document.received` among them: ```bash curl -X POST https://app.recommand.eu/api/v1/webhooks \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @create-webhook.json ``` ```json title="create-webhook.json" { "url": "https://your-app.example/webhooks/recommand", "companyId": null, "secret": "your_webhook_signing_secret" } ``` Pass a `secret` and verify the HMAC SHA-256 signature on every delivery before you trust the payload, then acknowledge with a 200 before doing the heavy processing. Both are covered in [working with webhooks](/docs/working-with-webhooks). Polling the inbox [#polling-the-inbox] If you would rather pull, the [inbox endpoint](/reference/documents/get-inbox) lists unread documents, and [mark as read](/reference/documents/mark-as-read) drops one off the list once your system has it. Fetch details, the original XML or a rendered PDF from the [documents endpoints](/reference/documents/get-document). Receiving without writing code [#receiving-without-writing-code] * **In the dashboard.** Incoming invoices appear under [Sent and received](https://app.recommand.eu/transmitted-documents), with the original XML, a readable rendering, attachments and the delivery history. * **By email.** Add notification email addresses per company so incoming documents land in the mailbox your bookkeeping already watches, attachments included. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **In your accounting software.** Forward incoming documents straight to Exact Online, Yuki, ClearFacts or another supported tool, see [integrations](/integrations). Two things worth setting up early, whichever route you take: * **Labels and suppliers** to keep documents organised as volume grows, see [suppliers and labels](/docs/suppliers-and-labels). * **Rules** to act on incoming documents automatically: forwarding, labelling, notifying, see [rules](/docs/rules). The full picture, including retries and idempotency, is in [receiving documents](/docs/receiving-documents). Report back on the invoices you receive [#report-back-on-the-invoices-you-receive] Inside the French perimeter, receiving an invoice comes with an obligation the other two countries do not have: you report its lifecycle back to the sender. Recommand models those status messages as a document type of their own, `frenchInvoicingCdar`, so you send them the same way you send anything else. When an invoice arrives, Recommand automatically sends the transmission statuses back to the sender: `202` (received) when the document reaches the access point, and `203` (made available) when it is delivered to you. You only send the later processing statuses. ```javascript await fetch(`https://app.recommand.eu/api/v1/${companyId}/send`, { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify({ recipient: "0225:987654321", documentType: "frenchInvoicingCdar", document: { businessProcess: "REGULATED", senderRole: "WK", issuerRole: "BY", issuerLegalId: "123456789", issuerLegalIdScheme: "0002", recipientRole: "SE", statusCode: "205", statusDate: "2026-08-17T14:05:09", invoiceId: "INV-2026-001", invoiceTypeCode: "380", invoiceIssueDate: "2026-08-17", sellerLegalId: "987654321", sellerLegalIdScheme: "0002", }, }), }); ``` The processing statuses that matter most on the receiving side: | Status | Meaning | | ------ | ------------------------------------ | | `204` | Taken in charge (processing started) | | `205` | Approved | | `206` | Partially approved | | `207` | In dispute | | `210` | Refused | | `211` | Payment sent | A refusal, partial approval or dispute carries a coded reason (`DOUBLON`, `TX_TVA_ERR`, `NON_CONFORME`, …) and an optional free-text note, so the sender knows what to fix. The full status and reason lists are on the [send document endpoint](/reference/sending/send-document). Report collection on the invoices you sent [#report-collection-on-the-invoices-you-sent] `212` (collected) runs the other way: it is the seller who reports that a payment came in. It carries `collectedAmounts`, at least one entry naming an `amount`, its `currency` and the `vatPercent` it falls under. A disbursement is expressed as a negative amount. `212` is not a terminal status. An invoice settled in several instalments gets one `212` per payment received, each carrying only the amount of that payment rather than the running total. Successive messages are told apart by the CDAR's own `id`, generated for you when you leave it off, with `statusDate` naming the moment of collection and `issueDate` the moment the message was written. Incoming CDAR messages are parsed, stored and shown next to your other documents, and delivered through your existing webhooks and notifications, so this is also how you learn what your customers did with the invoices you sent them, including the `202` and `203` their access point sent when they received yours. What counts towards your document quota [#what-counts-towards-your-document-quota] You pay for documents and for the business answers to them, not for the messages platforms exchange to move them. Transmission statuses (`200`, `201`, `202`, `203`, `213` and `501`) never count, whether you receive them or Recommand sends them for you. Processing statuses (`204` to `212` and `214`) count as one document each, in both directions, exactly like an invoice: the party sending the decision and the party receiving it are treated alike. Going live [#going-live] A short list before you start sending or receiving real invoices: * **A valid subscription**, so sending is not blocked. Playgrounds skip that check; production does not. * **The company verified**, with `isVerified` true. Until then it cannot exchange documents. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of whoever can fix it rather than logging it. * **Webhook endpoint hardened**, if you took that route: signature verification, a fast 200, retries and idempotency on your side. * **One real document sent and received**, ideally between two companies you control, so you have seen both ends. * **Notification addresses set**, so incoming documents also reach a mailbox somebody reads. Once you are live, your Peppol address is public on the network: suppliers can find and reach you without any action from you. Ask customers who still email PDFs to switch, and let your accountant know where the documents now land. Before you go live in France [#before-you-go-live-in-france] France adds a few checks to the list above, all of them things that only show up once real documents move: * **The mandate is accepted.** `isVerified` is `true`, which for a French company means the signed mandate cleared its review. Plan this in: it is the one step that is not instant. * **The company carries the SIREN under scheme `0002`.** Both the documents you send and the mandate itself are built from the company's own identifiers, so a SIRET or a missing scheme surfaces as rejected documents rather than as a registration error. * **You know which side of the perimeter you are on.** Regulated is the default; transactions outside it have to say so explicitly, and the counterparty has to be registered for the process you use. If the company sends documents, two more: * **The format and process are what you meant.** Check one document before the first real send: the preview in the dashboard, or `generate` from the API, shows the resolved `doctypeId` and `processId`. * **Invoices are in EUR**, with the billing mode and the three mandatory statements filled in. B2B invoices are only half of the French obligation. If the company also sells to private individuals, or invoices businesses outside France, those operations have to be reported to the tax administration separately. Register the company for e-reporting and submit the reports through the API, as described in the e-reporting section of the [French sending guides](/getting-started/france). Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Sending and receiving Peppol documents in France for your own company (/getting-started/france/business/sending-and-receiving) This guide walks through everything needed to exchange Peppol documents for a company registered in France, assuming you are setting up your own French company, and that the company sends and receives documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are setting up [#what-you-are-setting-up] You are putting one company, your own or one you represent, on the Peppol network, so it can exchange invoices electronically with its customers and suppliers. The setup is a one-time affair: registering the company and getting it verified takes a few minutes in the [Recommand dashboard](https://app.recommand.eu), and there is nothing to gain from automating something you do once. What you do integrate is the part that repeats: sending and receiving documents. Our existing [integrations](/integrations) can also connect Recommand to accounting or invoicing software you already use, with no code at all. A single team can hold several companies at no extra cost, useful if you run more than one legal entity, and the document volume of all of them counts towards one plan. If you are building e-invoicing or Peppol integration into a product for your own customers, and will be registering their companies rather than only your own, switch the first answer above to **Many companies**. The API is the same; what changes is how companies, verification and billing are organised. Peppol in France [#peppol-in-france] French domestic e-invoicing follows the French e-invoicing reform rather than plain Peppol BIS 3. Recommand covers the French specifics for you, but they do change what you send and how a company is onboarded. What is specific to France: * **A French-accredited access point and SMP.** Companies you register with country `FR` are automatically published on a French-accredited SMP and exchange documents through the matching access point. You do not choose or configure this: it follows from the company's country. * **A signed mandate.** Before a French company can operate, its authorised representative signs a mandate that lets that accredited platform act for the company, and the file is reviewed before the company goes live. This is the one step in this guide that is not instant, so start it early. * **French document formats.** Invoices and credit notes travel as French CIUS or Extended UBL, CII D22B (CIUS or Extended), or Factur-X (a PDF/A-3 with the CII XML embedded), next to plain Peppol BIS 3 UBL. * **Two processes.** The same document types are published for a **regulated** process (`urn:peppol:france:billing:regulated`, transactions inside the French e-invoicing perimeter) and a **non-regulated** one (`urn:peppol:france:billing:non-regulated`, transactions outside it). * **Mandatory content.** French invoices carry a billing mode and three statements (recovery costs, late-payment penalties, early-payment discount) that plain EN 16931 does not require. They go in a `countrySpecific` block. * **Lifecycle statuses.** Inside the perimeter, receivers report back on the invoices they receive with an invoice lifecycle status. * **E-reporting.** What falls outside the e-invoicing perimeter is reported instead: B2C sales as daily totals, and invoices to businesses abroad one by one. Recommand files both report types on the company's behalf. * **Identifiers are SIREN-based.** French companies are published under scheme `0225`. The reform phases the obligations in over time: from **1 September 2026** every company must be able to receive electronic invoices, with issuance starting for large and mid-size companies, and from **1 September 2027** issuance applies to small and micro companies as well. Confirm the schedule and what falls inside the perimeter with your accountant or legal advisor. This documentation describes what the API does, not what your obligations are. Create your account and API credentials [#create-your-account-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). 2. Your account starts with a **team**. The team holds your company, your subscription and your document history, and you can invite colleagues to it. 3. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 4. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Sending and receiving can also be driven entirely from the dashboard or through an [integration](/integrations), and each section below says how. The dashboard is available in English, Dutch, French and German; pick your language on the [account page](https://app.recommand.eu/account). Try it safely first [#try-it-safely-first] You do not have to get anything right the first time. Everything below, adding the company, registering it, sending and receiving, can be done in a **playground team** first, where nothing is delivered over the real Peppol network, nothing is registered on it, and nothing is billed. Open the team switcher at the top of the [dashboard](https://app.recommand.eu) and pick **Add playground**. Give it a name, leave the Peppol Test Network box unticked, and you are switched into the new team straight away. There is nothing to set up beyond that. Add a company to that team and use it as both sender and recipient to watch a document travel end to end. When the flow does what you want, repeat it once in your real team. Two things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. A playground stays useful after you are live, too: it is the safest place to try a new invoice layout or a new integration. See [how can I test without sending real invoices](/faq/api-and-development/how-can-i-test-without-sending-real-invoices). Playground companies are not registered on the Peppol network and playground documents never leave it, so nothing you do there affects your real company. Register the company [#register-the-company] You are registering one company, once, so the dashboard is the shortest path. 1. Open [Companies](https://app.recommand.eu/companies) and start the company wizard. 2. Fill in the legal name, address and country, plus the identifiers described in the next section. 3. Choose whether the company should also **receive** documents over Peppol, or only send them. 4. Save. The company is registered on the Peppol network as part of this step: its identifiers and the document types for its country are set up for you. Right after saving, the dashboard offers the verification step, which the section below covers. Note the company's ID from its detail page. Every API call for sending and receiving takes it in the path. The [create company endpoint](/reference/companies/create-company) does exactly the same thing, and returns the company `id` and a `verificationUrl` in one response. It is worth using when company creation is part of a flow you are automating, which is likely the case if you are registering many companies. Switch the first answer above to **Many companies** for that version. Add each legal entity as its own company: run the wizard again. There is no per-company fee, and all of them share your document volume. French identifiers and Peppol address [#french-identifiers-and-peppol-address] In France the identifier you register decides whether your documents will pass validation later, so it is worth getting exactly right. | Field | French value | | ------------------------ | --------------------------------------- | | `country` | `"FR"` | | `enterpriseNumber` | The nine-digit **SIREN** of the company | | `enterpriseNumberScheme` | `"0002"` | | `vatNumber` | `FR` + the French VAT number | ```json title="company.json" { "name": "Société de Test SAS", "address": "10 rue de la Paix", "postalCode": "75002", "city": "Paris", "country": "FR", "enterpriseNumber": "133512194", "enterpriseNumberScheme": "0002", "vatNumber": "FR23133512194" } ``` French regulated invoices must carry the seller's nine-digit SIREN as `enterpriseNumber` with `enterpriseNumberScheme` `"0002"`. Because the seller block of a document defaults to the company's own details, a company registered with a SIRET or without the scheme produces invoices that are rejected at validation time. Register the SIREN, and name a specific establishment through the document's `delivery.locationIdentifier` (scheme `0009`) when you need to. One Peppol identifier is registered for the company: * `0225:133512194` is the French electronic address The company's Peppol address is therefore **`0225:` followed by the SIREN**. French addresses may also carry a routing suffix, as in `0225:987654321_STATUTS`; treat the whole string after the scheme as the identifier when a recipient gives you one. Both SIREN (9 digits) and SIRET (14 digits) are checked with the Luhn algorithm before they are filed, and numbers that disagree with each other are refused rather than guessed at. Registering for both directions [#registering-for-both-directions] Sending needs no registration of its own; receiving does. So register the company as a recipient, which is the default: ```json { "isSmpRecipient": true } ``` What that means: * The company becomes findable on the Peppol network and can be delivered to through Recommand's access point, while sending its own documents out through the same access point. * Recipient registration is **exclusive**. If the company already receives through another Peppol provider, registration fails until it is deregistered there. What that takes depends on the country, which the next section covers. * The document types the company accepts are registered along with it, based on its country. Which ones those are is covered further down. * The company is only published once it is verified. If the company still receives elsewhere and you do not want to move that yet, register it with `isSmpRecipient: false` and start with sending only. Flipping the field later publishes it as a recipient. Where a French company is published [#where-a-french-company-is-published] A French company is published on the **French-accredited SMP**, and it exchanges documents through the matching access point. This follows from the company's country: there is nothing to choose or configure. Two consequences for the order of your onboarding: * **The mandate gates the go-live.** The accredited platform only acts for the company once the signed mandate has been accepted, so the company is not operational the minute it is created. The verification section below covers that step; start it early. * **Deregister elsewhere first.** Recipient registration is exclusive here as well, and France has no automatic migration path. A company that currently receives through another platform has to be deregistered there before it can be registered with Recommand. Sign the mandate and verify the company [#sign-the-mandate-and-verify-the-company] French companies go through the same identity check as everyone else, plus two steps that are specific to France: the representative signs a mandate, and the resulting file is reviewed before the company goes live. 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. **Read and sign the mandate.** The verification page shows the mandate that authorises the French-accredited platform to act for the company on the Peppol network, naming the company by its SIREN and the establishment it is filed under. The representative accepts it before the identity check starts. 3. **Complete the identity check.** The identity verification is what signs the mandate: the proof reference is recorded on it. 4. **Wait for the review.** The signed mandate and the company's details are filed with the accredited platform, and the verification sits in review until that file is accepted. Only then does `isVerified` become `true` and the company start operating. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. This is the one step of French onboarding that is not immediate. Start verification as soon as the company is created, and do not promise your users a same-minute go-live for France. If a file seems stuck, mail [support@recommand.eu](mailto:support@recommand.eu) with the company ID. Companies in a playground team are never filed with the accredited platform, so there is no mandate and no review. Test the French flow in a playground first, then run the real thing once. Verifying once, in the dashboard [#verifying-once-in-the-dashboard] You have one company, and it is verified once. There is nothing here worth automating: open [Companies](https://app.recommand.eu/companies) in the dashboard, pick the company and start verification. If you are authorised to act for the company, complete the check yourself; otherwise use the button to forward the link to whoever is. The page is self-contained and works in any browser. The person completing it does not need a Recommand account. That is the whole step. From here on the API takes over: sending and receiving documents is what you actually integrate. Updating the company's `vatNumber` or `enterpriseNumber` sets `isVerified` back to `false`, and the company has to be verified again before it can exchange documents. Pick the French document format and process [#pick-the-french-document-format-and-process] A French invoice needs three decisions: the format, the process, and the mandatory French content. The format [#the-format] Name the format with `doctypeId` on the send request. Leave it off and the recipient is looked up and the document written in the first format, in [our order of preference](/changelog/2026-08-28-automatic-document-format-routing), they are registered to receive. Peppol BIS 3 UBL comes first in that order, so a French recipient who publishes it as well receives plain BIS 3: valid on the network, but not what the French reform asks for inside its perimeter. Name the French format you want for transactions inside the perimeter. | Format | `doctypeId` | | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | France UBL CIUS invoice | `urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:peppol:france:billing:cius:1.0::2.1` | | France UBL CIUS credit note | `urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2::CreditNote##urn:cen.eu:en16931:2017#compliant#urn:peppol:france:billing:cius:1.0::2.1` | | France UBL Extended invoice | `urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#conformant#urn:peppol:france:billing:extended:1.0::2.1` | | France CII CIUS | `urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100::CrossIndustryInvoice##urn:cen.eu:en16931:2017#compliant#urn:peppol:france:billing:cius:1.0::D22B` | | France CII Extended | `urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100::CrossIndustryInvoice##urn:cen.eu:en16931:2017#conformant#urn:peppol:france:billing:extended:1.0::D22B` | | France Factur-X | `urn:peppol:doctype:pdf+xml##urn:cen.eu:en16931:2017#conformant#urn:peppol:france:billing:Factur-X:1.0::D22B` | The CII and Factur-X document types carry both invoices and credit notes; the `documentType` field of your request decides which one it is. Start with **France UBL CIUS** unless you have a reason not to. Extended is for data the CIUS does not carry, and Factur-X is for recipients who want a human-readable PDF as the carrier. The process [#the-process] Set `countrySpecific.businessProcess` to say which side of the French perimeter the transaction is on. The document is then sent over the matching process: | `businessProcess` | Process identifier | Use for | | --------------------- | ----------------------------------------- | ---------------------------------------- | | `REGULATED` (default) | `urn:peppol:france:billing:regulated` | Transactions inside the French perimeter | | `NON_REGULATED` | `urn:peppol:france:billing:non-regulated` | Transactions outside it | The recipient must have registered the document type **for that process**. Pass the `processId` to the [verify document support endpoint](/reference/recipients/verify-document-support) to check exactly that combination rather than "any process". The mandatory French content [#the-mandatory-french-content] French UBL, CII and Factur-X require a `countrySpecific` block with the billing mode and the three statements French invoices must carry. It is required for those document types and must be omitted for plain EN 16931 documents. ```json { "countrySpecific": { "country": "FR", "billingMode": "S1", "businessProcess": "REGULATED", "recoveryCostsNote": "Indemnité forfaitaire de 40 EUR pour frais de recouvrement.", "latePaymentPenaltiesNote": "Pénalités de retard exigibles au taux prévu dans les conditions générales de vente.", "earlyPaymentDiscountNote": "Aucun escompte accordé pour paiement anticipé." } } ``` `billingMode` follows AFNOR XP Z12-012. The common ones are `B1` (goods), `S1` (services) and `M1` (mixed); the full list, including already-paid, advance payment, subcontracting and multi-seller variants, is documented on the [send document endpoint](/reference/sending/send-document). Invoicing outside France [#invoicing-outside-france] The French formats and processes are for the French perimeter. A counterparty in another country is registered for the **standard** Peppol billing process, so a regulated document does not match anything they published. For those invoices, send plain Peppol BIS 3 UBL and leave the `countrySpecific` block out with it, it belongs to the French document types only. The rest of the invoice is unchanged. * The seller's `enterpriseNumber` must be the nine-digit SIREN with `enterpriseNumberScheme` `"0002"`. * The currency must be `EUR`. * Factur-X needs a compliant PDF/A-3 to embed the XML in: either attach one as an embedded attachment, or let Recommand generate it with `pdfGeneration.enabled`. Send a document [#send-a-document] One endpoint sends everything: [`POST /:companyId/send`](/reference/sending/send-document). The `companyId` is the sender, `recipient` is the Peppol address of the receiver, and `document` is the invoice or credit note as JSON. Recommand will validate the document and generate the XML. Raw XML sending is supported as well: set `documentType` to `xml` and pass the document string in `document`, along with the correct `doctypeId`. See [working with raw UBL](/docs/ubl-format-guide#working-with-raw-ubl). ```bash curl -X POST https://app.recommand.eu/api/v1/{companyId}/send \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @send-invoice.json ``` ```json title="send-invoice.json" { "recipient": "0208:0123456789", "documentType": "invoice", "document": { "invoiceNumber": "INV-2026-001", "issueDate": "2026-08-17", "dueDate": "2026-09-16", "currency": "EUR", "buyer": { "name": "Customer Company", "street": "Customer Street 1", "city": "Antwerp", "postalZone": "2000", "country": "BE", "vatNumber": "BE0987654321" }, "paymentMeans": [{ "iban": "BE68539007547034" }], "lines": [ { "name": "Consulting Services", "quantity": "10.00", "unitCode": "HUR", "netPriceAmount": "100.00", "vat": { "category": "S", "percentage": "21.00" } } ] } } ``` The seller block is filled in from your company when you leave it out, which is usually what you want: it keeps your registered identifiers and the document in agreement. The full field reference lives in [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Worth wiring up while you are here: * **Validation errors.** Outgoing documents are always validated. A `success: false` response with `errors` keyed by field path is a document the recipient would have rejected. Surface it wherever the data was typed. * **Email fallback.** Pass `email.to` with `when: "on_peppol_failure"` to fall back to email when a recipient turns out not to be reachable over Peppol, or send with `recipient: null` for email-only delivery. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **PDFs.** `pdfGeneration.enabled` attaches a generated PDF of the document. You can also attach an existing PDF (or other files) via `attachments`; see [adding attachments](/docs/sending-invoices#adding-attachments). For a full field reference, see [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Sending without writing code [#sending-without-writing-code] The same send is available two other ways, and they mix freely with the API: * **From the dashboard.** [Send document](https://app.recommand.eu/send-document) takes the recipient and the invoice lines, previews what the recipient will get, and remembers your usual settings. You can also drop an existing UBL or CII XML file into the upload zone if your software already produces one. * **From your accounting or invoicing software.** If you use one of the supported tools, let it do the work: your invoices flow to Recommand and out over Peppol without retyping. See [integrations](/integrations) for the current list, including Microsoft Business Central, Exact Online, Yuki, ClearFacts, ERPNext and Harvest. Whichever route you use, Recommand validates a document before it leaves. If a field is missing or malformed you get a clear error instead of a rejection from the recipient days later. See the [troubleshooting guide](/docs/troubleshooting-guide) for the errors you are most likely to run into. French e-reporting [#french-e-reporting] French e-invoicing covers invoices between businesses established in France. Everything else a French company sells still has to reach the tax administration: sales to private individuals, and invoices to businesses outside France. That is e-reporting. You send Recommand the figures, and Recommand files them on the company's behalf. You never build a regulatory file yourself. B2C reports contain daily totals. Cross-border reports describe an individual invoice or credit note, or a payment received on an invoice. | Report | Endpoint (under `/api/v1`) | `type` | Scope | | -------------------- | ------------------------------------ | ---------- | --------------------------------------------------------------- | | B2C sales | `POST /:companyId/reporting/fr/b2c` | `sales` | Sales for one day, category and currency | | B2C payments | `POST /:companyId/reporting/fr/b2c` | `payments` | Payments received for one day and currency, grouped by VAT rate | | Cross-border invoice | `POST /:companyId/reporting/fr/b2bi` | `invoice` | One invoice or credit note issued to a business outside France | | Cross-border payment | `POST /:companyId/reporting/fr/b2bi` | `payment` | A payment received on a previously reported invoice | All reports are submitted per company, through the API only. Every accepted report is stored with the company's other documents and counts towards the document quota. Register the company first [#register-the-company-first] E-reporting has to be switched on per company, because the tax administration needs to know two things about the taxpayer before its first report: its VAT regime, which sets how often reports are filed, and whether its VAT becomes due on invoicing or on payment. Register the company once through [`PUT /:companyId/reporting/fr/declarant`](/reference/reporting/register-french-reporting-declarant), or from the company page in the dashboard. ```json { "vatRegime": "REEL_NORMAL_MENSUEL", "vatExigibility": "DEBITS" } ``` | Field | Values | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `vatRegime` | `REEL_NORMAL_MENSUEL` (régime réel normal), `REEL_SIMPLIFIE` (régime réel simplifié), `FRANCHISE_EN_BASE` (franchise en base de TVA) | | `vatExigibility` | `DEBITS` (VAT due on invoicing, typical for goods), `ENCAISSEMENTS` (VAT due on payment, typical for services) | The company must be registered in France with a valid SIREN or SIRET, and it must be verified with a signed French mandate whose annex covers e-reporting. That annex is what entitles Recommand to report for the SIREN. A company that was verified without one is refused with a 400; contact [support@recommand.eu](mailto:support@recommand.eu) to have e-reporting enabled for it. The response carries a `state`. Reports are accepted once it is `registered`; `pending` means the registration is still being completed in the background, and `blocked` means support has to intervene, for example because the company is already registered for e-reporting through another platform. It also carries `enabled`. A suspended registration keeps its `registered` state but refuses every report with a 400 until support switches it back on, so check both fields when reports start being refused. Registering makes the company's reporting periods due. Only register companies that will submit reports, and submit each day's figures promptly rather than at month end. Changing the VAT regime later can leave the open period unfiled, so coordinate such a change with support. Report B2C sales [#report-b2c-sales] Submit one sales report per day, per category and per currency through [`POST /:companyId/reporting/fr/b2c`](/reference/reporting/submit-french-b2creport), regardless of when customers pay. ```json { "reference": "B2C-SALES-2026-08-17-GOODS", "type": "sales", "date": "2026-08-17", "category": "goods", "currency": "EUR", "taxExclusiveAmount": "10000.00", "taxAmount": "2000.00", "transactionCount": 42, "vatBreakdown": [ { "percentage": "20.00", "taxableAmount": "10000.00", "taxAmount": "2000.00" } ] } ``` * `category` is `goods` or `services`; use a separate report when both were sold on the same day. Only taxable goods and taxable services are supported today, so exempt B2C sales have no report type yet. * Amounts are strings with two decimals and are never negative. VAT amounts are always in EUR, even when the sales currency is different. * `transactionCount` is the number of individual sales in the total. It is at least 1: a day without sales is not reported at all. Report B2C payments [#report-b2c-payments] For service payments where VAT becomes due on payment, submit the daily amounts received through the same B2C endpoint with `type: "payments"`. Group the amounts including VAT by VAT rate. Submit the sales report as usual as well. ```json { "reference": "B2C-PAYMENTS-2026-08-17-EUR", "type": "payments", "date": "2026-08-17", "currency": "EUR", "vatBreakdown": [ { "percentage": "20.00", "amount": "1200.00" } ] } ``` Payment reports are only accepted for companies registered with VAT due on payment (`ENCAISSEMENTS`). Report cross-border invoices [#report-cross-border-invoices] Submit every invoice or credit note issued to a business outside France through [`POST /:companyId/reporting/fr/b2bi`](/reference/reporting/submit-french-b2bi-report). An invoice to a French buyer is exchanged over the e-invoicing network instead and is refused here. Set `documentType` to `invoice` or `creditNote` to say which of the two you are reporting. It defaults to `invoice`, so you only have to name it for credit notes. The reporting company must carry its own French VAT number as well as its SIREN: a cross-border report identifies the seller by both. Add the VAT number to the company before its first cross-border report. ```json { "reference": "EREPORT-INV-2026-000431", "type": "invoice", "documentNumber": "INV-2026-000431", "issueDate": "2026-01-15", "currency": "EUR", "buyer": { "name": "Rossi Forniture S.r.l.", "country": "IT", "vatNumber": "IT00987654321" }, "taxExclusiveAmount": "10000.00", "taxAmount": "0.00", "vatBreakdown": [ { "percentage": "0.00", "taxableAmount": "10000.00", "taxAmount": "0.00", "category": "K", "exemptionReasonCode": "VATEX-EU-IC" } ] } ``` The buyer is identified the way the tax administration identifies foreign businesses: * **In the European Union**: by its intra-community VAT number, which is required. * **Outside the European Union**: by its country and name; no VAT number is needed. * **In Nouvelle-Calédonie or Polynésie française**: by its local registration number (RIDET or TAHITI), in `enterpriseNumber`. Cross-border operations are usually exempt or reverse charged rather than taxed. When a VAT breakdown entry uses an exempt category, name why: give `exemptionReason`, `exemptionReasonCode`, or both. A breakdown that leaves both off on an exempt category is refused. Report a cross-border payment [#report-a-cross-border-payment] Submit a payment received on a previously reported invoice through the same cross-border endpoint with `type: "payment"`. Set `invoiceNumber` to the original report's `documentNumber` and `issueDate` to the invoice date. The `date` field is the day the payment was received. For a payment of EUR 10,000 on the invoice above: ```json { "reference": "EREPORT-PAYMENT-2026-000431-1", "type": "payment", "invoiceNumber": "INV-2026-000431", "issueDate": "2026-01-15", "date": "2026-02-10", "currency": "EUR", "vatBreakdown": [ { "percentage": "0.00", "amount": "10000.00" } ] } ``` Amounts include VAT and are grouped by VAT rate. As with B2C payments, payment reports are only accepted for companies registered with VAT due on payment (`ENCAISSEMENTS`). References, retries, corrections [#references-retries-corrections] Every report needs its own `reference`, at most 128 characters. It is your idempotency key: retrying the exact same request with the same reference returns the report filed the first time, with `duplicate: true`, and files nothing again. Use this after a timeout or a `502`. To change a report you already filed, send a new report with a **new reference** and the `action` field: * `action: "correct"` replaces the earlier report. It is matched on the data that identifies the report: the day, category and currency of a B2C sales report, the day of a B2C payment report, or the document number of a cross-border invoice. * `action: "cancel"` withdraws it, matched the same way. Reusing the original reference for a correction would be treated as a retry of the original report, and nothing would change. When a report is refused [#when-a-report-is-refused] Submitting a report can fail for reasons that have nothing to do with the figures, so handle each status separately rather than treating any non-200 as bad data. | Status | What happened | What to do | | ------ | -------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | 400 | The company is not registered for e-reporting, its registration is still `pending` or `blocked`, or it is suspended (`enabled: false`) | Register it, or wait for the state to become `registered`. A `blocked` or suspended registration needs support | | 400 | The reporting service refused the report; the reason is in the message | Fix what the message names and submit again under a new reference | | 400 | A payment report was sent for a company whose VAT is due on invoicing (`DEBITS`), or a cross-border report named a French buyer | Neither is reportable. A French buyer is invoiced over the e-invoicing network instead | | 409 | The report conflicts with what was already filed, for example a correction of something that was never reported | Look at what is on file before resubmitting | | 502 | The reporting service could not be reached | Retry later with the **same** reference. The reference is the idempotency key, so a retry cannot file the report twice | The 502 case is the one worth building for: it is the only status where reusing the reference is right. Every other failure needs a fresh reference once you have fixed the cause. Follow the report until it is filed [#follow-the-report-until-it-is-filed] Accepting a report is not filing it. The tax administration receives a filing per reporting period, assembled after the period ends, and can still reject it. Every report you submit therefore carries a `reporting` block in the [documents API](/reference/documents/get-document), which Recommand keeps up to date: | `reportingStatus` | Meaning | | ----------------------- | -------------------------------------------------------------------------------------- | | `accepted` | On file, inside its reporting period. Not yet filed. | | `pending_rectificative` | Arrived after its period was already filed; it will be carried by a corrective filing. | | `filed` | Reported to the tax administration within its own period. | | `filed_rectificative` | Reported by a corrective filing, because it arrived late. | | `superseded` | Replaced by a later correction, or cancelled. | | `rejected` | The tax administration rejected the filing carrying it; see `outcomeCode`. | The block also names the reporting period (`periodStart`, `periodEnd`), the filing the report was carried on (`submissionId`) and when the status was last checked. Every change fires a `document.reporting_status_changed` webhook event, so you can route rejections to whoever handles them. Reports from playground teams and teams on the test network are validated, recorded and shown exactly like real ones, but they are never filed with the tax administration. Their status stays `accepted` and is marked as simulated. Use them to build the integration; use a production team to file. Registration is immediate there: it comes back `registered` straight away rather than going through `pending`, so you can submit reports as soon as you have registered. Registrations are also kept per environment. A team on the test network registers in `TEST`, a production team in `PROD`, and the two are separate registrations for the same company. The `environment` field on the registration response says which one you are looking at. Document types registered for you [#document-types-registered-for-you] A French company is published for the whole French set, all on the **regulated** process, so any sender inside the perimeter can reach it in the format they prefer: | Document type | Registered process | | ------------------------------------------- | ------------------------------------- | | Invoice + credit note (Peppol BIS 3 UBL) | `urn:peppol:france:billing:regulated` | | Invoice + credit note (France UBL CIUS) | `urn:peppol:france:billing:regulated` | | Invoice + credit note (France UBL Extended) | `urn:peppol:france:billing:regulated` | | Invoice + credit note (France CII CIUS) | `urn:peppol:france:billing:regulated` | | Invoice + credit note (France CII Extended) | `urn:peppol:france:billing:regulated` | | Factur-X invoice + credit note | `urn:peppol:france:billing:regulated` | | Invoice lifecycle status (CDAR) | `urn:peppol:france:billing:regulated` | Whichever format arrives, you read the same parsed document out of the API. For Factur-X, the CII XML is extracted from the PDF/A-3 and parsed like any other document, and the original PDF is kept and included in the document's [download package](/reference/documents/download-package). The defaults cover the regulated process. If counterparties will send you documents over `urn:peppol:france:billing:non-regulated`, register the same document types for that process as well with the [create company document type endpoint](/reference/company-document-types/create-company-document-type). Pick up incoming documents [#pick-up-incoming-documents] Once the company is published as a recipient, everything sent to it arrives in Recommand automatically. There are two ways to get the documents into your own systems. Webhooks (recommended) [#webhooks-recommended] Register an endpoint once with the [create webhook endpoint](/reference/webhooks/create-webhook) and events are pushed to you as they happen, `document.received` among them: ```bash curl -X POST https://app.recommand.eu/api/v1/webhooks \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @create-webhook.json ``` ```json title="create-webhook.json" { "url": "https://your-app.example/webhooks/recommand", "companyId": null, "secret": "your_webhook_signing_secret" } ``` Pass a `secret` and verify the HMAC SHA-256 signature on every delivery before you trust the payload, then acknowledge with a 200 before doing the heavy processing. Both are covered in [working with webhooks](/docs/working-with-webhooks). Polling the inbox [#polling-the-inbox] If you would rather pull, the [inbox endpoint](/reference/documents/get-inbox) lists unread documents, and [mark as read](/reference/documents/mark-as-read) drops one off the list once your system has it. Fetch details, the original XML or a rendered PDF from the [documents endpoints](/reference/documents/get-document). Receiving without writing code [#receiving-without-writing-code] * **In the dashboard.** Incoming invoices appear under [Sent and received](https://app.recommand.eu/transmitted-documents), with the original XML, a readable rendering, attachments and the delivery history. * **By email.** Add notification email addresses per company so incoming documents land in the mailbox your bookkeeping already watches, attachments included. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **In your accounting software.** Forward incoming documents straight to Exact Online, Yuki, ClearFacts or another supported tool, see [integrations](/integrations). Two things worth setting up early, whichever route you take: * **Labels and suppliers** to keep documents organised as volume grows, see [suppliers and labels](/docs/suppliers-and-labels). * **Rules** to act on incoming documents automatically: forwarding, labelling, notifying, see [rules](/docs/rules). The full picture, including retries and idempotency, is in [receiving documents](/docs/receiving-documents). Report back on the invoices you receive [#report-back-on-the-invoices-you-receive] Inside the French perimeter, receiving an invoice comes with an obligation the other two countries do not have: you report its lifecycle back to the sender. Recommand models those status messages as a document type of their own, `frenchInvoicingCdar`, so you send them the same way you send anything else. When an invoice arrives, Recommand automatically sends the transmission statuses back to the sender: `202` (received) when the document reaches the access point, and `203` (made available) when it is delivered to you. You only send the later processing statuses. ```javascript await fetch(`https://app.recommand.eu/api/v1/${companyId}/send`, { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify({ recipient: "0225:987654321", documentType: "frenchInvoicingCdar", document: { businessProcess: "REGULATED", senderRole: "WK", issuerRole: "BY", issuerLegalId: "123456789", issuerLegalIdScheme: "0002", recipientRole: "SE", statusCode: "205", statusDate: "2026-08-17T14:05:09", invoiceId: "INV-2026-001", invoiceTypeCode: "380", invoiceIssueDate: "2026-08-17", sellerLegalId: "987654321", sellerLegalIdScheme: "0002", }, }), }); ``` The processing statuses that matter most on the receiving side: | Status | Meaning | | ------ | ------------------------------------ | | `204` | Taken in charge (processing started) | | `205` | Approved | | `206` | Partially approved | | `207` | In dispute | | `210` | Refused | | `211` | Payment sent | A refusal, partial approval or dispute carries a coded reason (`DOUBLON`, `TX_TVA_ERR`, `NON_CONFORME`, …) and an optional free-text note, so the sender knows what to fix. The full status and reason lists are on the [send document endpoint](/reference/sending/send-document). Report collection on the invoices you sent [#report-collection-on-the-invoices-you-sent] `212` (collected) runs the other way: it is the seller who reports that a payment came in. It carries `collectedAmounts`, at least one entry naming an `amount`, its `currency` and the `vatPercent` it falls under. A disbursement is expressed as a negative amount. `212` is not a terminal status. An invoice settled in several instalments gets one `212` per payment received, each carrying only the amount of that payment rather than the running total. Successive messages are told apart by the CDAR's own `id`, generated for you when you leave it off, with `statusDate` naming the moment of collection and `issueDate` the moment the message was written. Incoming CDAR messages are parsed, stored and shown next to your other documents, and delivered through your existing webhooks and notifications, so this is also how you learn what your customers did with the invoices you sent them, including the `202` and `203` their access point sent when they received yours. What counts towards your document quota [#what-counts-towards-your-document-quota] You pay for documents and for the business answers to them, not for the messages platforms exchange to move them. Transmission statuses (`200`, `201`, `202`, `203`, `213` and `501`) never count, whether you receive them or Recommand sends them for you. Processing statuses (`204` to `212` and `214`) count as one document each, in both directions, exactly like an invoice: the party sending the decision and the party receiving it are treated alike. Going live [#going-live] A short list before you start sending or receiving real invoices: * **A valid subscription**, so sending is not blocked. Playgrounds skip that check; production does not. * **The company verified**, with `isVerified` true. Until then it cannot exchange documents. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of whoever can fix it rather than logging it. * **Webhook endpoint hardened**, if you took that route: signature verification, a fast 200, retries and idempotency on your side. * **One real document sent and received**, ideally between two companies you control, so you have seen both ends. * **Notification addresses set**, so incoming documents also reach a mailbox somebody reads. Once you are live, your Peppol address is public on the network: suppliers can find and reach you without any action from you. Ask customers who still email PDFs to switch, and let your accountant know where the documents now land. Before you go live in France [#before-you-go-live-in-france] France adds a few checks to the list above, all of them things that only show up once real documents move: * **The mandate is accepted.** `isVerified` is `true`, which for a French company means the signed mandate cleared its review. Plan this in: it is the one step that is not instant. * **The company carries the SIREN under scheme `0002`.** Both the documents you send and the mandate itself are built from the company's own identifiers, so a SIRET or a missing scheme surfaces as rejected documents rather than as a registration error. * **You know which side of the perimeter you are on.** Regulated is the default; transactions outside it have to say so explicitly, and the counterparty has to be registered for the process you use. If the company sends documents, two more: * **The format and process are what you meant.** Check one document before the first real send: the preview in the dashboard, or `generate` from the API, shows the resolved `doctypeId` and `processId`. * **Invoices are in EUR**, with the billing mode and the three mandatory statements filled in. B2B invoices are only half of the French obligation. If the company also sells to private individuals, or invoices businesses outside France, those operations have to be reported to the tax administration separately. Register the company for e-reporting and submit the reports through the API, as described in the e-reporting section of the [French sending guides](/getting-started/france). Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Sending Peppol documents in the Netherlands for the companies you onboard (/getting-started/netherlands/platform/sending) This guide walks through everything needed to exchange Peppol documents for a company registered in the Netherlands, assuming you are integrating Recommand into your own product and onboarding Dutch companies as your users, and that the company only sends documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are building [#what-you-are-building] You are onboarding companies that are not your own: one Recommand team, and a company inside it for every customer you put on the network. Your customers never need a Recommand account. They see your interface, and Recommand stays behind your API calls. That shape has a few consequences worth knowing before you write code: * **One team, many companies.** There is no limit on companies per team, and billing is per team with the document volume of all companies pooled together, so the more companies you onboard the lower your price per document. See [pricing per team](/faq/general-usage/is-pricing-per-company-or-per-team). * **Every company is registered and verified individually.** Peppol identifies companies, not platforms. Each company gets its own Peppol address and its own authorisation record. * **Verification is taken care of.** Recommand hands you a URL that the company's authorised representative opens to confirm their identity. You present or forward that link; you never need to handle identity documents yourself. If you prefer to handle verification yourself, reach out to us at [support@recommand.eu](mailto:support@recommand.eu), we have a few other flows we can set up for you. * **You can run the whole flow under your own brand.** The API is designed for white-label use, see [can I whitelabel Recommand](/faq/general-usage/can-i-whitelabel-integrate-recommand). The [Recommand dashboard](https://app.recommand.eu) shows the same teams, companies and documents your API calls produce, which is the quickest way to see what a customer is looking at while you are debugging. If the only company you will register is your own, switch the first answer above to **One company** for the shorter version of this guide. The endpoints are the same; there is simply less to organise. Peppol in the Netherlands [#peppol-in-the-netherlands] The Netherlands sits between Belgium and France in complexity: the network is plain Peppol, but Dutch buyers commonly expect the Dutch specialisation of EN 16931 next to Peppol BIS 3. What is specific to the Netherlands: * **SI-UBL 2.0 (NLCIUS) alongside Peppol BIS 3.** Dutch companies are registered for both, so a sender can reach them with either. Recommand can write and read both formats. * **KVK numbers are the Peppol address.** Dutch companies are published under scheme `0106` (Chamber of Commerce), so a Dutch Peppol address looks like `0106:12345678`. The VAT number is registered as well, under scheme `9944`. * **No general B2B mandate (yet).** Unlike Belgium, the Netherlands does not require electronic invoicing between businesses across the board. E-invoicing is required when invoicing Dutch central government, and Peppol is the established channel for it. No country-specific fields are needed on the documents themselves. A valid EN 16931 invoice is accepted; sending SI-UBL is a matter of selecting that format, not of filling in extra data. Create your team and API credentials [#create-your-team-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). The team you get is the container for every company you will onboard. 2. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 3. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Try it safely first [#try-it-safely-first] Build the whole flow against a **playground team** before you touch production. Playgrounds look and behave like production teams, but nothing is delivered over the real Peppol network, there are no SMP registrations, no subscription checks and no billing. Create one from the team switcher at the top of the [dashboard](https://app.recommand.eu): **Add playground**, give it a name, and you are switched into it. There is no limit on how many you create. Everything that follows in this guide is identical there: same endpoints, same validation, same webhooks (triggered by simulated inbound delivery). Register a company in the playground and use it as both sender and recipient to see a document arrive. Three things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`, which is the quickest way to check that your country-specific fields map to the format and process you expect. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. * **The Peppol Test Network.** For genuine end-to-end tests with real counterparties, tick **Use Peppol Test Network** when you create the playground. It then uses dedicated test access point and SMP endpoints while staying fully separated from production. The setting cannot be changed after creation, so make a second playground if you want both. More detail in the [getting started guide](/docs) and [how do I use the playground environment](/faq/api-and-development/how-do-i-use-the-playground-environment). Register the company [#register-the-company] Create one company per customer with the [create company endpoint](/reference/companies/create-company). Registration on the Peppol network happens as part of this call: identifiers and document types are set up for you, based on the company's country. ```javascript const auth = "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"); const response = await fetch("https://app.recommand.eu/api/v1/companies", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(company), }); const result = await response.json(); if (!result.success) throw new Error(JSON.stringify(result.errors)); const companyId = result.company.id; const verificationUrl = result.verificationUrl; // hand this to your user ``` ```bash curl -X POST https://app.recommand.eu/api/v1/companies \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @company.json ``` The response carries a `verificationUrl` straight away. Keep it: the next step is to put it in front of the company's representative. Register the companies that use your platform, not the companies they invoice. Customers and suppliers manage their own Peppol registration; adding them causes registration conflicts. See [managing companies](/docs/managing-companies). The exact identifier fields to send depend on the country, which is what the next section covers. If you would rather create identifiers and document types yourself instead of accepting the country defaults, pass `skipDefaultCompanySetup: true` and use the [company identifiers](/reference/company-identifiers/create-company-identifier) and [company document types](/reference/company-document-types/get-company-document-types) endpoints. Dutch identifiers and Peppol address [#dutch-identifiers-and-peppol-address] | Field | Dutch value | | ------------------------ | -------------------------------- | | `country` | `"NL"` | | `enterpriseNumber` | KVK number, exactly 8 digits | | `enterpriseNumberScheme` | `"0106"` | | `vatNumber` | `NL` + 9 digits + `B` + 2 digits | ```json title="company.json" { "name": "Voorbeeld B.V.", "address": "Keizersgracht 1", "postalCode": "1015 CJ", "city": "Amsterdam", "country": "NL", "enterpriseNumber": "12345678", "enterpriseNumberScheme": "0106", "vatNumber": "NL123456789B01" } ``` Both are validated against the Dutch formats (an 8-digit KVK number and a VAT number shaped like `NL123456789B01`) and rejected if they do not match. Two Peppol identifiers are registered for the company: * `0106:12345678` is the KVK number, and the address others will use * `9944:NL123456789B01` is the VAT number The company's Peppol address is the first one: **`0106:` followed by the KVK number**. Registering for sending only [#registering-for-sending-only] Because you are only looking to send invoices or other documents, register the company **without** recipient registration: set `isSmpRecipient` to `false` (or leave the checkbox unticked in the dashboard). ```json { "isSmpRecipient": false } ``` What that means: * The company is not published as a recipient on an SMP, so nothing is delivered to it over Peppol through your integration. * Registration succeeds even when the company already receives its documents through another Peppol provider. The other Peppol provider will remain in charge for processing received documents for this company. * Nothing changes for sending: outgoing documents leave through the access point as normal. You can flip `isSmpRecipient` to `true` on an existing company at any time. Recommand then publishes it as a recipient and registers the document types for its country. That registration is exclusive, so the company has to be deregistered at its current provider first. Verify the company [#verify-the-company] A company cannot exchange documents on Peppol until an authorised representative has confirmed their identity. The company object exposes this as `isVerified`, and it stays `false` until the check is done. For Dutch companies the flow is short: 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. The representative fills in their name and completes the identity check. 3. `isVerified` flips to `true` and the company is published on the Peppol network. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. Building verification into your onboarding [#building-verification-into-your-onboarding] With one company you would click through this once. With many, verification is part of the flow you build: every company you register needs its own, and it is the step most likely to leave a customer stuck halfway. **Show the URL immediately.** The create-company response already carries `verificationUrl`, so no extra call is needed. Put it in front of the user while they are still in your onboarding. **Ask for a fresh one when the moment has passed.** Links get lost, and companies you created earlier never had one shown. The [verify company endpoint](/reference/companies/verify-company) starts a new verification session: ```bash curl -X POST https://app.recommand.eu/api/v1/companies/{companyId}/verify \ -u key_xxx:secret_xxx ``` The `company.verification` webhook fires when verification reaches a final state: `verified`, `rejected` or `error`. A company that comes back `rejected` or `error` and is not surfaced anywhere sits silently unusable. See [working with webhooks](/docs/working-with-webhooks). **Respect `isVerified` in your own UI.** Do not let a user press send for a company that is not verified yet; this will result in an error. You should inform the user what is missing instead. **Re-verify after identifier changes.** Updating a company's `vatNumber` or `enterpriseNumber` resets `isVerified` to `false`. Check the field after an update and present a new `verificationUrl` if it flipped. The full mechanics are in the [company verification guide](/docs/company-verification). Pick the document format [#pick-the-document-format] Dutch recipients registered through Recommand accept both Peppol BIS 3 UBL and SI-UBL 2.0 (NLCIUS). Send BIS 3 unless a buyer asks for SI-UBL, in which case name the SI-UBL document type on the send request: | What you send | `doctypeId` | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | Invoice (default) | not needed, defaults to Peppol BIS 3 UBL | | Credit note (default) | not needed, defaults to Peppol BIS 3 UBL | | SI-UBL 2.0 invoice | `urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:nen.nl:nlcius:v1.0::2.1` | | SI-UBL 2.0 credit note | `urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2::CreditNote##urn:cen.eu:en16931:2017#compliant#urn:fdc:nen.nl:nlcius:v1.0::2.1` | The document you post is the same in both cases: the format decides how the XML is written, not which fields you fill in. Before a first send to a new recipient, check that the recipient exists with the [verify endpoint](/reference/recipients/verify-recipient) and that it accepts the format you intend to use with the [verify document support endpoint](/reference/recipients/verify-document-support). A recipient outside Recommand may well be registered for BIS 3 only. Send a document [#send-a-document] One endpoint sends everything: [`POST /:companyId/send`](/reference/sending/send-document). The `companyId` is the sender, `recipient` is the Peppol address of the receiver, and `document` is the invoice or credit note as JSON. Recommand will validate the document and generate the XML. Raw XML sending is supported as well: set `documentType` to `xml` and pass the document string in `document`, along with the correct `doctypeId`. See [working with raw UBL](/docs/ubl-format-guide#working-with-raw-ubl). ```javascript const response = await fetch( `https://app.recommand.eu/api/v1/${companyId}/send`, { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, // The body below, with doctypeId and countrySpecific where the country // needs them. body: JSON.stringify(sendRequest), } ); const result = await response.json(); if (!result.success) { // result.errors is keyed by field path, e.g. { "buyer.vatNumber": [...] } } ``` ```bash curl -X POST https://app.recommand.eu/api/v1/{companyId}/send \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @send-invoice.json ``` ```json title="send-invoice.json" { "recipient": "0208:0123456789", "documentType": "invoice", "document": { "invoiceNumber": "INV-2026-001", "issueDate": "2026-08-17", "dueDate": "2026-09-16", "currency": "EUR", "buyer": { "name": "Customer Company", "street": "Customer Street 1", "city": "Antwerp", "postalZone": "2000", "country": "BE", "vatNumber": "BE0987654321" }, "paymentMeans": [{ "iban": "BE68539007547034" }], "lines": [ { "name": "Consulting Services", "quantity": "10.00", "unitCode": "HUR", "netPriceAmount": "100.00", "vat": { "category": "S", "percentage": "21.00" } } ] } } ``` The seller block is filled in from the company when you leave it out, which is usually what you want: it keeps the company's registered identifiers and the document in agreement. Things worth wiring up while you are here: * **Validation errors.** Outgoing documents are always validated. A `success: false` response with `errors` keyed by field path is a document your recipient would have rejected, so surface it to the user who typed the data. * **Email fallback.** Pass `email.to` with `when: "on_peppol_failure"` to fall back to email when a recipient turns out not to be reachable over Peppol, or send with `recipient: null` for email-only delivery. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **PDFs.** `pdfGeneration.enabled` attaches a generated PDF of the document. You can also attach an existing PDF (or other files) via `attachments`; see [adding attachments](/docs/sending-invoices#adding-attachments). For a full field reference, see [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Going live [#going-live] Before you switch your first real customer over, walk this list: * **A valid subscription in production.** Playgrounds skip the subscription check; production does not. * **Verification handled in your UI.** Show the `verificationUrl` at the right moment, make it forwardable, and handle the `company.verification` webhook so a company that comes back `rejected` or `error` does not sit silently unusable. * **`isVerified` respected.** Do not let a user press send for a company that is not verified yet; explain what is missing instead. * **Webhook endpoint hardened.** Signature verification, a fast 200, retries and idempotency on your side. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of the person who can fix it. * **One real document, end to end.** Send an invoice between two companies you control on production before letting customers in. Documents are counted per team, with the volume of all your companies pooled, so onboarding more companies lowers your price per document rather than adding per-company fees. Received documents count towards the quota as well as sent ones, so budget for both sides of the exchange. Generated XML through `generate` is not billed; emails and submitted reports are. Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Receiving Peppol documents in the Netherlands for the companies you onboard (/getting-started/netherlands/platform/receiving) This guide walks through everything needed to exchange Peppol documents for a company registered in the Netherlands, assuming you are integrating Recommand into your own product and onboarding Dutch companies as your users, and that the company only receives documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are building [#what-you-are-building] You are onboarding companies that are not your own: one Recommand team, and a company inside it for every customer you put on the network. Your customers never need a Recommand account. They see your interface, and Recommand stays behind your API calls. That shape has a few consequences worth knowing before you write code: * **One team, many companies.** There is no limit on companies per team, and billing is per team with the document volume of all companies pooled together, so the more companies you onboard the lower your price per document. See [pricing per team](/faq/general-usage/is-pricing-per-company-or-per-team). * **Every company is registered and verified individually.** Peppol identifies companies, not platforms. Each company gets its own Peppol address and its own authorisation record. * **Verification is taken care of.** Recommand hands you a URL that the company's authorised representative opens to confirm their identity. You present or forward that link; you never need to handle identity documents yourself. If you prefer to handle verification yourself, reach out to us at [support@recommand.eu](mailto:support@recommand.eu), we have a few other flows we can set up for you. * **You can run the whole flow under your own brand.** The API is designed for white-label use, see [can I whitelabel Recommand](/faq/general-usage/can-i-whitelabel-integrate-recommand). The [Recommand dashboard](https://app.recommand.eu) shows the same teams, companies and documents your API calls produce, which is the quickest way to see what a customer is looking at while you are debugging. If the only company you will register is your own, switch the first answer above to **One company** for the shorter version of this guide. The endpoints are the same; there is simply less to organise. Peppol in the Netherlands [#peppol-in-the-netherlands] The Netherlands sits between Belgium and France in complexity: the network is plain Peppol, but Dutch buyers commonly expect the Dutch specialisation of EN 16931 next to Peppol BIS 3. What is specific to the Netherlands: * **SI-UBL 2.0 (NLCIUS) alongside Peppol BIS 3.** Dutch companies are registered for both, so a sender can reach them with either. Recommand can write and read both formats. * **KVK numbers are the Peppol address.** Dutch companies are published under scheme `0106` (Chamber of Commerce), so a Dutch Peppol address looks like `0106:12345678`. The VAT number is registered as well, under scheme `9944`. * **No general B2B mandate (yet).** Unlike Belgium, the Netherlands does not require electronic invoicing between businesses across the board. E-invoicing is required when invoicing Dutch central government, and Peppol is the established channel for it. No country-specific fields are needed on the documents themselves. A valid EN 16931 invoice is accepted; sending SI-UBL is a matter of selecting that format, not of filling in extra data. Create your team and API credentials [#create-your-team-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). The team you get is the container for every company you will onboard. 2. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 3. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Try it safely first [#try-it-safely-first] Build the whole flow against a **playground team** before you touch production. Playgrounds look and behave like production teams, but nothing is delivered over the real Peppol network, there are no SMP registrations, no subscription checks and no billing. Create one from the team switcher at the top of the [dashboard](https://app.recommand.eu): **Add playground**, give it a name, and you are switched into it. There is no limit on how many you create. Everything that follows in this guide is identical there: same endpoints, same validation, same webhooks (triggered by simulated inbound delivery). Register a company in the playground and use it as both sender and recipient to see a document arrive. Three things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`, which is the quickest way to check that your country-specific fields map to the format and process you expect. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. * **The Peppol Test Network.** For genuine end-to-end tests with real counterparties, tick **Use Peppol Test Network** when you create the playground. It then uses dedicated test access point and SMP endpoints while staying fully separated from production. The setting cannot be changed after creation, so make a second playground if you want both. More detail in the [getting started guide](/docs) and [how do I use the playground environment](/faq/api-and-development/how-do-i-use-the-playground-environment). Register the company [#register-the-company] Create one company per customer with the [create company endpoint](/reference/companies/create-company). Registration on the Peppol network happens as part of this call: identifiers and document types are set up for you, based on the company's country. ```javascript const auth = "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"); const response = await fetch("https://app.recommand.eu/api/v1/companies", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(company), }); const result = await response.json(); if (!result.success) throw new Error(JSON.stringify(result.errors)); const companyId = result.company.id; const verificationUrl = result.verificationUrl; // hand this to your user ``` ```bash curl -X POST https://app.recommand.eu/api/v1/companies \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @company.json ``` The response carries a `verificationUrl` straight away. Keep it: the next step is to put it in front of the company's representative. Register the companies that use your platform, not the companies they invoice. Customers and suppliers manage their own Peppol registration; adding them causes registration conflicts. See [managing companies](/docs/managing-companies). The exact identifier fields to send depend on the country, which is what the next section covers. If you would rather create identifiers and document types yourself instead of accepting the country defaults, pass `skipDefaultCompanySetup: true` and use the [company identifiers](/reference/company-identifiers/create-company-identifier) and [company document types](/reference/company-document-types/get-company-document-types) endpoints. Dutch identifiers and Peppol address [#dutch-identifiers-and-peppol-address] | Field | Dutch value | | ------------------------ | -------------------------------- | | `country` | `"NL"` | | `enterpriseNumber` | KVK number, exactly 8 digits | | `enterpriseNumberScheme` | `"0106"` | | `vatNumber` | `NL` + 9 digits + `B` + 2 digits | ```json title="company.json" { "name": "Voorbeeld B.V.", "address": "Keizersgracht 1", "postalCode": "1015 CJ", "city": "Amsterdam", "country": "NL", "enterpriseNumber": "12345678", "enterpriseNumberScheme": "0106", "vatNumber": "NL123456789B01" } ``` Both are validated against the Dutch formats (an 8-digit KVK number and a VAT number shaped like `NL123456789B01`) and rejected if they do not match. Two Peppol identifiers are registered for the company: * `0106:12345678` is the KVK number, and the address others will use * `9944:NL123456789B01` is the VAT number The company's Peppol address is the first one: **`0106:` followed by the KVK number**. Registering as a recipient [#registering-as-a-recipient] To receive documents, the company must be published as a recipient on an SMP (Service Metadata Publisher). That is what `isSmpRecipient` does, and it is the default: ```json { "isSmpRecipient": true } ``` What that means: * The company becomes findable on the Peppol network: any sender can look it up and deliver to it via the Peppol network. * Recipient registration is **exclusive**. If the company is already registered for receiving through another Peppol provider, registration fails until it is deregistered there. * The document types the company accepts are registered along with it, based on its country. Which ones those are is covered further down. * The company is only published once it is verified. Moving an existing Dutch registration [#moving-an-existing-dutch-registration] Dutch companies are commonly already reachable over Peppol, because e-invoicing towards Dutch central government has been the norm for years and accounting software often registers the company on the sender's behalf. There is no automatic migration for the Netherlands: the company has to be deregistered at its current provider before it can be registered here. If you do not know who that provider is, look the KVK number up as a recipient. The [verify endpoint](/reference/recipients/verify-recipient) returns the SMP the company is published on. Verify the company [#verify-the-company] A company cannot exchange documents on Peppol until an authorised representative has confirmed their identity. The company object exposes this as `isVerified`, and it stays `false` until the check is done. For Dutch companies the flow is short: 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. The representative fills in their name and completes the identity check. 3. `isVerified` flips to `true` and the company is published on the Peppol network. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. Building verification into your onboarding [#building-verification-into-your-onboarding] With one company you would click through this once. With many, verification is part of the flow you build: every company you register needs its own, and it is the step most likely to leave a customer stuck halfway. **Show the URL immediately.** The create-company response already carries `verificationUrl`, so no extra call is needed. Put it in front of the user while they are still in your onboarding. **Ask for a fresh one when the moment has passed.** Links get lost, and companies you created earlier never had one shown. The [verify company endpoint](/reference/companies/verify-company) starts a new verification session: ```bash curl -X POST https://app.recommand.eu/api/v1/companies/{companyId}/verify \ -u key_xxx:secret_xxx ``` The `company.verification` webhook fires when verification reaches a final state: `verified`, `rejected` or `error`. A company that comes back `rejected` or `error` and is not surfaced anywhere sits silently unusable. See [working with webhooks](/docs/working-with-webhooks). **Respect `isVerified` in your own UI.** Do not let a user press send for a company that is not verified yet; this will result in an error. You should inform the user what is missing instead. **Re-verify after identifier changes.** Updating a company's `vatNumber` or `enterpriseNumber` resets `isVerified` to `false`. Check the field after an update and present a new `verificationUrl` if it flipped. The full mechanics are in the [company verification guide](/docs/company-verification). Document types registered for you [#document-types-registered-for-you] When you register a Dutch company as a recipient, it is published for four document types, so senders can reach it with either the European or the Dutch flavour of EN 16931: | Document type | Process | | ------------------------------ | --------------------------------------------- | | Invoice (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Credit note (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Invoice (SI-UBL 2.0) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Credit note (SI-UBL 2.0) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | Whichever of the four a sender picks, you get the same parsed document out of the API. The format difference stays in the XML. Need more document types, such as self-billing, message level responses, invoice responses? Register the combinations you want with the [create company document type endpoint](/reference/company-document-types/create-company-document-type). Get incoming documents into your product [#get-incoming-documents-into-your-product] Recommand receives, validates and stores incoming documents for every company in your team. You pick them up in one of two ways. Webhooks (recommended) [#webhooks-recommended] Register an endpoint once with the [create webhook endpoint](/reference/webhooks/create-webhook) or through the dashboard and events are pushed to you as they happen, `document.received` among them: ```javascript await fetch("https://app.recommand.eu/api/v1/webhooks", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(webhook), // the body below }); ``` ```bash curl -X POST https://app.recommand.eu/api/v1/webhooks \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @create-webhook.json ``` ```json title="create-webhook.json" { "url": "https://your-app.example/webhooks/recommand", "companyId": null, "secret": "your_webhook_signing_secret" } ``` `companyId: null` covers every company in the team. Pass a `secret` and verify the HMAC SHA-256 signature on every delivery before you trust the payload. Switch on `event.eventType`, and acknowledge with a 200 before doing the heavy processing. Both are covered in [working with webhooks](/docs/working-with-webhooks). Polling the inbox [#polling-the-inbox] If you would rather pull, the [inbox endpoint](/reference/documents/get-inbox) lists unread documents: ```javascript const inbox = await fetch("https://app.recommand.eu/api/v1/inbox", { headers: { Authorization: auth }, }).then((r) => r.json()); ``` Mark each document as read with the [mark as read endpoint](/reference/documents/mark-as-read) once your system has it, so it drops off the list. After you have the document [#after-you-have-the-document] * Fetch details, the original XML or a rendered PDF from the [documents endpoints](/reference/documents/get-document). * Route documents to the right customer with [labels and suppliers](/docs/suppliers-and-labels), and automate that routing with [rules](/docs/rules). * Let Recommand mail incoming documents on to an address of your choosing when that is easier than an API call, see [email delivery and notifications](/docs/email-delivery-and-notifications). For the full picture, including retries and idempotency, see [receiving documents](/docs/receiving-documents). Going live [#going-live] Before you switch your first real customer over, walk this list: * **A valid subscription in production.** Playgrounds skip the subscription check; production does not. * **Verification handled in your UI.** Show the `verificationUrl` at the right moment, make it forwardable, and handle the `company.verification` webhook so a company that comes back `rejected` or `error` does not sit silently unusable. * **`isVerified` respected.** Do not let a user press send for a company that is not verified yet; explain what is missing instead. * **Webhook endpoint hardened.** Signature verification, a fast 200, retries and idempotency on your side. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of the person who can fix it. * **One real document, end to end.** Send an invoice between two companies you control on production before letting customers in. Documents are counted per team, with the volume of all your companies pooled, so onboarding more companies lowers your price per document rather than adding per-company fees. Received documents count towards the quota as well as sent ones, so budget for both sides of the exchange. Generated XML through `generate` is not billed; emails and submitted reports are. Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Sending and receiving Peppol documents in the Netherlands for the companies you onboard (/getting-started/netherlands/platform/sending-and-receiving) This guide walks through everything needed to exchange Peppol documents for a company registered in the Netherlands, assuming you are integrating Recommand into your own product and onboarding Dutch companies as your users, and that the company sends and receives documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are building [#what-you-are-building] You are onboarding companies that are not your own: one Recommand team, and a company inside it for every customer you put on the network. Your customers never need a Recommand account. They see your interface, and Recommand stays behind your API calls. That shape has a few consequences worth knowing before you write code: * **One team, many companies.** There is no limit on companies per team, and billing is per team with the document volume of all companies pooled together, so the more companies you onboard the lower your price per document. See [pricing per team](/faq/general-usage/is-pricing-per-company-or-per-team). * **Every company is registered and verified individually.** Peppol identifies companies, not platforms. Each company gets its own Peppol address and its own authorisation record. * **Verification is taken care of.** Recommand hands you a URL that the company's authorised representative opens to confirm their identity. You present or forward that link; you never need to handle identity documents yourself. If you prefer to handle verification yourself, reach out to us at [support@recommand.eu](mailto:support@recommand.eu), we have a few other flows we can set up for you. * **You can run the whole flow under your own brand.** The API is designed for white-label use, see [can I whitelabel Recommand](/faq/general-usage/can-i-whitelabel-integrate-recommand). The [Recommand dashboard](https://app.recommand.eu) shows the same teams, companies and documents your API calls produce, which is the quickest way to see what a customer is looking at while you are debugging. If the only company you will register is your own, switch the first answer above to **One company** for the shorter version of this guide. The endpoints are the same; there is simply less to organise. Peppol in the Netherlands [#peppol-in-the-netherlands] The Netherlands sits between Belgium and France in complexity: the network is plain Peppol, but Dutch buyers commonly expect the Dutch specialisation of EN 16931 next to Peppol BIS 3. What is specific to the Netherlands: * **SI-UBL 2.0 (NLCIUS) alongside Peppol BIS 3.** Dutch companies are registered for both, so a sender can reach them with either. Recommand can write and read both formats. * **KVK numbers are the Peppol address.** Dutch companies are published under scheme `0106` (Chamber of Commerce), so a Dutch Peppol address looks like `0106:12345678`. The VAT number is registered as well, under scheme `9944`. * **No general B2B mandate (yet).** Unlike Belgium, the Netherlands does not require electronic invoicing between businesses across the board. E-invoicing is required when invoicing Dutch central government, and Peppol is the established channel for it. No country-specific fields are needed on the documents themselves. A valid EN 16931 invoice is accepted; sending SI-UBL is a matter of selecting that format, not of filling in extra data. Create your team and API credentials [#create-your-team-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). The team you get is the container for every company you will onboard. 2. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 3. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Try it safely first [#try-it-safely-first] Build the whole flow against a **playground team** before you touch production. Playgrounds look and behave like production teams, but nothing is delivered over the real Peppol network, there are no SMP registrations, no subscription checks and no billing. Create one from the team switcher at the top of the [dashboard](https://app.recommand.eu): **Add playground**, give it a name, and you are switched into it. There is no limit on how many you create. Everything that follows in this guide is identical there: same endpoints, same validation, same webhooks (triggered by simulated inbound delivery). Register a company in the playground and use it as both sender and recipient to see a document arrive. Three things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`, which is the quickest way to check that your country-specific fields map to the format and process you expect. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. * **The Peppol Test Network.** For genuine end-to-end tests with real counterparties, tick **Use Peppol Test Network** when you create the playground. It then uses dedicated test access point and SMP endpoints while staying fully separated from production. The setting cannot be changed after creation, so make a second playground if you want both. More detail in the [getting started guide](/docs) and [how do I use the playground environment](/faq/api-and-development/how-do-i-use-the-playground-environment). Register the company [#register-the-company] Create one company per customer with the [create company endpoint](/reference/companies/create-company). Registration on the Peppol network happens as part of this call: identifiers and document types are set up for you, based on the company's country. ```javascript const auth = "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"); const response = await fetch("https://app.recommand.eu/api/v1/companies", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(company), }); const result = await response.json(); if (!result.success) throw new Error(JSON.stringify(result.errors)); const companyId = result.company.id; const verificationUrl = result.verificationUrl; // hand this to your user ``` ```bash curl -X POST https://app.recommand.eu/api/v1/companies \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @company.json ``` The response carries a `verificationUrl` straight away. Keep it: the next step is to put it in front of the company's representative. Register the companies that use your platform, not the companies they invoice. Customers and suppliers manage their own Peppol registration; adding them causes registration conflicts. See [managing companies](/docs/managing-companies). The exact identifier fields to send depend on the country, which is what the next section covers. If you would rather create identifiers and document types yourself instead of accepting the country defaults, pass `skipDefaultCompanySetup: true` and use the [company identifiers](/reference/company-identifiers/create-company-identifier) and [company document types](/reference/company-document-types/get-company-document-types) endpoints. Dutch identifiers and Peppol address [#dutch-identifiers-and-peppol-address] | Field | Dutch value | | ------------------------ | -------------------------------- | | `country` | `"NL"` | | `enterpriseNumber` | KVK number, exactly 8 digits | | `enterpriseNumberScheme` | `"0106"` | | `vatNumber` | `NL` + 9 digits + `B` + 2 digits | ```json title="company.json" { "name": "Voorbeeld B.V.", "address": "Keizersgracht 1", "postalCode": "1015 CJ", "city": "Amsterdam", "country": "NL", "enterpriseNumber": "12345678", "enterpriseNumberScheme": "0106", "vatNumber": "NL123456789B01" } ``` Both are validated against the Dutch formats (an 8-digit KVK number and a VAT number shaped like `NL123456789B01`) and rejected if they do not match. Two Peppol identifiers are registered for the company: * `0106:12345678` is the KVK number, and the address others will use * `9944:NL123456789B01` is the VAT number The company's Peppol address is the first one: **`0106:` followed by the KVK number**. Registering for both directions [#registering-for-both-directions] Sending needs no registration of its own; receiving does. So register the company as a recipient, which is the default: ```json { "isSmpRecipient": true } ``` What that means: * The company becomes findable on the Peppol network and can be delivered to through Recommand's access point, while sending its own documents out through the same access point. * Recipient registration is **exclusive**. If the company already receives through another Peppol provider, registration fails until it is deregistered there. What that takes depends on the country, which the next section covers. * The document types the company accepts are registered along with it, based on its country. Which ones those are is covered further down. * The company is only published once it is verified. If the company still receives elsewhere and you do not want to move that yet, register it with `isSmpRecipient: false` and start with sending only. Flipping the field later publishes it as a recipient. Moving an existing Dutch registration [#moving-an-existing-dutch-registration] Dutch companies are commonly already reachable over Peppol, because e-invoicing towards Dutch central government has been the norm for years and accounting software often registers the company on the sender's behalf. There is no automatic migration for the Netherlands: the company has to be deregistered at its current provider before it can be registered here. If you do not know who that provider is, look the KVK number up as a recipient. The [verify endpoint](/reference/recipients/verify-recipient) returns the SMP the company is published on. Verify the company [#verify-the-company] A company cannot exchange documents on Peppol until an authorised representative has confirmed their identity. The company object exposes this as `isVerified`, and it stays `false` until the check is done. For Dutch companies the flow is short: 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. The representative fills in their name and completes the identity check. 3. `isVerified` flips to `true` and the company is published on the Peppol network. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. Building verification into your onboarding [#building-verification-into-your-onboarding] With one company you would click through this once. With many, verification is part of the flow you build: every company you register needs its own, and it is the step most likely to leave a customer stuck halfway. **Show the URL immediately.** The create-company response already carries `verificationUrl`, so no extra call is needed. Put it in front of the user while they are still in your onboarding. **Ask for a fresh one when the moment has passed.** Links get lost, and companies you created earlier never had one shown. The [verify company endpoint](/reference/companies/verify-company) starts a new verification session: ```bash curl -X POST https://app.recommand.eu/api/v1/companies/{companyId}/verify \ -u key_xxx:secret_xxx ``` The `company.verification` webhook fires when verification reaches a final state: `verified`, `rejected` or `error`. A company that comes back `rejected` or `error` and is not surfaced anywhere sits silently unusable. See [working with webhooks](/docs/working-with-webhooks). **Respect `isVerified` in your own UI.** Do not let a user press send for a company that is not verified yet; this will result in an error. You should inform the user what is missing instead. **Re-verify after identifier changes.** Updating a company's `vatNumber` or `enterpriseNumber` resets `isVerified` to `false`. Check the field after an update and present a new `verificationUrl` if it flipped. The full mechanics are in the [company verification guide](/docs/company-verification). Pick the document format [#pick-the-document-format] Dutch recipients registered through Recommand accept both Peppol BIS 3 UBL and SI-UBL 2.0 (NLCIUS). Send BIS 3 unless a buyer asks for SI-UBL, in which case name the SI-UBL document type on the send request: | What you send | `doctypeId` | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | Invoice (default) | not needed, defaults to Peppol BIS 3 UBL | | Credit note (default) | not needed, defaults to Peppol BIS 3 UBL | | SI-UBL 2.0 invoice | `urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:nen.nl:nlcius:v1.0::2.1` | | SI-UBL 2.0 credit note | `urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2::CreditNote##urn:cen.eu:en16931:2017#compliant#urn:fdc:nen.nl:nlcius:v1.0::2.1` | The document you post is the same in both cases: the format decides how the XML is written, not which fields you fill in. Before a first send to a new recipient, check that the recipient exists with the [verify endpoint](/reference/recipients/verify-recipient) and that it accepts the format you intend to use with the [verify document support endpoint](/reference/recipients/verify-document-support). A recipient outside Recommand may well be registered for BIS 3 only. Send a document [#send-a-document] One endpoint sends everything: [`POST /:companyId/send`](/reference/sending/send-document). The `companyId` is the sender, `recipient` is the Peppol address of the receiver, and `document` is the invoice or credit note as JSON. Recommand will validate the document and generate the XML. Raw XML sending is supported as well: set `documentType` to `xml` and pass the document string in `document`, along with the correct `doctypeId`. See [working with raw UBL](/docs/ubl-format-guide#working-with-raw-ubl). ```javascript const response = await fetch( `https://app.recommand.eu/api/v1/${companyId}/send`, { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, // The body below, with doctypeId and countrySpecific where the country // needs them. body: JSON.stringify(sendRequest), } ); const result = await response.json(); if (!result.success) { // result.errors is keyed by field path, e.g. { "buyer.vatNumber": [...] } } ``` ```bash curl -X POST https://app.recommand.eu/api/v1/{companyId}/send \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @send-invoice.json ``` ```json title="send-invoice.json" { "recipient": "0208:0123456789", "documentType": "invoice", "document": { "invoiceNumber": "INV-2026-001", "issueDate": "2026-08-17", "dueDate": "2026-09-16", "currency": "EUR", "buyer": { "name": "Customer Company", "street": "Customer Street 1", "city": "Antwerp", "postalZone": "2000", "country": "BE", "vatNumber": "BE0987654321" }, "paymentMeans": [{ "iban": "BE68539007547034" }], "lines": [ { "name": "Consulting Services", "quantity": "10.00", "unitCode": "HUR", "netPriceAmount": "100.00", "vat": { "category": "S", "percentage": "21.00" } } ] } } ``` The seller block is filled in from the company when you leave it out, which is usually what you want: it keeps the company's registered identifiers and the document in agreement. Things worth wiring up while you are here: * **Validation errors.** Outgoing documents are always validated. A `success: false` response with `errors` keyed by field path is a document your recipient would have rejected, so surface it to the user who typed the data. * **Email fallback.** Pass `email.to` with `when: "on_peppol_failure"` to fall back to email when a recipient turns out not to be reachable over Peppol, or send with `recipient: null` for email-only delivery. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **PDFs.** `pdfGeneration.enabled` attaches a generated PDF of the document. You can also attach an existing PDF (or other files) via `attachments`; see [adding attachments](/docs/sending-invoices#adding-attachments). For a full field reference, see [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Document types registered for you [#document-types-registered-for-you] When you register a Dutch company as a recipient, it is published for four document types, so senders can reach it with either the European or the Dutch flavour of EN 16931: | Document type | Process | | ------------------------------ | --------------------------------------------- | | Invoice (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Credit note (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Invoice (SI-UBL 2.0) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Credit note (SI-UBL 2.0) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | Whichever of the four a sender picks, you get the same parsed document out of the API. The format difference stays in the XML. Need more document types, such as self-billing, message level responses, invoice responses? Register the combinations you want with the [create company document type endpoint](/reference/company-document-types/create-company-document-type). Get incoming documents into your product [#get-incoming-documents-into-your-product] Recommand receives, validates and stores incoming documents for every company in your team. You pick them up in one of two ways. Webhooks (recommended) [#webhooks-recommended] Register an endpoint once with the [create webhook endpoint](/reference/webhooks/create-webhook) or through the dashboard and events are pushed to you as they happen, `document.received` among them: ```javascript await fetch("https://app.recommand.eu/api/v1/webhooks", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(webhook), // the body below }); ``` ```bash curl -X POST https://app.recommand.eu/api/v1/webhooks \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @create-webhook.json ``` ```json title="create-webhook.json" { "url": "https://your-app.example/webhooks/recommand", "companyId": null, "secret": "your_webhook_signing_secret" } ``` `companyId: null` covers every company in the team. Pass a `secret` and verify the HMAC SHA-256 signature on every delivery before you trust the payload. Switch on `event.eventType`, and acknowledge with a 200 before doing the heavy processing. Both are covered in [working with webhooks](/docs/working-with-webhooks). Polling the inbox [#polling-the-inbox] If you would rather pull, the [inbox endpoint](/reference/documents/get-inbox) lists unread documents: ```javascript const inbox = await fetch("https://app.recommand.eu/api/v1/inbox", { headers: { Authorization: auth }, }).then((r) => r.json()); ``` Mark each document as read with the [mark as read endpoint](/reference/documents/mark-as-read) once your system has it, so it drops off the list. After you have the document [#after-you-have-the-document] * Fetch details, the original XML or a rendered PDF from the [documents endpoints](/reference/documents/get-document). * Route documents to the right customer with [labels and suppliers](/docs/suppliers-and-labels), and automate that routing with [rules](/docs/rules). * Let Recommand mail incoming documents on to an address of your choosing when that is easier than an API call, see [email delivery and notifications](/docs/email-delivery-and-notifications). For the full picture, including retries and idempotency, see [receiving documents](/docs/receiving-documents). Going live [#going-live] Before you switch your first real customer over, walk this list: * **A valid subscription in production.** Playgrounds skip the subscription check; production does not. * **Verification handled in your UI.** Show the `verificationUrl` at the right moment, make it forwardable, and handle the `company.verification` webhook so a company that comes back `rejected` or `error` does not sit silently unusable. * **`isVerified` respected.** Do not let a user press send for a company that is not verified yet; explain what is missing instead. * **Webhook endpoint hardened.** Signature verification, a fast 200, retries and idempotency on your side. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of the person who can fix it. * **One real document, end to end.** Send an invoice between two companies you control on production before letting customers in. Documents are counted per team, with the volume of all your companies pooled, so onboarding more companies lowers your price per document rather than adding per-company fees. Received documents count towards the quota as well as sent ones, so budget for both sides of the exchange. Generated XML through `generate` is not billed; emails and submitted reports are. Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Sending Peppol documents in the Netherlands for your own company (/getting-started/netherlands/business/sending) This guide walks through everything needed to exchange Peppol documents for a company registered in the Netherlands, assuming you are setting up your own Dutch company, and that the company only sends documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are setting up [#what-you-are-setting-up] You are putting one company, your own or one you represent, on the Peppol network, so it can exchange invoices electronically with its customers and suppliers. The setup is a one-time affair: registering the company and getting it verified takes a few minutes in the [Recommand dashboard](https://app.recommand.eu), and there is nothing to gain from automating something you do once. What you do integrate is the part that repeats: sending and receiving documents. Our existing [integrations](/integrations) can also connect Recommand to accounting or invoicing software you already use, with no code at all. A single team can hold several companies at no extra cost, useful if you run more than one legal entity, and the document volume of all of them counts towards one plan. If you are building e-invoicing or Peppol integration into a product for your own customers, and will be registering their companies rather than only your own, switch the first answer above to **Many companies**. The API is the same; what changes is how companies, verification and billing are organised. Peppol in the Netherlands [#peppol-in-the-netherlands] The Netherlands sits between Belgium and France in complexity: the network is plain Peppol, but Dutch buyers commonly expect the Dutch specialisation of EN 16931 next to Peppol BIS 3. What is specific to the Netherlands: * **SI-UBL 2.0 (NLCIUS) alongside Peppol BIS 3.** Dutch companies are registered for both, so a sender can reach them with either. Recommand can write and read both formats. * **KVK numbers are the Peppol address.** Dutch companies are published under scheme `0106` (Chamber of Commerce), so a Dutch Peppol address looks like `0106:12345678`. The VAT number is registered as well, under scheme `9944`. * **No general B2B mandate (yet).** Unlike Belgium, the Netherlands does not require electronic invoicing between businesses across the board. E-invoicing is required when invoicing Dutch central government, and Peppol is the established channel for it. No country-specific fields are needed on the documents themselves. A valid EN 16931 invoice is accepted; sending SI-UBL is a matter of selecting that format, not of filling in extra data. Create your account and API credentials [#create-your-account-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). 2. Your account starts with a **team**. The team holds your company, your subscription and your document history, and you can invite colleagues to it. 3. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 4. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Sending and receiving can also be driven entirely from the dashboard or through an [integration](/integrations), and each section below says how. The dashboard is available in English, Dutch, French and German; pick your language on the [account page](https://app.recommand.eu/account). Try it safely first [#try-it-safely-first] You do not have to get anything right the first time. Everything below, adding the company, registering it, sending and receiving, can be done in a **playground team** first, where nothing is delivered over the real Peppol network, nothing is registered on it, and nothing is billed. Open the team switcher at the top of the [dashboard](https://app.recommand.eu) and pick **Add playground**. Give it a name, leave the Peppol Test Network box unticked, and you are switched into the new team straight away. There is nothing to set up beyond that. Add a company to that team and use it as both sender and recipient to watch a document travel end to end. When the flow does what you want, repeat it once in your real team. Two things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. A playground stays useful after you are live, too: it is the safest place to try a new invoice layout or a new integration. See [how can I test without sending real invoices](/faq/api-and-development/how-can-i-test-without-sending-real-invoices). Playground companies are not registered on the Peppol network and playground documents never leave it, so nothing you do there affects your real company. Register the company [#register-the-company] You are registering one company, once, so the dashboard is the shortest path. 1. Open [Companies](https://app.recommand.eu/companies) and start the company wizard. 2. Fill in the legal name, address and country, plus the identifiers described in the next section. 3. Choose whether the company should also **receive** documents over Peppol, or only send them. 4. Save. The company is registered on the Peppol network as part of this step: its identifiers and the document types for its country are set up for you. Right after saving, the dashboard offers the verification step, which the section below covers. Note the company's ID from its detail page. Every API call for sending and receiving takes it in the path. The [create company endpoint](/reference/companies/create-company) does exactly the same thing, and returns the company `id` and a `verificationUrl` in one response. It is worth using when company creation is part of a flow you are automating, which is likely the case if you are registering many companies. Switch the first answer above to **Many companies** for that version. Add each legal entity as its own company: run the wizard again. There is no per-company fee, and all of them share your document volume. Dutch identifiers and Peppol address [#dutch-identifiers-and-peppol-address] | Field | Dutch value | | ------------------------ | -------------------------------- | | `country` | `"NL"` | | `enterpriseNumber` | KVK number, exactly 8 digits | | `enterpriseNumberScheme` | `"0106"` | | `vatNumber` | `NL` + 9 digits + `B` + 2 digits | ```json title="company.json" { "name": "Voorbeeld B.V.", "address": "Keizersgracht 1", "postalCode": "1015 CJ", "city": "Amsterdam", "country": "NL", "enterpriseNumber": "12345678", "enterpriseNumberScheme": "0106", "vatNumber": "NL123456789B01" } ``` Both are validated against the Dutch formats (an 8-digit KVK number and a VAT number shaped like `NL123456789B01`) and rejected if they do not match. Two Peppol identifiers are registered for the company: * `0106:12345678` is the KVK number, and the address others will use * `9944:NL123456789B01` is the VAT number The company's Peppol address is the first one: **`0106:` followed by the KVK number**. Registering for sending only [#registering-for-sending-only] Because you are only looking to send invoices or other documents, register the company **without** recipient registration: set `isSmpRecipient` to `false` (or leave the checkbox unticked in the dashboard). ```json { "isSmpRecipient": false } ``` What that means: * The company is not published as a recipient on an SMP, so nothing is delivered to it over Peppol through your integration. * Registration succeeds even when the company already receives its documents through another Peppol provider. The other Peppol provider will remain in charge for processing received documents for this company. * Nothing changes for sending: outgoing documents leave through the access point as normal. You can flip `isSmpRecipient` to `true` on an existing company at any time. Recommand then publishes it as a recipient and registers the document types for its country. That registration is exclusive, so the company has to be deregistered at its current provider first. Verify the company [#verify-the-company] A company cannot exchange documents on Peppol until an authorised representative has confirmed their identity. The company object exposes this as `isVerified`, and it stays `false` until the check is done. For Dutch companies the flow is short: 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. The representative fills in their name and completes the identity check. 3. `isVerified` flips to `true` and the company is published on the Peppol network. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. Verifying once, in the dashboard [#verifying-once-in-the-dashboard] You have one company, and it is verified once. There is nothing here worth automating: open [Companies](https://app.recommand.eu/companies) in the dashboard, pick the company and start verification. If you are authorised to act for the company, complete the check yourself; otherwise use the button to forward the link to whoever is. The page is self-contained and works in any browser. The person completing it does not need a Recommand account. That is the whole step. From here on the API takes over: sending and receiving documents is what you actually integrate. Updating the company's `vatNumber` or `enterpriseNumber` sets `isVerified` back to `false`, and the company has to be verified again before it can exchange documents. Pick the document format [#pick-the-document-format] Dutch recipients registered through Recommand accept both Peppol BIS 3 UBL and SI-UBL 2.0 (NLCIUS). Send BIS 3 unless a buyer asks for SI-UBL, in which case name the SI-UBL document type on the send request: | What you send | `doctypeId` | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | Invoice (default) | not needed, defaults to Peppol BIS 3 UBL | | Credit note (default) | not needed, defaults to Peppol BIS 3 UBL | | SI-UBL 2.0 invoice | `urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:nen.nl:nlcius:v1.0::2.1` | | SI-UBL 2.0 credit note | `urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2::CreditNote##urn:cen.eu:en16931:2017#compliant#urn:fdc:nen.nl:nlcius:v1.0::2.1` | The document you post is the same in both cases: the format decides how the XML is written, not which fields you fill in. Before a first send to a new recipient, check that the recipient exists with the [verify endpoint](/reference/recipients/verify-recipient) and that it accepts the format you intend to use with the [verify document support endpoint](/reference/recipients/verify-document-support). A recipient outside Recommand may well be registered for BIS 3 only. Send a document [#send-a-document] One endpoint sends everything: [`POST /:companyId/send`](/reference/sending/send-document). The `companyId` is the sender, `recipient` is the Peppol address of the receiver, and `document` is the invoice or credit note as JSON. Recommand will validate the document and generate the XML. Raw XML sending is supported as well: set `documentType` to `xml` and pass the document string in `document`, along with the correct `doctypeId`. See [working with raw UBL](/docs/ubl-format-guide#working-with-raw-ubl). ```bash curl -X POST https://app.recommand.eu/api/v1/{companyId}/send \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @send-invoice.json ``` ```json title="send-invoice.json" { "recipient": "0208:0123456789", "documentType": "invoice", "document": { "invoiceNumber": "INV-2026-001", "issueDate": "2026-08-17", "dueDate": "2026-09-16", "currency": "EUR", "buyer": { "name": "Customer Company", "street": "Customer Street 1", "city": "Antwerp", "postalZone": "2000", "country": "BE", "vatNumber": "BE0987654321" }, "paymentMeans": [{ "iban": "BE68539007547034" }], "lines": [ { "name": "Consulting Services", "quantity": "10.00", "unitCode": "HUR", "netPriceAmount": "100.00", "vat": { "category": "S", "percentage": "21.00" } } ] } } ``` The seller block is filled in from your company when you leave it out, which is usually what you want: it keeps your registered identifiers and the document in agreement. The full field reference lives in [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Worth wiring up while you are here: * **Validation errors.** Outgoing documents are always validated. A `success: false` response with `errors` keyed by field path is a document the recipient would have rejected. Surface it wherever the data was typed. * **Email fallback.** Pass `email.to` with `when: "on_peppol_failure"` to fall back to email when a recipient turns out not to be reachable over Peppol, or send with `recipient: null` for email-only delivery. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **PDFs.** `pdfGeneration.enabled` attaches a generated PDF of the document. You can also attach an existing PDF (or other files) via `attachments`; see [adding attachments](/docs/sending-invoices#adding-attachments). For a full field reference, see [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Sending without writing code [#sending-without-writing-code] The same send is available two other ways, and they mix freely with the API: * **From the dashboard.** [Send document](https://app.recommand.eu/send-document) takes the recipient and the invoice lines, previews what the recipient will get, and remembers your usual settings. You can also drop an existing UBL or CII XML file into the upload zone if your software already produces one. * **From your accounting or invoicing software.** If you use one of the supported tools, let it do the work: your invoices flow to Recommand and out over Peppol without retyping. See [integrations](/integrations) for the current list, including Microsoft Business Central, Exact Online, Yuki, ClearFacts, ERPNext and Harvest. Whichever route you use, Recommand validates a document before it leaves. If a field is missing or malformed you get a clear error instead of a rejection from the recipient days later. See the [troubleshooting guide](/docs/troubleshooting-guide) for the errors you are most likely to run into. Going live [#going-live] A short list before you start sending or receiving real invoices: * **A valid subscription**, so sending is not blocked. Playgrounds skip that check; production does not. * **The company verified**, with `isVerified` true. Until then it cannot exchange documents. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of whoever can fix it rather than logging it. * **Webhook endpoint hardened**, if you took that route: signature verification, a fast 200, retries and idempotency on your side. * **One real document sent and received**, ideally between two companies you control, so you have seen both ends. * **Notification addresses set**, so incoming documents also reach a mailbox somebody reads. Once you are live, your Peppol address is public on the network: suppliers can find and reach you without any action from you. Ask customers who still email PDFs to switch, and let your accountant know where the documents now land. Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Receiving Peppol documents in the Netherlands for your own company (/getting-started/netherlands/business/receiving) This guide walks through everything needed to exchange Peppol documents for a company registered in the Netherlands, assuming you are setting up your own Dutch company, and that the company only receives documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are setting up [#what-you-are-setting-up] You are putting one company, your own or one you represent, on the Peppol network, so it can exchange invoices electronically with its customers and suppliers. The setup is a one-time affair: registering the company and getting it verified takes a few minutes in the [Recommand dashboard](https://app.recommand.eu), and there is nothing to gain from automating something you do once. What you do integrate is the part that repeats: sending and receiving documents. Our existing [integrations](/integrations) can also connect Recommand to accounting or invoicing software you already use, with no code at all. A single team can hold several companies at no extra cost, useful if you run more than one legal entity, and the document volume of all of them counts towards one plan. If you are building e-invoicing or Peppol integration into a product for your own customers, and will be registering their companies rather than only your own, switch the first answer above to **Many companies**. The API is the same; what changes is how companies, verification and billing are organised. Peppol in the Netherlands [#peppol-in-the-netherlands] The Netherlands sits between Belgium and France in complexity: the network is plain Peppol, but Dutch buyers commonly expect the Dutch specialisation of EN 16931 next to Peppol BIS 3. What is specific to the Netherlands: * **SI-UBL 2.0 (NLCIUS) alongside Peppol BIS 3.** Dutch companies are registered for both, so a sender can reach them with either. Recommand can write and read both formats. * **KVK numbers are the Peppol address.** Dutch companies are published under scheme `0106` (Chamber of Commerce), so a Dutch Peppol address looks like `0106:12345678`. The VAT number is registered as well, under scheme `9944`. * **No general B2B mandate (yet).** Unlike Belgium, the Netherlands does not require electronic invoicing between businesses across the board. E-invoicing is required when invoicing Dutch central government, and Peppol is the established channel for it. No country-specific fields are needed on the documents themselves. A valid EN 16931 invoice is accepted; sending SI-UBL is a matter of selecting that format, not of filling in extra data. Create your account and API credentials [#create-your-account-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). 2. Your account starts with a **team**. The team holds your company, your subscription and your document history, and you can invite colleagues to it. 3. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 4. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Sending and receiving can also be driven entirely from the dashboard or through an [integration](/integrations), and each section below says how. The dashboard is available in English, Dutch, French and German; pick your language on the [account page](https://app.recommand.eu/account). Try it safely first [#try-it-safely-first] You do not have to get anything right the first time. Everything below, adding the company, registering it, sending and receiving, can be done in a **playground team** first, where nothing is delivered over the real Peppol network, nothing is registered on it, and nothing is billed. Open the team switcher at the top of the [dashboard](https://app.recommand.eu) and pick **Add playground**. Give it a name, leave the Peppol Test Network box unticked, and you are switched into the new team straight away. There is nothing to set up beyond that. Add a company to that team and use it as both sender and recipient to watch a document travel end to end. When the flow does what you want, repeat it once in your real team. Two things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. A playground stays useful after you are live, too: it is the safest place to try a new invoice layout or a new integration. See [how can I test without sending real invoices](/faq/api-and-development/how-can-i-test-without-sending-real-invoices). Playground companies are not registered on the Peppol network and playground documents never leave it, so nothing you do there affects your real company. Register the company [#register-the-company] You are registering one company, once, so the dashboard is the shortest path. 1. Open [Companies](https://app.recommand.eu/companies) and start the company wizard. 2. Fill in the legal name, address and country, plus the identifiers described in the next section. 3. Choose whether the company should also **receive** documents over Peppol, or only send them. 4. Save. The company is registered on the Peppol network as part of this step: its identifiers and the document types for its country are set up for you. Right after saving, the dashboard offers the verification step, which the section below covers. Note the company's ID from its detail page. Every API call for sending and receiving takes it in the path. The [create company endpoint](/reference/companies/create-company) does exactly the same thing, and returns the company `id` and a `verificationUrl` in one response. It is worth using when company creation is part of a flow you are automating, which is likely the case if you are registering many companies. Switch the first answer above to **Many companies** for that version. Add each legal entity as its own company: run the wizard again. There is no per-company fee, and all of them share your document volume. Dutch identifiers and Peppol address [#dutch-identifiers-and-peppol-address] | Field | Dutch value | | ------------------------ | -------------------------------- | | `country` | `"NL"` | | `enterpriseNumber` | KVK number, exactly 8 digits | | `enterpriseNumberScheme` | `"0106"` | | `vatNumber` | `NL` + 9 digits + `B` + 2 digits | ```json title="company.json" { "name": "Voorbeeld B.V.", "address": "Keizersgracht 1", "postalCode": "1015 CJ", "city": "Amsterdam", "country": "NL", "enterpriseNumber": "12345678", "enterpriseNumberScheme": "0106", "vatNumber": "NL123456789B01" } ``` Both are validated against the Dutch formats (an 8-digit KVK number and a VAT number shaped like `NL123456789B01`) and rejected if they do not match. Two Peppol identifiers are registered for the company: * `0106:12345678` is the KVK number, and the address others will use * `9944:NL123456789B01` is the VAT number The company's Peppol address is the first one: **`0106:` followed by the KVK number**. Registering as a recipient [#registering-as-a-recipient] To receive documents, the company must be published as a recipient on an SMP (Service Metadata Publisher). That is what `isSmpRecipient` does, and it is the default: ```json { "isSmpRecipient": true } ``` What that means: * The company becomes findable on the Peppol network: any sender can look it up and deliver to it via the Peppol network. * Recipient registration is **exclusive**. If the company is already registered for receiving through another Peppol provider, registration fails until it is deregistered there. * The document types the company accepts are registered along with it, based on its country. Which ones those are is covered further down. * The company is only published once it is verified. Moving an existing Dutch registration [#moving-an-existing-dutch-registration] Dutch companies are commonly already reachable over Peppol, because e-invoicing towards Dutch central government has been the norm for years and accounting software often registers the company on the sender's behalf. There is no automatic migration for the Netherlands: the company has to be deregistered at its current provider before it can be registered here. If you do not know who that provider is, look the KVK number up as a recipient. The [verify endpoint](/reference/recipients/verify-recipient) returns the SMP the company is published on. Verify the company [#verify-the-company] A company cannot exchange documents on Peppol until an authorised representative has confirmed their identity. The company object exposes this as `isVerified`, and it stays `false` until the check is done. For Dutch companies the flow is short: 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. The representative fills in their name and completes the identity check. 3. `isVerified` flips to `true` and the company is published on the Peppol network. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. Verifying once, in the dashboard [#verifying-once-in-the-dashboard] You have one company, and it is verified once. There is nothing here worth automating: open [Companies](https://app.recommand.eu/companies) in the dashboard, pick the company and start verification. If you are authorised to act for the company, complete the check yourself; otherwise use the button to forward the link to whoever is. The page is self-contained and works in any browser. The person completing it does not need a Recommand account. That is the whole step. From here on the API takes over: sending and receiving documents is what you actually integrate. Updating the company's `vatNumber` or `enterpriseNumber` sets `isVerified` back to `false`, and the company has to be verified again before it can exchange documents. Document types registered for you [#document-types-registered-for-you] When you register a Dutch company as a recipient, it is published for four document types, so senders can reach it with either the European or the Dutch flavour of EN 16931: | Document type | Process | | ------------------------------ | --------------------------------------------- | | Invoice (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Credit note (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Invoice (SI-UBL 2.0) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Credit note (SI-UBL 2.0) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | Whichever of the four a sender picks, you get the same parsed document out of the API. The format difference stays in the XML. Need more document types, such as self-billing, message level responses, invoice responses? Register the combinations you want with the [create company document type endpoint](/reference/company-document-types/create-company-document-type). Pick up incoming documents [#pick-up-incoming-documents] Once the company is published as a recipient, everything sent to it arrives in Recommand automatically. There are two ways to get the documents into your own systems. Webhooks (recommended) [#webhooks-recommended] Register an endpoint once with the [create webhook endpoint](/reference/webhooks/create-webhook) and events are pushed to you as they happen, `document.received` among them: ```bash curl -X POST https://app.recommand.eu/api/v1/webhooks \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @create-webhook.json ``` ```json title="create-webhook.json" { "url": "https://your-app.example/webhooks/recommand", "companyId": null, "secret": "your_webhook_signing_secret" } ``` Pass a `secret` and verify the HMAC SHA-256 signature on every delivery before you trust the payload, then acknowledge with a 200 before doing the heavy processing. Both are covered in [working with webhooks](/docs/working-with-webhooks). Polling the inbox [#polling-the-inbox] If you would rather pull, the [inbox endpoint](/reference/documents/get-inbox) lists unread documents, and [mark as read](/reference/documents/mark-as-read) drops one off the list once your system has it. Fetch details, the original XML or a rendered PDF from the [documents endpoints](/reference/documents/get-document). Receiving without writing code [#receiving-without-writing-code] * **In the dashboard.** Incoming invoices appear under [Sent and received](https://app.recommand.eu/transmitted-documents), with the original XML, a readable rendering, attachments and the delivery history. * **By email.** Add notification email addresses per company so incoming documents land in the mailbox your bookkeeping already watches, attachments included. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **In your accounting software.** Forward incoming documents straight to Exact Online, Yuki, ClearFacts or another supported tool, see [integrations](/integrations). Two things worth setting up early, whichever route you take: * **Labels and suppliers** to keep documents organised as volume grows, see [suppliers and labels](/docs/suppliers-and-labels). * **Rules** to act on incoming documents automatically: forwarding, labelling, notifying, see [rules](/docs/rules). The full picture, including retries and idempotency, is in [receiving documents](/docs/receiving-documents). Going live [#going-live] A short list before you start sending or receiving real invoices: * **A valid subscription**, so sending is not blocked. Playgrounds skip that check; production does not. * **The company verified**, with `isVerified` true. Until then it cannot exchange documents. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of whoever can fix it rather than logging it. * **Webhook endpoint hardened**, if you took that route: signature verification, a fast 200, retries and idempotency on your side. * **One real document sent and received**, ideally between two companies you control, so you have seen both ends. * **Notification addresses set**, so incoming documents also reach a mailbox somebody reads. Once you are live, your Peppol address is public on the network: suppliers can find and reach you without any action from you. Ask customers who still email PDFs to switch, and let your accountant know where the documents now land. Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Sending and receiving Peppol documents in the Netherlands for your own company (/getting-started/netherlands/business/sending-and-receiving) This guide walks through everything needed to exchange Peppol documents for a company registered in the Netherlands, assuming you are setting up your own Dutch company, and that the company sends and receives documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are setting up [#what-you-are-setting-up] You are putting one company, your own or one you represent, on the Peppol network, so it can exchange invoices electronically with its customers and suppliers. The setup is a one-time affair: registering the company and getting it verified takes a few minutes in the [Recommand dashboard](https://app.recommand.eu), and there is nothing to gain from automating something you do once. What you do integrate is the part that repeats: sending and receiving documents. Our existing [integrations](/integrations) can also connect Recommand to accounting or invoicing software you already use, with no code at all. A single team can hold several companies at no extra cost, useful if you run more than one legal entity, and the document volume of all of them counts towards one plan. If you are building e-invoicing or Peppol integration into a product for your own customers, and will be registering their companies rather than only your own, switch the first answer above to **Many companies**. The API is the same; what changes is how companies, verification and billing are organised. Peppol in the Netherlands [#peppol-in-the-netherlands] The Netherlands sits between Belgium and France in complexity: the network is plain Peppol, but Dutch buyers commonly expect the Dutch specialisation of EN 16931 next to Peppol BIS 3. What is specific to the Netherlands: * **SI-UBL 2.0 (NLCIUS) alongside Peppol BIS 3.** Dutch companies are registered for both, so a sender can reach them with either. Recommand can write and read both formats. * **KVK numbers are the Peppol address.** Dutch companies are published under scheme `0106` (Chamber of Commerce), so a Dutch Peppol address looks like `0106:12345678`. The VAT number is registered as well, under scheme `9944`. * **No general B2B mandate (yet).** Unlike Belgium, the Netherlands does not require electronic invoicing between businesses across the board. E-invoicing is required when invoicing Dutch central government, and Peppol is the established channel for it. No country-specific fields are needed on the documents themselves. A valid EN 16931 invoice is accepted; sending SI-UBL is a matter of selecting that format, not of filling in extra data. Create your account and API credentials [#create-your-account-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). 2. Your account starts with a **team**. The team holds your company, your subscription and your document history, and you can invite colleagues to it. 3. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 4. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Sending and receiving can also be driven entirely from the dashboard or through an [integration](/integrations), and each section below says how. The dashboard is available in English, Dutch, French and German; pick your language on the [account page](https://app.recommand.eu/account). Try it safely first [#try-it-safely-first] You do not have to get anything right the first time. Everything below, adding the company, registering it, sending and receiving, can be done in a **playground team** first, where nothing is delivered over the real Peppol network, nothing is registered on it, and nothing is billed. Open the team switcher at the top of the [dashboard](https://app.recommand.eu) and pick **Add playground**. Give it a name, leave the Peppol Test Network box unticked, and you are switched into the new team straight away. There is nothing to set up beyond that. Add a company to that team and use it as both sender and recipient to watch a document travel end to end. When the flow does what you want, repeat it once in your real team. Two things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. A playground stays useful after you are live, too: it is the safest place to try a new invoice layout or a new integration. See [how can I test without sending real invoices](/faq/api-and-development/how-can-i-test-without-sending-real-invoices). Playground companies are not registered on the Peppol network and playground documents never leave it, so nothing you do there affects your real company. Register the company [#register-the-company] You are registering one company, once, so the dashboard is the shortest path. 1. Open [Companies](https://app.recommand.eu/companies) and start the company wizard. 2. Fill in the legal name, address and country, plus the identifiers described in the next section. 3. Choose whether the company should also **receive** documents over Peppol, or only send them. 4. Save. The company is registered on the Peppol network as part of this step: its identifiers and the document types for its country are set up for you. Right after saving, the dashboard offers the verification step, which the section below covers. Note the company's ID from its detail page. Every API call for sending and receiving takes it in the path. The [create company endpoint](/reference/companies/create-company) does exactly the same thing, and returns the company `id` and a `verificationUrl` in one response. It is worth using when company creation is part of a flow you are automating, which is likely the case if you are registering many companies. Switch the first answer above to **Many companies** for that version. Add each legal entity as its own company: run the wizard again. There is no per-company fee, and all of them share your document volume. Dutch identifiers and Peppol address [#dutch-identifiers-and-peppol-address] | Field | Dutch value | | ------------------------ | -------------------------------- | | `country` | `"NL"` | | `enterpriseNumber` | KVK number, exactly 8 digits | | `enterpriseNumberScheme` | `"0106"` | | `vatNumber` | `NL` + 9 digits + `B` + 2 digits | ```json title="company.json" { "name": "Voorbeeld B.V.", "address": "Keizersgracht 1", "postalCode": "1015 CJ", "city": "Amsterdam", "country": "NL", "enterpriseNumber": "12345678", "enterpriseNumberScheme": "0106", "vatNumber": "NL123456789B01" } ``` Both are validated against the Dutch formats (an 8-digit KVK number and a VAT number shaped like `NL123456789B01`) and rejected if they do not match. Two Peppol identifiers are registered for the company: * `0106:12345678` is the KVK number, and the address others will use * `9944:NL123456789B01` is the VAT number The company's Peppol address is the first one: **`0106:` followed by the KVK number**. Registering for both directions [#registering-for-both-directions] Sending needs no registration of its own; receiving does. So register the company as a recipient, which is the default: ```json { "isSmpRecipient": true } ``` What that means: * The company becomes findable on the Peppol network and can be delivered to through Recommand's access point, while sending its own documents out through the same access point. * Recipient registration is **exclusive**. If the company already receives through another Peppol provider, registration fails until it is deregistered there. What that takes depends on the country, which the next section covers. * The document types the company accepts are registered along with it, based on its country. Which ones those are is covered further down. * The company is only published once it is verified. If the company still receives elsewhere and you do not want to move that yet, register it with `isSmpRecipient: false` and start with sending only. Flipping the field later publishes it as a recipient. Moving an existing Dutch registration [#moving-an-existing-dutch-registration] Dutch companies are commonly already reachable over Peppol, because e-invoicing towards Dutch central government has been the norm for years and accounting software often registers the company on the sender's behalf. There is no automatic migration for the Netherlands: the company has to be deregistered at its current provider before it can be registered here. If you do not know who that provider is, look the KVK number up as a recipient. The [verify endpoint](/reference/recipients/verify-recipient) returns the SMP the company is published on. Verify the company [#verify-the-company] A company cannot exchange documents on Peppol until an authorised representative has confirmed their identity. The company object exposes this as `isVerified`, and it stays `false` until the check is done. For Dutch companies the flow is short: 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. The representative fills in their name and completes the identity check. 3. `isVerified` flips to `true` and the company is published on the Peppol network. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. Verifying once, in the dashboard [#verifying-once-in-the-dashboard] You have one company, and it is verified once. There is nothing here worth automating: open [Companies](https://app.recommand.eu/companies) in the dashboard, pick the company and start verification. If you are authorised to act for the company, complete the check yourself; otherwise use the button to forward the link to whoever is. The page is self-contained and works in any browser. The person completing it does not need a Recommand account. That is the whole step. From here on the API takes over: sending and receiving documents is what you actually integrate. Updating the company's `vatNumber` or `enterpriseNumber` sets `isVerified` back to `false`, and the company has to be verified again before it can exchange documents. Pick the document format [#pick-the-document-format] Dutch recipients registered through Recommand accept both Peppol BIS 3 UBL and SI-UBL 2.0 (NLCIUS). Send BIS 3 unless a buyer asks for SI-UBL, in which case name the SI-UBL document type on the send request: | What you send | `doctypeId` | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | Invoice (default) | not needed, defaults to Peppol BIS 3 UBL | | Credit note (default) | not needed, defaults to Peppol BIS 3 UBL | | SI-UBL 2.0 invoice | `urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:nen.nl:nlcius:v1.0::2.1` | | SI-UBL 2.0 credit note | `urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2::CreditNote##urn:cen.eu:en16931:2017#compliant#urn:fdc:nen.nl:nlcius:v1.0::2.1` | The document you post is the same in both cases: the format decides how the XML is written, not which fields you fill in. Before a first send to a new recipient, check that the recipient exists with the [verify endpoint](/reference/recipients/verify-recipient) and that it accepts the format you intend to use with the [verify document support endpoint](/reference/recipients/verify-document-support). A recipient outside Recommand may well be registered for BIS 3 only. Send a document [#send-a-document] One endpoint sends everything: [`POST /:companyId/send`](/reference/sending/send-document). The `companyId` is the sender, `recipient` is the Peppol address of the receiver, and `document` is the invoice or credit note as JSON. Recommand will validate the document and generate the XML. Raw XML sending is supported as well: set `documentType` to `xml` and pass the document string in `document`, along with the correct `doctypeId`. See [working with raw UBL](/docs/ubl-format-guide#working-with-raw-ubl). ```bash curl -X POST https://app.recommand.eu/api/v1/{companyId}/send \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @send-invoice.json ``` ```json title="send-invoice.json" { "recipient": "0208:0123456789", "documentType": "invoice", "document": { "invoiceNumber": "INV-2026-001", "issueDate": "2026-08-17", "dueDate": "2026-09-16", "currency": "EUR", "buyer": { "name": "Customer Company", "street": "Customer Street 1", "city": "Antwerp", "postalZone": "2000", "country": "BE", "vatNumber": "BE0987654321" }, "paymentMeans": [{ "iban": "BE68539007547034" }], "lines": [ { "name": "Consulting Services", "quantity": "10.00", "unitCode": "HUR", "netPriceAmount": "100.00", "vat": { "category": "S", "percentage": "21.00" } } ] } } ``` The seller block is filled in from your company when you leave it out, which is usually what you want: it keeps your registered identifiers and the document in agreement. The full field reference lives in [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Worth wiring up while you are here: * **Validation errors.** Outgoing documents are always validated. A `success: false` response with `errors` keyed by field path is a document the recipient would have rejected. Surface it wherever the data was typed. * **Email fallback.** Pass `email.to` with `when: "on_peppol_failure"` to fall back to email when a recipient turns out not to be reachable over Peppol, or send with `recipient: null` for email-only delivery. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **PDFs.** `pdfGeneration.enabled` attaches a generated PDF of the document. You can also attach an existing PDF (or other files) via `attachments`; see [adding attachments](/docs/sending-invoices#adding-attachments). For a full field reference, see [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Sending without writing code [#sending-without-writing-code] The same send is available two other ways, and they mix freely with the API: * **From the dashboard.** [Send document](https://app.recommand.eu/send-document) takes the recipient and the invoice lines, previews what the recipient will get, and remembers your usual settings. You can also drop an existing UBL or CII XML file into the upload zone if your software already produces one. * **From your accounting or invoicing software.** If you use one of the supported tools, let it do the work: your invoices flow to Recommand and out over Peppol without retyping. See [integrations](/integrations) for the current list, including Microsoft Business Central, Exact Online, Yuki, ClearFacts, ERPNext and Harvest. Whichever route you use, Recommand validates a document before it leaves. If a field is missing or malformed you get a clear error instead of a rejection from the recipient days later. See the [troubleshooting guide](/docs/troubleshooting-guide) for the errors you are most likely to run into. Document types registered for you [#document-types-registered-for-you] When you register a Dutch company as a recipient, it is published for four document types, so senders can reach it with either the European or the Dutch flavour of EN 16931: | Document type | Process | | ------------------------------ | --------------------------------------------- | | Invoice (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Credit note (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Invoice (SI-UBL 2.0) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Credit note (SI-UBL 2.0) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | Whichever of the four a sender picks, you get the same parsed document out of the API. The format difference stays in the XML. Need more document types, such as self-billing, message level responses, invoice responses? Register the combinations you want with the [create company document type endpoint](/reference/company-document-types/create-company-document-type). Pick up incoming documents [#pick-up-incoming-documents] Once the company is published as a recipient, everything sent to it arrives in Recommand automatically. There are two ways to get the documents into your own systems. Webhooks (recommended) [#webhooks-recommended] Register an endpoint once with the [create webhook endpoint](/reference/webhooks/create-webhook) and events are pushed to you as they happen, `document.received` among them: ```bash curl -X POST https://app.recommand.eu/api/v1/webhooks \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @create-webhook.json ``` ```json title="create-webhook.json" { "url": "https://your-app.example/webhooks/recommand", "companyId": null, "secret": "your_webhook_signing_secret" } ``` Pass a `secret` and verify the HMAC SHA-256 signature on every delivery before you trust the payload, then acknowledge with a 200 before doing the heavy processing. Both are covered in [working with webhooks](/docs/working-with-webhooks). Polling the inbox [#polling-the-inbox] If you would rather pull, the [inbox endpoint](/reference/documents/get-inbox) lists unread documents, and [mark as read](/reference/documents/mark-as-read) drops one off the list once your system has it. Fetch details, the original XML or a rendered PDF from the [documents endpoints](/reference/documents/get-document). Receiving without writing code [#receiving-without-writing-code] * **In the dashboard.** Incoming invoices appear under [Sent and received](https://app.recommand.eu/transmitted-documents), with the original XML, a readable rendering, attachments and the delivery history. * **By email.** Add notification email addresses per company so incoming documents land in the mailbox your bookkeeping already watches, attachments included. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **In your accounting software.** Forward incoming documents straight to Exact Online, Yuki, ClearFacts or another supported tool, see [integrations](/integrations). Two things worth setting up early, whichever route you take: * **Labels and suppliers** to keep documents organised as volume grows, see [suppliers and labels](/docs/suppliers-and-labels). * **Rules** to act on incoming documents automatically: forwarding, labelling, notifying, see [rules](/docs/rules). The full picture, including retries and idempotency, is in [receiving documents](/docs/receiving-documents). Going live [#going-live] A short list before you start sending or receiving real invoices: * **A valid subscription**, so sending is not blocked. Playgrounds skip that check; production does not. * **The company verified**, with `isVerified` true. Until then it cannot exchange documents. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of whoever can fix it rather than logging it. * **Webhook endpoint hardened**, if you took that route: signature verification, a fast 200, retries and idempotency on your side. * **One real document sent and received**, ideally between two companies you control, so you have seen both ends. * **Notification addresses set**, so incoming documents also reach a mailbox somebody reads. Once you are live, your Peppol address is public on the network: suppliers can find and reach you without any action from you. Ask customers who still email PDFs to switch, and let your accountant know where the documents now land. Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Sending Peppol documents in other countries for the companies you onboard (/getting-started/other/platform/sending) This guide walks through everything needed to exchange Peppol documents for a company registered in a country other than Belgium, France or the Netherlands, assuming you are integrating Recommand into your own product and onboarding companies in other countries as your users, and that the company only sends documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are building [#what-you-are-building] You are onboarding companies that are not your own: one Recommand team, and a company inside it for every customer you put on the network. Your customers never need a Recommand account. They see your interface, and Recommand stays behind your API calls. That shape has a few consequences worth knowing before you write code: * **One team, many companies.** There is no limit on companies per team, and billing is per team with the document volume of all companies pooled together, so the more companies you onboard the lower your price per document. See [pricing per team](/faq/general-usage/is-pricing-per-company-or-per-team). * **Every company is registered and verified individually.** Peppol identifies companies, not platforms. Each company gets its own Peppol address and its own authorisation record. * **Verification is taken care of.** Recommand hands you a URL that the company's authorised representative opens to confirm their identity. You present or forward that link; you never need to handle identity documents yourself. If you prefer to handle verification yourself, reach out to us at [support@recommand.eu](mailto:support@recommand.eu), we have a few other flows we can set up for you. * **You can run the whole flow under your own brand.** The API is designed for white-label use, see [can I whitelabel Recommand](/faq/general-usage/can-i-whitelabel-integrate-recommand). The [Recommand dashboard](https://app.recommand.eu) shows the same teams, companies and documents your API calls produce, which is the quickest way to see what a customer is looking at while you are debugging. If the only company you will register is your own, switch the first answer above to **One company** for the shorter version of this guide. The endpoints are the same; there is simply less to organise. Peppol internationally [#peppol-internationally] Each country carries one of three support levels: | Level | What it means | | --------------- | ----------------------------------------------------------------------------------------------------- | | **Supported** | Companies work end to end, and the country's own identifier schemes are registered for you. | | **Partial** | Companies are functional, but country-specific features or local requirements may not be covered yet. | | **Unsupported** | New companies cannot be created there, and existing companies cannot be switched to it. | The [countries page on our website](https://recommand.eu/countries) is the source of truth: it shows the level for the country you select. Support is added country by country. If the one you need is unsupported, or supported only partially in a way that blocks you, mail [support@recommand.eu](mailto:support@recommand.eu). Knowing there is demand is what moves a country up the list. Create your team and API credentials [#create-your-team-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). The team you get is the container for every company you will onboard. 2. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 3. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Try it safely first [#try-it-safely-first] Build the whole flow against a **playground team** before you touch production. Playgrounds look and behave like production teams, but nothing is delivered over the real Peppol network, there are no SMP registrations, no subscription checks and no billing. Create one from the team switcher at the top of the [dashboard](https://app.recommand.eu): **Add playground**, give it a name, and you are switched into it. There is no limit on how many you create. Everything that follows in this guide is identical there: same endpoints, same validation, same webhooks (triggered by simulated inbound delivery). Register a company in the playground and use it as both sender and recipient to see a document arrive. Three things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`, which is the quickest way to check that your country-specific fields map to the format and process you expect. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. * **The Peppol Test Network.** For genuine end-to-end tests with real counterparties, tick **Use Peppol Test Network** when you create the playground. It then uses dedicated test access point and SMP endpoints while staying fully separated from production. The setting cannot be changed after creation, so make a second playground if you want both. More detail in the [getting started guide](/docs) and [how do I use the playground environment](/faq/api-and-development/how-do-i-use-the-playground-environment). Register the company [#register-the-company] Create one company per customer with the [create company endpoint](/reference/companies/create-company). Registration on the Peppol network happens as part of this call: identifiers and document types are set up for you, based on the company's country. ```javascript const auth = "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"); const response = await fetch("https://app.recommand.eu/api/v1/companies", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(company), }); const result = await response.json(); if (!result.success) throw new Error(JSON.stringify(result.errors)); const companyId = result.company.id; const verificationUrl = result.verificationUrl; // hand this to your user ``` ```bash curl -X POST https://app.recommand.eu/api/v1/companies \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @company.json ``` The response carries a `verificationUrl` straight away. Keep it: the next step is to put it in front of the company's representative. Register the companies that use your platform, not the companies they invoice. Customers and suppliers manage their own Peppol registration; adding them causes registration conflicts. See [managing companies](/docs/managing-companies). The exact identifier fields to send depend on the country, which is what the next section covers. If you would rather create identifiers and document types yourself instead of accepting the country defaults, pass `skipDefaultCompanySetup: true` and use the [company identifiers](/reference/company-identifiers/create-company-identifier) and [company document types](/reference/company-document-types/get-company-document-types) endpoints. Identifiers and the Peppol address [#identifiers-and-the-peppol-address] Three fields decide how the company is published on the network: | Field | Value | | ------------------ | ------------------------------------------------------- | | `country` | ISO 3166-1 alpha-2, e.g. `"DE"`, `"SE"`, `"IT"` | | `enterpriseNumber` | The national company or organisation number | | `vatNumber` | The VAT number, **starting with the same country code** | ```json title="company.json" { "name": "Exempel AB", "address": "Storgatan 1", "postalCode": "111 51", "city": "Stockholm", "country": "SE", "enterpriseNumber": "5567321707", "vatNumber": "SE556732170701" } ``` A VAT number whose country code does not match `country` is rejected. That is the one identifier rule enforced for every country. National format checks (the modulo-97 check digit for Belgium, the KVK length for the Netherlands, the CVR length for Denmark) only exist for the countries that have them; elsewhere the number is taken as given, so check it before you send it. There is also an optional `enterpriseNumberScheme`. It does not decide which Peppol identifier is registered (the country does, as the next section shows), but it is written into the documents the company sends, as the scheme of the seller's legal identifier. Leave it out unless the country expects a specific one. Which schemes are registered for you [#which-schemes-are-registered-for-you] Each country has its own [Peppol Electronic Address Scheme](https://docs.peppol.eu/poacc/billing/3.0/codelist/eas/), and Recommand tries to automatically register the correct scheme for you. The Peppol address is also what a document is sent from. A company with no identifier at all cannot send: the attempt fails with *no sending company identifier found*, and it cannot be published as a recipient either, because there is no address to publish. In some countries, adding an identifier yourself is part of onboarding rather than an optional extra. Adding identifiers by hand [#adding-identifiers-by-hand] Whatever the defaults do, the full set is yours to manage: [list identifiers](/reference/company-identifiers/get-company-identifiers), [add one](/reference/company-identifiers/create-company-identifier), [update one](/reference/company-identifiers/update-company-identifier) or [remove one](/reference/company-identifiers/delete-company-identifier). Every identifier you add is registered in the SMP as another address the company can be reached on. ```bash curl -X POST https://app.recommand.eu/api/v1/companies/{companyId}/identifiers \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d '{"scheme":"0007","identifier":"5567321707"}' ``` This is also the escape hatch for a country with no defaults, and for the case where your customers know a company by a different identifier than the one registered for it. Registering for sending only [#registering-for-sending-only] Because you are only looking to send invoices or other documents, register the company **without** recipient registration: set `isSmpRecipient` to `false` (or leave the checkbox unticked in the dashboard). ```json { "isSmpRecipient": false } ``` What that means: * The company is not published as a recipient on an SMP, so nothing is delivered to it over Peppol through your integration. * Registration succeeds even when the company already receives its documents through another Peppol provider. The other Peppol provider will remain in charge for processing received documents for this company. * Nothing changes for sending: outgoing documents leave through the access point as normal. You can flip `isSmpRecipient` to `true` on an existing company at any time. Recommand then publishes it as a recipient and registers the document types for its country. That registration is exclusive, so the company has to be deregistered at its current provider first. Verify the company [#verify-the-company] A company cannot exchange documents on Peppol until an authorised representative has confirmed their identity. The company object exposes this as `isVerified`, and it stays `false` until the check is done. The flow is short: 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. The representative fills in their name and completes the identity check. 3. `isVerified` flips to `true` and the company is published on the Peppol network. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. Building verification into your onboarding [#building-verification-into-your-onboarding] With one company you would click through this once. With many, verification is part of the flow you build: every company you register needs its own, and it is the step most likely to leave a customer stuck halfway. **Show the URL immediately.** The create-company response already carries `verificationUrl`, so no extra call is needed. Put it in front of the user while they are still in your onboarding. **Ask for a fresh one when the moment has passed.** Links get lost, and companies you created earlier never had one shown. The [verify company endpoint](/reference/companies/verify-company) starts a new verification session: ```bash curl -X POST https://app.recommand.eu/api/v1/companies/{companyId}/verify \ -u key_xxx:secret_xxx ``` The `company.verification` webhook fires when verification reaches a final state: `verified`, `rejected` or `error`. A company that comes back `rejected` or `error` and is not surfaced anywhere sits silently unusable. See [working with webhooks](/docs/working-with-webhooks). **Respect `isVerified` in your own UI.** Do not let a user press send for a company that is not verified yet; this will result in an error. You should inform the user what is missing instead. **Re-verify after identifier changes.** Updating a company's `vatNumber` or `enterpriseNumber` resets `isVerified` to `false`. Check the field after an update and present a new `verificationUrl` if it flipped. The full mechanics are in the [company verification guide](/docs/company-verification). Pick the document format [#pick-the-document-format] Send **Peppol BIS 3 UBL**, over the standard Peppol billing process. It is the format most Peppol participants accept. Some countries have a national CIUS on top of EN 16931, SI-UBL 2.0 in the Netherlands, for instance. If a buyer asks for one and Recommand supports it, you name its document type in `doctypeId` on the send request; the document you post stays the same, because the format decides how the XML is written, not which fields you fill in. Before a first send to a new recipient, check two things: * **Is the recipient on the network?** The [verify endpoint](/reference/recipients/verify-recipient) answers that, and sending performs the same check automatically. * **Does the recipient accept this document type?** The [verify document support endpoint](/reference/recipients/verify-document-support) answers that, which matters more abroad than at home: a recipient in another country may be registered for its own national profile only. See [verifying recipients](/docs/verifying-recipients) for the full flow, including what to do when a recipient cannot be reached. Send a document [#send-a-document] One endpoint sends everything: [`POST /:companyId/send`](/reference/sending/send-document). The `companyId` is the sender, `recipient` is the Peppol address of the receiver, and `document` is the invoice or credit note as JSON. Recommand will validate the document and generate the XML. Raw XML sending is supported as well: set `documentType` to `xml` and pass the document string in `document`, along with the correct `doctypeId`. See [working with raw UBL](/docs/ubl-format-guide#working-with-raw-ubl). ```javascript const response = await fetch( `https://app.recommand.eu/api/v1/${companyId}/send`, { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, // The body below, with doctypeId and countrySpecific where the country // needs them. body: JSON.stringify(sendRequest), } ); const result = await response.json(); if (!result.success) { // result.errors is keyed by field path, e.g. { "buyer.vatNumber": [...] } } ``` ```bash curl -X POST https://app.recommand.eu/api/v1/{companyId}/send \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @send-invoice.json ``` ```json title="send-invoice.json" { "recipient": "0208:0123456789", "documentType": "invoice", "document": { "invoiceNumber": "INV-2026-001", "issueDate": "2026-08-17", "dueDate": "2026-09-16", "currency": "EUR", "buyer": { "name": "Customer Company", "street": "Customer Street 1", "city": "Antwerp", "postalZone": "2000", "country": "BE", "vatNumber": "BE0987654321" }, "paymentMeans": [{ "iban": "BE68539007547034" }], "lines": [ { "name": "Consulting Services", "quantity": "10.00", "unitCode": "HUR", "netPriceAmount": "100.00", "vat": { "category": "S", "percentage": "21.00" } } ] } } ``` The seller block is filled in from the company when you leave it out, which is usually what you want: it keeps the company's registered identifiers and the document in agreement. Things worth wiring up while you are here: * **Validation errors.** Outgoing documents are always validated. A `success: false` response with `errors` keyed by field path is a document your recipient would have rejected, so surface it to the user who typed the data. * **Email fallback.** Pass `email.to` with `when: "on_peppol_failure"` to fall back to email when a recipient turns out not to be reachable over Peppol, or send with `recipient: null` for email-only delivery. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **PDFs.** `pdfGeneration.enabled` attaches a generated PDF of the document. You can also attach an existing PDF (or other files) via `attachments`; see [adding attachments](/docs/sending-invoices#adding-attachments). For a full field reference, see [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Going live [#going-live] Before you switch your first real customer over, walk this list: * **A valid subscription in production.** Playgrounds skip the subscription check; production does not. * **Verification handled in your UI.** Show the `verificationUrl` at the right moment, make it forwardable, and handle the `company.verification` webhook so a company that comes back `rejected` or `error` does not sit silently unusable. * **`isVerified` respected.** Do not let a user press send for a company that is not verified yet; explain what is missing instead. * **Webhook endpoint hardened.** Signature verification, a fast 200, retries and idempotency on your side. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of the person who can fix it. * **One real document, end to end.** Send an invoice between two companies you control on production before letting customers in. Documents are counted per team, with the volume of all your companies pooled, so onboarding more companies lowers your price per document rather than adding per-company fees. Received documents count towards the quota as well as sent ones, so budget for both sides of the exchange. Generated XML through `generate` is not billed; emails and submitted reports are. Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Receiving Peppol documents in other countries for the companies you onboard (/getting-started/other/platform/receiving) This guide walks through everything needed to exchange Peppol documents for a company registered in a country other than Belgium, France or the Netherlands, assuming you are integrating Recommand into your own product and onboarding companies in other countries as your users, and that the company only receives documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are building [#what-you-are-building] You are onboarding companies that are not your own: one Recommand team, and a company inside it for every customer you put on the network. Your customers never need a Recommand account. They see your interface, and Recommand stays behind your API calls. That shape has a few consequences worth knowing before you write code: * **One team, many companies.** There is no limit on companies per team, and billing is per team with the document volume of all companies pooled together, so the more companies you onboard the lower your price per document. See [pricing per team](/faq/general-usage/is-pricing-per-company-or-per-team). * **Every company is registered and verified individually.** Peppol identifies companies, not platforms. Each company gets its own Peppol address and its own authorisation record. * **Verification is taken care of.** Recommand hands you a URL that the company's authorised representative opens to confirm their identity. You present or forward that link; you never need to handle identity documents yourself. If you prefer to handle verification yourself, reach out to us at [support@recommand.eu](mailto:support@recommand.eu), we have a few other flows we can set up for you. * **You can run the whole flow under your own brand.** The API is designed for white-label use, see [can I whitelabel Recommand](/faq/general-usage/can-i-whitelabel-integrate-recommand). The [Recommand dashboard](https://app.recommand.eu) shows the same teams, companies and documents your API calls produce, which is the quickest way to see what a customer is looking at while you are debugging. If the only company you will register is your own, switch the first answer above to **One company** for the shorter version of this guide. The endpoints are the same; there is simply less to organise. Peppol internationally [#peppol-internationally] Each country carries one of three support levels: | Level | What it means | | --------------- | ----------------------------------------------------------------------------------------------------- | | **Supported** | Companies work end to end, and the country's own identifier schemes are registered for you. | | **Partial** | Companies are functional, but country-specific features or local requirements may not be covered yet. | | **Unsupported** | New companies cannot be created there, and existing companies cannot be switched to it. | The [countries page on our website](https://recommand.eu/countries) is the source of truth: it shows the level for the country you select. Support is added country by country. If the one you need is unsupported, or supported only partially in a way that blocks you, mail [support@recommand.eu](mailto:support@recommand.eu). Knowing there is demand is what moves a country up the list. Create your team and API credentials [#create-your-team-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). The team you get is the container for every company you will onboard. 2. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 3. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Try it safely first [#try-it-safely-first] Build the whole flow against a **playground team** before you touch production. Playgrounds look and behave like production teams, but nothing is delivered over the real Peppol network, there are no SMP registrations, no subscription checks and no billing. Create one from the team switcher at the top of the [dashboard](https://app.recommand.eu): **Add playground**, give it a name, and you are switched into it. There is no limit on how many you create. Everything that follows in this guide is identical there: same endpoints, same validation, same webhooks (triggered by simulated inbound delivery). Register a company in the playground and use it as both sender and recipient to see a document arrive. Three things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`, which is the quickest way to check that your country-specific fields map to the format and process you expect. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. * **The Peppol Test Network.** For genuine end-to-end tests with real counterparties, tick **Use Peppol Test Network** when you create the playground. It then uses dedicated test access point and SMP endpoints while staying fully separated from production. The setting cannot be changed after creation, so make a second playground if you want both. More detail in the [getting started guide](/docs) and [how do I use the playground environment](/faq/api-and-development/how-do-i-use-the-playground-environment). Register the company [#register-the-company] Create one company per customer with the [create company endpoint](/reference/companies/create-company). Registration on the Peppol network happens as part of this call: identifiers and document types are set up for you, based on the company's country. ```javascript const auth = "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"); const response = await fetch("https://app.recommand.eu/api/v1/companies", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(company), }); const result = await response.json(); if (!result.success) throw new Error(JSON.stringify(result.errors)); const companyId = result.company.id; const verificationUrl = result.verificationUrl; // hand this to your user ``` ```bash curl -X POST https://app.recommand.eu/api/v1/companies \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @company.json ``` The response carries a `verificationUrl` straight away. Keep it: the next step is to put it in front of the company's representative. Register the companies that use your platform, not the companies they invoice. Customers and suppliers manage their own Peppol registration; adding them causes registration conflicts. See [managing companies](/docs/managing-companies). The exact identifier fields to send depend on the country, which is what the next section covers. If you would rather create identifiers and document types yourself instead of accepting the country defaults, pass `skipDefaultCompanySetup: true` and use the [company identifiers](/reference/company-identifiers/create-company-identifier) and [company document types](/reference/company-document-types/get-company-document-types) endpoints. Identifiers and the Peppol address [#identifiers-and-the-peppol-address] Three fields decide how the company is published on the network: | Field | Value | | ------------------ | ------------------------------------------------------- | | `country` | ISO 3166-1 alpha-2, e.g. `"DE"`, `"SE"`, `"IT"` | | `enterpriseNumber` | The national company or organisation number | | `vatNumber` | The VAT number, **starting with the same country code** | ```json title="company.json" { "name": "Exempel AB", "address": "Storgatan 1", "postalCode": "111 51", "city": "Stockholm", "country": "SE", "enterpriseNumber": "5567321707", "vatNumber": "SE556732170701" } ``` A VAT number whose country code does not match `country` is rejected. That is the one identifier rule enforced for every country. National format checks (the modulo-97 check digit for Belgium, the KVK length for the Netherlands, the CVR length for Denmark) only exist for the countries that have them; elsewhere the number is taken as given, so check it before you send it. There is also an optional `enterpriseNumberScheme`. It does not decide which Peppol identifier is registered (the country does, as the next section shows), but it is written into the documents the company sends, as the scheme of the seller's legal identifier. Leave it out unless the country expects a specific one. Which schemes are registered for you [#which-schemes-are-registered-for-you] Each country has its own [Peppol Electronic Address Scheme](https://docs.peppol.eu/poacc/billing/3.0/codelist/eas/), and Recommand tries to automatically register the correct scheme for you. The Peppol address is also what a document is sent from. A company with no identifier at all cannot send: the attempt fails with *no sending company identifier found*, and it cannot be published as a recipient either, because there is no address to publish. In some countries, adding an identifier yourself is part of onboarding rather than an optional extra. Adding identifiers by hand [#adding-identifiers-by-hand] Whatever the defaults do, the full set is yours to manage: [list identifiers](/reference/company-identifiers/get-company-identifiers), [add one](/reference/company-identifiers/create-company-identifier), [update one](/reference/company-identifiers/update-company-identifier) or [remove one](/reference/company-identifiers/delete-company-identifier). Every identifier you add is registered in the SMP as another address the company can be reached on. ```bash curl -X POST https://app.recommand.eu/api/v1/companies/{companyId}/identifiers \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d '{"scheme":"0007","identifier":"5567321707"}' ``` This is also the escape hatch for a country with no defaults, and for the case where your customers know a company by a different identifier than the one registered for it. Registering as a recipient [#registering-as-a-recipient] To receive documents, the company must be published as a recipient on an SMP (Service Metadata Publisher). That is what `isSmpRecipient` does, and it is the default: ```json { "isSmpRecipient": true } ``` What that means: * The company becomes findable on the Peppol network: any sender can look it up and deliver to it via the Peppol network. * Recipient registration is **exclusive**. If the company is already registered for receiving through another Peppol provider, registration fails until it is deregistered there. * The document types the company accepts are registered along with it, based on its country. Which ones those are is covered further down. * The company is only published once it is verified. Moving an existing registration [#moving-an-existing-registration] Recipient registration is exclusive everywhere: a company that already receives through another Peppol provider has to be deregistered there before it can be registered with Recommand. If you do not know who the current provider is, look the company up as a recipient: the [verify endpoint](/reference/recipients/verify-recipient) returns the SMP it is published on, which names the provider to ask. Verify the company [#verify-the-company] A company cannot exchange documents on Peppol until an authorised representative has confirmed their identity. The company object exposes this as `isVerified`, and it stays `false` until the check is done. The flow is short: 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. The representative fills in their name and completes the identity check. 3. `isVerified` flips to `true` and the company is published on the Peppol network. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. Building verification into your onboarding [#building-verification-into-your-onboarding] With one company you would click through this once. With many, verification is part of the flow you build: every company you register needs its own, and it is the step most likely to leave a customer stuck halfway. **Show the URL immediately.** The create-company response already carries `verificationUrl`, so no extra call is needed. Put it in front of the user while they are still in your onboarding. **Ask for a fresh one when the moment has passed.** Links get lost, and companies you created earlier never had one shown. The [verify company endpoint](/reference/companies/verify-company) starts a new verification session: ```bash curl -X POST https://app.recommand.eu/api/v1/companies/{companyId}/verify \ -u key_xxx:secret_xxx ``` The `company.verification` webhook fires when verification reaches a final state: `verified`, `rejected` or `error`. A company that comes back `rejected` or `error` and is not surfaced anywhere sits silently unusable. See [working with webhooks](/docs/working-with-webhooks). **Respect `isVerified` in your own UI.** Do not let a user press send for a company that is not verified yet; this will result in an error. You should inform the user what is missing instead. **Re-verify after identifier changes.** Updating a company's `vatNumber` or `enterpriseNumber` resets `isVerified` to `false`. Check the field after an update and present a new `verificationUrl` if it flipped. The full mechanics are in the [company verification guide](/docs/company-verification). Document types registered for you [#document-types-registered-for-you] When you register the company as a recipient, it is published for the two document types that carry almost all cross-border traffic: | Document type | Process | | ------------------------------ | --------------------------------------------- | | Invoice (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Credit note (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | Anything sent to the company in one of these formats is accepted, validated, stored and handed to you. A sender who tries a document type the company is not published for gets an error before delivery, which is exactly the point of the registration. Need more document types, such as a national CIUS your suppliers use, self-billing, message level responses, invoice responses? Register the combinations you want with the [create company document type endpoint](/reference/company-document-types/create-company-document-type) or through the dashboard. Get incoming documents into your product [#get-incoming-documents-into-your-product] Recommand receives, validates and stores incoming documents for every company in your team. You pick them up in one of two ways. Webhooks (recommended) [#webhooks-recommended] Register an endpoint once with the [create webhook endpoint](/reference/webhooks/create-webhook) or through the dashboard and events are pushed to you as they happen, `document.received` among them: ```javascript await fetch("https://app.recommand.eu/api/v1/webhooks", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(webhook), // the body below }); ``` ```bash curl -X POST https://app.recommand.eu/api/v1/webhooks \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @create-webhook.json ``` ```json title="create-webhook.json" { "url": "https://your-app.example/webhooks/recommand", "companyId": null, "secret": "your_webhook_signing_secret" } ``` `companyId: null` covers every company in the team. Pass a `secret` and verify the HMAC SHA-256 signature on every delivery before you trust the payload. Switch on `event.eventType`, and acknowledge with a 200 before doing the heavy processing. Both are covered in [working with webhooks](/docs/working-with-webhooks). Polling the inbox [#polling-the-inbox] If you would rather pull, the [inbox endpoint](/reference/documents/get-inbox) lists unread documents: ```javascript const inbox = await fetch("https://app.recommand.eu/api/v1/inbox", { headers: { Authorization: auth }, }).then((r) => r.json()); ``` Mark each document as read with the [mark as read endpoint](/reference/documents/mark-as-read) once your system has it, so it drops off the list. After you have the document [#after-you-have-the-document] * Fetch details, the original XML or a rendered PDF from the [documents endpoints](/reference/documents/get-document). * Route documents to the right customer with [labels and suppliers](/docs/suppliers-and-labels), and automate that routing with [rules](/docs/rules). * Let Recommand mail incoming documents on to an address of your choosing when that is easier than an API call, see [email delivery and notifications](/docs/email-delivery-and-notifications). For the full picture, including retries and idempotency, see [receiving documents](/docs/receiving-documents). Going live [#going-live] Before you switch your first real customer over, walk this list: * **A valid subscription in production.** Playgrounds skip the subscription check; production does not. * **Verification handled in your UI.** Show the `verificationUrl` at the right moment, make it forwardable, and handle the `company.verification` webhook so a company that comes back `rejected` or `error` does not sit silently unusable. * **`isVerified` respected.** Do not let a user press send for a company that is not verified yet; explain what is missing instead. * **Webhook endpoint hardened.** Signature verification, a fast 200, retries and idempotency on your side. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of the person who can fix it. * **One real document, end to end.** Send an invoice between two companies you control on production before letting customers in. Documents are counted per team, with the volume of all your companies pooled, so onboarding more companies lowers your price per document rather than adding per-company fees. Received documents count towards the quota as well as sent ones, so budget for both sides of the exchange. Generated XML through `generate` is not billed; emails and submitted reports are. Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Sending and receiving Peppol documents in other countries for the companies you onboard (/getting-started/other/platform/sending-and-receiving) This guide walks through everything needed to exchange Peppol documents for a company registered in a country other than Belgium, France or the Netherlands, assuming you are integrating Recommand into your own product and onboarding companies in other countries as your users, and that the company sends and receives documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are building [#what-you-are-building] You are onboarding companies that are not your own: one Recommand team, and a company inside it for every customer you put on the network. Your customers never need a Recommand account. They see your interface, and Recommand stays behind your API calls. That shape has a few consequences worth knowing before you write code: * **One team, many companies.** There is no limit on companies per team, and billing is per team with the document volume of all companies pooled together, so the more companies you onboard the lower your price per document. See [pricing per team](/faq/general-usage/is-pricing-per-company-or-per-team). * **Every company is registered and verified individually.** Peppol identifies companies, not platforms. Each company gets its own Peppol address and its own authorisation record. * **Verification is taken care of.** Recommand hands you a URL that the company's authorised representative opens to confirm their identity. You present or forward that link; you never need to handle identity documents yourself. If you prefer to handle verification yourself, reach out to us at [support@recommand.eu](mailto:support@recommand.eu), we have a few other flows we can set up for you. * **You can run the whole flow under your own brand.** The API is designed for white-label use, see [can I whitelabel Recommand](/faq/general-usage/can-i-whitelabel-integrate-recommand). The [Recommand dashboard](https://app.recommand.eu) shows the same teams, companies and documents your API calls produce, which is the quickest way to see what a customer is looking at while you are debugging. If the only company you will register is your own, switch the first answer above to **One company** for the shorter version of this guide. The endpoints are the same; there is simply less to organise. Peppol internationally [#peppol-internationally] Each country carries one of three support levels: | Level | What it means | | --------------- | ----------------------------------------------------------------------------------------------------- | | **Supported** | Companies work end to end, and the country's own identifier schemes are registered for you. | | **Partial** | Companies are functional, but country-specific features or local requirements may not be covered yet. | | **Unsupported** | New companies cannot be created there, and existing companies cannot be switched to it. | The [countries page on our website](https://recommand.eu/countries) is the source of truth: it shows the level for the country you select. Support is added country by country. If the one you need is unsupported, or supported only partially in a way that blocks you, mail [support@recommand.eu](mailto:support@recommand.eu). Knowing there is demand is what moves a country up the list. Create your team and API credentials [#create-your-team-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). The team you get is the container for every company you will onboard. 2. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 3. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Try it safely first [#try-it-safely-first] Build the whole flow against a **playground team** before you touch production. Playgrounds look and behave like production teams, but nothing is delivered over the real Peppol network, there are no SMP registrations, no subscription checks and no billing. Create one from the team switcher at the top of the [dashboard](https://app.recommand.eu): **Add playground**, give it a name, and you are switched into it. There is no limit on how many you create. Everything that follows in this guide is identical there: same endpoints, same validation, same webhooks (triggered by simulated inbound delivery). Register a company in the playground and use it as both sender and recipient to see a document arrive. Three things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`, which is the quickest way to check that your country-specific fields map to the format and process you expect. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. * **The Peppol Test Network.** For genuine end-to-end tests with real counterparties, tick **Use Peppol Test Network** when you create the playground. It then uses dedicated test access point and SMP endpoints while staying fully separated from production. The setting cannot be changed after creation, so make a second playground if you want both. More detail in the [getting started guide](/docs) and [how do I use the playground environment](/faq/api-and-development/how-do-i-use-the-playground-environment). Register the company [#register-the-company] Create one company per customer with the [create company endpoint](/reference/companies/create-company). Registration on the Peppol network happens as part of this call: identifiers and document types are set up for you, based on the company's country. ```javascript const auth = "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"); const response = await fetch("https://app.recommand.eu/api/v1/companies", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(company), }); const result = await response.json(); if (!result.success) throw new Error(JSON.stringify(result.errors)); const companyId = result.company.id; const verificationUrl = result.verificationUrl; // hand this to your user ``` ```bash curl -X POST https://app.recommand.eu/api/v1/companies \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @company.json ``` The response carries a `verificationUrl` straight away. Keep it: the next step is to put it in front of the company's representative. Register the companies that use your platform, not the companies they invoice. Customers and suppliers manage their own Peppol registration; adding them causes registration conflicts. See [managing companies](/docs/managing-companies). The exact identifier fields to send depend on the country, which is what the next section covers. If you would rather create identifiers and document types yourself instead of accepting the country defaults, pass `skipDefaultCompanySetup: true` and use the [company identifiers](/reference/company-identifiers/create-company-identifier) and [company document types](/reference/company-document-types/get-company-document-types) endpoints. Identifiers and the Peppol address [#identifiers-and-the-peppol-address] Three fields decide how the company is published on the network: | Field | Value | | ------------------ | ------------------------------------------------------- | | `country` | ISO 3166-1 alpha-2, e.g. `"DE"`, `"SE"`, `"IT"` | | `enterpriseNumber` | The national company or organisation number | | `vatNumber` | The VAT number, **starting with the same country code** | ```json title="company.json" { "name": "Exempel AB", "address": "Storgatan 1", "postalCode": "111 51", "city": "Stockholm", "country": "SE", "enterpriseNumber": "5567321707", "vatNumber": "SE556732170701" } ``` A VAT number whose country code does not match `country` is rejected. That is the one identifier rule enforced for every country. National format checks (the modulo-97 check digit for Belgium, the KVK length for the Netherlands, the CVR length for Denmark) only exist for the countries that have them; elsewhere the number is taken as given, so check it before you send it. There is also an optional `enterpriseNumberScheme`. It does not decide which Peppol identifier is registered (the country does, as the next section shows), but it is written into the documents the company sends, as the scheme of the seller's legal identifier. Leave it out unless the country expects a specific one. Which schemes are registered for you [#which-schemes-are-registered-for-you] Each country has its own [Peppol Electronic Address Scheme](https://docs.peppol.eu/poacc/billing/3.0/codelist/eas/), and Recommand tries to automatically register the correct scheme for you. The Peppol address is also what a document is sent from. A company with no identifier at all cannot send: the attempt fails with *no sending company identifier found*, and it cannot be published as a recipient either, because there is no address to publish. In some countries, adding an identifier yourself is part of onboarding rather than an optional extra. Adding identifiers by hand [#adding-identifiers-by-hand] Whatever the defaults do, the full set is yours to manage: [list identifiers](/reference/company-identifiers/get-company-identifiers), [add one](/reference/company-identifiers/create-company-identifier), [update one](/reference/company-identifiers/update-company-identifier) or [remove one](/reference/company-identifiers/delete-company-identifier). Every identifier you add is registered in the SMP as another address the company can be reached on. ```bash curl -X POST https://app.recommand.eu/api/v1/companies/{companyId}/identifiers \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d '{"scheme":"0007","identifier":"5567321707"}' ``` This is also the escape hatch for a country with no defaults, and for the case where your customers know a company by a different identifier than the one registered for it. Registering for both directions [#registering-for-both-directions] Sending needs no registration of its own; receiving does. So register the company as a recipient, which is the default: ```json { "isSmpRecipient": true } ``` What that means: * The company becomes findable on the Peppol network and can be delivered to through Recommand's access point, while sending its own documents out through the same access point. * Recipient registration is **exclusive**. If the company already receives through another Peppol provider, registration fails until it is deregistered there. What that takes depends on the country, which the next section covers. * The document types the company accepts are registered along with it, based on its country. Which ones those are is covered further down. * The company is only published once it is verified. If the company still receives elsewhere and you do not want to move that yet, register it with `isSmpRecipient: false` and start with sending only. Flipping the field later publishes it as a recipient. Moving an existing registration [#moving-an-existing-registration] Recipient registration is exclusive everywhere: a company that already receives through another Peppol provider has to be deregistered there before it can be registered with Recommand. If you do not know who the current provider is, look the company up as a recipient: the [verify endpoint](/reference/recipients/verify-recipient) returns the SMP it is published on, which names the provider to ask. Verify the company [#verify-the-company] A company cannot exchange documents on Peppol until an authorised representative has confirmed their identity. The company object exposes this as `isVerified`, and it stays `false` until the check is done. The flow is short: 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. The representative fills in their name and completes the identity check. 3. `isVerified` flips to `true` and the company is published on the Peppol network. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. Building verification into your onboarding [#building-verification-into-your-onboarding] With one company you would click through this once. With many, verification is part of the flow you build: every company you register needs its own, and it is the step most likely to leave a customer stuck halfway. **Show the URL immediately.** The create-company response already carries `verificationUrl`, so no extra call is needed. Put it in front of the user while they are still in your onboarding. **Ask for a fresh one when the moment has passed.** Links get lost, and companies you created earlier never had one shown. The [verify company endpoint](/reference/companies/verify-company) starts a new verification session: ```bash curl -X POST https://app.recommand.eu/api/v1/companies/{companyId}/verify \ -u key_xxx:secret_xxx ``` The `company.verification` webhook fires when verification reaches a final state: `verified`, `rejected` or `error`. A company that comes back `rejected` or `error` and is not surfaced anywhere sits silently unusable. See [working with webhooks](/docs/working-with-webhooks). **Respect `isVerified` in your own UI.** Do not let a user press send for a company that is not verified yet; this will result in an error. You should inform the user what is missing instead. **Re-verify after identifier changes.** Updating a company's `vatNumber` or `enterpriseNumber` resets `isVerified` to `false`. Check the field after an update and present a new `verificationUrl` if it flipped. The full mechanics are in the [company verification guide](/docs/company-verification). Pick the document format [#pick-the-document-format] Send **Peppol BIS 3 UBL**, over the standard Peppol billing process. It is the format most Peppol participants accept. Some countries have a national CIUS on top of EN 16931, SI-UBL 2.0 in the Netherlands, for instance. If a buyer asks for one and Recommand supports it, you name its document type in `doctypeId` on the send request; the document you post stays the same, because the format decides how the XML is written, not which fields you fill in. Before a first send to a new recipient, check two things: * **Is the recipient on the network?** The [verify endpoint](/reference/recipients/verify-recipient) answers that, and sending performs the same check automatically. * **Does the recipient accept this document type?** The [verify document support endpoint](/reference/recipients/verify-document-support) answers that, which matters more abroad than at home: a recipient in another country may be registered for its own national profile only. See [verifying recipients](/docs/verifying-recipients) for the full flow, including what to do when a recipient cannot be reached. Send a document [#send-a-document] One endpoint sends everything: [`POST /:companyId/send`](/reference/sending/send-document). The `companyId` is the sender, `recipient` is the Peppol address of the receiver, and `document` is the invoice or credit note as JSON. Recommand will validate the document and generate the XML. Raw XML sending is supported as well: set `documentType` to `xml` and pass the document string in `document`, along with the correct `doctypeId`. See [working with raw UBL](/docs/ubl-format-guide#working-with-raw-ubl). ```javascript const response = await fetch( `https://app.recommand.eu/api/v1/${companyId}/send`, { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, // The body below, with doctypeId and countrySpecific where the country // needs them. body: JSON.stringify(sendRequest), } ); const result = await response.json(); if (!result.success) { // result.errors is keyed by field path, e.g. { "buyer.vatNumber": [...] } } ``` ```bash curl -X POST https://app.recommand.eu/api/v1/{companyId}/send \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @send-invoice.json ``` ```json title="send-invoice.json" { "recipient": "0208:0123456789", "documentType": "invoice", "document": { "invoiceNumber": "INV-2026-001", "issueDate": "2026-08-17", "dueDate": "2026-09-16", "currency": "EUR", "buyer": { "name": "Customer Company", "street": "Customer Street 1", "city": "Antwerp", "postalZone": "2000", "country": "BE", "vatNumber": "BE0987654321" }, "paymentMeans": [{ "iban": "BE68539007547034" }], "lines": [ { "name": "Consulting Services", "quantity": "10.00", "unitCode": "HUR", "netPriceAmount": "100.00", "vat": { "category": "S", "percentage": "21.00" } } ] } } ``` The seller block is filled in from the company when you leave it out, which is usually what you want: it keeps the company's registered identifiers and the document in agreement. Things worth wiring up while you are here: * **Validation errors.** Outgoing documents are always validated. A `success: false` response with `errors` keyed by field path is a document your recipient would have rejected, so surface it to the user who typed the data. * **Email fallback.** Pass `email.to` with `when: "on_peppol_failure"` to fall back to email when a recipient turns out not to be reachable over Peppol, or send with `recipient: null` for email-only delivery. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **PDFs.** `pdfGeneration.enabled` attaches a generated PDF of the document. You can also attach an existing PDF (or other files) via `attachments`; see [adding attachments](/docs/sending-invoices#adding-attachments). For a full field reference, see [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Document types registered for you [#document-types-registered-for-you] When you register the company as a recipient, it is published for the two document types that carry almost all cross-border traffic: | Document type | Process | | ------------------------------ | --------------------------------------------- | | Invoice (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Credit note (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | Anything sent to the company in one of these formats is accepted, validated, stored and handed to you. A sender who tries a document type the company is not published for gets an error before delivery, which is exactly the point of the registration. Need more document types, such as a national CIUS your suppliers use, self-billing, message level responses, invoice responses? Register the combinations you want with the [create company document type endpoint](/reference/company-document-types/create-company-document-type) or through the dashboard. Get incoming documents into your product [#get-incoming-documents-into-your-product] Recommand receives, validates and stores incoming documents for every company in your team. You pick them up in one of two ways. Webhooks (recommended) [#webhooks-recommended] Register an endpoint once with the [create webhook endpoint](/reference/webhooks/create-webhook) or through the dashboard and events are pushed to you as they happen, `document.received` among them: ```javascript await fetch("https://app.recommand.eu/api/v1/webhooks", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify(webhook), // the body below }); ``` ```bash curl -X POST https://app.recommand.eu/api/v1/webhooks \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @create-webhook.json ``` ```json title="create-webhook.json" { "url": "https://your-app.example/webhooks/recommand", "companyId": null, "secret": "your_webhook_signing_secret" } ``` `companyId: null` covers every company in the team. Pass a `secret` and verify the HMAC SHA-256 signature on every delivery before you trust the payload. Switch on `event.eventType`, and acknowledge with a 200 before doing the heavy processing. Both are covered in [working with webhooks](/docs/working-with-webhooks). Polling the inbox [#polling-the-inbox] If you would rather pull, the [inbox endpoint](/reference/documents/get-inbox) lists unread documents: ```javascript const inbox = await fetch("https://app.recommand.eu/api/v1/inbox", { headers: { Authorization: auth }, }).then((r) => r.json()); ``` Mark each document as read with the [mark as read endpoint](/reference/documents/mark-as-read) once your system has it, so it drops off the list. After you have the document [#after-you-have-the-document] * Fetch details, the original XML or a rendered PDF from the [documents endpoints](/reference/documents/get-document). * Route documents to the right customer with [labels and suppliers](/docs/suppliers-and-labels), and automate that routing with [rules](/docs/rules). * Let Recommand mail incoming documents on to an address of your choosing when that is easier than an API call, see [email delivery and notifications](/docs/email-delivery-and-notifications). For the full picture, including retries and idempotency, see [receiving documents](/docs/receiving-documents). Going live [#going-live] Before you switch your first real customer over, walk this list: * **A valid subscription in production.** Playgrounds skip the subscription check; production does not. * **Verification handled in your UI.** Show the `verificationUrl` at the right moment, make it forwardable, and handle the `company.verification` webhook so a company that comes back `rejected` or `error` does not sit silently unusable. * **`isVerified` respected.** Do not let a user press send for a company that is not verified yet; explain what is missing instead. * **Webhook endpoint hardened.** Signature verification, a fast 200, retries and idempotency on your side. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of the person who can fix it. * **One real document, end to end.** Send an invoice between two companies you control on production before letting customers in. Documents are counted per team, with the volume of all your companies pooled, so onboarding more companies lowers your price per document rather than adding per-company fees. Received documents count towards the quota as well as sent ones, so budget for both sides of the exchange. Generated XML through `generate` is not billed; emails and submitted reports are. Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Sending Peppol documents in other countries for your own company (/getting-started/other/business/sending) This guide walks through everything needed to exchange Peppol documents for a company registered in a country other than Belgium, France or the Netherlands, assuming you are setting up your own company in another country, and that the company only sends documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are setting up [#what-you-are-setting-up] You are putting one company, your own or one you represent, on the Peppol network, so it can exchange invoices electronically with its customers and suppliers. The setup is a one-time affair: registering the company and getting it verified takes a few minutes in the [Recommand dashboard](https://app.recommand.eu), and there is nothing to gain from automating something you do once. What you do integrate is the part that repeats: sending and receiving documents. Our existing [integrations](/integrations) can also connect Recommand to accounting or invoicing software you already use, with no code at all. A single team can hold several companies at no extra cost, useful if you run more than one legal entity, and the document volume of all of them counts towards one plan. If you are building e-invoicing or Peppol integration into a product for your own customers, and will be registering their companies rather than only your own, switch the first answer above to **Many companies**. The API is the same; what changes is how companies, verification and billing are organised. Peppol internationally [#peppol-internationally] Each country carries one of three support levels: | Level | What it means | | --------------- | ----------------------------------------------------------------------------------------------------- | | **Supported** | Companies work end to end, and the country's own identifier schemes are registered for you. | | **Partial** | Companies are functional, but country-specific features or local requirements may not be covered yet. | | **Unsupported** | New companies cannot be created there, and existing companies cannot be switched to it. | The [countries page on our website](https://recommand.eu/countries) is the source of truth: it shows the level for the country you select. Support is added country by country. If the one you need is unsupported, or supported only partially in a way that blocks you, mail [support@recommand.eu](mailto:support@recommand.eu). Knowing there is demand is what moves a country up the list. Create your account and API credentials [#create-your-account-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). 2. Your account starts with a **team**. The team holds your company, your subscription and your document history, and you can invite colleagues to it. 3. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 4. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Sending and receiving can also be driven entirely from the dashboard or through an [integration](/integrations), and each section below says how. The dashboard is available in English, Dutch, French and German; pick your language on the [account page](https://app.recommand.eu/account). Try it safely first [#try-it-safely-first] You do not have to get anything right the first time. Everything below, adding the company, registering it, sending and receiving, can be done in a **playground team** first, where nothing is delivered over the real Peppol network, nothing is registered on it, and nothing is billed. Open the team switcher at the top of the [dashboard](https://app.recommand.eu) and pick **Add playground**. Give it a name, leave the Peppol Test Network box unticked, and you are switched into the new team straight away. There is nothing to set up beyond that. Add a company to that team and use it as both sender and recipient to watch a document travel end to end. When the flow does what you want, repeat it once in your real team. Two things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. A playground stays useful after you are live, too: it is the safest place to try a new invoice layout or a new integration. See [how can I test without sending real invoices](/faq/api-and-development/how-can-i-test-without-sending-real-invoices). Playground companies are not registered on the Peppol network and playground documents never leave it, so nothing you do there affects your real company. Register the company [#register-the-company] You are registering one company, once, so the dashboard is the shortest path. 1. Open [Companies](https://app.recommand.eu/companies) and start the company wizard. 2. Fill in the legal name, address and country, plus the identifiers described in the next section. 3. Choose whether the company should also **receive** documents over Peppol, or only send them. 4. Save. The company is registered on the Peppol network as part of this step: its identifiers and the document types for its country are set up for you. Right after saving, the dashboard offers the verification step, which the section below covers. Note the company's ID from its detail page. Every API call for sending and receiving takes it in the path. The [create company endpoint](/reference/companies/create-company) does exactly the same thing, and returns the company `id` and a `verificationUrl` in one response. It is worth using when company creation is part of a flow you are automating, which is likely the case if you are registering many companies. Switch the first answer above to **Many companies** for that version. Add each legal entity as its own company: run the wizard again. There is no per-company fee, and all of them share your document volume. Identifiers and the Peppol address [#identifiers-and-the-peppol-address] Three fields decide how the company is published on the network: | Field | Value | | ------------------ | ------------------------------------------------------- | | `country` | ISO 3166-1 alpha-2, e.g. `"DE"`, `"SE"`, `"IT"` | | `enterpriseNumber` | The national company or organisation number | | `vatNumber` | The VAT number, **starting with the same country code** | ```json title="company.json" { "name": "Exempel AB", "address": "Storgatan 1", "postalCode": "111 51", "city": "Stockholm", "country": "SE", "enterpriseNumber": "5567321707", "vatNumber": "SE556732170701" } ``` A VAT number whose country code does not match `country` is rejected. That is the one identifier rule enforced for every country. National format checks (the modulo-97 check digit for Belgium, the KVK length for the Netherlands, the CVR length for Denmark) only exist for the countries that have them; elsewhere the number is taken as given, so check it before you send it. There is also an optional `enterpriseNumberScheme`. It does not decide which Peppol identifier is registered (the country does, as the next section shows), but it is written into the documents the company sends, as the scheme of the seller's legal identifier. Leave it out unless the country expects a specific one. Which schemes are registered for you [#which-schemes-are-registered-for-you] Each country has its own [Peppol Electronic Address Scheme](https://docs.peppol.eu/poacc/billing/3.0/codelist/eas/), and Recommand tries to automatically register the correct scheme for you. The Peppol address is also what a document is sent from. A company with no identifier at all cannot send: the attempt fails with *no sending company identifier found*, and it cannot be published as a recipient either, because there is no address to publish. In some countries, adding an identifier yourself is part of onboarding rather than an optional extra. Adding identifiers by hand [#adding-identifiers-by-hand] Whatever the defaults do, the full set is yours to manage: [list identifiers](/reference/company-identifiers/get-company-identifiers), [add one](/reference/company-identifiers/create-company-identifier), [update one](/reference/company-identifiers/update-company-identifier) or [remove one](/reference/company-identifiers/delete-company-identifier). Every identifier you add is registered in the SMP as another address the company can be reached on. ```bash curl -X POST https://app.recommand.eu/api/v1/companies/{companyId}/identifiers \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d '{"scheme":"0007","identifier":"5567321707"}' ``` This is also the escape hatch for a country with no defaults, and for the case where your customers know a company by a different identifier than the one registered for it. Registering for sending only [#registering-for-sending-only] Because you are only looking to send invoices or other documents, register the company **without** recipient registration: set `isSmpRecipient` to `false` (or leave the checkbox unticked in the dashboard). ```json { "isSmpRecipient": false } ``` What that means: * The company is not published as a recipient on an SMP, so nothing is delivered to it over Peppol through your integration. * Registration succeeds even when the company already receives its documents through another Peppol provider. The other Peppol provider will remain in charge for processing received documents for this company. * Nothing changes for sending: outgoing documents leave through the access point as normal. You can flip `isSmpRecipient` to `true` on an existing company at any time. Recommand then publishes it as a recipient and registers the document types for its country. That registration is exclusive, so the company has to be deregistered at its current provider first. Verify the company [#verify-the-company] A company cannot exchange documents on Peppol until an authorised representative has confirmed their identity. The company object exposes this as `isVerified`, and it stays `false` until the check is done. The flow is short: 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. The representative fills in their name and completes the identity check. 3. `isVerified` flips to `true` and the company is published on the Peppol network. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. Verifying once, in the dashboard [#verifying-once-in-the-dashboard] You have one company, and it is verified once. There is nothing here worth automating: open [Companies](https://app.recommand.eu/companies) in the dashboard, pick the company and start verification. If you are authorised to act for the company, complete the check yourself; otherwise use the button to forward the link to whoever is. The page is self-contained and works in any browser. The person completing it does not need a Recommand account. That is the whole step. From here on the API takes over: sending and receiving documents is what you actually integrate. Updating the company's `vatNumber` or `enterpriseNumber` sets `isVerified` back to `false`, and the company has to be verified again before it can exchange documents. Pick the document format [#pick-the-document-format] Send **Peppol BIS 3 UBL**, over the standard Peppol billing process. It is the format most Peppol participants accept. Some countries have a national CIUS on top of EN 16931, SI-UBL 2.0 in the Netherlands, for instance. If a buyer asks for one and Recommand supports it, you name its document type in `doctypeId` on the send request; the document you post stays the same, because the format decides how the XML is written, not which fields you fill in. Before a first send to a new recipient, check two things: * **Is the recipient on the network?** The [verify endpoint](/reference/recipients/verify-recipient) answers that, and sending performs the same check automatically. * **Does the recipient accept this document type?** The [verify document support endpoint](/reference/recipients/verify-document-support) answers that, which matters more abroad than at home: a recipient in another country may be registered for its own national profile only. See [verifying recipients](/docs/verifying-recipients) for the full flow, including what to do when a recipient cannot be reached. Send a document [#send-a-document] One endpoint sends everything: [`POST /:companyId/send`](/reference/sending/send-document). The `companyId` is the sender, `recipient` is the Peppol address of the receiver, and `document` is the invoice or credit note as JSON. Recommand will validate the document and generate the XML. Raw XML sending is supported as well: set `documentType` to `xml` and pass the document string in `document`, along with the correct `doctypeId`. See [working with raw UBL](/docs/ubl-format-guide#working-with-raw-ubl). ```bash curl -X POST https://app.recommand.eu/api/v1/{companyId}/send \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @send-invoice.json ``` ```json title="send-invoice.json" { "recipient": "0208:0123456789", "documentType": "invoice", "document": { "invoiceNumber": "INV-2026-001", "issueDate": "2026-08-17", "dueDate": "2026-09-16", "currency": "EUR", "buyer": { "name": "Customer Company", "street": "Customer Street 1", "city": "Antwerp", "postalZone": "2000", "country": "BE", "vatNumber": "BE0987654321" }, "paymentMeans": [{ "iban": "BE68539007547034" }], "lines": [ { "name": "Consulting Services", "quantity": "10.00", "unitCode": "HUR", "netPriceAmount": "100.00", "vat": { "category": "S", "percentage": "21.00" } } ] } } ``` The seller block is filled in from your company when you leave it out, which is usually what you want: it keeps your registered identifiers and the document in agreement. The full field reference lives in [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Worth wiring up while you are here: * **Validation errors.** Outgoing documents are always validated. A `success: false` response with `errors` keyed by field path is a document the recipient would have rejected. Surface it wherever the data was typed. * **Email fallback.** Pass `email.to` with `when: "on_peppol_failure"` to fall back to email when a recipient turns out not to be reachable over Peppol, or send with `recipient: null` for email-only delivery. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **PDFs.** `pdfGeneration.enabled` attaches a generated PDF of the document. You can also attach an existing PDF (or other files) via `attachments`; see [adding attachments](/docs/sending-invoices#adding-attachments). For a full field reference, see [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Sending without writing code [#sending-without-writing-code] The same send is available two other ways, and they mix freely with the API: * **From the dashboard.** [Send document](https://app.recommand.eu/send-document) takes the recipient and the invoice lines, previews what the recipient will get, and remembers your usual settings. You can also drop an existing UBL or CII XML file into the upload zone if your software already produces one. * **From your accounting or invoicing software.** If you use one of the supported tools, let it do the work: your invoices flow to Recommand and out over Peppol without retyping. See [integrations](/integrations) for the current list, including Microsoft Business Central, Exact Online, Yuki, ClearFacts, ERPNext and Harvest. Whichever route you use, Recommand validates a document before it leaves. If a field is missing or malformed you get a clear error instead of a rejection from the recipient days later. See the [troubleshooting guide](/docs/troubleshooting-guide) for the errors you are most likely to run into. Going live [#going-live] A short list before you start sending or receiving real invoices: * **A valid subscription**, so sending is not blocked. Playgrounds skip that check; production does not. * **The company verified**, with `isVerified` true. Until then it cannot exchange documents. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of whoever can fix it rather than logging it. * **Webhook endpoint hardened**, if you took that route: signature verification, a fast 200, retries and idempotency on your side. * **One real document sent and received**, ideally between two companies you control, so you have seen both ends. * **Notification addresses set**, so incoming documents also reach a mailbox somebody reads. Once you are live, your Peppol address is public on the network: suppliers can find and reach you without any action from you. Ask customers who still email PDFs to switch, and let your accountant know where the documents now land. Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Receiving Peppol documents in other countries for your own company (/getting-started/other/business/receiving) This guide walks through everything needed to exchange Peppol documents for a company registered in a country other than Belgium, France or the Netherlands, assuming you are setting up your own company in another country, and that the company only receives documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are setting up [#what-you-are-setting-up] You are putting one company, your own or one you represent, on the Peppol network, so it can exchange invoices electronically with its customers and suppliers. The setup is a one-time affair: registering the company and getting it verified takes a few minutes in the [Recommand dashboard](https://app.recommand.eu), and there is nothing to gain from automating something you do once. What you do integrate is the part that repeats: sending and receiving documents. Our existing [integrations](/integrations) can also connect Recommand to accounting or invoicing software you already use, with no code at all. A single team can hold several companies at no extra cost, useful if you run more than one legal entity, and the document volume of all of them counts towards one plan. If you are building e-invoicing or Peppol integration into a product for your own customers, and will be registering their companies rather than only your own, switch the first answer above to **Many companies**. The API is the same; what changes is how companies, verification and billing are organised. Peppol internationally [#peppol-internationally] Each country carries one of three support levels: | Level | What it means | | --------------- | ----------------------------------------------------------------------------------------------------- | | **Supported** | Companies work end to end, and the country's own identifier schemes are registered for you. | | **Partial** | Companies are functional, but country-specific features or local requirements may not be covered yet. | | **Unsupported** | New companies cannot be created there, and existing companies cannot be switched to it. | The [countries page on our website](https://recommand.eu/countries) is the source of truth: it shows the level for the country you select. Support is added country by country. If the one you need is unsupported, or supported only partially in a way that blocks you, mail [support@recommand.eu](mailto:support@recommand.eu). Knowing there is demand is what moves a country up the list. Create your account and API credentials [#create-your-account-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). 2. Your account starts with a **team**. The team holds your company, your subscription and your document history, and you can invite colleagues to it. 3. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 4. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Sending and receiving can also be driven entirely from the dashboard or through an [integration](/integrations), and each section below says how. The dashboard is available in English, Dutch, French and German; pick your language on the [account page](https://app.recommand.eu/account). Try it safely first [#try-it-safely-first] You do not have to get anything right the first time. Everything below, adding the company, registering it, sending and receiving, can be done in a **playground team** first, where nothing is delivered over the real Peppol network, nothing is registered on it, and nothing is billed. Open the team switcher at the top of the [dashboard](https://app.recommand.eu) and pick **Add playground**. Give it a name, leave the Peppol Test Network box unticked, and you are switched into the new team straight away. There is nothing to set up beyond that. Add a company to that team and use it as both sender and recipient to watch a document travel end to end. When the flow does what you want, repeat it once in your real team. Two things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. A playground stays useful after you are live, too: it is the safest place to try a new invoice layout or a new integration. See [how can I test without sending real invoices](/faq/api-and-development/how-can-i-test-without-sending-real-invoices). Playground companies are not registered on the Peppol network and playground documents never leave it, so nothing you do there affects your real company. Register the company [#register-the-company] You are registering one company, once, so the dashboard is the shortest path. 1. Open [Companies](https://app.recommand.eu/companies) and start the company wizard. 2. Fill in the legal name, address and country, plus the identifiers described in the next section. 3. Choose whether the company should also **receive** documents over Peppol, or only send them. 4. Save. The company is registered on the Peppol network as part of this step: its identifiers and the document types for its country are set up for you. Right after saving, the dashboard offers the verification step, which the section below covers. Note the company's ID from its detail page. Every API call for sending and receiving takes it in the path. The [create company endpoint](/reference/companies/create-company) does exactly the same thing, and returns the company `id` and a `verificationUrl` in one response. It is worth using when company creation is part of a flow you are automating, which is likely the case if you are registering many companies. Switch the first answer above to **Many companies** for that version. Add each legal entity as its own company: run the wizard again. There is no per-company fee, and all of them share your document volume. Identifiers and the Peppol address [#identifiers-and-the-peppol-address] Three fields decide how the company is published on the network: | Field | Value | | ------------------ | ------------------------------------------------------- | | `country` | ISO 3166-1 alpha-2, e.g. `"DE"`, `"SE"`, `"IT"` | | `enterpriseNumber` | The national company or organisation number | | `vatNumber` | The VAT number, **starting with the same country code** | ```json title="company.json" { "name": "Exempel AB", "address": "Storgatan 1", "postalCode": "111 51", "city": "Stockholm", "country": "SE", "enterpriseNumber": "5567321707", "vatNumber": "SE556732170701" } ``` A VAT number whose country code does not match `country` is rejected. That is the one identifier rule enforced for every country. National format checks (the modulo-97 check digit for Belgium, the KVK length for the Netherlands, the CVR length for Denmark) only exist for the countries that have them; elsewhere the number is taken as given, so check it before you send it. There is also an optional `enterpriseNumberScheme`. It does not decide which Peppol identifier is registered (the country does, as the next section shows), but it is written into the documents the company sends, as the scheme of the seller's legal identifier. Leave it out unless the country expects a specific one. Which schemes are registered for you [#which-schemes-are-registered-for-you] Each country has its own [Peppol Electronic Address Scheme](https://docs.peppol.eu/poacc/billing/3.0/codelist/eas/), and Recommand tries to automatically register the correct scheme for you. The Peppol address is also what a document is sent from. A company with no identifier at all cannot send: the attempt fails with *no sending company identifier found*, and it cannot be published as a recipient either, because there is no address to publish. In some countries, adding an identifier yourself is part of onboarding rather than an optional extra. Adding identifiers by hand [#adding-identifiers-by-hand] Whatever the defaults do, the full set is yours to manage: [list identifiers](/reference/company-identifiers/get-company-identifiers), [add one](/reference/company-identifiers/create-company-identifier), [update one](/reference/company-identifiers/update-company-identifier) or [remove one](/reference/company-identifiers/delete-company-identifier). Every identifier you add is registered in the SMP as another address the company can be reached on. ```bash curl -X POST https://app.recommand.eu/api/v1/companies/{companyId}/identifiers \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d '{"scheme":"0007","identifier":"5567321707"}' ``` This is also the escape hatch for a country with no defaults, and for the case where your customers know a company by a different identifier than the one registered for it. Registering as a recipient [#registering-as-a-recipient] To receive documents, the company must be published as a recipient on an SMP (Service Metadata Publisher). That is what `isSmpRecipient` does, and it is the default: ```json { "isSmpRecipient": true } ``` What that means: * The company becomes findable on the Peppol network: any sender can look it up and deliver to it via the Peppol network. * Recipient registration is **exclusive**. If the company is already registered for receiving through another Peppol provider, registration fails until it is deregistered there. * The document types the company accepts are registered along with it, based on its country. Which ones those are is covered further down. * The company is only published once it is verified. Moving an existing registration [#moving-an-existing-registration] Recipient registration is exclusive everywhere: a company that already receives through another Peppol provider has to be deregistered there before it can be registered with Recommand. If you do not know who the current provider is, look the company up as a recipient: the [verify endpoint](/reference/recipients/verify-recipient) returns the SMP it is published on, which names the provider to ask. Verify the company [#verify-the-company] A company cannot exchange documents on Peppol until an authorised representative has confirmed their identity. The company object exposes this as `isVerified`, and it stays `false` until the check is done. The flow is short: 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. The representative fills in their name and completes the identity check. 3. `isVerified` flips to `true` and the company is published on the Peppol network. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. Verifying once, in the dashboard [#verifying-once-in-the-dashboard] You have one company, and it is verified once. There is nothing here worth automating: open [Companies](https://app.recommand.eu/companies) in the dashboard, pick the company and start verification. If you are authorised to act for the company, complete the check yourself; otherwise use the button to forward the link to whoever is. The page is self-contained and works in any browser. The person completing it does not need a Recommand account. That is the whole step. From here on the API takes over: sending and receiving documents is what you actually integrate. Updating the company's `vatNumber` or `enterpriseNumber` sets `isVerified` back to `false`, and the company has to be verified again before it can exchange documents. Document types registered for you [#document-types-registered-for-you] When you register the company as a recipient, it is published for the two document types that carry almost all cross-border traffic: | Document type | Process | | ------------------------------ | --------------------------------------------- | | Invoice (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Credit note (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | Anything sent to the company in one of these formats is accepted, validated, stored and handed to you. A sender who tries a document type the company is not published for gets an error before delivery, which is exactly the point of the registration. Need more document types, such as a national CIUS your suppliers use, self-billing, message level responses, invoice responses? Register the combinations you want with the [create company document type endpoint](/reference/company-document-types/create-company-document-type) or through the dashboard. Pick up incoming documents [#pick-up-incoming-documents] Once the company is published as a recipient, everything sent to it arrives in Recommand automatically. There are two ways to get the documents into your own systems. Webhooks (recommended) [#webhooks-recommended] Register an endpoint once with the [create webhook endpoint](/reference/webhooks/create-webhook) and events are pushed to you as they happen, `document.received` among them: ```bash curl -X POST https://app.recommand.eu/api/v1/webhooks \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @create-webhook.json ``` ```json title="create-webhook.json" { "url": "https://your-app.example/webhooks/recommand", "companyId": null, "secret": "your_webhook_signing_secret" } ``` Pass a `secret` and verify the HMAC SHA-256 signature on every delivery before you trust the payload, then acknowledge with a 200 before doing the heavy processing. Both are covered in [working with webhooks](/docs/working-with-webhooks). Polling the inbox [#polling-the-inbox] If you would rather pull, the [inbox endpoint](/reference/documents/get-inbox) lists unread documents, and [mark as read](/reference/documents/mark-as-read) drops one off the list once your system has it. Fetch details, the original XML or a rendered PDF from the [documents endpoints](/reference/documents/get-document). Receiving without writing code [#receiving-without-writing-code] * **In the dashboard.** Incoming invoices appear under [Sent and received](https://app.recommand.eu/transmitted-documents), with the original XML, a readable rendering, attachments and the delivery history. * **By email.** Add notification email addresses per company so incoming documents land in the mailbox your bookkeeping already watches, attachments included. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **In your accounting software.** Forward incoming documents straight to Exact Online, Yuki, ClearFacts or another supported tool, see [integrations](/integrations). Two things worth setting up early, whichever route you take: * **Labels and suppliers** to keep documents organised as volume grows, see [suppliers and labels](/docs/suppliers-and-labels). * **Rules** to act on incoming documents automatically: forwarding, labelling, notifying, see [rules](/docs/rules). The full picture, including retries and idempotency, is in [receiving documents](/docs/receiving-documents). Going live [#going-live] A short list before you start sending or receiving real invoices: * **A valid subscription**, so sending is not blocked. Playgrounds skip that check; production does not. * **The company verified**, with `isVerified` true. Until then it cannot exchange documents. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of whoever can fix it rather than logging it. * **Webhook endpoint hardened**, if you took that route: signature verification, a fast 200, retries and idempotency on your side. * **One real document sent and received**, ideally between two companies you control, so you have seen both ends. * **Notification addresses set**, so incoming documents also reach a mailbox somebody reads. Once you are live, your Peppol address is public on the network: suppliers can find and reach you without any action from you. Ask customers who still email PDFs to switch, and let your accountant know where the documents now land. Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Sending and receiving Peppol documents in other countries for your own company](/getting-started/other/business/sending-and-receiving.md) # Sending and receiving Peppol documents in other countries for your own company (/getting-started/other/business/sending-and-receiving) This guide walks through everything needed to exchange Peppol documents for a company registered in a country other than Belgium, France or the Netherlands, assuming you are setting up your own company in another country, and that the company sends and receives documents over Peppol. Change any of the three answers at the top of the page to get the guide for a different situation. What you are setting up [#what-you-are-setting-up] You are putting one company, your own or one you represent, on the Peppol network, so it can exchange invoices electronically with its customers and suppliers. The setup is a one-time affair: registering the company and getting it verified takes a few minutes in the [Recommand dashboard](https://app.recommand.eu), and there is nothing to gain from automating something you do once. What you do integrate is the part that repeats: sending and receiving documents. Our existing [integrations](/integrations) can also connect Recommand to accounting or invoicing software you already use, with no code at all. A single team can hold several companies at no extra cost, useful if you run more than one legal entity, and the document volume of all of them counts towards one plan. If you are building e-invoicing or Peppol integration into a product for your own customers, and will be registering their companies rather than only your own, switch the first answer above to **Many companies**. The API is the same; what changes is how companies, verification and billing are organised. Peppol internationally [#peppol-internationally] Each country carries one of three support levels: | Level | What it means | | --------------- | ----------------------------------------------------------------------------------------------------- | | **Supported** | Companies work end to end, and the country's own identifier schemes are registered for you. | | **Partial** | Companies are functional, but country-specific features or local requirements may not be covered yet. | | **Unsupported** | New companies cannot be created there, and existing companies cannot be switched to it. | The [countries page on our website](https://recommand.eu/countries) is the source of truth: it shows the level for the country you select. Support is added country by country. If the one you need is unsupported, or supported only partially in a way that blocks you, mail [support@recommand.eu](mailto:support@recommand.eu). Knowing there is demand is what moves a country up the list. Create your account and API credentials [#create-your-account-and-api-credentials] 1. Sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup). 2. Your account starts with a **team**. The team holds your company, your subscription and your document history, and you can invite colleagues to it. 3. Create an API key on the [API keys page](https://app.recommand.eu/api-keys). Note the key, the secret and your team ID. 4. Check the credentials with a request that needs no data of its own: ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` It answers `{"success": true}` when the key and secret are accepted, and 401 when they are not, so it tells you about your credentials and nothing else. All endpoints in this guide live under `https://app.recommand.eu/api/v1` and accept HTTP Basic authentication with the key as username and the secret as password. If you would rather not store a long-lived secret, JWT API keys and OAuth2 with a JWT assertion are available too, see the [authentication guide](/docs/authentication). Sending and receiving can also be driven entirely from the dashboard or through an [integration](/integrations), and each section below says how. The dashboard is available in English, Dutch, French and German; pick your language on the [account page](https://app.recommand.eu/account). Try it safely first [#try-it-safely-first] You do not have to get anything right the first time. Everything below, adding the company, registering it, sending and receiving, can be done in a **playground team** first, where nothing is delivered over the real Peppol network, nothing is registered on it, and nothing is billed. Open the team switcher at the top of the [dashboard](https://app.recommand.eu) and pick **Add playground**. Give it a name, leave the Peppol Test Network box unticked, and you are switched into the new team straight away. There is nothing to set up beyond that. Add a company to that team and use it as both sender and recipient to watch a document travel end to end. When the flow does what you want, repeat it once in your real team. Two things worth knowing before you start: * **`POST /:companyId/generate`** takes the same body as the send endpoint minus the email delivery options, which have no meaning when nothing is delivered, and returns the exact XML that sending would produce, fully validated, without transmitting, storing or billing it. Raw XML is not accepted here: there is nothing to generate from a document you already have. It also returns the resolved `documentType`, `doctypeId` and `processId`. * **Failure addresses.** In a playground that is not connected to the Peppol Test Network, sending to `404:404` or `0208:1234567894` always fails, so you can exercise your error handling. Any other unregistered recipient is skipped without an error. A playground stays useful after you are live, too: it is the safest place to try a new invoice layout or a new integration. See [how can I test without sending real invoices](/faq/api-and-development/how-can-i-test-without-sending-real-invoices). Playground companies are not registered on the Peppol network and playground documents never leave it, so nothing you do there affects your real company. Register the company [#register-the-company] You are registering one company, once, so the dashboard is the shortest path. 1. Open [Companies](https://app.recommand.eu/companies) and start the company wizard. 2. Fill in the legal name, address and country, plus the identifiers described in the next section. 3. Choose whether the company should also **receive** documents over Peppol, or only send them. 4. Save. The company is registered on the Peppol network as part of this step: its identifiers and the document types for its country are set up for you. Right after saving, the dashboard offers the verification step, which the section below covers. Note the company's ID from its detail page. Every API call for sending and receiving takes it in the path. The [create company endpoint](/reference/companies/create-company) does exactly the same thing, and returns the company `id` and a `verificationUrl` in one response. It is worth using when company creation is part of a flow you are automating, which is likely the case if you are registering many companies. Switch the first answer above to **Many companies** for that version. Add each legal entity as its own company: run the wizard again. There is no per-company fee, and all of them share your document volume. Identifiers and the Peppol address [#identifiers-and-the-peppol-address] Three fields decide how the company is published on the network: | Field | Value | | ------------------ | ------------------------------------------------------- | | `country` | ISO 3166-1 alpha-2, e.g. `"DE"`, `"SE"`, `"IT"` | | `enterpriseNumber` | The national company or organisation number | | `vatNumber` | The VAT number, **starting with the same country code** | ```json title="company.json" { "name": "Exempel AB", "address": "Storgatan 1", "postalCode": "111 51", "city": "Stockholm", "country": "SE", "enterpriseNumber": "5567321707", "vatNumber": "SE556732170701" } ``` A VAT number whose country code does not match `country` is rejected. That is the one identifier rule enforced for every country. National format checks (the modulo-97 check digit for Belgium, the KVK length for the Netherlands, the CVR length for Denmark) only exist for the countries that have them; elsewhere the number is taken as given, so check it before you send it. There is also an optional `enterpriseNumberScheme`. It does not decide which Peppol identifier is registered (the country does, as the next section shows), but it is written into the documents the company sends, as the scheme of the seller's legal identifier. Leave it out unless the country expects a specific one. Which schemes are registered for you [#which-schemes-are-registered-for-you] Each country has its own [Peppol Electronic Address Scheme](https://docs.peppol.eu/poacc/billing/3.0/codelist/eas/), and Recommand tries to automatically register the correct scheme for you. The Peppol address is also what a document is sent from. A company with no identifier at all cannot send: the attempt fails with *no sending company identifier found*, and it cannot be published as a recipient either, because there is no address to publish. In some countries, adding an identifier yourself is part of onboarding rather than an optional extra. Adding identifiers by hand [#adding-identifiers-by-hand] Whatever the defaults do, the full set is yours to manage: [list identifiers](/reference/company-identifiers/get-company-identifiers), [add one](/reference/company-identifiers/create-company-identifier), [update one](/reference/company-identifiers/update-company-identifier) or [remove one](/reference/company-identifiers/delete-company-identifier). Every identifier you add is registered in the SMP as another address the company can be reached on. ```bash curl -X POST https://app.recommand.eu/api/v1/companies/{companyId}/identifiers \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d '{"scheme":"0007","identifier":"5567321707"}' ``` This is also the escape hatch for a country with no defaults, and for the case where your customers know a company by a different identifier than the one registered for it. Registering for both directions [#registering-for-both-directions] Sending needs no registration of its own; receiving does. So register the company as a recipient, which is the default: ```json { "isSmpRecipient": true } ``` What that means: * The company becomes findable on the Peppol network and can be delivered to through Recommand's access point, while sending its own documents out through the same access point. * Recipient registration is **exclusive**. If the company already receives through another Peppol provider, registration fails until it is deregistered there. What that takes depends on the country, which the next section covers. * The document types the company accepts are registered along with it, based on its country. Which ones those are is covered further down. * The company is only published once it is verified. If the company still receives elsewhere and you do not want to move that yet, register it with `isSmpRecipient: false` and start with sending only. Flipping the field later publishes it as a recipient. Moving an existing registration [#moving-an-existing-registration] Recipient registration is exclusive everywhere: a company that already receives through another Peppol provider has to be deregistered there before it can be registered with Recommand. If you do not know who the current provider is, look the company up as a recipient: the [verify endpoint](/reference/recipients/verify-recipient) returns the SMP it is published on, which names the provider to ask. Verify the company [#verify-the-company] A company cannot exchange documents on Peppol until an authorised representative has confirmed their identity. The company object exposes this as `isVerified`, and it stays `false` until the check is done. The flow is short: 1. Open the verification URL (from the create-company response, the dashboard, or a fresh one from the [verify company endpoint](/reference/companies/verify-company)). 2. The representative fills in their name and completes the identity check. 3. `isVerified` flips to `true` and the company is published on the Peppol network. In some cases manual verification by our team will be required. If that's the case, `isVerified` will remain `false` until this manual verification is completed. The user is informed of this in the verification process. Verifying once, in the dashboard [#verifying-once-in-the-dashboard] You have one company, and it is verified once. There is nothing here worth automating: open [Companies](https://app.recommand.eu/companies) in the dashboard, pick the company and start verification. If you are authorised to act for the company, complete the check yourself; otherwise use the button to forward the link to whoever is. The page is self-contained and works in any browser. The person completing it does not need a Recommand account. That is the whole step. From here on the API takes over: sending and receiving documents is what you actually integrate. Updating the company's `vatNumber` or `enterpriseNumber` sets `isVerified` back to `false`, and the company has to be verified again before it can exchange documents. Pick the document format [#pick-the-document-format] Send **Peppol BIS 3 UBL**, over the standard Peppol billing process. It is the format most Peppol participants accept. Some countries have a national CIUS on top of EN 16931, SI-UBL 2.0 in the Netherlands, for instance. If a buyer asks for one and Recommand supports it, you name its document type in `doctypeId` on the send request; the document you post stays the same, because the format decides how the XML is written, not which fields you fill in. Before a first send to a new recipient, check two things: * **Is the recipient on the network?** The [verify endpoint](/reference/recipients/verify-recipient) answers that, and sending performs the same check automatically. * **Does the recipient accept this document type?** The [verify document support endpoint](/reference/recipients/verify-document-support) answers that, which matters more abroad than at home: a recipient in another country may be registered for its own national profile only. See [verifying recipients](/docs/verifying-recipients) for the full flow, including what to do when a recipient cannot be reached. Send a document [#send-a-document] One endpoint sends everything: [`POST /:companyId/send`](/reference/sending/send-document). The `companyId` is the sender, `recipient` is the Peppol address of the receiver, and `document` is the invoice or credit note as JSON. Recommand will validate the document and generate the XML. Raw XML sending is supported as well: set `documentType` to `xml` and pass the document string in `document`, along with the correct `doctypeId`. See [working with raw UBL](/docs/ubl-format-guide#working-with-raw-ubl). ```bash curl -X POST https://app.recommand.eu/api/v1/{companyId}/send \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @send-invoice.json ``` ```json title="send-invoice.json" { "recipient": "0208:0123456789", "documentType": "invoice", "document": { "invoiceNumber": "INV-2026-001", "issueDate": "2026-08-17", "dueDate": "2026-09-16", "currency": "EUR", "buyer": { "name": "Customer Company", "street": "Customer Street 1", "city": "Antwerp", "postalZone": "2000", "country": "BE", "vatNumber": "BE0987654321" }, "paymentMeans": [{ "iban": "BE68539007547034" }], "lines": [ { "name": "Consulting Services", "quantity": "10.00", "unitCode": "HUR", "netPriceAmount": "100.00", "vat": { "category": "S", "percentage": "21.00" } } ] } } ``` The seller block is filled in from your company when you leave it out, which is usually what you want: it keeps your registered identifiers and the document in agreement. The full field reference lives in [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Worth wiring up while you are here: * **Validation errors.** Outgoing documents are always validated. A `success: false` response with `errors` keyed by field path is a document the recipient would have rejected. Surface it wherever the data was typed. * **Email fallback.** Pass `email.to` with `when: "on_peppol_failure"` to fall back to email when a recipient turns out not to be reachable over Peppol, or send with `recipient: null` for email-only delivery. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **PDFs.** `pdfGeneration.enabled` attaches a generated PDF of the document. You can also attach an existing PDF (or other files) via `attachments`; see [adding attachments](/docs/sending-invoices#adding-attachments). For a full field reference, see [sending invoices](/docs/sending-invoices) and [sending credit notes](/docs/sending-credit-notes). Sending without writing code [#sending-without-writing-code] The same send is available two other ways, and they mix freely with the API: * **From the dashboard.** [Send document](https://app.recommand.eu/send-document) takes the recipient and the invoice lines, previews what the recipient will get, and remembers your usual settings. You can also drop an existing UBL or CII XML file into the upload zone if your software already produces one. * **From your accounting or invoicing software.** If you use one of the supported tools, let it do the work: your invoices flow to Recommand and out over Peppol without retyping. See [integrations](/integrations) for the current list, including Microsoft Business Central, Exact Online, Yuki, ClearFacts, ERPNext and Harvest. Whichever route you use, Recommand validates a document before it leaves. If a field is missing or malformed you get a clear error instead of a rejection from the recipient days later. See the [troubleshooting guide](/docs/troubleshooting-guide) for the errors you are most likely to run into. Document types registered for you [#document-types-registered-for-you] When you register the company as a recipient, it is published for the two document types that carry almost all cross-border traffic: | Document type | Process | | ------------------------------ | --------------------------------------------- | | Invoice (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | | Credit note (Peppol BIS 3 UBL) | `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` | Anything sent to the company in one of these formats is accepted, validated, stored and handed to you. A sender who tries a document type the company is not published for gets an error before delivery, which is exactly the point of the registration. Need more document types, such as a national CIUS your suppliers use, self-billing, message level responses, invoice responses? Register the combinations you want with the [create company document type endpoint](/reference/company-document-types/create-company-document-type) or through the dashboard. Pick up incoming documents [#pick-up-incoming-documents] Once the company is published as a recipient, everything sent to it arrives in Recommand automatically. There are two ways to get the documents into your own systems. Webhooks (recommended) [#webhooks-recommended] Register an endpoint once with the [create webhook endpoint](/reference/webhooks/create-webhook) and events are pushed to you as they happen, `document.received` among them: ```bash curl -X POST https://app.recommand.eu/api/v1/webhooks \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @create-webhook.json ``` ```json title="create-webhook.json" { "url": "https://your-app.example/webhooks/recommand", "companyId": null, "secret": "your_webhook_signing_secret" } ``` Pass a `secret` and verify the HMAC SHA-256 signature on every delivery before you trust the payload, then acknowledge with a 200 before doing the heavy processing. Both are covered in [working with webhooks](/docs/working-with-webhooks). Polling the inbox [#polling-the-inbox] If you would rather pull, the [inbox endpoint](/reference/documents/get-inbox) lists unread documents, and [mark as read](/reference/documents/mark-as-read) drops one off the list once your system has it. Fetch details, the original XML or a rendered PDF from the [documents endpoints](/reference/documents/get-document). Receiving without writing code [#receiving-without-writing-code] * **In the dashboard.** Incoming invoices appear under [Sent and received](https://app.recommand.eu/transmitted-documents), with the original XML, a readable rendering, attachments and the delivery history. * **By email.** Add notification email addresses per company so incoming documents land in the mailbox your bookkeeping already watches, attachments included. See [email delivery and notifications](/docs/email-delivery-and-notifications). * **In your accounting software.** Forward incoming documents straight to Exact Online, Yuki, ClearFacts or another supported tool, see [integrations](/integrations). Two things worth setting up early, whichever route you take: * **Labels and suppliers** to keep documents organised as volume grows, see [suppliers and labels](/docs/suppliers-and-labels). * **Rules** to act on incoming documents automatically: forwarding, labelling, notifying, see [rules](/docs/rules). The full picture, including retries and idempotency, is in [receiving documents](/docs/receiving-documents). Going live [#going-live] A short list before you start sending or receiving real invoices: * **A valid subscription**, so sending is not blocked. Playgrounds skip that check; production does not. * **The company verified**, with `isVerified` true. Until then it cannot exchange documents. * **Errors surfaced, not swallowed.** Validation errors name the field that is wrong; put that in front of whoever can fix it rather than logging it. * **Webhook endpoint hardened**, if you took that route: signature verification, a fast 200, retries and idempotency on your side. * **One real document sent and received**, ideally between two companies you control, so you have seen both ends. * **Notification addresses set**, so incoming documents also reach a mailbox somebody reads. Once you are live, your Peppol address is public on the network: suppliers can find and reach you without any action from you. Ask customers who still email PDFs to switch, and let your accountant know where the documents now land. Where to get help [#where-to-get-help] * **Troubleshooting.** Common rejections, delivery failures and validation errors are collected in the [troubleshooting guide](/docs/troubleshooting-guide). * **Questions.** The [FAQ](/faq) covers Peppol, addressing, VAT and billing. * **Email.** [support@recommand.eu](mailto:support@recommand.eu):include the company ID and, for a delivery problem, the document ID. * **Discord.** [Join the server](https://discord.gg/a2tcQYA3ew) for release announcements and quick questions. * **Keep track of changes.** New endpoints and behaviour are recorded in the [changelog](/changelog). ## Guides for other situations - [Sending Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending.md) - [Receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/receiving.md) - [Sending and receiving Peppol documents in Belgium for the companies you onboard](/getting-started/belgium/platform/sending-and-receiving.md) - [Sending Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending.md) - [Receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/receiving.md) - [Sending and receiving Peppol documents in Belgium for your own company](/getting-started/belgium/business/sending-and-receiving.md) - [Sending Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending.md) - [Receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/receiving.md) - [Sending and receiving Peppol documents in France for the companies you onboard](/getting-started/france/platform/sending-and-receiving.md) - [Sending Peppol documents in France for your own company](/getting-started/france/business/sending.md) - [Receiving Peppol documents in France for your own company](/getting-started/france/business/receiving.md) - [Sending and receiving Peppol documents in France for your own company](/getting-started/france/business/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending.md) - [Receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for the companies you onboard](/getting-started/netherlands/platform/sending-and-receiving.md) - [Sending Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending.md) - [Receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/receiving.md) - [Sending and receiving Peppol documents in the Netherlands for your own company](/getting-started/netherlands/business/sending-and-receiving.md) - [Sending Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending.md) - [Receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/receiving.md) - [Sending and receiving Peppol documents in other countries for the companies you onboard](/getting-started/other/platform/sending-and-receiving.md) - [Sending Peppol documents in other countries for your own company](/getting-started/other/business/sending.md) - [Receiving Peppol documents in other countries for your own company](/getting-started/other/business/receiving.md) # Authentication (/docs/authentication) This guide explains how to authenticate with the Recommand Peppol API using our supported methods. Your API secret is shown only once in the dashboard. Store it securely. If you lose it, generate a new key pair and revoke the old one. Authentication Methods [#authentication-methods] The Recommand Peppol API supports multiple authentication methods for different use cases. API Key Authentication [#api-key-authentication] Basic API Keys [#basic-api-keys] Basic API keys use HTTP Basic Authentication. The API key ID is used as the username and the secret as the password. **Usage:** ```http Authorization: Basic ``` **Creating a Basic API Key:** 1. Navigate to the API Keys section in the dashboard 2. Create a new API key with type `basic` 3. Store the returned `secret` securely (it's only shown once) The examples below call the list companies endpoint, because it needs no input of its own and shows you real data back. If you only want to know whether your credentials work, call the [verify authentication endpoint](/reference/authentication/verify-auth) instead: it answers `{"success": true}` or 401 and nothing else. ```bash curl -X GET https://app.recommand.eu/api/core/auth/verify \ -u key_xxx:secret_xxx ``` **Examples** Use the tabs to view your preferred language. ```bash curl -X GET https://app.recommand.eu/api/v1/companies \ -u key_aBcDeFgHiJkLmNoPqRsT123456:secret_7uVwXyZ1234567890AbCdEfGhIj ``` ```javascript const fetch = require("node-fetch"); const API_KEY = "key_aBcDeFgHiJkLmNoPqRsT123456"; const API_SECRET = "secret_7uVwXyZ1234567890AbCdEfGhIj"; const credentials = Buffer.from(`${API_KEY}:${API_SECRET}`).toString("base64"); async function fetchCompanies() { const response = await fetch(`https://app.recommand.eu/api/v1/companies`, { headers: { Authorization: `Basic ${credentials}`, }, }); return response.json(); } ``` ```python import requests import base64 API_KEY = 'key_aBcDeFgHiJkLmNoPqRsT123456' API_SECRET = 'secret_7uVwXyZ1234567890AbCdEfGhIj' credentials = base64.b64encode(f"{API_KEY}:{API_SECRET}".encode()).decode() def fetch_companies(): response = requests.get( f"https://app.recommand.eu/api/v1/companies", headers={"Authorization": f"Basic {credentials}"} ) return response.json() ``` ```php ``` JWT API Keys [#jwt-api-keys] JWT API keys use Bearer token authentication. The JWT token is provided directly in the Authorization header. **Usage:** ```http Authorization: Bearer ``` **Creating a JWT API Key:** 1. Navigate to the API Keys section in the dashboard 2. Create a new API key with type `jwt` 3. Use the returned `jwt` token in your requests **Examples** Use the tabs to view your preferred language. ```bash curl -X GET https://app.recommand.eu/api/v1/companies \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." ``` ```javascript const fetch = require("node-fetch"); const JWT_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."; async function fetchCompanies() { const response = await fetch(`https://app.recommand.eu/api/v1/companies`, { headers: { Authorization: `Bearer ${JWT_TOKEN}`, }, }); return response.json(); } ``` ```python import requests JWT_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' def fetch_companies(): response = requests.get( "https://app.recommand.eu/api/v1/companies", headers={"Authorization": f"Bearer {JWT_TOKEN}"} ) return response.json() ``` ```php ``` JWT API keys have expiration dates and must be refreshed when they expire. OAuth2 with JWT Assertion [#oauth2-with-jwt-assertion] OAuth2 with JWT assertion is only available for enterprise customers on request. Contact support to enable this feature for your team. OAuth2 with JWT assertion allows you to authenticate using a client-signed JWT token. This method is suitable for server-to-server authentication where you control the private key used to sign the assertion. **Token Endpoint:** ``` POST /api/core/oauth2/token ``` **Request Parameters:** * `grant_type`: `urn:ietf:params:oauth:grant-type:jwt-bearer` * `assertion`: A JWT token signed with your private key (RS256 algorithm) **Request Format:** Parameters MUST be sent in the HTTP request body as `application/x-www-form-urlencoded` with this header: ```http Content-Type: application/x-www-form-urlencoded ``` **Response:** ```json { "success": true, "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "Bearer", "expires_in": 3600, "id": "key_xxx" } ``` Expiration of the access token is controlled by the expiration time of the JWT assertion. **Using the Access Token:** Use the returned `access_token` in subsequent API requests: ```http Authorization: Bearer ``` **JWT Assertion Requirements:** * Algorithm: RS256 * Claims: * `iss`: Your team ID * `sub`: Your team ID * `team_id`: Your team ID * `user_id`: Your user ID * `exp`: Expiration time (Unix timestamp) * `aud`: `https://app.recommand.eu/api/core/oauth2/token` **Example:** ```bash # Request access token (OAuth 2.0 JWT Bearer Grant) curl -X POST "https://app.recommand.eu/api/core/oauth2/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" \ --data-urlencode "assertion=eyJhbGciOiJSUzI1NiJ9..." # Use access token curl -H "Authorization: Bearer " https://app.recommand.eu/api/v1/companies ``` When OAuth2 with JWT assertion is enabled for a team, standard API key creation is disabled for that team. Enabling OAuth2 with JWT Assertion [#enabling-oauth2-with-jwt-assertion] To enable OAuth2 with JWT assertion for your team, contact support and provide the following information. Keep in mind this feature is only available for enterprise customers on request. * **Team ID**: Your team identifier (found in the API Keys section of the dashboard) * **JWKS (JSON Web Key Set)**: A JSON document containing your public key(s) in JWKS format. The public key(s) will be used to verify the JWT assertions you sign with your corresponding private key(s). The JWKS should follow the [RFC 7517](https://tools.ietf.org/html/rfc7517) specification and contain at least one RSA public key (for RS256 algorithm). The JWKS MUST only contain the public portion of the RSA keys. Example JWKS structure: ```json { "keys": [ { "kty": "RSA", "use": "sig", "alg": "RS256", "n": "base64url-encoded-modulus", "e": "base64url-encoded-exponent", "kid": "your-key-id" } ] } ``` Once enabled, standard API key creation will be disabled for your team, and you'll be able to use OAuth2 with JWT assertion for authentication. Security Best Practices [#security-best-practices] 1. Environment variables: Store keys as environment variables or in a secure vault. 2. Separate keys: Use different keys for development, testing, and production. 3. Rotate regularly: Generate new keys periodically and revoke old ones. Troubleshooting [#troubleshooting] Authentication errors [#authentication-errors] If you receive a 401 Unauthorized response: * Verify your API key and secret are correct * Check if the key has been revoked * Ensure the Base64 encoding is correct * For JWT or OAuth2, ensure your token is not expired * Make sure the team ID you are using is correct, all API keys are team-specific Next Steps [#next-steps] Learn about the UBL document structure. Learn how to create and send invoices. Complete details on authentication in the API reference. Solve common authentication issues. # Company Verification (/docs/company-verification) This guide explains how company verification works and how to complete it, either directly from the [Recommand dashboard](https://app.recommand.eu) or via the API. Overview [#overview] Before a company can send or receive documents on the Peppol network, an authorised representative must complete a short identity check to confirm they are entitled to act on behalf of that company. This produces a clear, auditable record of authorisation for every company on the network. Each company has an `isVerified` field. As long as this field is `false`, the company cannot participate in document exchange on Peppol. Verification can be completed entirely from the [Recommand dashboard](https://app.recommand.eu/companies) without writing any code. The API is only needed if you want to initiate or automate verification programmatically. Prerequisites [#prerequisites] * A Recommand account with API access * Your API key and secret * The ID of the company you want to verify Initiating Verification [#initiating-verification] When you create a company, the response already includes a `verificationUrl`. Present it to your user immediately without any additional API call. The verification page itself lets them forward the link to an authorised representative if needed. If you need a fresh URL later (e.g. the original link was lost or you want to verify an existing company), call the [verify company endpoint](/reference/companies/verify-company) to generate a new verification session. ```javascript async function initiateVerification(companyId) { const response = await fetch( `https://app.recommand.eu/api/v1/companies/${companyId}/verify`, { method: "POST", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), }, } ); return response.json(); } // Example usage const result = await initiateVerification("company_id"); if (result.success) { console.log("Verification URL:", result.verificationUrl); // Present this URL to your user — they can forward it to an authorised representative if needed } else { console.error("Failed to initiate verification:", result.errors); } ``` Response Structure [#response-structure] ```json { "success": true, "verificationUrl": "https://app.recommand.eu/company-verification/cvl_01ABCDE/verify" } ``` * `verificationUrl`: A URL to present to your user. From that page, they can complete the identity check themselves or forward the link to the appropriate person within their organisation. Presenting the Verification URL [#presenting-the-verification-url] Present the `verificationUrl` to your user, for example by displaying it in your UI or redirecting them to it directly. The verification page is self-contained and works in any browser; no Recommand account is required. From there, the user can forward the link to whoever in their organisation is authorised to complete the identity check. You can also kick off verification directly from the [Recommand dashboard](https://app.recommand.eu) without using the API. Checking Verification Status [#checking-verification-status] The `isVerified` field on the company object reflects the current verification state. You can poll it using the [get company endpoint](/reference/companies/get-company): ```javascript async function getCompany(companyId) { const response = await fetch( `https://app.recommand.eu/api/v1/companies/${companyId}`, { headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), }, } ); return response.json(); } // Example usage const result = await getCompany("company_id"); if (result.success) { console.log("Verified:", result.company.isVerified); } ``` `isVerified` becomes `true` once the identity check is successfully completed. It is automatically reset to `false` if the company's `vatNumber` or `enterpriseNumber` is changed. In that case the company must go through verification again before it can participate on the Peppol network. Webhook Notification [#webhook-notification] Rather than polling, you can listen for the `company.verification` webhook event, which fires when verification reaches a final state. The payload includes a `status` field: * `"verified"`: identity check passed and the company is active on the Peppol network * `"rejected"`: identity check failed * `"error"`: identity check completed, but a subsequent Peppol network operation failed; the company is not yet active. An `errorMessage` field is included with details. Contact [support@recommand.eu](mailto:support@recommand.eu) if this occurs and you are not sure what to do. ```json { "eventType": "company.verification", "companyId": "c_xxx", "teamId": "team_xxx", "status": "verified" } ``` See [Working with Webhooks](/docs/working-with-webhooks) for how to register a webhook endpoint. Best Practices [#best-practices] 1. **Verify early**: Initiate verification as soon as you create a company. 2. **Present the URL to your user**: Display it in your UI or redirect to it. The verification page lets the user forward the link to whoever in their organisation can complete the identity check. 3. **Watch for reverification after updates**: If you update a company's `vatNumber` or `enterpriseNumber`, `isVerified` is reset automatically. Check the field after updates and present a new `verificationUrl` to your user if needed. 4. **One session at a time**: Each call to the verify endpoint creates a new session. Avoid initiating multiple sessions for the same company unnecessarily. Next Steps [#next-steps] Create and update company profiles. Send invoices from a verified company. Full reference for the verify company endpoint. # Discounts & Surcharges (/docs/discounts-and-surcharges) This guide explains how to apply discounts and surcharges to Peppol documents sent through the [Recommand JSON API](/reference/sending/send-document). Discounts and surcharges work identically across all document types: invoices, credit notes, self-billing invoices, and self-billing credit notes. Overview [#overview] The Peppol standard supports two levels of discounts and surcharges: * **Document-level**: applied to the entire document (e.g. a 5% volume discount on the total) * **Line-level**: applied to a specific line item (e.g. a promotional discount on one product) Both levels support multiple entries, meaning you can add several discounts and surcharges to a single document or line. Document-Level Discounts & Surcharges [#document-level-discounts--surcharges] Document-level discounts and surcharges are defined in the top-level `discounts` and `surcharges` arrays of your document payload. Each entry requires its own VAT information, since different discounts may fall under different tax rates. Structure [#structure] | Field | Required | Description | Example | | ------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------ | | `reasonCode` | One of\* | Reason code: [UNCL5189](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) for discounts, [UNCL7161](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) for surcharges | `"95"` | | `reason` | One of\* | Free-text reason | `"Discount"` | | `amount` | Yes | Amount as a decimal string | `"10.00"` | | `vat` | Yes | VAT category and percentage. See [VatInfo model](/reference/sending/send-document) | See below | \* At least one of `reasonCode` or `reason` must be provided. You can provide both. Example [#example] ```json { "invoiceNumber": "INV-TEST-001", "issueDate": "2025-01-15", "dueDate": "2025-02-14", "buyer": { "vatNumber": "BE0123456789", "name": "Customer NV", "street": "Main Street 1", "city": "Brussels", "postalZone": "1000", "country": "BE" }, "paymentMeans": [{ "iban": "BE68539007547034" }], "lines": [ { "name": "Consulting Services", "quantity": "10.00", "unitCode": "HUR", "netPriceAmount": "100.00", "vat": { "percentage": "21.00" } } ], "discounts": [ { "reasonCode": "95", "reason": "Volume discount", "amount": "50.00", "vat": { "category": "S", "percentage": "21.00" } } ], "surcharges": [ { "reasonCode": "FC", "reason": "Freight services", "amount": "25.00", "vat": { "category": "S", "percentage": "21.00" } } ] } ``` In this example, the invoice has a line total of 1000.00 EUR (10 x 100.00), minus a 50.00 discount, plus a 25.00 surcharge, for a tax-exclusive total of 975.00 EUR. Line-Level Discounts & Surcharges [#line-level-discounts--surcharges] Line-level discounts and surcharges are defined in the `discounts` and `surcharges` arrays on each line item. Unlike document-level entries, line-level entries do **not** include VAT information - they inherit the VAT category from the line they belong to. Line discounts are **not** informational. They actively affect the line net amount. Set `netPriceAmount` to the unit price **before** any discounts. The API subtracts the discount `amount` from `quantity × netPriceAmount` to calculate the line `netAmount`. Structure [#structure-1] | Field | Required | Description | Example | | ------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------- | | `reasonCode` | One of\* | Reason code: [UNCL5189](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) for discounts, [UNCL7161](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) for surcharges | `"95"` | | `reason` | One of\* | Free-text reason | `"Promo"` | | `amount` | Yes | Amount as a decimal string | `"5.00"` | \* At least one of `reasonCode` or `reason` must be provided. Example [#example-1] ```json { "invoiceNumber": "INV-TEST-002", "issueDate": "2025-01-15", "buyer": { "vatNumber": "BE0123456789", "name": "Customer NV", "street": "Main Street 1", "city": "Brussels", "postalZone": "1000", "country": "BE" }, "paymentMeans": [{ "iban": "BE68539007547034" }], "lines": [ { "name": "Product A", "quantity": "5.00", "netPriceAmount": "40.00", "vat": { "percentage": "21.00" }, "discounts": [ { "reason": "Promotional discount", "amount": "10.00" } ] }, { "name": "Product B", "quantity": "2.00", "netPriceAmount": "60.00", "vat": { "percentage": "6.00" }, "surcharges": [ { "reason": "Special packaging", "amount": "5.00" } ] } ] } ``` In this example: * **Product A**: (5 x 40.00) - 10.00 discount = **190.00** net * **Product B**: (2 x 60.00) + 5.00 surcharge = **125.00** net How Totals Are Calculated [#how-totals-are-calculated] Understanding how discounts and surcharges affect totals is important for validation. The API will calculate totals automatically if you omit them, but here is how it works: Line Net Amount [#line-net-amount] ``` lineNetAmount = (quantity x netPriceAmount) - line discounts + line surcharges ``` Document Totals [#document-totals] ``` linesAmount = sum of all lineNetAmounts discountAmount = sum of all document-level discounts surchargeAmount = sum of all document-level surcharges taxExclusiveAmount = linesAmount - discountAmount + surchargeAmount taxInclusiveAmount = taxExclusiveAmount + totalVAT ``` VAT Calculation [#vat-calculation] Each document-level discount or surcharge contributes to the VAT subtotal for its own VAT category and percentage: * Discounts **reduce** the taxable amount for their VAT category * Surcharges **increase** the taxable amount for their VAT category Line-level discounts and surcharges are factored into their line's net amount, which contributes to the line's VAT category subtotal. Advanced: Financial Discounts [#advanced-financial-discounts] A **financial discount** (early-payment discount, or *korting contant* in Dutch) is conditional: it only applies when the customer pays within an agreed period. Because the invoice must still show the full amount due when the discount is not taken, it is modeled with a document-level allowance and a matching document-level charge rather than a plain discount. See the [Financial Discounts](/docs/financial-discounts) guide for the rules, a worked example, and a minimal request payload. # Email Delivery and Notifications (/docs/email-delivery-and-notifications) This guide covers the two ways email is used in Recommand: delivering documents to recipients via email, and sending notifications about document activity to your team. Email Delivery [#email-delivery] Recommand uses a single API endpoint for sending all your documents, whether the recipient is on Peppol or not. You can include email delivery alongside Peppol, as a fallback when Peppol fails, or as the sole delivery method for recipients who aren't on the Peppol network. Common use cases: * **B2C customers** who aren't on the Peppol network * **International recipients** outside countries with Peppol mandates * **Fallback delivery** when Peppol transmission fails * **Additional delivery** when you want both Peppol and email How It Works [#how-it-works] Add the `email` field to your [send document](/reference/sending/send-document) request: ```javascript const response = await fetch( "https://app.recommand.eu/api/v1/{companyId}/send", { method: "POST", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify({ recipient: "0208:987654321", documentType: "invoice", document: { // ... your invoice data }, email: { when: "always", to: ["customer@example.com"], }, }), }, ); ``` Email Options [#email-options] | Field | Description | Default | | ---------------- | ------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------- | | `email.when` | `"always"` sends email regardless of the Peppol result. `"on_peppol_failure"` only sends email if Peppol delivery fails. | `"on_peppol_failure"` | | `email.to` | Array of recipient email addresses. | Required | | `email.subject` | Custom email subject line. | Auto-generated from document type and number | | `email.htmlBody` | Custom HTML body for the email. | Auto-generated | Sending Without a Peppol Recipient [#sending-without-a-peppol-recipient] For customers who aren't on the Peppol network, you can set `recipient` to `null` to send exclusively via email. This works with invoices, credit notes, self-billing invoices, and self-billing credit notes. ```javascript { recipient: null, documentType: "invoice", document: { // ... your invoice data }, email: { to: ["customer@example.com"], }, pdfGeneration: { enabled: true, }, } ``` When `recipient` is `null`, email becomes the primary delivery method and `email.to` is required. The `when` field is ignored since there is no Peppol delivery to fall back from. Since these emails are not sent over the Peppol network, the PDF attachment effectively becomes the document your recipient receives. You can either let Recommand generate a PDF from your document data, or attach your own custom PDF. See [PDF Attachments](#pdf-attachments) below. This means you can use a single API endpoint and document format for all your customers. Recommand handles the delivery method based on the recipient. PDF Attachments [#pdf-attachments] When sending documents via email, you can attach a PDF in two ways: **Auto-generated PDF.** Recommand renders a PDF from your document data: ```javascript { pdfGeneration: { enabled: true, filename: "INV-2025-001.pdf", // optional custom filename }, } ``` **Custom PDF.** Include your own PDF via the document's `attachments` field. This is useful if you have a branded invoice template or generate PDFs in your own system. See the [sending invoices guide](/docs/sending-invoices) for details on attachments. When sending via Peppol, emails also include the UBL XML document as an attachment. Response [#response] The send document response tells you how the document was delivered: ```json { "success": true, "id": "doc_xxx", "sentOverPeppol": true, "sentOverEmail": true, "emailRecipients": ["customer@example.com"] } ``` Each email sent counts toward your document quota. Email Notifications [#email-notifications] Email notifications alert you (or your systems) when documents are sent or received. They are configured per company and can be set up from the [dashboard](https://app.recommand.eu) or via the API. What Notifications Include [#what-notifications-include] Every notification email includes: * A summary of the document (type, number, amount, sender or recipient) * The original UBL XML as an attachment * Any attachments embedded in the original document You can optionally include: * **Auto-generated PDF**: a visual PDF rendering of the UBL XML document, generated by Recommand * **Document JSON**: the structured JSON representation with metadata Setting Up Notifications [#setting-up-notifications] Via the Dashboard [#via-the-dashboard] In the dashboard, navigate to your company and open the notification email settings. From there you can add email addresses and configure which notifications each address receives. Via the API [#via-the-api] Use the [notification email address endpoints](/reference/company-notification-email-addresses/get-company-notification-email-addresses) to manage notification emails programmatically. Create a notification email address: ```javascript const response = await fetch( "https://app.recommand.eu/api/v1/companies/{companyId}/notification-email-addresses", { method: "POST", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify({ email: "accounting@yourcompany.com", notifyIncoming: true, notifyOutgoing: false, includeAutoGeneratedPdfIncoming: true, includeDocumentJsonIncoming: false, }), }, ); ``` Configuration Options [#configuration-options] Each email address can be configured independently: | Setting | Description | | --------------------------------- | ----------------------------------------------------------------- | | `notifyIncoming` | Receive notifications when documents are received | | `notifyOutgoing` | Receive notifications when documents are sent | | `includeAutoGeneratedPdfIncoming` | Attach a PDF rendering of the XML document for incoming documents | | `includeAutoGeneratedPdfOutgoing` | Attach a PDF rendering of the XML document for outgoing documents | | `includeDocumentJsonIncoming` | Attach the structured JSON for incoming documents | | `includeDocumentJsonOutgoing` | Attach the structured JSON for outgoing documents | At least one of `notifyIncoming` or `notifyOutgoing` must be enabled. You can add multiple email addresses per company, each with different settings. Common Setups [#common-setups] **Notify your team about incoming invoices:** ```json { "email": "finance@yourcompany.com", "notifyIncoming": true, "notifyOutgoing": false, "includeAutoGeneratedPdfIncoming": true } ``` **Forward documents to accounting software:** Many accounting tools offer an email inbox that automatically processes incoming UBL/XML documents. Point a notification email at that inbox and documents flow from Peppol into your accounting software automatically, with no code required. See the setup guides for [Exact Online](/integrations/exact-online), [Yuki](/integrations/yuki), and [ClearFacts](/integrations/clearfacts). ```json { "email": "inbox@accounting-tool.com", "notifyIncoming": true, "notifyOutgoing": false, "includeAutoGeneratedPdfIncoming": false, "includeDocumentJsonIncoming": false } ``` The XML is always attached, which is all most accounting tools need. See the [integrations page](/integrations) for all available setup guides. **Keep a copy of all outgoing documents:** ```json { "email": "archive@yourcompany.com", "notifyIncoming": false, "notifyOutgoing": true, "includeAutoGeneratedPdfOutgoing": true, "includeDocumentJsonOutgoing": true } ``` Managing Notification Emails [#managing-notification-emails] You can list, update, and delete notification email addresses through the API: ```javascript // List all notification emails for a company const list = await fetch( "https://app.recommand.eu/api/v1/companies/{companyId}/notification-email-addresses", { headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), }, }, ); // Update settings const update = await fetch( "https://app.recommand.eu/api/v1/companies/{companyId}/notification-email-addresses/{addressId}", { method: "PUT", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify({ email: "accounting@yourcompany.com", notifyIncoming: true, notifyOutgoing: true, includeAutoGeneratedPdfIncoming: true, includeAutoGeneratedPdfOutgoing: false, includeDocumentJsonIncoming: false, includeDocumentJsonOutgoing: false, }), }, ); // Delete a notification email const remove = await fetch( "https://app.recommand.eu/api/v1/companies/{companyId}/notification-email-addresses/{addressId}", { method: "DELETE", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), }, }, ); ``` Next Steps [#next-steps] Full guide on creating and sending invoices. Process incoming documents using webhooks or polling. Connect Recommand with your accounting software and other tools. Complete API reference for notification email endpoints. # Financial Discount (/docs/financial-discounts) This guide shows how to apply a **financial discount** (also called an early-payment discount, or *korting contant* in Dutch) on a Peppol document sent through the [Recommand JSON API](/reference/sending/send-document). A financial discount differs from a regular [document-level discount](/docs/discounts-and-surcharges) because it is **conditional**: it only applies when the customer pays within an agreed period. The invoice must still show the full amount due when the discount is not taken. Principles [#principles] * A financial discount is conditional: it only applies when the customer pays within the agreed period. * The invoice VAT is calculated on the discounted amount. * The invoice should still show the full amount due when the discount is not taken. * In UBL/Peppol, that is modeled with a document-level **allowance** for the discount and a matching document-level **charge** for the non-discounted amount. Rules [#rules] * Use a document-level **allowance** for the financial discount and a matching document-level **charge** to keep the payable amount unchanged. * As the balancing charge uses VAT category `E` (exempt), include `document.vat.exemptionReason` or `document.vat.exemptionReasonCode`. The allowance reduces the VAT base (so VAT is calculated on the discounted amount), while the matching charge (at VAT category `E`, exempt) keeps the payable total equal to the full amount due. This way, the customer pays the reduced amount only when they pay within the discount period, and the full amount otherwise. Example [#example] Given a single line of `1000.00 EUR` at 21% VAT and a `100.00 EUR` financial discount for payment within one week: | Field | Amount (EUR) | | ---------------------------------------------- | -----------: | | Line amount | 1000.00 | | Financial discount allowance | -100.00 | | VAT base | 900.00 | | VAT (21%) | 189.00 | | Balancing charge (vat exempt) | 100.00 | | **Total payable if the discount is not taken** | **1189.00** | | **Total payable if the discount is taken** | **1089.00** | The invoice total shows the full amount due when the discount is not taken. In the invoice payment terms, explain that when the discount is taken, the total payable amount is `1089,00 EUR`. Minimal Send Document JSON [#minimal-send-document-json] The following is a minimal example of a send document request payload for a financial discount that can be sent through the [Recommand Send Document JSON API](/reference/sending/send-document). ```json { "recipient": "0208:1012081766", "documentType": "invoice", "document": { "invoiceNumber": "FIN-DISCOUNT-001", "buyer": { "name": "Example Customer", "street": "Kerkstraat 1", "city": "Hasselt", "postalZone": "3500", "country": "BE" }, "paymentTerms": { "note": "Financial discount of 100,00 EUR for payment within 1 week. When paying within 1 week, the total payable amount is 1089,00 EUR. Otherwise, the total payable amount is 1189,00 EUR." }, "lines": [ { "name": "Example Product", "quantity": "1", "netPriceAmount": "1000.00", "vat": { "category": "S", "percentage": "21.00" } } ], "discounts": [ { "reason": "Financial discount of 100,00 EUR for payment within 1 week.", "amount": "100.00", "vat": { "category": "S", "percentage": "21.00" } } ], "surcharges": [ { "reason": "Financial discount balancing charge", "amount": "100.00", "vat": { "category": "E", "percentage": "0.00" } } ], "vat": { "exemptionReason": "Financial discount" } } } ``` Related [#related] General guide to document-level and line-level discounts and surcharges. Full reference for the send document endpoint. # Getting Started (/docs) Welcome to Recommand's Peppol API documentation. This guide will help you set up and start using our API for Peppol document exchange. What onboarding looks like depends on where your companies are registered. Answer three questions (one company or many, which country, which direction) and get only the steps that apply: [country-specific getting started guides](/getting-started) for [Belgium](/getting-started/belgium), [France](/getting-started/france), the [Netherlands](/getting-started/netherlands) and [every other supported country](/getting-started/other). Overview [#overview] Recommand's Peppol API provides a simple and effective way to integrate Peppol document exchange into your existing systems. The API supports document creation, sending, receiving, and management through simple REST endpoints. Prerequisites [#prerequisites] Before you begin, ensure you have: * A Recommand account (sign up at [app.recommand.eu/signup](https://app.recommand.eu/signup)) * Your API key and secret, available from [your dashboard](https://app.recommand.eu/api-keys) * A development environment capable of making HTTP requests Playground Environment [#playground-environment] The Playground is a safe, isolated test environment. Playground teams look and behave like production teams, but they do not send documents over the real Peppol network. You can create as many playground teams as you like. Key characteristics: * No real Peppol delivery: sending is simulated * Data isolation: documents and companies stay within the playground team * No billing/subscription checks and no SMP registrations * Webhooks work the same, triggered by simulated inbound delivery Optionally, you can connect a playground to the **Peppol Test Network** for end-to-end testing with real Peppol participants. Test Network playgrounds use dedicated AP/SMP endpoints and register companies against the test infrastructure, while remaining fully separated from production.
Create a playground team [#create-a-playground-team] * Dashboard: create a new team and choose Playground * API: ```bash curl -X POST https://app.recommand.eu/api/v1/playgrounds \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d '{"name":"My Playground"}' ``` ```javascript const res = await fetch("https://app.recommand.eu/api/v1/playgrounds", { method: "POST", headers: { Authorization: "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify({ name: "My Playground" }), }); const body = await res.json(); // body.success === true, body.playground.isPlayground === true ``` Using a playground [#using-a-playground] * Use the same endpoints as production; just ensure your `{teamId}`/`{companyId}` belong to the playground team * Sending documents simulates delivery; a document is only “received” if the recipient company exists in the same playground team * Configure webhooks on the playground team to receive simulated inbound events (e.g. `document.received`) To test Peppol send failure handling in playgrounds that are **not** connected to the Peppol Test Network, send to one of these recipient addresses: * `404:404` - always fails, simulating a Peppol address that does not exist * `0208:1234567894` - same behavior, but using a valid Peppol address The send endpoint returns **422** unless email delivery is configured as a fallback. For any other recipient that is not registered as an SMP recipient in the same playground team, Peppol delivery is skipped without an error. That is different from the addresses above, which always return an explicit failure. These addresses only apply when delivery is simulated. Test Network playgrounds send over the real Peppol test infrastructure instead. Check if a team is a playground [#check-if-a-team-is-a-playground] ```bash curl -X GET https://app.recommand.eu/api/v1/playgrounds/current \ -u key_xxx:secret_xxx ``` ```javascript const res = await fetch("https://app.recommand.eu/api/v1/playgrounds/current", { headers: { Authorization: "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"), }, }); if (res.status === 404) { // Not a playground team } else { const { playground } = await res.json(); console.log("isPlayground:", playground.isPlayground); } ```
Authentication [#authentication] All API requests must be authenticated using Basic Authentication, JWT bearer authentication, or OAuth2. More information on the authentication methods can be found in the [authentication guide](/docs/authentication). Below is an example of how to use Basic Authentication: ```bash # Your API key as username, API secret as password curl -X GET https://app.recommand.eu/api/v1/companies \ -u key_xxx:secret_xxx ``` ```javascript // Node.js example const response = await fetch("https://app.recommand.eu/api/v1/companies", { headers: { Authorization: "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"), }, }); ``` Core Concepts [#core-concepts] Companies [#companies] Companies represent businesses that can send or receive Peppol documents. Each company must be [registered](/docs/managing-companies) and [verified](/docs/company-verification) before it can participate in document exchange: ```javascript const response = await fetch("https://app.recommand.eu/api/v1/companies", { method: "POST", headers: { Authorization: "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify({ name: "ACME Corporation", address: "123 Main Street", postalCode: "1000", city: "Brussels", country: "BE", enterpriseNumber: "0123456789", vatNumber: "BE0123456789", }), }); ``` Sending Invoices [#sending-invoices] The primary function is sending Peppol-compliant invoices using the [send document endpoint](/reference/sending/send-document). A few things to note: * Remember to replace `{companyId}` with the correct company ID of the sender * Use your own API credentials, as explained above * The `recipient` field is the Peppol address of the recipient. In the example below, it's `0208:987654321`, where `0208` is the Belgian [Peppol Electronic Address Scheme](https://docs.peppol.eu/poacc/billing/3.0/codelist/eas/) and `987654321` is the recipient's enterprise number. * If you want to send a test invoice, you can simply register a new company and use it as both the sender and recipient. ```javascript const response = await fetch( "https://app.recommand.eu/api/v1/{companyId}/send", { method: "POST", headers: { Authorization: "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify({ recipient: "0208:987654321", // Peppol address of recipient documentType: "invoice", document: { invoiceNumber: "INV-2025-001", issueDate: "2024-05-15", dueDate: "2024-06-15", buyer: { vatNumber: "BE0987654321", name: "Customer Company", street: "Customer Street 1", city: "Antwerp", postalZone: "2000", country: "BE", }, paymentMeans: [ { iban: "BE1234567890", }, ], lines: [ { name: "Consulting Services", netPriceAmount: "100.00", vat: { percentage: "21.00", }, }, ], }, }), } ); ``` You can also easily test the API with our [interactive API docs](/reference). Verifying Recipients [#verifying-recipients] Before sending documents, you can verify if the recipient is registered in the Peppol network using the [verify endpoint](/reference/recipients/verify-recipient). This will be done automatically as well when you send a document. ```javascript const response = await fetch("https://app.recommand.eu/api/v1/verify", { method: "POST", headers: { Authorization: "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify({ peppolAddress: "0208:987654321", }), }); console.log(await response.json()); ``` For valid recipients, you should get a response like this: ```json { "success": true, "isValid": true, "smpUrl": "http://B-c6451d3d5bd755bb0c2576c41fea37fb.iso6523-actorid-upis.edelivery.tech.ec.europa.eu/iso6523-actorid-upis::0208%3A1012081766" } ``` Receiving Documents [#receiving-documents] When a business partner sends you a document through Peppol, Recommand automatically receives, validates, and stores it. You can consume incoming documents using webhooks (real-time push) or by polling the inbox: ```javascript // Poll the inbox for unread documents const response = await fetch("https://app.recommand.eu/api/v1/inbox", { headers: { Authorization: "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"), }, }); ``` After processing a document in your system, mark it as read using the [mark as read endpoint](/reference/documents/mark-as-read) so it no longer appears in the inbox. For the full guide on webhooks, polling, fetching document details, and processing incoming documents, see the [Receiving Documents](/docs/receiving-documents) guide. Error Handling [#error-handling] The API returns structured error responses: ```json { "success": false, "errors": { "document.buyer.vatNumber": ["document.buyer.vatNumber: Required"] }, "invalidInputDetails": [ { "path": "document.buyer.vatNumber", "message": "Required" } ] } ``` Before processing results, always check the HTTP status code or the `success` property. The keys of `errors` are full paths from the root of the request body, so a field inside the document you are sending reads as `document.buyer.vatNumber` rather than `buyer.vatNumber`. Each value is a list of messages that repeat the path, which makes them safe to show to a user as they are. `errors` is what you display; `invalidInputDetails` is the same information as a structured list you can walk in code. When the body matched none of the document types, each entry in `invalidInputDetails` also carries a `unionErrors` array holding the errors each document type reported. Complete Invoice Example [#complete-invoice-example] Here's a complete invoice example with all supported fields. You can view it in more detail in our [interactive API docs](/reference/sending/send-document). ```javascript const invoice = { invoiceNumber: "INV-2025-001", issueDate: "2024-05-15", dueDate: "2024-06-15", note: "Thank you for your business", buyerReference: "PO-2024-001", seller: { vatNumber: "BE0123456789", name: "Your Company", street: "Your Street 1", city: "Brussels", postalZone: "1000", country: "BE", }, buyer: { vatNumber: "BE0987654321", name: "Customer Company", street: "Customer Street 1", city: "Antwerp", postalZone: "2000", country: "BE", }, paymentMeans: [ { paymentMethod: "credit_transfer", reference: "INV-2025-001", iban: "BE1234567890", }, ], paymentTerms: { note: "Net 30", }, lines: [ { name: "Consulting Services", description: "Professional consulting services", sellersId: "CS-001", quantity: "10.00", unitCode: "HUR", // Hours netPriceAmount: "100.00", netAmount: "1000.00", vat: { category: "S", percentage: "21.00", }, }, ], attachments: [ { id: "ATT-001", mimeCode: "application/pdf", filename: "contract.pdf", embeddedDocument: "base64encodeddocument...", }, ], }; ``` Next Steps [#next-steps] Tailored setup steps for Belgium, France, the Netherlands and beyond. Set up and test HTTP Basic authentication. Create and manage company profiles. Verify a company before it can send or receive documents. Create and send your first invoice. Process incoming documents using webhooks or polling. Understand UBL structure and fields. Explore all endpoints and models. Support [#support] If you encounter any issues or have questions, our support team is here to help: * Email: [support@recommand.eu](mailto:support@recommand.eu) * GitHub Issues: [github.com/brbxai/recommand-peppol/issues](https://github.com/brbxai/recommand-peppol/issues) # Managing Companies (/docs/managing-companies) This guide explains how to create, update, and manage company profiles in Recommand for Peppol document exchange using the [Recommand API](/reference/companies/get-companies). Overview [#overview] A company in Recommand represents a business entity that can send or receive Peppol documents. Each company must be registered before it can participate in document exchange. Only add companies that you are responsible for, typically your own organization or entities you manage. Do not add companies that you send documents to (customers) or receive documents from (suppliers). Those companies manage their own Peppol registration independently. Trying to add them to your account will cause registration conflicts. Prerequisites [#prerequisites] * A Recommand account with API access * Your API key and secret * Your team ID Retrieving Your Team ID [#retrieving-your-team-id] Your team ID is required for most company management operations. You can find it in the Recommand dashboard under [Account > API Keys](https://app.recommand.eu/api-keys). Strict Identifier Validation [#strict-identifier-validation] Recommand enforces strict format validation on Peppol identifiers and company VAT and enterprise numbers. Numbers that do not pass national validation rules (such as the Belgian modulo-97 check digit) are rejected at creation and update time. Ensure the values you submit are correctly formatted. Listing Companies [#listing-companies] To retrieve all companies associated with your team using the [list companies endpoint](/reference/companies/get-companies): ```javascript async function listCompanies() { const response = await fetch( `https://app.recommand.eu/api/v1/companies`, { headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), }, } ); const result = await response.json(); return result.companies; } // Example usage const companies = await listCompanies("your_team_id"); companies.forEach((company) => { console.log(`${company.name} (${company.id})`); }); ``` Creating a Company [#creating-a-company] To create a new company using the [create company endpoint](/reference/companies/create-company). When creating a new company, it is automatically registered in the Peppol network. If you choose to register the company as SMP recipient (via `isSmpRecipient: true`), which means they will be able to receive documents on top of sending documents, this will fail if the company is already registered through another provider for receiving documents. If you only want to send documents, you can simply omit the `isSmpRecipient` field or set it to `false` and then you will be able to register the company even if it is already registered through another Peppol provider for receiving documents. ```javascript async function createCompany(companyData) { const response = await fetch( `https://app.recommand.eu/api/v1/companies`, { method: "POST", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify(companyData), } ); return response.json(); } // Example usage const newCompany = await createCompany("your_team_id", { name: "ACME Corporation", address: "123 Main Street", postalCode: "1000", city: "Brussels", country: "BE", enterpriseNumber: "0123456789", vatNumber: "BE0123456789", }); if (newCompany.success) { console.log(`Company created with ID: ${newCompany.company.id}`); console.log(`Verification URL: ${newCompany.verificationUrl}`); // Present this URL to your user — they can complete or forward the identity check from there } else { console.error("Failed to create company:", newCompany.errors); } ``` The same request with curl [#the-same-request-with-curl] ```bash curl -X POST https://app.recommand.eu/api/v1/companies \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @company.json ``` The `company.json` body is the JSON object shown above; the [country-specific guides](/getting-started) give the exact identifier fields per country. Company Fields [#company-fields] | Field | Description | Required | Example | | ------------------------- | ----------------------------------------------------------------------------- | -------- | -------------------- | | `name` | Company name | Yes | `"ACME Corporation"` | | `address` | Street address | Yes | `"123 Main Street"` | | `postalCode` | Postal/zip code | Yes | `"1000"` | | `city` | City | Yes | `"Brussels"` | | `country` | Country code (2-letter ISO code) | Yes | `"BE"` | | `enterpriseNumber` | Enterprise number | No | `"0123456789"` | | `enterpriseNumberScheme` | Scheme of the enterprise number, written into the documents the company sends | No | `"0208"` | | `vatNumber` | VAT registration number | No | `"BE0123456789"` | | `email` | Contact email | No | `"billing@acme.be"` | | `phone` | Contact phone number | No | `"+32 3 123 45 67"` | | `isSmpRecipient` | Register the company to receive documents (defaults to `true`) | No | `true` | | `skipDefaultCompanySetup` | Skip the automatic identifiers and document types, and create them yourself | No | `false` | | `isVerified` | Whether the company has been verified (read-only) | n/a | `false` | Which identifiers a company needs, and which Peppol identifiers and document types are registered from them, depends on its country. The [country-specific getting started guides](/getting-started) list the exact fields per country: [Belgium](/getting-started/belgium), [France](/getting-started/france), the [Netherlands](/getting-started/netherlands) and [every other supported country](/getting-started/other). Retrieving a Company [#retrieving-a-company] To get details about a specific company using the [get company endpoint](/reference/companies/get-company): ```javascript async function getCompany(companyId) { const response = await fetch( `https://app.recommand.eu/api/v1/companies/${companyId}`, { headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), }, } ); return response.json(); } // Example usage const companyDetails = await getCompany("your_team_id", "company_id"); if (companyDetails.success) { console.log(companyDetails.company); } else { console.error("Failed to retrieve company:", companyDetails.errors); } ``` Updating a Company [#updating-a-company] To update an existing company using the [update company endpoint](/reference/companies/update-company): ```javascript async function updateCompany(companyId, updatedData) { const response = await fetch( `https://app.recommand.eu/api/v1/companies/${companyId}`, { method: "PUT", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify(updatedData), } ); return response.json(); } // Example usage const updateResult = await updateCompany("company_id", { name: "ACME Corporation Updated", address: "456 New Street", postalCode: "1000", city: "Brussels", country: "BE", enterpriseNumber: "0123456789", vatNumber: "BE0123456789", }); if (updateResult.success) { console.log("Company updated successfully"); // If vatNumber or enterpriseNumber changed, isVerified is reset to false — reverification required } else { console.error("Failed to update company:", updateResult.errors); } ``` If you update a company's `vatNumber` or `enterpriseNumber`, `isVerified` is automatically reset to `false` and the company must be verified again before it can participate on the Peppol network. Deleting a Company [#deleting-a-company] To delete a company using the [delete company endpoint](/reference/companies/delete-company): ```javascript async function deleteCompany(companyId) { const response = await fetch( `https://app.recommand.eu/api/v1/companies/${companyId}`, { method: "DELETE", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), }, } ); return response.json(); } // Example usage const deleteResult = await deleteCompany("company_id"); if (deleteResult.success) { console.log("Company deleted successfully"); } else { console.error("Failed to delete company:", deleteResult.errors); } ``` Verifying a Company [#verifying-a-company] After creating a company, an authorised representative must complete an identity check before the company can send or receive documents on the Peppol network. The `isVerified` field on a company object reflects whether this step has been completed. The create company response already includes a `verificationUrl`. Present it to your user straight away. The verification page lets them forward the link to the right person within their organisation. If you need a fresh URL later (e.g. the link was lost or you want to verify an existing company), call the [verify company endpoint](/reference/companies/verify-company): ```javascript const result = await fetch( `https://app.recommand.eu/api/v1/companies/${companyId}/verify`, { method: "POST", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), }, } ).then((r) => r.json()); if (result.success) { console.log("Verification URL:", result.verificationUrl); // Present this URL to your user — they can complete or forward the identity check from there } ``` Verification can also be completed directly from the [Recommand dashboard](https://app.recommand.eu/companies) without using the API. For the full flow, see the [Company Verification](/docs/company-verification) guide. Complete Example: Company Management [#complete-example-company-management] Here's a full example of creating, updating, and managing companies: ```javascript // Setup authentication const API_KEY = "your_api_key"; const API_SECRET = "your_api_secret"; const TEAM_ID = "your_team_id"; const auth = "Basic " + Buffer.from(`${API_KEY}:${API_SECRET}`).toString("base64"); const baseUrl = "https://app.recommand.eu/api/v1"; // Create a new company async function createCompany() { const response = await fetch(`${baseUrl}/companies`, { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json", }, body: JSON.stringify({ name: "Test Company", address: "123 Test Street", postalCode: "1000", city: "Brussels", country: "BE", enterpriseNumber: "0123456789", vatNumber: "BE0123456789", }), }); const result = await response.json(); if (result.success) { console.log(`Company created with ID: ${result.company.id}`); return result.company.id; } else { console.error("Failed to create company:", result.errors); return null; } } // List all companies async function listCompanies() { const response = await fetch(`${baseUrl}/companies`, { headers: { Authorization: auth }, }); const result = await response.json(); if (result.success) { console.log("Companies:"); result.companies.forEach((company) => { console.log(`- ${company.name} (${company.id})`); }); return result.companies; } else { console.error("Failed to list companies:", result.errors); return []; } } // Update a company async function updateCompany(companyId) { const response = await fetch(`${baseUrl}/companies/${companyId}`, { method: "PUT", headers: { Authorization: auth, "Content-Type": "application/json", }, body: JSON.stringify({ name: "Updated Test Company", address: "456 Updated Street", postalCode: "1000", city: "Brussels", country: "BE", enterpriseNumber: "0123456789", vatNumber: "BE0123456789", }), }); const result = await response.json(); if (result.success) { console.log("Company updated successfully"); return true; } else { console.error("Failed to update company:", result.errors); return false; } } // Delete a company async function deleteCompany(companyId) { const response = await fetch(`${baseUrl}/companies/${companyId}`, { method: "DELETE", headers: { Authorization: auth }, }); const result = await response.json(); if (result.success) { console.log("Company deleted successfully"); return true; } else { console.error("Failed to delete company:", result.errors); return false; } } // Example workflow async function manageCompanies() { // List existing companies console.log("Existing companies:"); await listCompanies(); // Create a new company console.log("\nCreating a new company..."); const companyId = await createCompany(); if (!companyId) return; // List companies again to see the new one console.log("\nUpdated company list:"); await listCompanies(); // Update the company console.log("\nUpdating the company..."); await updateCompany(companyId); // List companies again to see the update console.log("\nAfter update:"); await listCompanies(); // Delete the company console.log("\nDeleting the company..."); await deleteCompany(companyId); // Final company list console.log("\nFinal company list:"); await listCompanies(); } // Run the workflow manageCompanies().catch((error) => { console.error("Error in company management workflow:", error); }); ``` Best Practices [#best-practices] 1. **Check Peppol Registration**: Before creating a company, check if the company is already registered in the Peppol network. 2. **Validate data**: Ensure company information is accurate before creating or updating 3. **Handle errors**: Implement proper error handling for API responses 4. **Check before delete**: Ensure a company is not in use before deleting it 5. **Limit company creation**: Create only the companies you need to avoid clutter Next Steps [#next-steps] Create and send invoices from your companies. Issue credit notes to correct invoices. Receive events across your companies and teams. Verify a company before it can participate on the Peppol network. Check recipients before sending documents. Explore all endpoints and models. # Peppol Network Basics (/docs/peppol-network-basics) This guide introduces the fundamental concepts of the Peppol network and its role in electronic document exchange. What is Peppol? [#what-is-peppol] Peppol (Pan-European Public Procurement Online) is a standardized network that enables organizations to exchange electronic business documents across borders. Originally developed for European public procurement, it has expanded globally to facilitate e-invoicing and other business document exchanges between organizations of all types. Key characteristics of Peppol: * **Open network**: Any organization can join through an accredited service provider * **Standardized**: Common document formats and transmission protocols * **Interoperable**: Connect once, reach all network participants * **Secure**: Trusted and authenticated document delivery * **Global**: Used across Europe, Asia, and beyond Peppol Network Structure [#peppol-network-structure] Peppol operates as a "4-corner model" for document transmission: **Peppol 4-corner model** * **Corner 1**: Sender * **Corner 2**: Sender's Access Point * **Corner 3**: Recipient's Access Point * **Corner 4**: Recipient This structure allows any participant to exchange documents with any other participant through their respective service providers without bilateral agreements. Key Components [#key-components] 1. Peppol IDs [#1-peppol-ids] Every participant in the Peppol network is identified by a unique Peppol ID, typically structured as: ``` [Identifier Scheme]:[Identifier Value] ``` Common electronic address schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/eas/). In Belgium, "0208" (Belgian Enterprise Number) is often used. The identifier is often the company's national identifier, such as a VAT number or enterprise number. 2. Access Points [#2-access-points] Access Points are service providers (like Recommand) that connect organizations to the Peppol network. They handle: * Document validation * Protocol conversion * Secure transmission * Digital signatures 3. SML and SMP [#3-sml-and-smp] * **SML (Service Metadata Locator)**: Central directory that helps locate the right SMP server * **SMP (Service Metadata Publisher)**: Contains information about recipients' capabilities and how to route documents to them Aside from being an access point service provider, Recommand also acts as an SMP. Document Exchange Process [#document-exchange-process] 1. **Addressing**: Documents are addressed using the recipient's Peppol ID 2. **Discovery**: * The sender's Access Point queries the SML to find the recipient's SMP * The SMP provides details about what document types the recipient can receive 3. **Validation**: Documents are validated against Peppol standards 4. **Transmission**: Documents are securely transmitted between Access Points 5. **Delivery**: The recipient's Access Point delivers the document to the recipient Benefits of Using Peppol [#benefits-of-using-peppol] * **Reduced costs**: Eliminate paper-based processes * **Faster processing**: Near real-time document delivery * **Increased accuracy**: Standardized formats reduce errors * **Regulatory compliance**: Meet legal requirements for e-invoicing * **Simplified supplier onboarding**: One connection to reach many trading partners * **International reach**: Seamlessly exchange documents across borders Peppol in Practice [#peppol-in-practice] Verification [#verification] Before sending a document, you can verify if the recipient is registered in the Peppol network using the [verify endpoint](/reference/recipients/verify-recipient): ```javascript // Check if recipient exists in Peppol network const response = await fetch("https://app.recommand.eu/api/v1/verify", { method: "POST", headers: { Authorization: "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify({ peppolAddress: "0208:987654321", }), }); ``` Document Types Support [#document-types-support] You can also check if a recipient supports specific document types using the [verify document support endpoint](/reference/recipients/verify-document-support): ```javascript // Check document type support const response = await fetch( "https://app.recommand.eu/api/v1/verify-document-support", { method: "POST", headers: { Authorization: "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify({ peppolAddress: "0208:987654321", documentType: "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1", }), } ); ``` Joining Peppol with Recommand [#joining-peppol-with-recommand] Recommand provides a fully managed Peppol Access Point and SMP service: 1. **Register your company** in the Recommand platform 2. **Configure your Peppol ID** (typically your enterprise number) by [creating a company](/docs/managing-companies) 3. **Start sending and receiving** Peppol documents instantly Next Steps [#next-steps] Learn about standards, identifiers, and validation rules. Follow the step-by-step guide to send an invoice. Check recipients exist and support the right document types. Create and manage your company profiles. # Peppol Standards and Compliance (/docs/peppol-standards-and-compliance) This guide covers the key standards and compliance requirements for [Peppol document exchange](/reference). Peppol BIS (Business Interoperability Specifications) [#peppol-bis-business-interoperability-specifications] Peppol BIS defines the business rules and document formats for different types of electronic documents. These specifications ensure interoperability between trading partners. Key BIS Specifications [#key-bis-specifications] | BIS Specification | Description | Document Types | | ----------------------- | -------------------------------- | ------------------------------------- | | BIS Billing 3.0 | Invoice and credit note exchange | Invoice, Credit Note | | BIS Ordering 3.3 | Purchase order process | Order, Order Response | | BIS Catalogue 3.1 | Product catalogue exchange | Catalogue, Catalogue Response | | BIS Despatch Advice 3.1 | Shipping information | Despatch Advice | | BIS Order Agreement 3.0 | Standing agreements | Order Agreement | | BIS Punch Out 3.1 | Catalogue request and response | Catalogue Request, Catalogue Response | BIS Billing 3.0 [#bis-billing-30] The most commonly used specification is BIS Billing 3.0, which supports: * **EN16931-compliant invoices**: Conforming to the European Standard for e-invoicing * **Credit notes**: For refunds and corrections * **Self-billing**: Where the customer creates the invoice on behalf of the supplier Document Formats and Identifiers [#document-formats-and-identifiers] Document Type Identifiers [#document-type-identifiers] Document type identifiers in Peppol follow this pattern: ```text root namespace::document element name##customization ID::version ID ``` For example, the standard invoice identifier: ```text urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1 ``` Process Identifiers [#process-identifiers] Process identifiers specify the business process context: ```text urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 ``` Where: * poacc indicates Post-Award processes * billing is the process group * 01 is the specific process (e.g., billing) * 1.0 is the version Validation Rules [#validation-rules] Peppol documents must pass multiple validation levels: 1. **Syntax Validation** Basic XML schema validation ensuring the document structure is correct. 2. **Semantic Validation (Schematron)** Business rules validation using Schematron, checking that: * Mandatory fields are present * Field values are in valid formats * Business logic is consistent 3. **Peppol Rules** Additional Peppol-specific rules, such as: * Valid Peppol identifiers * Required party information * Allowable code values Regional Compliance Requirements [#regional-compliance-requirements] Many countries have specific e-invoicing requirements that Peppol implementations must satisfy: European Union [#european-union] * **Directive 2014/55/EU**: Mandates that all public sector entities must be able to receive and process e-invoices * **EN16931**: European standard for e-invoicing core elements Compliance in the Recommand API [#compliance-in-the-recommand-api] The Recommand Peppol API handles many compliance details automatically: Document Validation [#document-validation] When sending a document through Recommand using the [send document endpoint](/reference/sending/send-document): ```javascript await fetch("https://app.recommand.eu/api/v1/{companyId}/send", { method: "POST", headers: { /* authentication headers */ }, body: JSON.stringify({ recipient: "0208:987654321", documentType: "invoice", document: invoiceData, }), }); ``` The API automatically: 1. Validates the document against the appropriate BIS specification 2. Converts your JSON payload to compliant UBL XML 3. Adds required Peppol headers and identifiers 4. Applies digital signatures as required Support for Multiple Document Types [#support-for-multiple-document-types] The API supports sending both high-level JSON documents and raw XML: ```javascript // Using JSON (automatically converted to UBL) { "recipient": "0208:987654321", "documentType": "invoice", "document": { /* invoice JSON */ } } // Using raw UBL { "recipient": "0208:987654321", "documentType": "xml", "document": "...", "doctypeId": "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1" } ``` Testing and certification [#testing-and-certification] Before going live with Peppol: 1. **Test documents** against Peppol validation rules 2. **Verify recipient readiness** using the [verification endpoints](/reference/recipients/verify-recipient) 3. **Send test documents** to known recipients in a controlled manner Common Compliance Challenges [#common-compliance-challenges] 1. **Missing mandatory fields**: Ensure all required fields are provided 2. **Incorrect party information**: Verify all party identifiers are correct 3. **Invalid code values**: Use only approved codes for units, countries, currencies, etc. 4. **Country-specific rules**: Be aware of additional national requirements Next Steps [#next-steps] Follow the step-by-step guide to send an invoice. Set up your company to start sending. Validate recipients before sending documents. # Receiving Documents (/docs/receiving-documents) This guide explains how to receive and process incoming Peppol documents using the [Recommand API](/reference/documents/get-documents). It covers the two main approaches, webhooks (push) and inbox polling (pull). It also explains how to retrieve and process document details. Overview [#overview] When a business partner sends you a document through the Peppol network, Recommand automatically receives, validates, and stores it. To consume these documents in your system, you have two options: 1. **Webhooks (recommended)**: receive real-time notifications as documents arrive 2. **Polling the Inbox**: periodically check for new unread documents Both approaches follow the same processing flow: 1. Detect a new incoming document 2. Fetch the full document details 3. Process the document in your system 4. Mark the document as read Prerequisites [#prerequisites] * A Recommand account with API access * Your API key and secret * At least one registered company with a [Peppol identifier](/docs/managing-companies) and [document types](/reference/company-document-types/create-company-document-type) configured Option 1: Webhooks (Recommended) [#option-1-webhooks-recommended] Webhooks push a notification to your server the moment a document arrives. This is the recommended approach because it gives you real-time delivery without unnecessary API calls. For a detailed guide on setting up webhook endpoints, registering webhooks, and managing them, see the [Working with Webhooks](/docs/working-with-webhooks) guide. This section focuses on the document processing flow. How It Works [#how-it-works] When a document is received, Recommand sends a POST request to your registered webhook URL: ```json { "eventType": "document.received", "documentId": "doc_xxx", "teamId": "team_xxx", "companyId": "c_xxx" } ``` Your handler should: 1. Acknowledge the webhook immediately (respond with `200 OK`) 2. Fetch the full document using the `documentId` 3. Process the document in your system 4. Mark the document as read Example: Webhook Handler [#example-webhook-handler] ```javascript app.post("/peppol-webhook", async (req, res) => { const event = req.body; // Acknowledge immediately res.status(200).send("OK"); if (event.eventType === "document.received") { // Fetch, process, and mark as read const document = await fetchDocument(event.documentId); await processInYourSystem(document); await markAsRead(event.documentId); } }); ``` When to Use Webhooks [#when-to-use-webhooks] * You need real-time processing of incoming documents * Your system can expose a publicly accessible HTTPS endpoint * You want to minimize API calls Option 2: Polling the Inbox [#option-2-polling-the-inbox] If you cannot expose a public endpoint for webhooks, you can poll the inbox at regular intervals to check for new documents. How It Works [#how-it-works-1] The [inbox endpoint](/reference/documents/get-inbox) returns all incoming documents that have not been marked as read. Once you process a document, mark it as read so it no longer appears in the inbox on the next poll. The inbox is not paginated. Every unread document comes back in one response, so marking documents as read is what keeps the response a sensible size. If you want a paged view of unread documents instead, use the [list documents endpoint](/reference/documents/get-documents) with `isUnread=true`. ```javascript async function pollInbox() { const response = await fetch("https://app.recommand.eu/api/v1/inbox", { headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), }, }); const result = await response.json(); return result.documents; // Array of unread incoming documents } ``` You can optionally filter by company: ```javascript const response = await fetch( "https://app.recommand.eu/api/v1/inbox?companyId=c_xxx", { headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), }, } ); ``` Example: Polling Loop [#example-polling-loop] ```javascript const POLL_INTERVAL = 60_000; // 1 minute async function startPolling() { while (true) { const documents = await pollInbox(); for (const doc of documents) { const fullDocument = await fetchDocument(doc.id); await processInYourSystem(fullDocument); await markAsRead(doc.id); } await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL)); } } startPolling(); ``` When to Use Polling [#when-to-use-polling] * Your system cannot expose a public webhook endpoint * You prefer a simpler architecture without inbound HTTP handling * Near-real-time processing is not required Recommended Polling Intervals [#recommended-polling-intervals] | Use Case | Interval | Notes | | ------------------- | ------------- | ------------------------------------------ | | Near-real-time | 1 minute | Higher API usage | | Standard processing | 5 minutes | Good balance for most integrations | | Batch processing | 15–60 minutes | For systems that process documents in bulk | Fetching Document Details [#fetching-document-details] Both approaches require fetching the full document to access its content. The inbox and webhook payloads provide a document ID but not the full parsed document. Use the [get document endpoint](/reference/documents/get-document) to retrieve the complete document: ```javascript async function fetchDocument(documentId) { const response = await fetch( `https://app.recommand.eu/api/v1/documents/${documentId}`, { headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), }, } ); const result = await response.json(); if (!result.success) { throw new Error(`Failed to fetch document: ${JSON.stringify(result.errors)}`); } return result.document; } ``` Document Response Structure [#document-response-structure] The document object contains the following key fields: | Field | Description | Example | | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | | `id` | Unique document ID | `"doc_xxx"` | | `companyId` | The company that received the document | `"c_xxx"` | | `direction` | Always `"incoming"` for received documents | `"incoming"` | | `type` | Document type: `invoice`, `creditNote`, `selfBillingInvoice`, `selfBillingCreditNote`, `messageLevelResponse`, `frenchInvoicingCdar`, `frenchB2CSalesReport`, `frenchB2CPaymentReport`, `frenchB2BiInvoiceReport`, `frenchB2BiPaymentReport`, or `unknown` | `"invoice"` | | `senderId` | Peppol address of the sender | `"0208:0123456789"` | | `receiverId` | Peppol address of the receiver (your company) | `"0208:9876543210"` | | `parsed` | The structured document content (invoice, credit note, etc.) | See below | | `xml` | The raw UBL XML | `" Forward incoming documents to email or accounting software automatically. Set up webhook endpoints and manage webhook registrations. Route incoming documents automatically based on supplier labels. Explore all document endpoints including inbox, get, list, and mark as read. # Working with Rules (/docs/rules) Rules let you automate what happens after key Peppol events in Recommand. Today, rules are configured in the dashboard and are intended for teams who want more control than the classic webhook setup. Rules are a more powerful and flexible alternative to our original webhook setup. If you only need a webhook with optional company scoping and HMAC signing, see [Working with Webhooks](/docs/working-with-webhooks). Overview [#overview] Each rule has four parts: * **Trigger**: the event that starts the rule * **Conditions**: optional filters to narrow the rule down * **Actions**: what should happen when the rule matches In the dashboard, you manage these from **Webhooks and rules** (accessible via the user selector in the bottom left corner). When to Use Rules [#when-to-use-rules] Use a rule when you want to: * send a webhook only for certain events instead of all webhook events * notify one or more email recipients when something happens * combine multiple actions, such as sending both a webhook and an email * take automated action on certain conditions, such as when a certain label is assigned to a document * filter by details such as document type, sender, label, or verification status If you only want one webhook endpoint that receives all supported webhook events, you can still use the simpler webhook flow described in [Working with Webhooks](/docs/working-with-webhooks). Supported Triggers [#supported-triggers] At the moment, rules can react to these Peppol events: * **Document received** * **Document sent** * **Document label assigned** * **Document label unassigned** * **Report status changed** * **Company verification** The exact filter options depend on the event you choose. Common examples include: * company * document type * sender address * receiver address * label * verification status * reporting status * outcome code The dashboard rule builder only shows filters that are supported for the selected event type. Supported Actions [#supported-actions] Rules currently support these actions: * **Webhook**: send an HTTP POST request to your endpoint, with an optional signing secret * **Email**: send a notification email to one or more recipients A single rule can have more than one action. For example, you can send a webhook to your ERP and also email your operations team. For email actions, Recommand can also include relevant attachments for supported document events, such as: * embedded attachments * the original XML document * an auto-generated PDF * a `document.json` attachment Creating a Rule in the Dashboard [#creating-a-rule-in-the-dashboard] 1. Open **Webhooks and rules** in the dashboard via the user selector in the bottom left corner. 2. Click **Create rule**. 3. Choose whether the rule is **team-wide** or **company-specific**. 4. Select the event type you want to react to. 5. Optionally add one or more conditions. 6. Add one or more actions. 7. Enable the rule and save it. If you want a broad webhook subscription, choose **All supported webhook events**. This is the closest equivalent to the classic webhook setup. This option is limited to webhook delivery only. It does not support conditions or email actions. Delivery and Monitoring [#delivery-and-monitoring] Rules run asynchronously. In the dashboard you can review deliveries per rule, including: * current status * number of attempts * processed time * last error If a delivery fails, Recommand retries it automatically for a limited number of times. You can also manually retry failed deliveries from the dashboard. After the final attempt, the delivery is marked as failed permanently. In the deliveries view, you may also see statuses such as pending, in progress, succeeded, failed, and giving up. A rule with two actions creates two separate deliveries. For example, if a rule sends both a webhook and an email, those are tracked separately so you can see which action succeeded or failed. Webhook Delivery Details [#webhook-delivery-details] Webhook actions keep the same simple event payloads used by the existing webhook feature. For example, a document received event still looks like this: ```json { "eventType": "document.received", "documentId": "doc_xxx", "teamId": "team_xxx", "companyId": "c_xxx" } ``` For technical integrations, Recommand also sends: * `X-Idempotency-Key` to help you deduplicate deliveries * `X-Signature` when you configure a signing secret As with regular webhooks, your endpoint should acknowledge quickly and handle heavier work asynchronously. Verifying Webhook Signatures [#verifying-webhook-signatures] When you set a signing secret on a webhook action, Recommand signs the **raw request body** with HMAC SHA-256 and sends it as: * `X-Signature: sha256=` Node.js example: ```javascript import crypto from "node:crypto"; function verifySignature(rawBody, signatureHeader, secret) { const expected = `sha256=${crypto .createHmac("sha256", secret) .update(rawBody) .digest("hex")}`; return signatureHeader === expected; } ``` Use the exact raw request body when verifying the signature. Availability [#availability] Rules are currently configured through the **Webhooks and rules** page in the dashboard. The dedicated rules API is not publicly available yet. If you want to integrate through a public API today, use the existing webhook endpoints. Those endpoints keep the classic broad webhook subscription model with URL and company scope and support HMAC signing secrets, but they do not expose advanced rule features such as conditions or email actions. For the currently available public endpoints, see the [API reference](/reference) and the [Working with Webhooks](/docs/working-with-webhooks) guide. Typical Examples [#typical-examples] * Send a webhook when a new invoice is received * Forward incoming invoices with a specific label or from a specific supplier to an external accounting system * Email your operations team when a company verification finishes * Notify your team when a specific label is assigned to a document * Create a company-specific automation for one legal entity in your team Related [#related] Use the classic webhook setup flow and see payload examples. Process incoming documents after a webhook or rule fires. Use labels to help route documents and build targeted automations. Understand the verification flow and related status updates. Explore the currently available public API endpoints. # Self‑Billing (/docs/self-billing) This guide explains how to issue and send Peppol‑compliant self‑billing documents (invoices and credit notes) using the Recommand API. What is self‑billing? [#what-is-selfbilling] Self‑billing is when the buyer (your company) creates the invoice on behalf of the supplier for goods or services received. The invoice is then sent to the supplier via Peppol. This is common in: * Long‑term supply agreements * High‑volume purchasing with automated pricing * Marketplace and platform settlements Important: You must have a prior agreement with the supplier to use self‑billing, and your self‑billing documents must meet local VAT and record‑keeping rules. Prerequisites [#prerequisites] * A Recommand account with API access * A registered company for your team (the buyer/issuer) * The supplier’s Peppol address * Your API key and secret Step‑by‑step [#stepbystep]
Verify the Supplier (Recipient) [#verify-the-supplier-recipient] Self‑billing documents are sent to your supplier. Verify the supplier’s Peppol address before sending to avoid delivery failures. ```javascript async function verifyRecipient(peppolAddress) { const response = await fetch("https://app.recommand.eu/api/v1/verify", { method: "POST", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify({ peppolAddress }), }); const result = await response.json(); return result.isValid; } ``` Create a Self‑Billing Invoice [#create-a-selfbilling-invoice] In self‑billing, the roles are: * buyer: your company (the issuer) * seller: your supplier (the recipient of the invoice and payment) Prepare the invoice payload [#prepare-the-invoice-payload] See generic models: [Party](/reference/sending/send-document), [PaymentMeans](/reference/sending/send-document), [Line](/reference/sending/send-document). ```javascript const selfBillingInvoice = { // Required identifiers invoiceNumber: "SBI-2025-001", // Recommended dates issueDate: "2025-01-15", dueDate: "2025-02-14", // Buyer = your company (issuer) - optional, will be auto-filled if omitted buyer: { vatNumber: "BE0123456789", name: "Your Company NV", street: "Main Street 1", city: "Brussels", postalZone: "1000", country: "BE", }, // Seller = supplier you are invoicing on their behalf seller: { vatNumber: "BE0987654321", name: "Supplier BV", street: "Supplier Street 5", city: "Antwerp", postalZone: "2000", country: "BE", }, // How you'll pay the supplier paymentMeans: [ { paymentMethod: "credit_transfer", reference: "SBI-2025-001", iban: "BE99000123456789", }, ], // Lines for delivered goods/services lines: [ { name: "Monthly supply of widgets", quantity: "100.00", unitCode: "C62", netPriceAmount: "5.00", vat: { category: "S", percentage: "21.00", }, }, ], // Optional references buyerReference: "PO-2025-1001", purchaseOrderReference: "PO-2025-1001", note: "Self-billing according to framework agreement 2025-01", }; ``` Send the self‑billing invoice [#send-the-selfbilling-invoice] Use the send endpoint with `documentType: "selfBillingInvoice"`: ```javascript async function sendSelfBillingInvoice(companyId, supplierPeppolId, document) { const token = Buffer.from("your_api_key:your_api_secret").toString("base64"); const response = await fetch( `https://app.recommand.eu/api/v1/${companyId}/send`, { method: "POST", headers: { Authorization: "Basic " + token, "Content-Type": "application/json", }, body: JSON.stringify({ recipient: supplierPeppolId, // send to your supplier documentType: "selfBillingInvoice", document, }), } ); return response.json(); } ``` Create a Self‑Billing Credit Note [#create-a-selfbilling-credit-note] When you need to correct a previously issued self‑billing invoice, issue a self‑billing credit note and reference the original invoice. Prepare the credit note payload [#prepare-the-credit-note-payload] ```javascript const selfBillingCreditNote = { creditNoteNumber: "SBCN-2025-001", issueDate: "2025-01-20", note: "Price correction for SBI-2025-001", // Buyer = your company (issuer) buyer: { vatNumber: "BE0123456789", name: "Your Company NV", street: "Main Street 1", city: "Brussels", postalZone: "1000", country: "BE", }, // Seller = supplier seller: { vatNumber: "BE0987654321", name: "Supplier BV", street: "Supplier Street 5", city: "Antwerp", postalZone: "2000", country: "BE", }, // Reference the original self-billing invoice invoiceReferences: [{ id: "SBI-2025-001" }], // Lines to credit lines: [ { name: "Price correction", quantity: "100.00", unitCode: "C62", netPriceAmount: "-0.50", // credit 0.50 per unit vat: { percentage: "21.00" }, }, ], }; ``` Send the self‑billing credit note [#send-the-selfbilling-credit-note] Use the send endpoint with `documentType: "selfBillingCreditNote"`: ```javascript async function sendSelfBillingCreditNote( companyId, supplierPeppolId, document ) { const token = Buffer.from("your_api_key:your_api_secret").toString("base64"); const response = await fetch( `https://app.recommand.eu/api/v1/${companyId}/send`, { method: "POST", headers: { Authorization: "Basic " + token, "Content-Type": "application/json", }, body: JSON.stringify({ recipient: supplierPeppolId, documentType: "selfBillingCreditNote", document, }), } ); return response.json(); } ```
Field notes and tips [#field-notes-and-tips] * Issue and due dates: If omitted, the API will default sensible values (issue date = today; due date = +1 month). * Totals and VAT: Totals are computed from lines if not supplied. You can provide `totals` and `vat` objects when you need explicit control. * Attachments: Add supporting documents via `attachments` (see [Attachment](/reference/sending/send-document)). * Payment details: Include the supplier’s bank information in `paymentMeans` to streamline settlement. * References: Use `buyerReference`, `purchaseOrderReference`, and `despatchReference` when applicable for matching. Best practices [#best-practices] 1. Have a written self‑billing agreement with each supplier and store its reference on the document. 2. Verify each supplier’s Peppol address before sending. 3. Keep consistent numbering series for self‑billing invoices and credit notes (e.g., `SBI-…`, `SBCN-…`). 4. Always reference the original invoice in credit notes (`invoiceReferences`). 5. Test end‑to‑end in a playground team before going live. Next steps [#next-steps] Validate suppliers and supported document types. Organize supplier data and workflows. Learn standard invoice flows. Correct issued documents when needed. Full parameters and response schema. # Sending Credit Notes (/docs/sending-credit-notes) This guide explains how to create and send credit notes through the [Recommand Peppol API](/reference/sending/send-document). Overview [#overview] Credit notes are documents that reverse or adjust previously issued invoices. Common reasons for issuing credit notes include: * Returning goods * Correcting billing errors * Applying discounts after an invoice has been issued * Canceling services or subscriptions In the Peppol network, credit notes follow similar structural requirements as invoices but serve the opposite financial purpose. Prerequisites [#prerequisites] * A Recommand account with API access * Your API key and secret * A registered company in your Recommand account * The Peppol address of your recipient Credit Note Structure [#credit-note-structure] A credit note in the Recommand API contains these key components (see [Credit Note model](/reference/sending/send-document) in the API reference): Required Fields [#required-fields] | Field | Description | Example | | ------------------ | ---------------------------------- | ---------------------------------------------------------- | | `creditNoteNumber` | Your unique credit note identifier | `"CN-2025-001"` | | `buyer` | Recipient company details | See [Party model](/reference/sending/send-document) | | `paymentMeans` | Payment instructions | See [PaymentMeans model](/reference/sending/send-document) | | `lines` | Credit note line items | See [Line model](/reference/sending/send-document) | Optional Fields [#optional-fields] | Field | Description | Example | | ---------------- | --------------------------------------------- | -------------------------------------------------------- | | `issueDate` | Credit note issue date (YYYY-MM-DD) | `"2024-05-15"` | | `note` | General credit note explanation | `"Returned damaged products"` | | `buyerReference` | Customer's reference number | `"RMA-2024-001"` | | `seller` | Your company details (auto-filled if omitted) | See [Party model](/reference/sending/send-document) | | `paymentTerms` | Textual payment terms | `{ note: "Refund within 14 days" }` | | `totals` | Credit note total amounts | See [Totals model](/reference/sending/send-document) | | `vat` | VAT breakdown | See [VatTotals model](/reference/sending/send-document) | | `attachments` | Supporting documents | See [Attachment model](/reference/sending/send-document) | Creating a Credit Note [#creating-a-credit-note] Here's a step-by-step guide to creating and sending a credit note: 1. Prepare the Credit Note Data [#1-prepare-the-credit-note-data] ```javascript const creditNote = { creditNoteNumber: "CN-2025-001", issueDate: "2024-05-15", note: "Credit for returned items from invoice INV-2025-001", // Buyer information (recipient) buyer: { vatNumber: "BE0123456789", name: "Customer Company", street: "Customer Street 1", city: "Brussels", postalZone: "1000", country: "BE", }, // Payment information (for refund) paymentMeans: [ { paymentMethod: "credit_transfer", reference: "CN-2025-001", iban: "BE1234567890", // Usually your bank account for refunds }, ], // Credit note lines lines: [ { name: "Product A", description: "Returned - Damaged on arrival", sellersId: "PROD-001", quantity: "5.00", unitCode: "C62", // Unit/piece netPriceAmount: "100.00", vat: { category: "S", percentage: "21.00", }, }, ], }; ``` 2. Send the Credit Note [#2-send-the-credit-note] Using the [send document endpoint](/reference/sending/send-document): ```javascript async function sendCreditNote(companyId, recipientPeppolId, creditNote) { const response = await fetch( `https://app.recommand.eu/api/v1/${companyId}/send`, { method: "POST", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify({ recipient: recipientPeppolId, documentType: "creditNote", document: creditNote, }), } ); return response.json(); } // Example usage const result = await sendCreditNote( "your_company_id", "0208:0123456789", creditNote ); if (result.success) { console.log("Credit note sent successfully!"); } else { console.error("Failed to send credit note:", result.errors); } ``` Common Credit Note Scenarios [#common-credit-note-scenarios] 1. Full Invoice Cancellation [#1-full-invoice-cancellation] To cancel an entire invoice, create a credit note with identical line items: ```javascript const fullCancellationCreditNote = { creditNoteNumber: "CN-2025-002", issueDate: "2024-05-16", note: "Full cancellation of invoice INV-2025-002", // ... buyer and payment details ... lines: [ // Identical line items to the original invoice, with same quantities and amounts ], }; ``` 2. Partial Refund [#2-partial-refund] For a partial refund, specify only the items being refunded: ```javascript const partialRefundCreditNote = { creditNoteNumber: "CN-2025-003", issueDate: "2024-05-17", note: "Partial refund for returned items from invoice INV-2025-003", // ... buyer and payment details ... lines: [ // Only include the items being refunded/credited { name: "Product B", quantity: "2.00", // Only 2 units returned out of more purchased netPriceAmount: "50.00", vat: { percentage: "21.00", }, }, ], }; ``` 3. Price Correction [#3-price-correction] To correct a pricing error: ```javascript const priceCorrectionCreditNote = { creditNoteNumber: "CN-2025-004", issueDate: "2024-05-18", note: "Price correction for invoice INV-2025-004", // ... buyer and payment details ... lines: [ { name: "Consulting Services", description: "Price adjustment - billed incorrectly", quantity: "10.00", unitCode: "HUR", // Hours netPriceAmount: "20.00", // The amount to be credited (e.g., $20 per hour refund) vat: { percentage: "21.00", }, }, ], }; ``` Specifying Totals [#specifying-totals] While the Recommand API can calculate totals automatically, you can also specify them manually: ```javascript const creditNote = { // ... other credit note fields ... totals: { taxExclusiveAmount: "500.00", // Total amount before tax taxInclusiveAmount: "605.00", // Total amount with tax payableAmount: "605.00", // Total amount to be refunded }, vat: { totalVatAmount: "105.00", subtotals: [ { taxableAmount: "500.00", vatAmount: "105.00", category: "S", percentage: "21.00", }, ], }, }; ``` Including Attachments [#including-attachments] You can attach supporting documents to your credit note: ```javascript const creditNote = { // ... other credit note fields ... attachments: [ { id: "ATT-001", mimeCode: "application/pdf", filename: "return_receipt.pdf", description: "Return receipt confirmation", embeddedDocument: "base64encodeddocument...", }, ], }; ``` If you want to try this out, you can use the following attachment object as an example: ```json { "id": "LOGO", "mimeCode": "image/png", "filename": "recommand.png", "description": "Recommand Logo", "embeddedDocument": "iVBORw0KGgoAAAANSUhEUgAAAfUAAAH1CAYAAADvSGcRAAAAAXNSR0IArs4c6QAAAIRlWElmTU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAAfWgAwAEAAAAAQAAAfUAAAAAPpJBcAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KGV7hBwAAQABJREFUeAHtnctuHEmWYM08KKlnMZ3KxnRjgBSlqF1JSkCsL0jmF0j5Bcncza5YX1Cs5ayKtZtdMb+gqOWsirmbXVFASapdhUQl0JgeoJW96pQUbnPN+YoIukf4w9zdHicAQeHm9jzXGdftce9Vig8EIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAgNcEpjvTu153kM5BAAKjEdCjtUzDEIiAwBePpztaq1Ilq42a2n9lw8yljFZmp+xekWbUV5X3Lm9o9ZPKzbGZZEfv/jo7uUzmfwhAIF0CKPV0ZR/9yBcVbjZXO6pC+RqTT1Wmp5VA6ijYysID3dDqh8lc783+NpsN1CLNQAACHhJAqXsoFLrUjcD9R9MDo82+MuqzbjUFVtrO3JXeP3s5Owqs53QXAhBwRACl7ggk1fhBYPvRg1PpyRM/ejNSL7T+DsU+EnuahcDIBLKR26d5CDgjYGfoUlnaCt3SNOaP24+ne/YrHwhAIC0CzNTTknfUo91+/OB9ckvuVRKVpfhc6d0fX87sygUfCEAgEQLM1BMRdOzDvPfldBeFviBlOU+QKXO4kMJXCEAgAQIo9QSEzBATJSCn9lmGT1T2DDtZAij1ZEXPwNMgYPbSGCejhAAELAGUOs9BFAS2thR7x2WSlNm6tdcvu0UaBCAQHwGUenwyTXJEs9PZexn4iyQHv2HQWZ7vb8jCbQhAIBICKPVIBMkwhIDWh3AoIaD1t9NfTqcld0iCAAQiI4BSj0ygKQ9ncksdiytY8arGZ5VAnqm91TSuIQCB+AhM4hsSI0qVwPt/ff+fd//583+Q8e+myqBy3Fr96p+++Px/WUaVebgBAQgET4CZevAiZACLBLJcHS1e8/2CgNitzz+qZ/CAAATiJoBSj1u+yY2uiFJmzPfJDbzGgI0xBzWykQUCEAiYAEo9YOHR9XICeZZxYK4EjfiEfrD9cMpsvYQNSRCIhQBKPRZJMo4rAoW/c4kvfpXAl2sCmYSk5QMBCERLAKUerWhTH5g+Sp1A6fhxRlOKhUQIxEIApR6LJBnHEgEbT9wo9WYpkYuCAM5oeBAgEC8BlHq8sk1+ZJnBGU3pQ2Cd0exM75beIxECEAiaAEo9aPHR+XUEsjti3oYzmlJE+QfF3nopGRIhEDYBlHrY8qP3awhYf/BGsbdehshoDsyVcSENAqETQKmHLkH6v5bA1lwdrs2Q6k1xRkOs9VSFz7hjJiCmq3wgEDeB7Yf3ZRlefxv3KJuPzh4kfPfqzbR5ST9KFC8lplhxeFJssxhzYsRHwbu/zk786CG9gMDwBFDqwzOnxYEJ3Ptyuqtz8+eBmw2iOZPpr0NUgvcfTQ+MMr8thSw+Cia39LOLcLylWUiEQKwEWH6PVbKM64rAhdIi1voVkesvOlDXsWvPBIgt/vyjmdmXueuR8g0CaRBAqachZ0ZJrPXyZ0AUYGix1gtXt3ImoHxAF6ly367O2Bn92nzchEBkBFDqkQmU4ZQTwBlNORebOtf5QfVdH+/kz+r2yi7Rbz+6f4xdfl1i5AudAEo9dAnS/9oEMszbylmF5owm07WV+vmA9dNPH8zpF4+nO+UASIVAPARQ6vHIkpFsIJDdFvM2nNGUUgrFGU2hmDctvZeMUE4EP8iM+cv9h9P9ktskQSAaAij1aETJQDYRKE5D5+Z4U74U7+fK7IUwblHOnfopB+x+b00cWY4PQdr0sQ0BlHobapQJlsDEZAfBdr7HjtuZbBDOaIxpuPReAk22G+YfzAnL8SVsSAqeAEo9eBEygCYEZn+bzZQyz5uUSSbvuSMXb4drlbB9+XDUwSeZMidBvMg4GjDVpEEApZ6GnBnlAgHrdWzhkq/XBJ74bNs9ydXudVcdfLN788b88d7jKc+DA5xU4QcBlLofcqAXAxLAGU01bJ3n+9V3x70j++F7ffRAHPD8evvRg9PQ7PX7YEGd4RNAqYcvQ0bQhgDOaCqo6ac+KreLPj2p6LSL5CfziTktHNu4qI06IDASAZT6SOBpdlwC1hkN5m3lMvDRGU2uVfcDcuXDvU61y/Ha/AkvdNdI+BYeAZR6eDKjx44IaKPZSy1jKc5dfDP5MjrfLetqH2mFF7rHD058Y9DHWKkzPgIo9fhkyohqEiic0dTMm1Q2mbH65IzmXLnqp4PKgKAwg+KmMXcEUOruWFJTYAQKZzTGfB9Ytwfprk/OaOYfB1h6L6MqLzdFUBi80JXRIc1TAih1TwVDt4YhgDOacs5eOaMx9QO4lI+mW2rhhY6gMN0gUnowAvK3yyc0AtYJx8SoZ/Jjs7vad6P0qQj1dHJLHRcz0dUMXN8gsC37p0qWW2/cSD1Bqx/OXr7ZHRuDmJuZsftg25dOvDFaP/vx5ezUh/7QBwiUEUCpl1HxNK1wDJKbIzuLqtdF89w6Wrmwy65XJMFclqtdZk1w6BuHbDL99ZjPT2FiJifSN3Z0yAxaf1dYTwzZJm1BoCYBlt9rgho7m/V6ZRVPfYVue6yf2jJ2Juqzp7Cx2VqlZWdhY/fDx/b1PN8bt1/jLr2Xjl280BEUppQMiR4QQKl7IIRNXbDhIq3Xq035Ku/L0nKh3G10ql9Op5X5Er6htT5IePjVQ7ex1sd8ZhrHTq8eitM7BIVxipPK3BFAqbtj2UtN9gfVHtRxUrn9IRKvWTjXuEnTnkHAGc1NLjbl00SN4jq2WF2yDmH8/RAUxl/ZJNszlLrnohclfOS0i/IjaZ1r3Hv0YIZLzGuy9lAhzmiueSx+0xJrfRRHLHIYdLEfXn63Lx0EhfFSNKl2CqXuseQLpdvTqexib14OINn9duJKnz8EWa6OPH4cxuuaKK78Z7U3eAdcxE4fqNMEhRkINM1sJIBS34honAx2ZiTL7v27MZWXhsyYv9iDeKPMxsbBW9pqEWsdZzSlbHJtBl2Cdxw7vXRMPSQSFKYHqFTZjABKvRmvwXJ/+qgOmp1079Y1O9OYfzQzeyivW01hl86JtV4qQPssbj+e7pXe7CHR+mHoodr+q7TL8QSF6Z8zLVQSkL9VPr4RsLMUO3sesV8vxD55f0z75BHHrnBGU0F/QGc0Nr659OJJRU/CSBZek1v6GU6gwhBXLL1kpu6hJDM1wLL7+nE/KUzgrGvMMc2Z1vexv7s50dtK4cpWzRDnLy6eubAVugUovOzqFz4iSp8mEnsigFLvCWzbaovl754OxzXvk356aQKX0n772evZMc5oyp+WLM97354ZJHZ6+fDcp8pyvH1BTn1byz1YaqwigFKvIjNCenE4LjMHIzRd3aT8KFkTuE8fzOmQe6rVHRrmTkas9XLQAzijMZkJcz+9nFiRSlCYNXC45ZQASt0pzm6VzX/OD2XJzktnG8WhPeseMxETuOyOmLdp9VM3icZZOs/6M28rVoS8WalyLT9Z+fpgMCF1jZX6lgig1JdwjHdR7LvJLGi8HtRsWX5w7SG+2H1f28NNEvHuqCaVpLLJrHO/r+2Y0WKnDyfBJ2JpctwXv+GGQUu+EkCp+yIZib7mS1dq9cO6nI3cBG5rrg5rsUgtk6wm9aZ8R46dPoQo7aqX/O0cD9EWbaRHAKXugcytL/ZieduDvjTqgt1vF7/01uVsjCd8cUZT/TQY09fZD/20utWI7siKV0pnVCKSnPdDQamPLKKLgC29nyjuc5j2heQyxGtsJnBmkh31yS7Uuq3MXccOcF2f72z7ezHyfeT0r08CKPU+6daouwjY4unhuBrdX84is495Zv5uVx5i2TMsHPCIE5HlgXJVEMhcu471MHZ6j6Lu48Wox+5SdSAEUOojCqrPgC0jDksO8Jvf2v32eJYXOTBX+jzJS5xTZzS+xk4vHbybRJOpXTc1UQsEzgmg1Ed6EuxMdpCALSONrzDNuzCBC32//ezl7AhnNOUPkitnNMUzEsuKVTmq0lQJa7tTeoNECLQkgFJvCa5rsfyD2rfLb13r8b68zOaK/faH949C3m/HGU3Fk2ad0cgLasXd+smhBnCpP0JyQmAQAij1QTAvN2KXLO0S9XJq5FfWBG5iTu1+e4gjxRlNtdTsC2r13Zp3AoqdXnNEZIPAKARQ6iNg9yBgywijliatCZy8zFgTuNBOOheRtnJsi8seHOuMpiy9bpp9yU1i1aoMSG5mZcmkQaAtAZR6W3ItyxWHx2RJumXxKIoVP+ASc9q6nA1pSX5isoMoBOB6EPKy1uVQZLCx011wzLITF9VQBwQuCaDUL0kM8P/53uPoYVUHGGnNJi5M4O49nh462Zet2WzbbIUzGmWety0fc7kuNtcy09+Nmc26seVKna67zz0INCWAUm9KrEN+nwO2dBhW56LiC/vXoZjAmSw77DzgCCuwqy+hWzkMLhYJGPTjyxlKfXDwcTeIUh9IvsUPXggBWwbicaMZa85kTeAePTj1WTkUzmiUenGj/yQoeTk7aIXBmPetyoVfCIUevgy9GwFKfSCRiFkXM7x6rJ8UJnCP7h97u9+uNbIsk6Vsp7SRmVZZkspNG31ShpE0CHQhgFLvQq9m2Qszric1s5OtICCxpy9M4Hzbb8cZTfUjOtf5QfXd8jtzrY7L78Sdagz76XFLeJzRodR75m5nLl1Nfnruor/VX5jAffpgTn0zgcuItV7+3LRwRnOxr5zclsbkjjoph0gqBNoTQKm3Z1er5DzLDwuXqbVyk6mMwKIJnFNf42WN1UzLbkusdTnoVDN7UtlaOaNJbEvDuh0ufB8k9WQw2CEIoNR7pHx+4CuR+NA9cryqWvZsM2P+sm1dzrpwTXpVcfMv585o9F7zkvGXyJVpzCW1LQ05VHgS/5PACMcggFLviXqhdHJz1FP1aVdrXc5KFLj7D6f7Y4I4ez07lhP734/ZBx/btisrbZzRpLSlkerhQB+f19j6hFLvSaLJBGzpid/Gau1+uza/ty5nxzSBO3v9dg/FXiIt09x1bEpbGvmEQ3IlTw1JDgjISzUf1wTs4bh5Zv7uul7qW0fAPJ/k2f6517d1+fq5Z7cEFH4IluCaTH99Yde/lL7uIhWOZ6/e8Nu77kHgXmsCzNRbo6suKKZYR9V3udMPATGBkxcpaz44xn77+Yxdf8PhuWvp6jxvvD2ShH99rX64psQ3CLglgFJ3y1MRsMUx0IbV2ShwhQnc4+lew6Kds9s99sktLSaM+g+dK4uiAv20qTOaFPzrG6WTdLYTxSMdwCBQ6g6FdD5DxHOcQ6StqpJ1zQeFy1mJAjf0frs9Ff/u5Ww/1/pXMmtPfkbWxhlN7P71dY59eqs/bArVIoBSr4WpXqZPH9UBNun1WA2SS0zgCpezI5jAWYcqZy/f7Mo++3dJL8ln+lnT7RC7D2/tuAd5RkZoRELNMlMfgXsqTaLUHUnazghttDFH1VGNSwKXJnCy3+6y2jp1WfvrpJfkxUqhjTMarfXgsqojz855xGHRWIc5O/edCoIgICuVfFwQsNHFpB78u7uA2WMdxQww03tNT2W76JL1hpcp2Z6RFQQX9YVSh2X+7tWbadP+bj9+8D6+lS/z/OzV22dNWZAfAnUJMFOvS2pNvgsnKCj0NYx8uWX324sledlvb3qIq+sYUl2St8zbuPeVKGaHXZn7Vh6nM75JJL7+oNQ7ytTuF5qsZRzpjm1TvAMBmS1bE7h7j6eHTfd8O7RaFE1xSV5+aHaaciuc0TQt5Hn+POOQnOciCr57KPWOIpx/yI/iWyLsCCWg4vYchHU528ataZdhXp6Stw5apJ7oI5Rpo6ZNeRX+9SNzwzvGtk9T7uQPmwBKvYP8CNjSAZ5PReUwV2ECJ+cihjaBsz/y4l1sR5aaf5P0KfmK5yEyZzTRv7xViJHkAQmg1LvAJmBLF3o+ln1yZQInrn6H7ODb17NDe0o+Vj/ypqUZV3FSPBZ7f2PsYVo+EOiVAEq9JV7rjtQeAGpZnGI+E7AmcBNzamU8ZDftcrN1NxvjkvzkTvu9ZPHQN6gcepN5lp30VjcVQ+CCgOglPk0JELClKbFw81tzLFka3y/CrA48DGtVURzCtNsDAX+00r97+2p20GUINhpf6C/R1sugtYDowoGyENhEgJn6JkIl9wnYUgIl0qRCkWjzJ7GZPmljltUFSxRL8nLQratCtwyDd0YjTmdQ6F3+GihblwBKvS6pi3zbD6fPUnMe0hBRnNnFBC4z5i9Dm8CFuCRvVzeUMs/tNkIRvc7BEzG5pY4DP0jIDN3Bc0AVmwmw/L6Z0VUOa89szZ8wYbtCkuYXmXXpXB/YmfTQAOw+v9Fm37Nn8IXse5/Ij8npZK5O+nKDWoxdovANzdxFey62IFz0gzriJ4BSbyBjO0vDv3sDYPFnfSGz0f2hbY/Pz3Tk8kKhn46CWE6jyzmDE3ui3R6AK+zJB+hI0GdZjP5mjHMZA4iFJjwjgFKvKZDCb7csv9bMTrakCJjnkzzb72uGWoWysKkXs0r5I+7PCkNWJcTMTmbh2an1hjb0C8zq2Lcl4p5ssH+7mu779eS2/nyolx/fWdC/fgmg1GvyJWBLTVAJZ7NLrNa16dA/3i6X5O1+uKxGnSgxv8plOd23w10hvlxbpm0C2iT8p8TQOxBAqdeAV5gWafP7GlnJkjiBQimKXbX17z4kig5L8uf74bk6sXG+h15taMPIWiIEdVhVLABcHRhsw4syaRFAqW+QN4fjNgDidjkB2XfOld4feqZrl+R1nu9X7rdf7IfbpfStLVHi4vCmfAD+phYWKGJm6G8Pl3tmXQCPcahyuRdcpUIApb5B0qHu4W0YFrcHIjDWD7p9Gf306Toymhxqez/0C0afiENyRmNN+8Y+i9CnLKjbLwIo9TXyOJ/1mD+vycItCGwmwPLrZkYNcxRR9Yz5Y8Nio2SXgD38zo5CPs1GcT6zTu4EbFlHh3t1Cchp7aH9yNftWqj5gnFGE0swmlAflAT7jVKvELr9EZbX6wcVt0mGQCMCRpymDB3WtVEHA8tszwLI1sbgzn+aYjJKnzYtQ34IdCGAUi+hZ08SF167Su6RBIHWBFj5aY2urKA1H7TWBmX3fEnTYlXgS1/oRxoEUOolci4CtgQeGatkWCSNTMCu/BR7wSP3I5bm7Wxd3NM+U9ZBjqcfayboadfoVqQEUOorgiVgywoQLt0SMOK3nY8zAucn+rWfTOVlIwS7f2fCoCIvCKDUV8Qgy+6HK0lcQsAlgSfW3MxlhanXZR392Fjl3i3FW898fCAwMAGU+gJwO0vncNwCEL72QmDRfryXBhKs1M7Yt27rHVmO/4Mvw7f+8n3pC/1IhwBKfUHWJlO7C5d8hQAEAiJg99jfvZztW2cvPszarde+gPDR1UgIoNQXBKmV2Vm45CsEIBAgAeu9zQZQsQF2xuw+XuTGpJ9u2yj1dGXPyCEQNYG3r2YHdq9dBvlihIGO0eYIw6RJ3wig1H2TCP2Jm4CciGYGN5yI7V67uGndsT74BzV9M4b99OHETEsLBFDqCzDw/rQAg6/9EMjNcT8VU+s6AjZK2mSud0Sx/7Aun7N7Eo/eWV1UBIEGBFDqC7Dk5Dtv1ws8+OqeQJ5lh+5rpcY6BKzN+NnLN7tDzNpzfkvqiIQ8PRBAqS9ADSZIxEKf+RoUgRcxhT8NivxCZ4tZ+y09Vco8X0h291W2WJCzO5zU1IwASn2BlzWJUSyPLhDhq1MC2v8AJE7H63Fl9m/97NXbZ8rob3rYa2fFz2PZx941lPqKhCd3sv0e/shXWuEyRQLFSlCKA/d4zGevZ8cTO2uXmPeuuinL+yeu6qIeCDQlgFJfIXY+W9d7K8lcQqAbAVEaxbPVrRZK90CgmLW/frvnymmNIYhLD1KiyroEUOolpOzbu0/uJku6SFJgBMwkOwqsy8l115oaunA1O7mDJ7nkHh6PBiwHvvlUEdh+eP9Iaf1t1X3SIVCHgHVZaj2c1clLHj8I3PtyuqvzIrjTkyY9QtZNaJG3DwLM1NdQPZMlOVHq37HHvgYStzYSyAwH5DZC8iyDnbUXTmsaupoVV9MckvNMlql1B6W+QeJFWEeldwdzWrGhP9wOj0B2Rx2F12t6bAk0djWrs2PIQWBMAiy/N6BfLMkZc6CM+qpBMbImTcA8L0ynkmYQx+DvP5xKBLji7/+zihG9sLP7inskQ2AQAszUG2AuluTEI5U9JcvMvQG4lLMaDsjFIv4rV7Nl5m/ifnZyW1b0+EBgZALM1DsIYPrL6XSu8wMO03WAGHFRDk3FK9zpzvTup0+qmJWLCdt7PMjFK+vQRoZSdyCxK+WeafFQpaqW5hy0RBUhEbDxvO2ebEh9pq8QgEDYBFDqDuVn397zD2rfaLOPcncINtCqJrn+hQ0iEmj36TYEIBAgAZR6D0K7VO65MnsC+EEPTVCl9wQ4IOe9iOggBCIkgFLvWajbj6d7Rk7Mo9x7Bu1b9eLfwJpD+tYt+gMBCMRNAKU+kHytcpdQj3uYww0EfMxmJPSmxO2+O2YXaBsCEEiTACZtA8ndztrkhx5zuIF4j9mMUfpozPZpGwIQSJcAM/WRZF84spnn1g3ttyN1gWZ7IsABuZ7AUi0EILCRAEp9I6J+M1yZw6Hc+wU9VO3ihMSuyAzVHO1AAAIQWCTA8vsijRG+W5MnGzjGzu6sXbN4qvtphG7QpDMCLL07Q0lFEIBAYwLM1Bsj67fApTkctu79cu6ldnkhm9zS09np7H0v9VMpBCAAgQ0EUOobAI112yr3+Uf1DHO4sSTQol3xCV6E621RlCIQgAAEXBBAqbug2HMd2Lr3DNhR9bnWv8IHuCOYVAMBCLQigFJvhW2cQoR+HYd7zVYJu1kTFNkgAIH+CHBQrj+2zmsm9KtzpO4q1PrQXWXUBAEIQKAdAWbq7bh5UQpzOC/EUHRCYml/zgE5f+RBTyCQKgGUegSSv1LuhH4dR5ockBuHO61CAAI3CKDUbyAJNwFzuHFkZzL9td0aGad1WoUABCBwTQClfs0imm+Xyp3Qr/2L1Cj15t2rN9P+W6IFCEAAApsJoNQ3Mwo6B+Zw/YpPG/2bt69nHJLrFzO1QwACNQmg1GuCCj0boV/7kSAH5PrhSq0QgEA7Aij1dtyCLYWtu0PRcUDOIUyqggAEXBBAqbugGGAdhH7tKDT8vHcESHEIQKAPAij1PqgGVOeVORyhX+tLTRR6rvQuLmHrIyMnBCAwDAGU+jCcvW/FKvc8U3tEh9sgKomXLgp9H4W+gRO3IQCBUQig1EfB7m+jl+ZwKPcFGdkY97k5Vio7Pns9k//5QAACEPCTAErdT7mM3qvUQ79a+3Ol9bHO1QmKfPTHkQ5AAAI1CaDUa4JKOVtCtu4vxO78aJ6pE5bXU37iGTsEwiWAUg9XdoP3PE5zOPNc6ex4Mlcns7/NZoNDpUEIQAACDgmg1B3CTKWqoJX7wv745I4o8tPZ+1TkxjghAIH4CaDU45dxbyMMxRzucn9c/j9iWb23x4GKIQABDwig1D0QQuhduFLufoV+LfbHM6OOWVYP/Qmj/xCAQF0CKPW6pMi3kcCo5nB2Wd2Yk2J//JYocpbVN8qLDBCAQHwEUOrxyXT0EV0q975Dv9pldW0VOfbjo8ucDkAAAn4QQKn7IYdoe9GDOdwLo/UJ++PRPjIMDAIQ6EAApd4BHkXrE+gW+tU81yY7YX+8Pm9yQgACaRJAqacp99FGfRUdbt2hukuzsyw7mbA/PpqsaBgCEAiPAEo9PJlF0+NzBa/uaq127KCMUacSVGaG2Vk0ImYgEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCECgAwFCr3aAR9FwCHzxeLojIV7vXvb43V9nJ5ff+R8CEIBALARQ6rFIknEsEZjuTO/OP6pnyuTPlNJPl25eX7zQRh9ld9TR7HT2/jqZbxCAAATCJIBSD1Nu9LqEQE1FfrOkVj/pXB+8fT07vHmTFAhAAALhEECphyMrelpBYPvhVGbjMiPX+tuKLDWTzfPJ7WyPWXtNXGSDAAS8I4BS904kdKgOgStFnmlZYlef1SlTM8+LyW29i2KvSYtsEICAVwS2vOoNnYHAGgL2sFuW5/uqUORGFLm8k5o1BdrdejL/aI6l6G674pSCAAQgMB4BZurjsaflGgSKU+tK7SljnsnD+qBGESdZ5ADdb9hjd4KSSiAAgQEJoNQHhE1T9QiMpciXeieH5ya39JRl+CUqXEAAAp4TYPndcwGl0r3pL6fTXKtnRhs7K38y+rhlnz7/WVYIlOJE/OjCoAMQgEBdAszU65Iin3MCS4pcqfEV+coIZbv+zbtXb6YryVxCAAIQ8JYASt1b0cTZsStbcmVn5Oor70ep9XdnL2dH3veTDkIAAhAQAiy/8xj0TuBKkYt3t/kH87T3Bp02IC8fSh05rZLKIAABCPREgJl6T2CpVqntx1OZja910xoEJpPpr/EVH4So6CQEkifATD35R8AtgGWnMBe25G6bGLw2Pc/3pNGTwRumQQhAAAINCTBTbwiM7DcJLCtyp97dbjY2Usok17+Y/W02G6l5moUABCBQiwAz9VqYyLRK4NKWXBcH3nrz7rba7GjXeVaYtx2M1gEahgAEIFCDADP1GpDIck7gUpEP7d3NC/44o/FCDHQCAhBYT4CZ+no+yd8tbMlllprLjFwbM5ibVu/AizOaIj47J+G9Ew0dggAErgkwU79mwbcLAr47hRlLUDijGYs87UIAAnUJoNTrkoo8H4q8poCN/ubs9cxGceMDAQhAwDsCLL97J5LhOrTkFEaF5hRmOE5LLWVmX65R6ktQuIAABHwhwEzdF0kM1I9FRS7xyAPz7jYQpA3N5Fr/6seXs9MN2bgNAS8JFE6hrNWKUjvyT55jfYQrZC9F1apTKPVW2MIrVNiSa+tEBUXeWXrGfH/2+q2w5AOBcAjc+3K6q3JzJD/6Nw682vMiKtN7eE4MR55VPUWpV5GJID0FpzBjiWlyW39OrPWx6NNuEwL2vMw8yw/rvdCb55M828fRUhPCfuVFqfslj869sW/jhVvTTD+TKGifda6QCkoJaKV/9/bV7KD0JokQ8ICA3WrLP6h9o8xvm3bHPt/ZbXXIi2tTcuPnR6mPL4POPUjaKUxnei0rEGc0Zy/f3G1ZmmIQ6JWAXaUz2hyWLbXXbdguyWutD9hvr0vMj3wodT/k0LgXKPLGyNwXINa6e6bU2ImA/V3IlDmUVbqvOlW0WFirH3Kl9zkcugjF3+8odX9lc6Nnl7bkuTb7Xd7Ab1RMQisCdibz7tWbaavCFIKAQwJ2qf3TR3UgXh9/7bDa5arkgOjkjuy3n87eL9/gyicCKHWfpFHSl0tFLktpe3L7SUkWkkYkQKz1EeHTdEHg/sPpvsnMwSBnaGTbSRt9yHkSfx8+lLqHsikOuPys9lDkHgpntUuyNCl767uryVxDoG8CxaHYXJbaR3jZt6tUmMD1LeF29aPU23FzXgqnMM6RDlYhsdYHQ01DQqCZiVrPyOSldjLXe5jA9cy5QfUo9QawXGdFkbsmOlJ9OKMZCXx6zd5/ND2QFbz9QZbaG+DFBK4BrJ6zotR7BlxWPU5hyqgEnEas9YCFF0bX13mD82YE8ncgDm72MYEbVyIo9YH4o8gHAj1SMzijGQl8As0WZmrG/CWYocqSvBH7dlzOjiMxlHqP3Is/xjzflwMleHfrkbMPVWPe5oMU4uzDvUcPZvJD/SC40VkTOJMdsN8+rORQ6o554xTGMdCQqsMZTUjSCqKvxQqfNn8KorNlncQEroxKr2kodQd4UeQOIMZRxYuzV2924hgKo/CBQHEwroXvdh/6vtgHu5Il9u37Z69nx4vpfHdPAKXekilOYVqCi7wYzmgiF/DAw9t+/ODEqcvXgft/ozlM4G4gcZ2w5brCmOtbVORzZfDuFrOwW46tiJCn1EnL4hSDwBIBY9Q0qpmX+KSfZ+bv9x5P/7B1Sx3gcnZJ3E4uonpenBBZqeTKllyJm1aXQRJW2uEyHgI4o4lHlmOPZPvRA1m5jvSDCVwvgs16qTWCSq1d6Paj+8fzD+bflTF/RKFHINSBhvBpovYHaopmIiZQ2KZHPL7CgY78tsqLy2n0Yx1Qjij1FdiFMpd9LJ2bP4sjhacrt7mEwEYCWlZ17ArPxoxkgMAaAlqW3tfcjunWE/t7aydRdoszpoGNMRaU+gJ12ec5LJQ5y+wLVPjamIBRn+USkKdxOQpAYIFAQkr9YtT66XxiTrcfT/cWMPC1IQGUugCzsyp7yrTXWMQNBUP2sAnYmPdhj4Dej01AfLzvjt2HwduXF2K73XnugXPw1qNoEKUuYpR987jMRqJ4NMMehJxAfcCMI2wZjt17e/J97D6M1n5mjtjCakc/eaW+/fD+kaDDPK3d80OptQTEYoIPBFoSsC+GLYuGX0xm7POf88PwBzL8CJJW6ucuGPW3w2OnxSQIyNkM620wibEySKcEOA0uOCVmBrP15o9V0kpd9qx4E2z+zFCiAYHMBvThA4GGBNI7JFcCyM7WP6pnJXdIWkMgWaVu9zuTXt5a81BwyyEBrb9ltuGQZyJVodQvBJ3nu4mI3Nkwk1XqcsKSGZSzx4iK1hGY/6x2193nHgRWCSR58n0Vgr3O9NT+x6c+gSSV+sXMicNx9Z8TcnYgoLXa6VCcogkSSPrke4LydjnkJJX6p0/8yLp8iKhrPQFj8un6HNyFwDIBtgaXeXBVn0CSSp39qvoPCDkdEGAJ0QHEdKrg5Hs6su5jpCj1PqhSJwQWCeRmtnjJdwisI8CkYx0d7m0ikKRSl/2q001guA8BVwS0zmau6qKe+Amg1K9lbJTmt/oaR61vaSr1iXpfiw6ZIOCAQJ6pEwfVUEUiBDj5fi3ozPBbfU2j3rcklfq7v85O6uEhFwQ6EtDqJ563jgwTK87J98QE7ni4SSr1c4bmuWOWVAeBmwRyc3wzkRQIVBPg5Ps1G7ZKr1nU/ZauUjfZUV1I5INAewIZSr09vORKcvJ9WeSGrdJlIDWuklXqZ69nx0apNzUYkQUC7QjI0rt9ztoVplSKBDgkl6LU3Y45WaVuMWZGH7rFSW0QWCDA0vsCDL7WIYBSX6a0tYWl0jKRzVdpK/U76kjJbGozJnJAoA0Blt7bUEu5DCffl6U/O529X07hahOBpJW6fWDEDvJoEyTuQ6AxAZbeGyOjgJI4U2oKBwh0IZC0UrfgtuaKJfguTxBlywmw9F7OhdS1BDj5voBHqx8Wrvhak0DySn32t9lMXo+/r8mLbBCoSYCl95qgyHZBgJPvPAouCCSv1C1EM8G8zcXDRB0XBFh651FoQYBDci2gUeQGAZS6ILnw+PXiBh0SINCGAEvvbaglXwalvvwIaKNPllO4qkMApX5JSWPedomC/7sSYOm9K8EUy3PyPUWpux8zSv2C6dnL2RHOaNw/YKnVaJ8hHM6kJnU34+XkuxuOqdeCUl94AjLM2xZo8LUVAa3xINcKHIU4+b78DBDdcJlH3SuU+gKp7LaYt+GMZoEIX5sSkJn6UdMy5IcABCDgigBKfYFk4b2IQ04LRPjahIBdev/x5ey0SRnyQuCSANt/lyTO/5ftCLzJLSOpdYVSX8E0MdnBShKXEKhHgKX3epzIVUpAazUrvZFoIi/I7QSPUl/hVjijwZPRChUu6xBg6b0OJfJUEdA55zGq2JBenwBKvYSV0fqgJJkkCFQSYOm9Eg03ahLIjOKQ5SUrzjZdkmj8P0q9BJl1RsP+VgkYkqoJsPRezYY7tQiwSriEibMpSzjqX6DUK1hpZusVZEguI8DSexkV0poSyJXeb1qG/BBYJIBSX6Sx8N06o8G8bQEIXysJsPReiYYbDQnYw2HiHvU3DYvFl90YTr63lCpKfQ04+eM6XHObWxA4J8DSO0+CQwJvX88O5VzPHxxWGVxVWmUsv7eUGkp9Dbgsx5HIGjzcuiDA0juPgmsC717O9pXR33C2xzXZ+OtDqa+RcXFwhVjrawhxi6V3noG+CNgYAu9evZkqrb9LTbkbbPZbP1Yo9Q3o8ixjCX4Do6Rvs/SetPiHGLw932OVu8n013LO54ch2hy7DZR6ewmg1DewK7waJfKHtAEFt0sIsPReAoWkXghYU9uzl292C+WuzPNeGqHS4Amg1OuIMOfAXB1MqeVh6T01ifsx3kK5v3r7bJLrX6hItwe3PuEyt+3TJtH++NQhcO/RgxmhEeuQSiePVvp3b1/NDvoe8XRnevfTJ7UjBzd3bVsS6OJ0Iv+KMx99N0793hOY/nI6nev8QGX6mTLqM+87XKODZ6/eoJtqcCrLArgyKiVp9x9O9402vy+5RVKiBOxMqU/Feu/L6a7O832l9NMyxHalIBOzy+yOOioiDJZlIi0ZAvblL/+g7O+UnJwPW7mj1Ns/tij1muzsH8z8o5mF/sdSc7hk20zghfzw7GzO1jxHMTP/qA60Mb+uX1r2WE12ZE9M1y9DzhgJFMr9Z7WXi3IPdHWxt7+tGOW9OiaU+iqRNdf3Hk8Pm/3QrqmMW0ETsF6/rJMQ14MoXh4/mBOp90mbuovZu9JH1sdCn6sIbfoWW5ntx9M9bdS0GJfE/rYBWXxjbvtojDkISrnLwWR7IDC252Wo8aDUG5Au9q4y8/cGRcgaKYG+lt63H92XmXb5cntjlIXVhj4qXB43LkyBKgLbD6fPVGaOSlft5OCamWRH9jBbVfkx0q1yl9MYe9Lnr8Zov1GbKPVGuFYzo9RXiWy43n54X3zC6283ZON23AR6WR7s7dyGDWOZm2Prc6Ew0YxbNr2N7nwVJT+q9dLl6QtVcU5DZu4+K3frIrfwqNebJOOueBL38NyP7h//++fvZcltz33N1BgKAVl6/58//b/3/8dlf4t9UGPsfvg/uKz3oq5/kBfRHXmD/x+f/fPdbz77l8//85++uDt7/6/v/7OHtqKs0ipDMzcic113W2QqIJ794z/f/e7uf/tcfX7v7t984P0f//f97D/+7aej//ovnz+XrcT/Yp8L3wSWKf2/f/q39ye+9SuU/mCn3lBSF8tqLxoWI3tEBOzeqevhzD+qocyRnohN3B/nH8y/21Unq6xcjyWm+uzLVnGWJjd/Ll1u3zBYu5dtrWbsIVtbj93C21BkkNt2xebs9du9mG3dBwHpYSMsv7cQSrE/JT+MLYpSJHwCvSy9bz96cCpo6s4CnVI01jSOw3U3mBYvPLk5sor5xs1OCea5ka0Qn/bd7ctGnqk9L8zhJJANVhztHzCUekt2OKNpCS7wYn2cer848f7vfqDBNM7K41Njk8JW0nshy9+HPh1kLLaBRrZ1t25wfXrhaSXZEQuh1FvCv/9oemCU+W3L4hQLlEAfp969XPmRw3VGZu9bc3Xom5lWn4/OF4+nO7LXfOx+dl7d66uVktvC+nT2vjrnsHfGModDqXeTM0q9Jb9idoUzmpb0gi3W09K7QzO2ftAWM8rJLbHD9kjpuB7q6C/qF1YKE5Md+PQiNbRyx5tctycbpd6BH+ZtHeAFWDT+pfcNQonUNM7OzjMjducjnWkopS4mcWLadeDTMvRQ5nAo9dInonYiSr02qpsZcUZzk0nMKZPb+nPXM9XCkYk2fwqNW7FkHIHf+dFn5xsEbzlrUe4+7bsXyn1NTIINQ9p4G6W+EdHaDCj1tXg239x+/ODEZ0cOm0dAjjoE+nKIEcdqT3iH67ycna97EGWVRFaKDjOP9t2LSY2NDufSGRfe5NY9BbXuYadeC1N1JrtEVn2XOzEQsLOlrVuqHznbcJnBf8Straw2WIuQEOzeree+TLX3rz+KuCTqmj2Ya+3dbf9H6cNKo3bff8nW3W7P8BmdADN1ByLAvM0BRI+ryLX+VR/uVUNdet8oKq2/82m5+LK/xcxyUvhs/+oyLdj/xce8Vag+9d+JOZyH4/KJcZ2+MFOvQ2lDHrvntSELt0MlIAqqD4VucZhM7YaKZW2/xTFTYaa3NtOwN+3sdj4xp9FslcmSt2+M7XmTt69mB5NbemoPldoVrqZS1iqzTpj4dCDATL0DvMuimLddkojof1lKzJXe7UuhW1JRr/AIv8lc74xtmhXV7Hz1z8syFgXq+vDmajNdrpuaw/XhB6JL/0Msy0zdgdTsH5U9xOKgKqrwgIA9FGd/LPtU6IWTE+fuRz2Ad9kF2QOe20NUI37s9kZUs/NVlsI4F+9vq8k+XdttmHev3kzlMN13qohcV907+3c39ktgde/CuYNSdySrLFdHjqqimrEIyH6enSnYsI99z35kiWxvrGEO1q4sEduZ8mDtXTRkV86KuPTWVFAU39DtD9le4at9yAZbtmWV+9nLN7vWW1ypcheF39th1JZ9DrUYy+8OJReHeZJDIKFUNYKjjzEDuAwplr5MAavGUBw+zIrDcFEr86Xxe3owcamPKxd2pWpiJDKhfIxWMx8PVq50OZhLlLpDUV3Yvv7FYZVU1S+BFzJz2B/aa1exz5uZv/c7NE9qH3DfN9WXansgrVji9kTkdGNcAiy/O+Rf7MFu2Ddy2BxVtSRQnMq1s5tXb3aGVui2y7k+n6G07H5Yxey+78/9bzVYz3BOnaAERFlmZg9C8A8QENKgu4pSdy4+feS8Sip0Q0BmjdbUxs5qxlzuk33QPTcDCqOWXJteD3PZFbLUIyZKZLmDMJ4Getk3AZS6Y8JWWbSxz3TcDapbJGCVudK/syfa376ejWqlYA9xSdeeLHYv9u92JtmnTXVmxj1l74X8jPpqjEOJXoydTiwRQKkv4XBzkWHe5gaki1rsiXarzMUpRt8n2ut0d/4xoaX3JSD9rE6cKzJxU8tHjW1CiAj8IIBS70EO2R0xb5PZYQ9VU2VdAhfmadaVpg/K/KrbJi9O/F5dp/JFZpJ97PsmdT5h07NiTQjPV4I25eR+xARQ6j0I1yoRo9hb7wHt5irloKL11V4ocwk4sbnAcDnOf3DTnVXqeb7nmrZR+Y7rOkOuz3dnNCGzDaXvKPWeJLU1V6Pu3fY0LH+rtbbm4tjCOrjo0xNcFwDzn9Vul/LBl+3DGU2mp8FzcTiAUJzROBwyVa0QQKmvAHF1ee7uUOJM8+mVwJV5mijzMczTmg0u0aX3BUh51r9520Jz6X0VE8I+DyWmBzS8EaPUe5SZyTJm633xtWcWxNZ8bPO0RsOLInZ6oxHfyGxnkuz73sDiNsH0a0LotrPU5poASt010YX6LmaOLxaS+NqVwIJ52pi25k2HUbgvjdwPeS0mwiBdC4BahFxketLHoUQXHaOO/gmg1PtmrIne5grxZfQ0X8zTmo2LpfdLXsahoxQ5kHp6WS//XxPQeb5/fcW3lAig1HuWNs5oHAAeMHqag96WViEvJLulNxJMLJzRSFhUF0OXulDqpSD1U5zRlIKJPhGlPoCIM8zb2lH22DytyYCij53eBMZl3szNvu/kljq+rJL/lwngjGaZRypXKPUBJJ3dxrytEeYAzNOajEdmk3tN8ieRV5zR2JedrmMtHAvJSk7XeqIsLwczOZQYpWTXDgqlvhaPm5v88NTjGJZ5Wr0xFbmMcbLU3KDFILJmjvZ9c6xMyuVtI+R9UPvlN0mNlYBMIvgMQSCpGNpNgRYudfV+SKfZ6w4Rua8nNbmtP3fhxnf78YMTJbP/9a2ld9e+KBNrPS25M1MfSN6FMxpZVh6ouTCaCdQ8rQlcfJOvp+VsJpljZVJGWmZtvUbIK2uTtHEJoNQH5C8noA8GbM7rpsI2T6uPNrXY6fXJnOd05db07PXsuNi+adqBFPLjjCYFKV+NEaV+haL/L9YZTfI/PBGYp9V9Ui5MipKKnV6XzVU+h25NNS/NV1hXvuCMZgVIzJco9YGlm+wPTyTmaU0el/lE7TbJn2peV85oCvO24nxGqiSrx91HhLzq1rgzJgGU+sD0k/vhicw8rdHjkmrs9EaQlLL7vi7cmtoDd9qwt16Kv48IeaUNkTg2AZT6wBJI5Yen2GaQgCs2FKr/0dPcPwSpx05vSlQ7ch2b5eqoadup5P80wbwtBVmj1EeQctQ/PHb5M7ToaT08AwQtaQhVzNFcuDUtrExwRlMKXyuzhzOaUjRRJaLURxBnlD88CZinNXpU8ny3UX4yK1duTXFGU/EwWWc0P+PdsIJONMko9ZFEGdMPTyrmaY0eFWKnN8JVZHbk1vTHl7NT2ajHJ0SJBHKJZ1+STFJEBFDqIwkzih+ehMzTmjwmxE5vQmshr1O3pvpooWa+XhDAGU38jwJKfVQZB/rDk6B5WrPHhNjpzXhd585l3/f6qv03Qh6vY+eG8boWuDceAZT6eOxVcD88KZunNXhOiJ3eANZKVpczyQzzthW6F5dyKNGFCWF55aSOTQClPrIEQvjhSd08rckjQuz0JrQq8jpya5rdEfM2nNGUQsYZTSmWKBJR6iOL0esfHszTGj8dMtPca1yIAqsEnLg1tT4hjAp0i2uViOtrnNG4JupNfSj1kUXh5Q8P5mntnwpip7dnt1BSO4q1vjVXhwvV8nWBQJ7xArqAI5qvMrHgMzYBn2JuW/O0rVvqwL5sjM0ltPZ9kmNo7Mr6O8n1LwqfDmU3G6RtP7wvy/D62wZF0sgqL++TW3rK33pc4mam7oE8z3+4zPNRu4J5Wmf8xE7vjHCpAlduTc0kO1qqmItzAmJCiOfD+B4GlLonMjVZNs4yIeZpzp4AYqc7Q1lUZN2auqjxIvbACxd1xVaHqwh5sXEJeTwodU+kV/zwDOkFC/M0p5IndrpTnOeVyUzSmemVJnpbmYQKE8KH02dl90gLkwBK3SO55Urv990dzNP6IUzs9H64SvCjXRc1B+cTwsWg69aR4Tq2LqoQ8qHUPZKSdR0r8aB/00uXME/rBetVpcROv0Lh65cM87Zy0YgzGutfofwmqaERQKl7JrG3r2eH9gS6s25hnuYMZVVFxE6vItM9Xc4p7Hav5byG7LaYt9mXWz43CGSOTAhvVEzC4ARQ6oMj39zgu5ezfRuTvOsPENHTNrN2kYMTxC4o9l9HYbqVm+P+WwqwBZzRBCi08i6j1Mu5jJ5q9wAnc72jxNSsUWfsTATztEbIOmdm6b0zwqoKxCPcadW9NukTkx20KZdCGZzRxCFlnM8EIEe7vFvMBgvloafS5SdL3bYn2eXHT+fq5Oz1jJnIEpz+L7YfP3iv5KR2/y2l14JW+ndvX80OXI58+9F9+RvRT13WGUVdMiE4e/nmbhRjSXgQKPWEhc/QuxMoYqdr86fuNVFDGQGT6a8v7MzLbrdKs2ZyOjd/blU49kKy7WdXCWMfZszjY/k9ZukytgEIEDu9T8hbW8rp8rvtq31JKEw7++x4oHXjjCZQwS10G6W+AIOvEGhMINPPGpehQF0CL/ryS661PqjbiZTyWWc0zhz+pATOo7Gi1D0SBl0Ji0Bh28teen9CM8b5LP2ys8USM+ZtlziW/tfGHCwlcBEUAZR6UOKisz4RkFnNnk/9ia4vWXbS55jE0dNhn/UHW7c4o7lwexzsEFLuOEo9Zekz9m4EiJ3ejd+G0rlyv5++2GThjGYxge9XBOY6P7i64EtQBDj9HpS46KwvBOzSe2bMX3zpT4z9OHv1pvffJ2KtVz85k9v6877ONFS3yp2uBJipdyVI+SQJTBwFGkkSXp1BDxSxEGc01cLIP6j96rvc8ZUASt1XydAvrwkQO71f8ch+90m/LZzXPvvbbCbumH8Yoq3Q2pBnHKUemtCkvyj1AIVGl8clQOz0/vkb0+9++tIIcg7MLfG4vBDLju3H073LS/4PgwBKPQw50UuPCORaPfOoO1F2ZXJHnQw1MOtaGWc0FbSJa1ABxt9klLq/sqFnnhIwOt/1tGtRdMsq2KEPaOGMpurRwUd+FRlf01HqvkqGfnlJgNjp/YtFq/6czlT1fnJLHXcNdVxVd+jpeJgLS4Io9bDkRW9HJkDs9P4FoE2/TmfKRmBXBnBGU0ZG4tnN1d3yO6T6SACl7qNU6JO/BNhj7F02+WTAQ3ILo8lydbRwydcLAlqrHWCEQwClHo6s6KkPBLTe9aEbMffBdajVuqwK8zZjvq+bn3wQ8JEASt1HqdAnLwkUsdMJ4NKvbEa2Gc+z7LDfAYZXu9FqFl6v0+0xSj1d2TPyxgSInd4YWcMCRunThkWcZv/x5ewUZzTLSFHqyzx8v0Kp+y4h+ucPAWKn9y4LcfY+qlIvBogzmiU5b215IJOlHnGxjgBKfR0d7kHgggCx04d5FCbz4ZzOVI0IZzRLZF4M7TNgqXUuGhNAqTdGRoEUCcgMci/FcQ86Zq1+Kg6rDdpoeWMZsdbPwWhc6JY/If6motT9lQ0984kAsdP7l4YxJ/03Uq+F7I6Yt8lLRr3cceaynv3OXs6O4hxdvKNCqccrW0bmiIBdepeZ+gNH1VFNBQGtsvH30y/6Zpec5dDeUUVX40+WFxqj9bP4BxrfCFHq8cmUETkmMDEEcHGMtLS6PBt/P32xY1tzdbh4ndL3XOndwhIgpUFHMlaUeiSCZBj9ETDKMGPpD+9Vzb6dsk7WGY3W36HQrx7L4L6g1IMTGR0ekgCx0wej7eUpazPJjgYj4ENDotDZR/dBEO37gFJvz46SCRAgdvpAQjbDR2arM7LCZe3IXu7q9NNJHhS6E4xjV4JSH1sCtO81AZOx9D6IgLLhI7PVH1cCB+ZQ6PUfB89zotQ9FxDdG49AETvdqK/G60E6Lec+eJKrwG2Xo615V8Xt8JNR6OHLcGEEKPUFGHyFwCIBYqcv0uj3u+8Hs7JYzdtQ6P0+2CPUjlIfATpNBkKA2OnDCCqAPevstpi3xeaMBoU+zPM9cCso9YGB01xIBPTTkHobal+10Se+973wf56bY9/7Wbt/KPTaqELLiFIPTWL0dxACRez0QVqiEWPCiAI2MdlBFNJCoUchxqpBoNSryJCeOAFipw/1AEzu+OVJrmrc58FmzPOq+0Gko9CDEFOXTqLUu9CjbLwEiJ0+iGztqfKQQnuaLAvXdSwKfZBneuxGUOpjS4D2vSNw78vprjLqM+86FmGHtPLT6UwV6sIZjVIvqu57m45C91Y0rjuGUndNlPrCJ0AAl8FkqI3PTmcqMIQWYxyFXiHIOJNR6nHKlVF1IUDs9C70GpXNJ2EcklscVOEbPRTzNhT6ouiS+I5ST0LMDLIuAfJBhWoAAAiPSURBVGKn1yXlJt/FcrabygasRczwvN9blz7+huAsAz4UnjSFUvdEEHTDDwLETh9QDgE4namiUTijqbrpQ7ox3799PfP+xcMHVLH1AaUem0QZTycCxE7vhK9RYaP0aaMCHmUuTuyL4vSoS9ddkX6dvX67d53At5QIoNRTkjZjXUuA2Olr8Ti/qT0O4lJnsF46o0Gh1xFd1HlQ6lGLl8E1IUDs9Ca0uuedzMNwOlM10sIZjU9bCCj0KlEllY5ST0rcDHYdAWKnr6Pj+J6cHj/30Oa43oGrM1ofDNxkeXMo9HIuCaai1BMUOkO+SYDY6TeZ9JpizEmv9Q9UuT29P3qsdRT6QNIOoxmUehhyopc9EyB2es+AV6rXKgv2kNzKUJQec7aOQl8VR/LXKPXkHwEAFASInT7og5BnYe+nL8IazRkNCn1RDHy/IIBS51GAQEGA2OlDPghbW+F5klvHZ3BnNCj0deJI+h5KPWnxM3hLgNjpgz8HL0KKzFaHTparozr5nORBoTvBGGslKPVYJcu4GhAgdnoDWN2zmrAis9UZcHGSX5Rtnbyd8qDQO+FLoTBKPQUpM8b1BIidvp6P67tZgJHZajDI+461jkKvIQWyoNR5BpImUCy9Ezt90GcgD9yTXBWsH1/OTlVfzmhQ6FXYSV8hgFJfAcJlWgRMpnbTGvH4oy2U3/jd6KcHeQ/R21Do/cgq0lpR6pEKlmHVJEDs9JqgHGXraybrqHtdqzl7PTt264zGPCc4S1eppFUepZ6WvBntAgFipy/AGOirmH6dDNTUaM04dEbzYnI72xttIDQcJAGUepBio9MuCEiUsD0X9VBHfQLGxGWfXjbyyS11LHvrP5Xda5AmCl3vxmb612D8ZG1JAKXeEhzFwiegjdkNfxRhjWByJx5PclXkrSKWWPFHVfdrpKPQa0AiSzkBlHo5F1IjJ0Ds9OEFbPeaU5l5bs3VYUvCKPSW4Ch2TgClzpOQJAFipw8vdq3iczpTRbGlMxoUehVQ0msTQKnXRkXGmAgQO314aWoTp9OZKpKTO9l+g711FHoVSNIbEUCpN8JF5mgIGPVVNGMJZCD5JP5DcouisFsNudK7NRQ7Cn0RHN87EUCpd8JH4RAJXOynh9j1oPv87q+zk6AH0KLz1tGOVexVtutG6z9wyr0FWIpUEtiqvMMNCERK4NOWmmrxVcpnQAKRO51ZR/LCg97UuiTWWu1c5rWR3Yq998sE/oeAAwIodQcQqQICEFhPQEy8TtfniP+u9TYno7T/+ECgNwIsv/eGloohAIFLAuLoJ3mlfsmC/yHQJwGUep90qRsCECgITObxO51B1BDwgQBK3Qcp0IdBCWxtMWscFLi4TGXveFDiNJYwAZR6wsJPdejnbjzVm1THP/i4jTkZvE0ahECiBFDqiQo++WFrzYGlgR4CrTL20wdiTTMQQKnzDCRJQOyGj5Ic+AiDzjP200fATpOJEkCpJyr41Idd2A4nbDs9pPw5wzAkbdpKnQBKPfUnIOHxT+Z6r4YLz4QJORn6i1QiszmhRSUQ6EgApd4RIMXDJXB+IlvvhzuCAHpu0onMFoA06GICBFDqCQiZIVYTOHs5O1JGf8OMvZpRpztZWpHZOrGiMAQcEECpO4BIFWETsO47ZSl+Rxnzfdgj8a/34mKfk+/+iYUeRUxAvDfygQAELgnYCG7zidpVeb6rMj1VhGi9RNPq/7NXb/iNaUWOQhBoR4A/uHbcKJUQgS8eT3dkSWtHzOB2tDIyoycWey3xi3XB2cs3u7XykgkCEHBCgChtTjBSScwELkJnLi0jo+g3S1wbfbI5FzkgAAGXBFDqLmlSVzIEail6mdnLrP6zZKCsDNQY9tNXkHAJgd4JsPzeO2IaSJlAsUevZdle/hltdoVFMoqe/fSUn3zGPhYBlPpY5Gk3WQJJKHqxJDh7/XYvWSEzcAiMRAClPhJ4moXAIoElRa9yOZSn5VCeerCYJ6TvJtNfv/vr7CSkPtNXCMRAAKUegxQZQ5QEpjvTu58+qZ0sV7smJEXPqfcon0cGFQYBlHoYcqKXECgIhKDoc61/dXGQEKlBAAIDE0CpDwyc5iDgmsCVop9bW/p8R2nxjqfUE9ft1KlPzNh+8/b17LBOXvJAAALuCaDU3TOlRgh4QeDel9PdbEhFz+E4L+ROJ9ImgFJPW/6MPjECvSl6FHpiTxLD9ZUASt1XydAvCAxEwCp6bdS0lRtcrX7SuT5gyX0gYdEMBDYQQKlvAMRtCKRIYJMbXHkBeJMpfZTdVoez09n7FBkxZghAAAIQgECwBKwtvZ3VBzsAOg4BCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCDgiMD/B+09j3M1DX+IAAAAAElFTkSuQmCC" } ``` Best Practices [#best-practices] 1. **Always reference the original invoice**: Include the invoice number in the credit note's note or description 2. **Be specific**: Clearly explain why the credit note is being issued 3. **Use correct amounts**: Ensure amounts reflect what's being credited 4. **Include proper VAT information**: VAT must be handled correctly for tax reporting 5. **Verify the recipient**: Always check if the recipient exists in the Peppol network before sending (see [recipient verification endpoint](/reference/recipients/verify-recipient)) 6. **Keep records**: Maintain relationships between invoices and their credit notes in your system Next Steps [#next-steps] Create and send invoices you may later credit. Validate recipients and document support. Receive inbound events and process refunds. Explore all endpoints and models. # Sending Invoices (/docs/sending-invoices) This guide walks you through the process of creating and sending Peppol-compliant invoices using the [Recommand API](/reference/sending/send-document). Overview [#overview] Sending an invoice through Peppol involves: 1. Preparing the invoice data 2. Verifying the recipient 3. Sending the document 4. Handling responses Prerequisites [#prerequisites] * A Recommand account with API access * A registered company in your Recommand account * Your API key and secret * Your company's ID in the system
Verify the Recipient [#verify-the-recipient] Before sending an invoice, you might want to verify if the recipient is registered in the Peppol network using the [verify endpoint](/reference/recipients/verify-recipient). If you don't do this and the recipient is not registered on the Peppol network, you will receive an error when sending the invoice. ```javascript async function verifyRecipient(peppolAddress) { const response = await fetch("https://app.recommand.eu/api/v1/verify", { method: "POST", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify({ peppolAddress }), }); const result = await response.json(); return result.isValid; } // Example usage const recipientExists = await verifyRecipient("0208:0123456789"); if (!recipientExists) { console.error("Recipient is not registered in the Peppol network"); return; } ``` Prepare the Invoice Data [#prepare-the-invoice-data] Create a JSON object representing your invoice, following the required structure (see [Invoice model](/reference/sending/send-document)): ```javascript const invoice = { // Required fields invoiceNumber: "INV-2025-001", issueDate: "2024-05-15", dueDate: "2024-06-15", // Buyer information (recipient) buyer: { vatNumber: "BE0123456789", name: "Recipient Company", street: "Recipient Street 1", city: "Brussels", postalZone: "1000", country: "BE", }, // Payment information paymentMeans: [ { iban: "BE1234567890", }, ], // Invoice lines lines: [ { name: "Consulting Services", netPriceAmount: "100.00", vat: { percentage: "21.00", }, }, ], }; ``` Invoice Fields Explained [#invoice-fields-explained] Required Fields [#required-fields] | Field | Description | Example | | --------------- | ------------------------------ | --------------------------------------------------- | | `invoiceNumber` | Your unique invoice identifier | `"INV-2025-001"` | | `buyer` | Recipient company details | See [Party model](/reference/sending/send-document) | | `lines` | Invoice line items | See [Line model](/reference/sending/send-document) | Optional Fields [#optional-fields] | Field | Description | Example | | ---------------- | ------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- | | `issueDate` | Invoice issue date (YYYY-MM-DD) | `"2024-05-15"` | | `dueDate` | Payment due date (YYYY-MM-DD) | `"2024-06-15"` | | `note` | General invoice note | `"Thank you for your business"` | | `buyerReference` | Customer's reference number | `"PO-2024-001"` | | `seller` | Your company details (auto-filled if omitted) | See [Party model](/reference/sending/send-document) | | `paymentMeans` | Payment instructions. Optional, but give them on any invoice you expect to be paid; leave them off for a prepaid invoice | See [PaymentMeans model](/reference/sending/send-document) | | `paymentTerms` | Textual payment terms | `{ note: "Net 30" }` | | `totals` | Invoice total amounts | See [Totals model](/reference/sending/send-document) | | `vat` | VAT breakdown | See [VatTotals model](/reference/sending/send-document) | | `attachments` | Supporting documents | See [Attachment model](/reference/sending/send-document) | Buyer/Seller Structure [#buyerseller-structure] ```javascript { vatNumber: "BE0123456789", // Optional, but needed on most VAT invoices name: "Company Name", // Required street: "Street Address", // Required street2: "Building B", // Optional city: "Brussels", // Required postalZone: "1000", // Required country: "BE" // Required, 2-letter country code } ``` Payment Means Structure [#payment-means-structure] ```javascript [ { paymentMethod: "credit_transfer", // Optional, defaults to "credit_transfer" reference: "INV-2025-001", // Optional, payment reference iban: "BE1234567890", // Required, bank account number }, ]; ``` Invoice Line Structure [#invoice-line-structure] ```javascript { name: "Consulting Services", // Required description: "Professional services", // Optional sellersId: "ITEM-001", // Optional, your item code quantity: "10.00", // Optional, defaults to "1.00" unitCode: "HUR", // Optional, defaults to "C62" (unit/piece) netPriceAmount: "100.00", // Required, price per unit netAmount: "1000.00", // Optional, calculated if omitted vat: { // Required category: "S", // Optional, defaults to Standard rate percentage: "21.00" // Required } } ``` Send the Invoice [#send-the-invoice] Send the prepared invoice using the [send document endpoint](/reference/sending/send-document): ```javascript async function sendInvoice(companyId, recipientPeppolId, invoice) { const response = await fetch( `https://app.recommand.eu/api/v1/${companyId}/send`, { method: "POST", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify({ recipient: recipientPeppolId, documentType: "invoice", document: invoice, }), } ); return response.json(); } // Example usage const result = await sendInvoice("your_company_id", "0208:0123456789", invoice); if (result.success) { console.log("Invoice sent successfully!"); } else { console.error("Failed to send invoice:", result.errors); } ``` The same request with curl [#the-same-request-with-curl] The whole request is one JSON body, so nothing about it is Node-specific: ```bash curl -X POST https://app.recommand.eu/api/v1/{companyId}/send \ -u key_xxx:secret_xxx \ -H "Content-Type: application/json" \ -d @send-invoice.json ``` ```json title="send-invoice.json" { "recipient": "0208:0123456789", "documentType": "invoice", "document": { "invoiceNumber": "INV-2026-001", "issueDate": "2026-08-17", "dueDate": "2026-09-16", "currency": "EUR", "buyer": { "name": "Customer Company", "street": "Customer Street 1", "city": "Antwerp", "postalZone": "2000", "country": "BE", "vatNumber": "BE0987654321" }, "paymentMeans": [{ "iban": "BE68539007547034" }], "lines": [ { "name": "Consulting Services", "quantity": "10.00", "unitCode": "HUR", "netPriceAmount": "100.00", "vat": { "category": "S", "percentage": "21.00" } } ] } } ``` Handle Responses and Errors [#handle-responses-and-errors] Along with a proper HTTP status code, the API will return a structured response indicating success or failure: Success Response [#success-response] ```json { "success": true, "id": "doc_01KA...", "sentOverPeppol": true, "sentOverEmail": true, "emailRecipients": [], "peppolMessageId": "3f6b1c48-92a7-4f1d-9a1e-0c7f5b2d84e3", "envelopeId": "7c2e5a19-64bd-4c73-8f05-91ab3de60f27", "teamId": "team_01JSH...", "companyId": "c_01JSG..." } ``` Store `id`: it is the Recommand document ID you pass to the documents endpoints to fetch, render or track the invoice later. `peppolMessageId` is the AS4 message ID and `envelopeId` is the SBDH instance identifier. Both are `null` when the document did not go over Peppol. Keep them if you ever need to trace one transmission, with support or with the recipient's provider. The `sentOverEmail` and `emailRecipients` fields indicate whether the document was also delivered via email. For more on email delivery, including sending to non-Peppol recipients and fallback options, see the [Email Delivery and Notifications](/docs/email-delivery-and-notifications) guide. Error Response [#error-response] ```json { "success": false, "errors": { "document.buyer.vatNumber": ["document.buyer.vatNumber: Required"] }, "invalidInputDetails": [ { "path": "document.buyer.vatNumber", "message": "Required" } ] } ``` The keys of `errors` are full paths from the root of the request body. The invoice you are sending sits under `document`, so a missing buyer VAT number reads as `document.buyer.vatNumber`. Each value is a list of messages that repeat the path, so you can show them to a user as they are. `errors` is what you display. `invalidInputDetails` is the same information as a structured list, which is easier to walk in code when you want to map problems back onto your own form fields. If the body matched none of the document types, each entry also carries a `unionErrors` array with the errors every document type reported, so you can see why the one you meant was rejected. Implement proper error handling to address validation issues: ```javascript if (!result.success && result.errors) { // Display errors to the user Object.entries(result.errors).forEach(([path, messages]) => { console.error(`${path}: ${messages.join(", ")}`); }); // Attempt to fix the issues if (result.errors["document.buyer.vatNumber"]) { // Prompt user to correct VAT number } } ```
Complete Example [#complete-example] Here's a full example incorporating all the steps: ```javascript const companyId = "c_xxx"; const recipientPeppolId = "0208:0123456789"; const token = Buffer.from("your_api_key:your_api_secret").toString("base64"); async function sendPeppolInvoice() { // Step 1: Prepare invoice data const invoice = { invoiceNumber: "INV-2025-001", issueDate: "2024-05-15", dueDate: "2024-06-15", note: "Thank you for your business", buyerReference: "PO-2024-001", buyer: { vatNumber: "BE0123456789", name: "Recipient Company", street: "Recipient Street 1", city: "Brussels", postalZone: "1000", country: "BE", }, paymentMeans: [ { paymentMethod: "credit_transfer", reference: "INV-2025-001", iban: "BE1234567890", }, ], paymentTerms: { note: "Net 30", }, lines: [ { name: "Consulting Services", description: "Professional consulting services", sellersId: "SRV-001", quantity: "10.00", unitCode: "HUR", netPriceAmount: "100.00", vat: { category: "S", percentage: "21.00", }, }, { name: "Software License", quantity: "1.00", netPriceAmount: "500.00", vat: { percentage: "21.00", }, }, ], }; // Step 2: Verify the recipient const verification = await fetch( "https://app.recommand.eu/api/v1/verify", { method: "POST", headers: { Authorization: "Basic " + token, "Content-Type": "application/json", }, body: JSON.stringify({ peppolAddress: recipientPeppolId, }), } ); const verificationResult = await verification.json(); if (!verificationResult.isValid) { console.error("Recipient is not registered in the Peppol network"); return; } // Step 3: Send the invoice const response = await fetch( `https://app.recommand.eu/api/v1/${companyId}/send`, { method: "POST", headers: { Authorization: "Basic " + token, "Content-Type": "application/json", }, body: JSON.stringify({ recipient: recipientPeppolId, documentType: "invoice", document: invoice, }), } ); // Step 4: Handle the response const result = await response.json(); if (result.success) { console.log("Invoice sent successfully!"); } else { console.error("Failed to send invoice:", result.errors); } } await sendPeppolInvoice(); ``` Advanced Features [#advanced-features] Country-Specific Formats and Processes [#country-specific-formats-and-processes] The examples above send Peppol BIS 3 UBL over the standard Peppol billing process, which is what almost every recipient expects. Two cases need more: * **French recipients inside the e-invoicing perimeter** are published for `urn:peppol:france:billing:regulated` rather than the standard process, so name it in `processId`, or send one of the French formats by naming its `doctypeId`. * **A buyer who asks for a national CIUS**, such as SI-UBL 2.0 in the Netherlands, is reached by naming that `doctypeId`. The invoice data itself does not change. The [country-specific getting started guides](/getting-started) list the document types and processes per country, and [verifying recipients](/docs/verifying-recipients) covers how to check a combination before you rely on it. Sending Your Own XML [#sending-your-own-xml] If your system already produces a complete Peppol UBL or CII document, you do not have to take it apart and rebuild it as an invoice object. Send it as it is with `documentType: "xml"`: ```json { "recipient": "0208:0123456789", "documentType": "xml", "doctypeId": "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1", "document": "..." } ``` The `document` is the XML as a string. Set `doctypeId` yourself when it cannot be detected from the XML. Everything else about the call, including email fallback and the response fields, works the same way. You are responsible for the contents in this mode: Recommand transports the document rather than building it, so a document that fails Peppol validation is your document to fix. See [can I send an XML document directly via the API](/faq/api-and-development/can-i-send-an-xml-document-directly-via-the-api). Adding Attachments [#adding-attachments] You can include attachments with your invoice: ```javascript const invoice = { // ... other invoice fields ... attachments: [ { id: "ATT-001", mimeCode: "application/pdf", filename: "contract.pdf", description: "Service contract", embeddedDocument: "base64_encoded_document_content", }, ], }; ``` If you want to try this out, you can use the following attachment object as an example: ```json { "id": "LOGO", "mimeCode": "image/png", "filename": "recommand.png", "description": "Recommand Logo", "embeddedDocument": "iVBORw0KGgoAAAANSUhEUgAAAfUAAAH1CAYAAADvSGcRAAAAAXNSR0IArs4c6QAAAIRlWElmTU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAAfWgAwAEAAAAAQAAAfUAAAAAPpJBcAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KGV7hBwAAQABJREFUeAHtnctuHEmWYM08KKlnMZ3KxnRjgBSlqF1JSkCsL0jmF0j5Bcncza5YX1Cs5ayKtZtdMb+gqOWsirmbXVFASapdhUQl0JgeoJW96pQUbnPN+YoIukf4w9zdHicAQeHm9jzXGdftce9Vig8EIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAgNcEpjvTu153kM5BAAKjEdCjtUzDEIiAwBePpztaq1Ilq42a2n9lw8yljFZmp+xekWbUV5X3Lm9o9ZPKzbGZZEfv/jo7uUzmfwhAIF0CKPV0ZR/9yBcVbjZXO6pC+RqTT1Wmp5VA6ijYysID3dDqh8lc783+NpsN1CLNQAACHhJAqXsoFLrUjcD9R9MDo82+MuqzbjUFVtrO3JXeP3s5Owqs53QXAhBwRACl7ggk1fhBYPvRg1PpyRM/ejNSL7T+DsU+EnuahcDIBLKR26d5CDgjYGfoUlnaCt3SNOaP24+ne/YrHwhAIC0CzNTTknfUo91+/OB9ckvuVRKVpfhc6d0fX87sygUfCEAgEQLM1BMRdOzDvPfldBeFviBlOU+QKXO4kMJXCEAgAQIo9QSEzBATJSCn9lmGT1T2DDtZAij1ZEXPwNMgYPbSGCejhAAELAGUOs9BFAS2thR7x2WSlNm6tdcvu0UaBCAQHwGUenwyTXJEs9PZexn4iyQHv2HQWZ7vb8jCbQhAIBICKPVIBMkwhIDWh3AoIaD1t9NfTqcld0iCAAQiI4BSj0ygKQ9ncksdiytY8arGZ5VAnqm91TSuIQCB+AhM4hsSI0qVwPt/ff+fd//583+Q8e+myqBy3Fr96p+++Px/WUaVebgBAQgET4CZevAiZACLBLJcHS1e8/2CgNitzz+qZ/CAAATiJoBSj1u+yY2uiFJmzPfJDbzGgI0xBzWykQUCEAiYAEo9YOHR9XICeZZxYK4EjfiEfrD9cMpsvYQNSRCIhQBKPRZJMo4rAoW/c4kvfpXAl2sCmYSk5QMBCERLAKUerWhTH5g+Sp1A6fhxRlOKhUQIxEIApR6LJBnHEgEbT9wo9WYpkYuCAM5oeBAgEC8BlHq8sk1+ZJnBGU3pQ2Cd0exM75beIxECEAiaAEo9aPHR+XUEsjti3oYzmlJE+QfF3nopGRIhEDYBlHrY8qP3awhYf/BGsbdehshoDsyVcSENAqETQKmHLkH6v5bA1lwdrs2Q6k1xRkOs9VSFz7hjJiCmq3wgEDeB7Yf3ZRlefxv3KJuPzh4kfPfqzbR5ST9KFC8lplhxeFJssxhzYsRHwbu/zk786CG9gMDwBFDqwzOnxYEJ3Ptyuqtz8+eBmw2iOZPpr0NUgvcfTQ+MMr8thSw+Cia39LOLcLylWUiEQKwEWH6PVbKM64rAhdIi1voVkesvOlDXsWvPBIgt/vyjmdmXueuR8g0CaRBAqachZ0ZJrPXyZ0AUYGix1gtXt3ImoHxAF6ly367O2Bn92nzchEBkBFDqkQmU4ZQTwBlNORebOtf5QfVdH+/kz+r2yi7Rbz+6f4xdfl1i5AudAEo9dAnS/9oEMszbylmF5owm07WV+vmA9dNPH8zpF4+nO+UASIVAPARQ6vHIkpFsIJDdFvM2nNGUUgrFGU2hmDctvZeMUE4EP8iM+cv9h9P9ktskQSAaAij1aETJQDYRKE5D5+Z4U74U7+fK7IUwblHOnfopB+x+b00cWY4PQdr0sQ0BlHobapQJlsDEZAfBdr7HjtuZbBDOaIxpuPReAk22G+YfzAnL8SVsSAqeAEo9eBEygCYEZn+bzZQyz5uUSSbvuSMXb4drlbB9+XDUwSeZMidBvMg4GjDVpEEApZ6GnBnlAgHrdWzhkq/XBJ74bNs9ydXudVcdfLN788b88d7jKc+DA5xU4QcBlLofcqAXAxLAGU01bJ3n+9V3x70j++F7ffRAHPD8evvRg9PQ7PX7YEGd4RNAqYcvQ0bQhgDOaCqo6ac+KreLPj2p6LSL5CfziTktHNu4qI06IDASAZT6SOBpdlwC1hkN5m3lMvDRGU2uVfcDcuXDvU61y/Ha/AkvdNdI+BYeAZR6eDKjx44IaKPZSy1jKc5dfDP5MjrfLetqH2mFF7rHD058Y9DHWKkzPgIo9fhkyohqEiic0dTMm1Q2mbH65IzmXLnqp4PKgKAwg+KmMXcEUOruWFJTYAQKZzTGfB9Ytwfprk/OaOYfB1h6L6MqLzdFUBi80JXRIc1TAih1TwVDt4YhgDOacs5eOaMx9QO4lI+mW2rhhY6gMN0gUnowAvK3yyc0AtYJx8SoZ/Jjs7vad6P0qQj1dHJLHRcz0dUMXN8gsC37p0qWW2/cSD1Bqx/OXr7ZHRuDmJuZsftg25dOvDFaP/vx5ezUh/7QBwiUEUCpl1HxNK1wDJKbIzuLqtdF89w6Wrmwy65XJMFclqtdZk1w6BuHbDL99ZjPT2FiJifSN3Z0yAxaf1dYTwzZJm1BoCYBlt9rgho7m/V6ZRVPfYVue6yf2jJ2Juqzp7Cx2VqlZWdhY/fDx/b1PN8bt1/jLr2Xjl280BEUppQMiR4QQKl7IIRNXbDhIq3Xq035Ku/L0nKh3G10ql9Op5X5Er6htT5IePjVQ7ex1sd8ZhrHTq8eitM7BIVxipPK3BFAqbtj2UtN9gfVHtRxUrn9IRKvWTjXuEnTnkHAGc1NLjbl00SN4jq2WF2yDmH8/RAUxl/ZJNszlLrnohclfOS0i/IjaZ1r3Hv0YIZLzGuy9lAhzmiueSx+0xJrfRRHLHIYdLEfXn63Lx0EhfFSNKl2CqXuseQLpdvTqexib14OINn9duJKnz8EWa6OPH4cxuuaKK78Z7U3eAdcxE4fqNMEhRkINM1sJIBS34honAx2ZiTL7v27MZWXhsyYv9iDeKPMxsbBW9pqEWsdZzSlbHJtBl2Cdxw7vXRMPSQSFKYHqFTZjABKvRmvwXJ/+qgOmp1079Y1O9OYfzQzeyivW01hl86JtV4qQPssbj+e7pXe7CHR+mHoodr+q7TL8QSF6Z8zLVQSkL9VPr4RsLMUO3sesV8vxD55f0z75BHHrnBGU0F/QGc0Nr659OJJRU/CSBZek1v6GU6gwhBXLL1kpu6hJDM1wLL7+nE/KUzgrGvMMc2Z1vexv7s50dtK4cpWzRDnLy6eubAVugUovOzqFz4iSp8mEnsigFLvCWzbaovl754OxzXvk356aQKX0n772evZMc5oyp+WLM97354ZJHZ6+fDcp8pyvH1BTn1byz1YaqwigFKvIjNCenE4LjMHIzRd3aT8KFkTuE8fzOmQe6rVHRrmTkas9XLQAzijMZkJcz+9nFiRSlCYNXC45ZQASt0pzm6VzX/OD2XJzktnG8WhPeseMxETuOyOmLdp9VM3icZZOs/6M28rVoS8WalyLT9Z+fpgMCF1jZX6lgig1JdwjHdR7LvJLGi8HtRsWX5w7SG+2H1f28NNEvHuqCaVpLLJrHO/r+2Y0WKnDyfBJ2JpctwXv+GGQUu+EkCp+yIZib7mS1dq9cO6nI3cBG5rrg5rsUgtk6wm9aZ8R46dPoQo7aqX/O0cD9EWbaRHAKXugcytL/ZieduDvjTqgt1vF7/01uVsjCd8cUZT/TQY09fZD/20utWI7siKV0pnVCKSnPdDQamPLKKLgC29nyjuc5j2heQyxGtsJnBmkh31yS7Uuq3MXccOcF2f72z7ezHyfeT0r08CKPU+6daouwjY4unhuBrdX84is495Zv5uVx5i2TMsHPCIE5HlgXJVEMhcu471MHZ6j6Lu48Wox+5SdSAEUOojCqrPgC0jDksO8Jvf2v32eJYXOTBX+jzJS5xTZzS+xk4vHbybRJOpXTc1UQsEzgmg1Ed6EuxMdpCALSONrzDNuzCBC32//ezl7AhnNOUPkitnNMUzEsuKVTmq0lQJa7tTeoNECLQkgFJvCa5rsfyD2rfLb13r8b68zOaK/faH949C3m/HGU3Fk2ad0cgLasXd+smhBnCpP0JyQmAQAij1QTAvN2KXLO0S9XJq5FfWBG5iTu1+e4gjxRlNtdTsC2r13Zp3AoqdXnNEZIPAKARQ6iNg9yBgywijliatCZy8zFgTuNBOOheRtnJsi8seHOuMpiy9bpp9yU1i1aoMSG5mZcmkQaAtAZR6W3ItyxWHx2RJumXxKIoVP+ASc9q6nA1pSX5isoMoBOB6EPKy1uVQZLCx011wzLITF9VQBwQuCaDUL0kM8P/53uPoYVUHGGnNJi5M4O49nh462Zet2WzbbIUzGmWety0fc7kuNtcy09+Nmc26seVKna67zz0INCWAUm9KrEN+nwO2dBhW56LiC/vXoZjAmSw77DzgCCuwqy+hWzkMLhYJGPTjyxlKfXDwcTeIUh9IvsUPXggBWwbicaMZa85kTeAePTj1WTkUzmiUenGj/yQoeTk7aIXBmPetyoVfCIUevgy9GwFKfSCRiFkXM7x6rJ8UJnCP7h97u9+uNbIsk6Vsp7SRmVZZkspNG31ShpE0CHQhgFLvQq9m2Qszric1s5OtICCxpy9M4Hzbb8cZTfUjOtf5QfXd8jtzrY7L78Sdagz76XFLeJzRodR75m5nLl1Nfnruor/VX5jAffpgTn0zgcuItV7+3LRwRnOxr5zclsbkjjoph0gqBNoTQKm3Z1er5DzLDwuXqbVyk6mMwKIJnFNf42WN1UzLbkusdTnoVDN7UtlaOaNJbEvDuh0ufB8k9WQw2CEIoNR7pHx+4CuR+NA9cryqWvZsM2P+sm1dzrpwTXpVcfMv585o9F7zkvGXyJVpzCW1LQ05VHgS/5PACMcggFLviXqhdHJz1FP1aVdrXc5KFLj7D6f7Y4I4ez07lhP734/ZBx/btisrbZzRpLSlkerhQB+f19j6hFLvSaLJBGzpid/Gau1+uza/ty5nxzSBO3v9dg/FXiIt09x1bEpbGvmEQ3IlTw1JDgjISzUf1wTs4bh5Zv7uul7qW0fAPJ/k2f6517d1+fq5Z7cEFH4IluCaTH99Yde/lL7uIhWOZ6/e8Nu77kHgXmsCzNRbo6suKKZYR9V3udMPATGBkxcpaz44xn77+Yxdf8PhuWvp6jxvvD2ShH99rX64psQ3CLglgFJ3y1MRsMUx0IbV2ShwhQnc4+lew6Kds9s99sktLSaM+g+dK4uiAv20qTOaFPzrG6WTdLYTxSMdwCBQ6g6FdD5DxHOcQ6StqpJ1zQeFy1mJAjf0frs9Ff/u5Ww/1/pXMmtPfkbWxhlN7P71dY59eqs/bArVIoBSr4WpXqZPH9UBNun1WA2SS0zgCpezI5jAWYcqZy/f7Mo++3dJL8ln+lnT7RC7D2/tuAd5RkZoRELNMlMfgXsqTaLUHUnazghttDFH1VGNSwKXJnCy3+6y2jp1WfvrpJfkxUqhjTMarfXgsqojz855xGHRWIc5O/edCoIgICuVfFwQsNHFpB78u7uA2WMdxQww03tNT2W76JL1hpcp2Z6RFQQX9YVSh2X+7tWbadP+bj9+8D6+lS/z/OzV22dNWZAfAnUJMFOvS2pNvgsnKCj0NYx8uWX324sledlvb3qIq+sYUl2St8zbuPeVKGaHXZn7Vh6nM75JJL7+oNQ7ytTuF5qsZRzpjm1TvAMBmS1bE7h7j6eHTfd8O7RaFE1xSV5+aHaaciuc0TQt5Hn+POOQnOciCr57KPWOIpx/yI/iWyLsCCWg4vYchHU528ataZdhXp6Stw5apJ7oI5Rpo6ZNeRX+9SNzwzvGtk9T7uQPmwBKvYP8CNjSAZ5PReUwV2ECJ+cihjaBsz/y4l1sR5aaf5P0KfmK5yEyZzTRv7xViJHkAQmg1LvAJmBLF3o+ln1yZQInrn6H7ODb17NDe0o+Vj/ypqUZV3FSPBZ7f2PsYVo+EOiVAEq9JV7rjtQeAGpZnGI+E7AmcBNzamU8ZDftcrN1NxvjkvzkTvu9ZPHQN6gcepN5lp30VjcVQ+CCgOglPk0JELClKbFw81tzLFka3y/CrA48DGtVURzCtNsDAX+00r97+2p20GUINhpf6C/R1sugtYDowoGyENhEgJn6JkIl9wnYUgIl0qRCkWjzJ7GZPmljltUFSxRL8nLQratCtwyDd0YjTmdQ6F3+GihblwBKvS6pi3zbD6fPUnMe0hBRnNnFBC4z5i9Dm8CFuCRvVzeUMs/tNkIRvc7BEzG5pY4DP0jIDN3Bc0AVmwmw/L6Z0VUOa89szZ8wYbtCkuYXmXXpXB/YmfTQAOw+v9Fm37Nn8IXse5/Ij8npZK5O+nKDWoxdovANzdxFey62IFz0gzriJ4BSbyBjO0vDv3sDYPFnfSGz0f2hbY/Pz3Tk8kKhn46CWE6jyzmDE3ui3R6AK+zJB+hI0GdZjP5mjHMZA4iFJjwjgFKvKZDCb7csv9bMTrakCJjnkzzb72uGWoWysKkXs0r5I+7PCkNWJcTMTmbh2an1hjb0C8zq2Lcl4p5ssH+7mu779eS2/nyolx/fWdC/fgmg1GvyJWBLTVAJZ7NLrNa16dA/3i6X5O1+uKxGnSgxv8plOd23w10hvlxbpm0C2iT8p8TQOxBAqdeAV5gWafP7GlnJkjiBQimKXbX17z4kig5L8uf74bk6sXG+h15taMPIWiIEdVhVLABcHRhsw4syaRFAqW+QN4fjNgDidjkB2XfOld4feqZrl+R1nu9X7rdf7IfbpfStLVHi4vCmfAD+phYWKGJm6G8Pl3tmXQCPcahyuRdcpUIApb5B0qHu4W0YFrcHIjDWD7p9Gf306Toymhxqez/0C0afiENyRmNN+8Y+i9CnLKjbLwIo9TXyOJ/1mD+vycItCGwmwPLrZkYNcxRR9Yz5Y8Nio2SXgD38zo5CPs1GcT6zTu4EbFlHh3t1Cchp7aH9yNftWqj5gnFGE0swmlAflAT7jVKvELr9EZbX6wcVt0mGQCMCRpymDB3WtVEHA8tszwLI1sbgzn+aYjJKnzYtQ34IdCGAUi+hZ08SF167Su6RBIHWBFj5aY2urKA1H7TWBmX3fEnTYlXgS1/oRxoEUOolci4CtgQeGatkWCSNTMCu/BR7wSP3I5bm7Wxd3NM+U9ZBjqcfayboadfoVqQEUOorgiVgywoQLt0SMOK3nY8zAucn+rWfTOVlIwS7f2fCoCIvCKDUV8Qgy+6HK0lcQsAlgSfW3MxlhanXZR392Fjl3i3FW898fCAwMAGU+gJwO0vncNwCEL72QmDRfryXBhKs1M7Yt27rHVmO/4Mvw7f+8n3pC/1IhwBKfUHWJlO7C5d8hQAEAiJg99jfvZztW2cvPszarde+gPDR1UgIoNQXBKmV2Vm45CsEIBAgAeu9zQZQsQF2xuw+XuTGpJ9u2yj1dGXPyCEQNYG3r2YHdq9dBvlihIGO0eYIw6RJ3wig1H2TCP2Jm4CciGYGN5yI7V67uGndsT74BzV9M4b99OHETEsLBFDqCzDw/rQAg6/9EMjNcT8VU+s6AjZK2mSud0Sx/7Aun7N7Eo/eWV1UBIEGBFDqC7Dk5Dtv1ws8+OqeQJ5lh+5rpcY6BKzN+NnLN7tDzNpzfkvqiIQ8PRBAqS9ADSZIxEKf+RoUgRcxhT8NivxCZ4tZ+y09Vco8X0h291W2WJCzO5zU1IwASn2BlzWJUSyPLhDhq1MC2v8AJE7H63Fl9m/97NXbZ8rob3rYa2fFz2PZx941lPqKhCd3sv0e/shXWuEyRQLFSlCKA/d4zGevZ8cTO2uXmPeuuinL+yeu6qIeCDQlgFJfIXY+W9d7K8lcQqAbAVEaxbPVrRZK90CgmLW/frvnymmNIYhLD1KiyroEUOolpOzbu0/uJku6SFJgBMwkOwqsy8l115oaunA1O7mDJ7nkHh6PBiwHvvlUEdh+eP9Iaf1t1X3SIVCHgHVZaj2c1clLHj8I3PtyuqvzIrjTkyY9QtZNaJG3DwLM1NdQPZMlOVHq37HHvgYStzYSyAwH5DZC8iyDnbUXTmsaupoVV9MckvNMlql1B6W+QeJFWEeldwdzWrGhP9wOj0B2Rx2F12t6bAk0djWrs2PIQWBMAiy/N6BfLMkZc6CM+qpBMbImTcA8L0ynkmYQx+DvP5xKBLji7/+zihG9sLP7inskQ2AQAszUG2AuluTEI5U9JcvMvQG4lLMaDsjFIv4rV7Nl5m/ifnZyW1b0+EBgZALM1DsIYPrL6XSu8wMO03WAGHFRDk3FK9zpzvTup0+qmJWLCdt7PMjFK+vQRoZSdyCxK+WeafFQpaqW5hy0RBUhEbDxvO2ebEh9pq8QgEDYBFDqDuVn397zD2rfaLOPcncINtCqJrn+hQ0iEmj36TYEIBAgAZR6D0K7VO65MnsC+EEPTVCl9wQ4IOe9iOggBCIkgFLvWajbj6d7Rk7Mo9x7Bu1b9eLfwJpD+tYt+gMBCMRNAKU+kHytcpdQj3uYww0EfMxmJPSmxO2+O2YXaBsCEEiTACZtA8ndztrkhx5zuIF4j9mMUfpozPZpGwIQSJcAM/WRZF84spnn1g3ttyN1gWZ7IsABuZ7AUi0EILCRAEp9I6J+M1yZw6Hc+wU9VO3ihMSuyAzVHO1AAAIQWCTA8vsijRG+W5MnGzjGzu6sXbN4qvtphG7QpDMCLL07Q0lFEIBAYwLM1Bsj67fApTkctu79cu6ldnkhm9zS09np7H0v9VMpBCAAgQ0EUOobAI112yr3+Uf1DHO4sSTQol3xCV6E621RlCIQgAAEXBBAqbug2HMd2Lr3DNhR9bnWv8IHuCOYVAMBCLQigFJvhW2cQoR+HYd7zVYJu1kTFNkgAIH+CHBQrj+2zmsm9KtzpO4q1PrQXWXUBAEIQKAdAWbq7bh5UQpzOC/EUHRCYml/zgE5f+RBTyCQKgGUegSSv1LuhH4dR5ockBuHO61CAAI3CKDUbyAJNwFzuHFkZzL9td0aGad1WoUABCBwTQClfs0imm+Xyp3Qr/2L1Cj15t2rN9P+W6IFCEAAApsJoNQ3Mwo6B+Zw/YpPG/2bt69nHJLrFzO1QwACNQmg1GuCCj0boV/7kSAH5PrhSq0QgEA7Aij1dtyCLYWtu0PRcUDOIUyqggAEXBBAqbugGGAdhH7tKDT8vHcESHEIQKAPAij1PqgGVOeVORyhX+tLTRR6rvQuLmHrIyMnBCAwDAGU+jCcvW/FKvc8U3tEh9sgKomXLgp9H4W+gRO3IQCBUQig1EfB7m+jl+ZwKPcFGdkY97k5Vio7Pns9k//5QAACEPCTAErdT7mM3qvUQ79a+3Ol9bHO1QmKfPTHkQ5AAAI1CaDUa4JKOVtCtu4vxO78aJ6pE5bXU37iGTsEwiWAUg9XdoP3PE5zOPNc6ex4Mlcns7/NZoNDpUEIQAACDgmg1B3CTKWqoJX7wv745I4o8tPZ+1TkxjghAIH4CaDU45dxbyMMxRzucn9c/j9iWb23x4GKIQABDwig1D0QQuhduFLufoV+LfbHM6OOWVYP/Qmj/xCAQF0CKPW6pMi3kcCo5nB2Wd2Yk2J//JYocpbVN8qLDBCAQHwEUOrxyXT0EV0q975Dv9pldW0VOfbjo8ucDkAAAn4QQKn7IYdoe9GDOdwLo/UJ++PRPjIMDAIQ6EAApd4BHkXrE+gW+tU81yY7YX+8Pm9yQgACaRJAqacp99FGfRUdbt2hukuzsyw7mbA/PpqsaBgCEAiPAEo9PJlF0+NzBa/uaq127KCMUacSVGaG2Vk0ImYgEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCECgAwFCr3aAR9FwCHzxeLojIV7vXvb43V9nJ5ff+R8CEIBALARQ6rFIknEsEZjuTO/OP6pnyuTPlNJPl25eX7zQRh9ld9TR7HT2/jqZbxCAAATCJIBSD1Nu9LqEQE1FfrOkVj/pXB+8fT07vHmTFAhAAALhEECphyMrelpBYPvhVGbjMiPX+tuKLDWTzfPJ7WyPWXtNXGSDAAS8I4BS904kdKgOgStFnmlZYlef1SlTM8+LyW29i2KvSYtsEICAVwS2vOoNnYHAGgL2sFuW5/uqUORGFLm8k5o1BdrdejL/aI6l6G674pSCAAQgMB4BZurjsaflGgSKU+tK7SljnsnD+qBGESdZ5ADdb9hjd4KSSiAAgQEJoNQHhE1T9QiMpciXeieH5ya39JRl+CUqXEAAAp4TYPndcwGl0r3pL6fTXKtnRhs7K38y+rhlnz7/WVYIlOJE/OjCoAMQgEBdAszU65Iin3MCS4pcqfEV+coIZbv+zbtXb6YryVxCAAIQ8JYASt1b0cTZsStbcmVn5Oor70ep9XdnL2dH3veTDkIAAhAQAiy/8xj0TuBKkYt3t/kH87T3Bp02IC8fSh05rZLKIAABCPREgJl6T2CpVqntx1OZja910xoEJpPpr/EVH4So6CQEkifATD35R8AtgGWnMBe25G6bGLw2Pc/3pNGTwRumQQhAAAINCTBTbwiM7DcJLCtyp97dbjY2Usok17+Y/W02G6l5moUABCBQiwAz9VqYyLRK4NKWXBcH3nrz7rba7GjXeVaYtx2M1gEahgAEIFCDADP1GpDIck7gUpEP7d3NC/44o/FCDHQCAhBYT4CZ+no+yd8tbMlllprLjFwbM5ibVu/AizOaIj47J+G9Ew0dggAErgkwU79mwbcLAr47hRlLUDijGYs87UIAAnUJoNTrkoo8H4q8poCN/ubs9cxGceMDAQhAwDsCLL97J5LhOrTkFEaF5hRmOE5LLWVmX65R6ktQuIAABHwhwEzdF0kM1I9FRS7xyAPz7jYQpA3N5Fr/6seXs9MN2bgNAS8JFE6hrNWKUjvyT55jfYQrZC9F1apTKPVW2MIrVNiSa+tEBUXeWXrGfH/2+q2w5AOBcAjc+3K6q3JzJD/6Nw682vMiKtN7eE4MR55VPUWpV5GJID0FpzBjiWlyW39OrPWx6NNuEwL2vMw8yw/rvdCb55M828fRUhPCfuVFqfslj869sW/jhVvTTD+TKGifda6QCkoJaKV/9/bV7KD0JokQ8ICA3WrLP6h9o8xvm3bHPt/ZbXXIi2tTcuPnR6mPL4POPUjaKUxnei0rEGc0Zy/f3G1ZmmIQ6JWAXaUz2hyWLbXXbdguyWutD9hvr0vMj3wodT/k0LgXKPLGyNwXINa6e6bU2ImA/V3IlDmUVbqvOlW0WFirH3Kl9zkcugjF3+8odX9lc6Nnl7bkuTb7Xd7Ab1RMQisCdibz7tWbaavCFIKAQwJ2qf3TR3UgXh9/7bDa5arkgOjkjuy3n87eL9/gyicCKHWfpFHSl0tFLktpe3L7SUkWkkYkQKz1EeHTdEHg/sPpvsnMwSBnaGTbSRt9yHkSfx8+lLqHsikOuPys9lDkHgpntUuyNCl767uryVxDoG8CxaHYXJbaR3jZt6tUmMD1LeF29aPU23FzXgqnMM6RDlYhsdYHQ01DQqCZiVrPyOSldjLXe5jA9cy5QfUo9QawXGdFkbsmOlJ9OKMZCXx6zd5/ND2QFbz9QZbaG+DFBK4BrJ6zotR7BlxWPU5hyqgEnEas9YCFF0bX13mD82YE8ncgDm72MYEbVyIo9YH4o8gHAj1SMzijGQl8As0WZmrG/CWYocqSvBH7dlzOjiMxlHqP3Is/xjzflwMleHfrkbMPVWPe5oMU4uzDvUcPZvJD/SC40VkTOJMdsN8+rORQ6o554xTGMdCQqsMZTUjSCqKvxQqfNn8KorNlncQEroxKr2kodQd4UeQOIMZRxYuzV2924hgKo/CBQHEwroXvdh/6vtgHu5Il9u37Z69nx4vpfHdPAKXekilOYVqCi7wYzmgiF/DAw9t+/ODEqcvXgft/ozlM4G4gcZ2w5brCmOtbVORzZfDuFrOwW46tiJCn1EnL4hSDwBIBY9Q0qpmX+KSfZ+bv9x5P/7B1Sx3gcnZJ3E4uonpenBBZqeTKllyJm1aXQRJW2uEyHgI4o4lHlmOPZPvRA1m5jvSDCVwvgs16qTWCSq1d6Paj+8fzD+bflTF/RKFHINSBhvBpovYHaopmIiZQ2KZHPL7CgY78tsqLy2n0Yx1Qjij1FdiFMpd9LJ2bP4sjhacrt7mEwEYCWlZ17ArPxoxkgMAaAlqW3tfcjunWE/t7aydRdoszpoGNMRaU+gJ12ec5LJQ5y+wLVPjamIBRn+USkKdxOQpAYIFAQkr9YtT66XxiTrcfT/cWMPC1IQGUugCzsyp7yrTXWMQNBUP2sAnYmPdhj4Dej01AfLzvjt2HwduXF2K73XnugXPw1qNoEKUuYpR987jMRqJ4NMMehJxAfcCMI2wZjt17e/J97D6M1n5mjtjCakc/eaW+/fD+kaDDPK3d80OptQTEYoIPBFoSsC+GLYuGX0xm7POf88PwBzL8CJJW6ucuGPW3w2OnxSQIyNkM620wibEySKcEOA0uOCVmBrP15o9V0kpd9qx4E2z+zFCiAYHMBvThA4GGBNI7JFcCyM7WP6pnJXdIWkMgWaVu9zuTXt5a81BwyyEBrb9ltuGQZyJVodQvBJ3nu4mI3Nkwk1XqcsKSGZSzx4iK1hGY/6x2193nHgRWCSR58n0Vgr3O9NT+x6c+gSSV+sXMicNx9Z8TcnYgoLXa6VCcogkSSPrke4LydjnkJJX6p0/8yLp8iKhrPQFj8un6HNyFwDIBtgaXeXBVn0CSSp39qvoPCDkdEGAJ0QHEdKrg5Hs6su5jpCj1PqhSJwQWCeRmtnjJdwisI8CkYx0d7m0ikKRSl/2q001guA8BVwS0zmau6qKe+Amg1K9lbJTmt/oaR61vaSr1iXpfiw6ZIOCAQJ6pEwfVUEUiBDj5fi3ozPBbfU2j3rcklfq7v85O6uEhFwQ6EtDqJ563jgwTK87J98QE7ni4SSr1c4bmuWOWVAeBmwRyc3wzkRQIVBPg5Ps1G7ZKr1nU/ZauUjfZUV1I5INAewIZSr09vORKcvJ9WeSGrdJlIDWuklXqZ69nx0apNzUYkQUC7QjI0rt9ztoVplSKBDgkl6LU3Y45WaVuMWZGH7rFSW0QWCDA0vsCDL7WIYBSX6a0tYWl0jKRzVdpK/U76kjJbGozJnJAoA0Blt7bUEu5DCffl6U/O529X07hahOBpJW6fWDEDvJoEyTuQ6AxAZbeGyOjgJI4U2oKBwh0IZC0UrfgtuaKJfguTxBlywmw9F7OhdS1BDj5voBHqx8Wrvhak0DySn32t9lMXo+/r8mLbBCoSYCl95qgyHZBgJPvPAouCCSv1C1EM8G8zcXDRB0XBFh651FoQYBDci2gUeQGAZS6ILnw+PXiBh0SINCGAEvvbaglXwalvvwIaKNPllO4qkMApX5JSWPedomC/7sSYOm9K8EUy3PyPUWpux8zSv2C6dnL2RHOaNw/YKnVaJ8hHM6kJnU34+XkuxuOqdeCUl94AjLM2xZo8LUVAa3xINcKHIU4+b78DBDdcJlH3SuU+gKp7LaYt+GMZoEIX5sSkJn6UdMy5IcABCDgigBKfYFk4b2IQ04LRPjahIBdev/x5ey0SRnyQuCSANt/lyTO/5ftCLzJLSOpdYVSX8E0MdnBShKXEKhHgKX3epzIVUpAazUrvZFoIi/I7QSPUl/hVjijwZPRChUu6xBg6b0OJfJUEdA55zGq2JBenwBKvYSV0fqgJJkkCFQSYOm9Eg03ahLIjOKQ5SUrzjZdkmj8P0q9BJl1RsP+VgkYkqoJsPRezYY7tQiwSriEibMpSzjqX6DUK1hpZusVZEguI8DSexkV0poSyJXeb1qG/BBYJIBSX6Sx8N06o8G8bQEIXysJsPReiYYbDQnYw2HiHvU3DYvFl90YTr63lCpKfQ04+eM6XHObWxA4J8DSO0+CQwJvX88O5VzPHxxWGVxVWmUsv7eUGkp9Dbgsx5HIGjzcuiDA0juPgmsC717O9pXR33C2xzXZ+OtDqa+RcXFwhVjrawhxi6V3noG+CNgYAu9evZkqrb9LTbkbbPZbP1Yo9Q3o8ixjCX4Do6Rvs/SetPiHGLw932OVu8n013LO54ch2hy7DZR6ewmg1DewK7waJfKHtAEFt0sIsPReAoWkXghYU9uzl292C+WuzPNeGqHS4Amg1OuIMOfAXB1MqeVh6T01ifsx3kK5v3r7bJLrX6hItwe3PuEyt+3TJtH++NQhcO/RgxmhEeuQSiePVvp3b1/NDvoe8XRnevfTJ7UjBzd3bVsS6OJ0Iv+KMx99N0793hOY/nI6nev8QGX6mTLqM+87XKODZ6/eoJtqcCrLArgyKiVp9x9O9402vy+5RVKiBOxMqU/Feu/L6a7O832l9NMyxHalIBOzy+yOOioiDJZlIi0ZAvblL/+g7O+UnJwPW7mj1Ns/tij1muzsH8z8o5mF/sdSc7hk20zghfzw7GzO1jxHMTP/qA60Mb+uX1r2WE12ZE9M1y9DzhgJFMr9Z7WXi3IPdHWxt7+tGOW9OiaU+iqRNdf3Hk8Pm/3QrqmMW0ETsF6/rJMQ14MoXh4/mBOp90mbuovZu9JH1sdCn6sIbfoWW5ntx9M9bdS0GJfE/rYBWXxjbvtojDkISrnLwWR7IDC252Wo8aDUG5Au9q4y8/cGRcgaKYG+lt63H92XmXb5cntjlIXVhj4qXB43LkyBKgLbD6fPVGaOSlft5OCamWRH9jBbVfkx0q1yl9MYe9Lnr8Zov1GbKPVGuFYzo9RXiWy43n54X3zC6283ZON23AR6WR7s7dyGDWOZm2Prc6Ew0YxbNr2N7nwVJT+q9dLl6QtVcU5DZu4+K3frIrfwqNebJOOueBL38NyP7h//++fvZcltz33N1BgKAVl6/58//b/3/8dlf4t9UGPsfvg/uKz3oq5/kBfRHXmD/x+f/fPdbz77l8//85++uDt7/6/v/7OHtqKs0ipDMzcic113W2QqIJ794z/f/e7uf/tcfX7v7t984P0f//f97D/+7aej//ovnz+XrcT/Yp8L3wSWKf2/f/q39ye+9SuU/mCn3lBSF8tqLxoWI3tEBOzeqevhzD+qocyRnohN3B/nH8y/21Unq6xcjyWm+uzLVnGWJjd/Ll1u3zBYu5dtrWbsIVtbj93C21BkkNt2xebs9du9mG3dBwHpYSMsv7cQSrE/JT+MLYpSJHwCvSy9bz96cCpo6s4CnVI01jSOw3U3mBYvPLk5sor5xs1OCea5ka0Qn/bd7ctGnqk9L8zhJJANVhztHzCUekt2OKNpCS7wYn2cer848f7vfqDBNM7K41Njk8JW0nshy9+HPh1kLLaBRrZ1t25wfXrhaSXZEQuh1FvCv/9oemCU+W3L4hQLlEAfp969XPmRw3VGZu9bc3Xom5lWn4/OF4+nO7LXfOx+dl7d66uVktvC+nT2vjrnsHfGModDqXeTM0q9Jb9idoUzmpb0gi3W09K7QzO2ftAWM8rJLbHD9kjpuB7q6C/qF1YKE5Md+PQiNbRyx5tctycbpd6BH+ZtHeAFWDT+pfcNQonUNM7OzjMjducjnWkopS4mcWLadeDTMvRQ5nAo9dInonYiSr02qpsZcUZzk0nMKZPb+nPXM9XCkYk2fwqNW7FkHIHf+dFn5xsEbzlrUe4+7bsXyn1NTIINQ9p4G6W+EdHaDCj1tXg239x+/ODEZ0cOm0dAjjoE+nKIEcdqT3iH67ycna97EGWVRFaKDjOP9t2LSY2NDufSGRfe5NY9BbXuYadeC1N1JrtEVn2XOzEQsLOlrVuqHznbcJnBf8Straw2WIuQEOzeree+TLX3rz+KuCTqmj2Ya+3dbf9H6cNKo3bff8nW3W7P8BmdADN1ByLAvM0BRI+ryLX+VR/uVUNdet8oKq2/82m5+LK/xcxyUvhs/+oyLdj/xce8Vag+9d+JOZyH4/KJcZ2+MFOvQ2lDHrvntSELt0MlIAqqD4VucZhM7YaKZW2/xTFTYaa3NtOwN+3sdj4xp9FslcmSt2+M7XmTt69mB5NbemoPldoVrqZS1iqzTpj4dCDATL0DvMuimLddkojof1lKzJXe7UuhW1JRr/AIv8lc74xtmhXV7Hz1z8syFgXq+vDmajNdrpuaw/XhB6JL/0Msy0zdgdTsH5U9xOKgKqrwgIA9FGd/LPtU6IWTE+fuRz2Ad9kF2QOe20NUI37s9kZUs/NVlsI4F+9vq8k+XdttmHev3kzlMN13qohcV907+3c39ktgde/CuYNSdySrLFdHjqqimrEIyH6enSnYsI99z35kiWxvrGEO1q4sEduZ8mDtXTRkV86KuPTWVFAU39DtD9le4at9yAZbtmWV+9nLN7vWW1ypcheF39th1JZ9DrUYy+8OJReHeZJDIKFUNYKjjzEDuAwplr5MAavGUBw+zIrDcFEr86Xxe3owcamPKxd2pWpiJDKhfIxWMx8PVq50OZhLlLpDUV3Yvv7FYZVU1S+BFzJz2B/aa1exz5uZv/c7NE9qH3DfN9WXansgrVji9kTkdGNcAiy/O+Rf7MFu2Ddy2BxVtSRQnMq1s5tXb3aGVui2y7k+n6G07H5Yxey+78/9bzVYz3BOnaAERFlmZg9C8A8QENKgu4pSdy4+feS8Sip0Q0BmjdbUxs5qxlzuk33QPTcDCqOWXJteD3PZFbLUIyZKZLmDMJ4Getk3AZS6Y8JWWbSxz3TcDapbJGCVudK/syfa376ejWqlYA9xSdeeLHYv9u92JtmnTXVmxj1l74X8jPpqjEOJXoydTiwRQKkv4XBzkWHe5gaki1rsiXarzMUpRt8n2ut0d/4xoaX3JSD9rE6cKzJxU8tHjW1CiAj8IIBS70EO2R0xb5PZYQ9VU2VdAhfmadaVpg/K/KrbJi9O/F5dp/JFZpJ97PsmdT5h07NiTQjPV4I25eR+xARQ6j0I1yoRo9hb7wHt5irloKL11V4ocwk4sbnAcDnOf3DTnVXqeb7nmrZR+Y7rOkOuz3dnNCGzDaXvKPWeJLU1V6Pu3fY0LH+rtbbm4tjCOrjo0xNcFwDzn9Vul/LBl+3DGU2mp8FzcTiAUJzROBwyVa0QQKmvAHF1ee7uUOJM8+mVwJV5mijzMczTmg0u0aX3BUh51r9520Jz6X0VE8I+DyWmBzS8EaPUe5SZyTJm633xtWcWxNZ8bPO0RsOLInZ6oxHfyGxnkuz73sDiNsH0a0LotrPU5poASt010YX6LmaOLxaS+NqVwIJ52pi25k2HUbgvjdwPeS0mwiBdC4BahFxketLHoUQXHaOO/gmg1PtmrIne5grxZfQ0X8zTmo2LpfdLXsahoxQ5kHp6WS//XxPQeb5/fcW3lAig1HuWNs5oHAAeMHqag96WViEvJLulNxJMLJzRSFhUF0OXulDqpSD1U5zRlIKJPhGlPoCIM8zb2lH22DytyYCij53eBMZl3szNvu/kljq+rJL/lwngjGaZRypXKPUBJJ3dxrytEeYAzNOajEdmk3tN8ieRV5zR2JedrmMtHAvJSk7XeqIsLwczOZQYpWTXDgqlvhaPm5v88NTjGJZ5Wr0xFbmMcbLU3KDFILJmjvZ9c6xMyuVtI+R9UPvlN0mNlYBMIvgMQSCpGNpNgRYudfV+SKfZ6w4Rua8nNbmtP3fhxnf78YMTJbP/9a2ld9e+KBNrPS25M1MfSN6FMxpZVh6ouTCaCdQ8rQlcfJOvp+VsJpljZVJGWmZtvUbIK2uTtHEJoNQH5C8noA8GbM7rpsI2T6uPNrXY6fXJnOd05db07PXsuNi+adqBFPLjjCYFKV+NEaV+haL/L9YZTfI/PBGYp9V9Ui5MipKKnV6XzVU+h25NNS/NV1hXvuCMZgVIzJco9YGlm+wPTyTmaU0el/lE7TbJn2peV85oCvO24nxGqiSrx91HhLzq1rgzJgGU+sD0k/vhicw8rdHjkmrs9EaQlLL7vi7cmtoDd9qwt16Kv48IeaUNkTg2AZT6wBJI5Yen2GaQgCs2FKr/0dPcPwSpx05vSlQ7ch2b5eqoadup5P80wbwtBVmj1EeQctQ/PHb5M7ToaT08AwQtaQhVzNFcuDUtrExwRlMKXyuzhzOaUjRRJaLURxBnlD88CZinNXpU8ny3UX4yK1duTXFGU/EwWWc0P+PdsIJONMko9ZFEGdMPTyrmaY0eFWKnN8JVZHbk1vTHl7NT2ajHJ0SJBHKJZ1+STFJEBFDqIwkzih+ehMzTmjwmxE5vQmshr1O3pvpooWa+XhDAGU38jwJKfVQZB/rDk6B5WrPHhNjpzXhd585l3/f6qv03Qh6vY+eG8boWuDceAZT6eOxVcD88KZunNXhOiJ3eANZKVpczyQzzthW6F5dyKNGFCWF55aSOTQClPrIEQvjhSd08rckjQuz0JrQq8jpya5rdEfM2nNGUQsYZTSmWKBJR6iOL0esfHszTGj8dMtPca1yIAqsEnLg1tT4hjAp0i2uViOtrnNG4JupNfSj1kUXh5Q8P5mntnwpip7dnt1BSO4q1vjVXhwvV8nWBQJ7xArqAI5qvMrHgMzYBn2JuW/O0rVvqwL5sjM0ltPZ9kmNo7Mr6O8n1LwqfDmU3G6RtP7wvy/D62wZF0sgqL++TW3rK33pc4mam7oE8z3+4zPNRu4J5Wmf8xE7vjHCpAlduTc0kO1qqmItzAmJCiOfD+B4GlLonMjVZNs4yIeZpzp4AYqc7Q1lUZN2auqjxIvbACxd1xVaHqwh5sXEJeTwodU+kV/zwDOkFC/M0p5IndrpTnOeVyUzSmemVJnpbmYQKE8KH02dl90gLkwBK3SO55Urv990dzNP6IUzs9H64SvCjXRc1B+cTwsWg69aR4Tq2LqoQ8qHUPZKSdR0r8aB/00uXME/rBetVpcROv0Lh65cM87Zy0YgzGutfofwmqaERQKl7JrG3r2eH9gS6s25hnuYMZVVFxE6vItM9Xc4p7Hav5byG7LaYt9mXWz43CGSOTAhvVEzC4ARQ6oMj39zgu5ezfRuTvOsPENHTNrN2kYMTxC4o9l9HYbqVm+P+WwqwBZzRBCi08i6j1Mu5jJ5q9wAnc72jxNSsUWfsTATztEbIOmdm6b0zwqoKxCPcadW9NukTkx20KZdCGZzRxCFlnM8EIEe7vFvMBgvloafS5SdL3bYn2eXHT+fq5Oz1jJnIEpz+L7YfP3iv5KR2/y2l14JW+ndvX80OXI58+9F9+RvRT13WGUVdMiE4e/nmbhRjSXgQKPWEhc/QuxMoYqdr86fuNVFDGQGT6a8v7MzLbrdKs2ZyOjd/blU49kKy7WdXCWMfZszjY/k9ZukytgEIEDu9T8hbW8rp8rvtq31JKEw7++x4oHXjjCZQwS10G6W+AIOvEGhMINPPGpehQF0CL/ryS661PqjbiZTyWWc0zhz+pATOo7Gi1D0SBl0Ji0Bh28teen9CM8b5LP2ys8USM+ZtlziW/tfGHCwlcBEUAZR6UOKisz4RkFnNnk/9ia4vWXbS55jE0dNhn/UHW7c4o7lwexzsEFLuOEo9Zekz9m4EiJ3ejd+G0rlyv5++2GThjGYxge9XBOY6P7i64EtQBDj9HpS46KwvBOzSe2bMX3zpT4z9OHv1pvffJ2KtVz85k9v6877ONFS3yp2uBJipdyVI+SQJTBwFGkkSXp1BDxSxEGc01cLIP6j96rvc8ZUASt1XydAvrwkQO71f8ch+90m/LZzXPvvbbCbumH8Yoq3Q2pBnHKUemtCkvyj1AIVGl8clQOz0/vkb0+9++tIIcg7MLfG4vBDLju3H073LS/4PgwBKPQw50UuPCORaPfOoO1F2ZXJHnQw1MOtaGWc0FbSJa1ABxt9klLq/sqFnnhIwOt/1tGtRdMsq2KEPaOGMpurRwUd+FRlf01HqvkqGfnlJgNjp/YtFq/6czlT1fnJLHXcNdVxVd+jpeJgLS4Io9bDkRW9HJkDs9P4FoE2/TmfKRmBXBnBGU0ZG4tnN1d3yO6T6SACl7qNU6JO/BNhj7F02+WTAQ3ILo8lydbRwydcLAlqrHWCEQwClHo6s6KkPBLTe9aEbMffBdajVuqwK8zZjvq+bn3wQ8JEASt1HqdAnLwkUsdMJ4NKvbEa2Gc+z7LDfAYZXu9FqFl6v0+0xSj1d2TPyxgSInd4YWcMCRunThkWcZv/x5ewUZzTLSFHqyzx8v0Kp+y4h+ucPAWKn9y4LcfY+qlIvBogzmiU5b215IJOlHnGxjgBKfR0d7kHgggCx04d5FCbz4ZzOVI0IZzRLZF4M7TNgqXUuGhNAqTdGRoEUCcgMci/FcQ86Zq1+Kg6rDdpoeWMZsdbPwWhc6JY/If6motT9lQ0984kAsdP7l4YxJ/03Uq+F7I6Yt8lLRr3cceaynv3OXs6O4hxdvKNCqccrW0bmiIBdepeZ+gNH1VFNBQGtsvH30y/6Zpec5dDeUUVX40+WFxqj9bP4BxrfCFHq8cmUETkmMDEEcHGMtLS6PBt/P32xY1tzdbh4ndL3XOndwhIgpUFHMlaUeiSCZBj9ETDKMGPpD+9Vzb6dsk7WGY3W36HQrx7L4L6g1IMTGR0ekgCx0wej7eUpazPJjgYj4ENDotDZR/dBEO37gFJvz46SCRAgdvpAQjbDR2arM7LCZe3IXu7q9NNJHhS6E4xjV4JSH1sCtO81AZOx9D6IgLLhI7PVH1cCB+ZQ6PUfB89zotQ9FxDdG49AETvdqK/G60E6Lec+eJKrwG2Xo615V8Xt8JNR6OHLcGEEKPUFGHyFwCIBYqcv0uj3u+8Hs7JYzdtQ6P0+2CPUjlIfATpNBkKA2OnDCCqAPevstpi3xeaMBoU+zPM9cCso9YGB01xIBPTTkHobal+10Se+973wf56bY9/7Wbt/KPTaqELLiFIPTWL0dxACRez0QVqiEWPCiAI2MdlBFNJCoUchxqpBoNSryJCeOAFipw/1AEzu+OVJrmrc58FmzPOq+0Gko9CDEFOXTqLUu9CjbLwEiJ0+iGztqfKQQnuaLAvXdSwKfZBneuxGUOpjS4D2vSNw78vprjLqM+86FmGHtPLT6UwV6sIZjVIvqu57m45C91Y0rjuGUndNlPrCJ0AAl8FkqI3PTmcqMIQWYxyFXiHIOJNR6nHKlVF1IUDs9C70GpXNJ2EcklscVOEbPRTzNhT6ouiS+I5ST0LMDLIuAfJBhWoAAAiPSURBVGKn1yXlJt/FcrabygasRczwvN9blz7+huAsAz4UnjSFUvdEEHTDDwLETh9QDgE4namiUTijqbrpQ7ox3799PfP+xcMHVLH1AaUem0QZTycCxE7vhK9RYaP0aaMCHmUuTuyL4vSoS9ddkX6dvX67d53At5QIoNRTkjZjXUuA2Olr8Ti/qT0O4lJnsF46o0Gh1xFd1HlQ6lGLl8E1IUDs9Ca0uuedzMNwOlM10sIZjU9bCCj0KlEllY5ST0rcDHYdAWKnr6Pj+J6cHj/30Oa43oGrM1ofDNxkeXMo9HIuCaai1BMUOkO+SYDY6TeZ9JpizEmv9Q9UuT29P3qsdRT6QNIOoxmUehhyopc9EyB2es+AV6rXKgv2kNzKUJQec7aOQl8VR/LXKPXkHwEAFASInT7og5BnYe+nL8IazRkNCn1RDHy/IIBS51GAQEGA2OlDPghbW+F5klvHZ3BnNCj0deJI+h5KPWnxM3hLgNjpgz8HL0KKzFaHTparozr5nORBoTvBGGslKPVYJcu4GhAgdnoDWN2zmrAis9UZcHGSX5Rtnbyd8qDQO+FLoTBKPQUpM8b1BIidvp6P67tZgJHZajDI+461jkKvIQWyoNR5BpImUCy9Ezt90GcgD9yTXBWsH1/OTlVfzmhQ6FXYSV8hgFJfAcJlWgRMpnbTGvH4oy2U3/jd6KcHeQ/R21Do/cgq0lpR6pEKlmHVJEDs9JqgHGXraybrqHtdqzl7PTt264zGPCc4S1eppFUepZ6WvBntAgFipy/AGOirmH6dDNTUaM04dEbzYnI72xttIDQcJAGUepBio9MuCEiUsD0X9VBHfQLGxGWfXjbyyS11LHvrP5Xda5AmCl3vxmb612D8ZG1JAKXeEhzFwiegjdkNfxRhjWByJx5PclXkrSKWWPFHVfdrpKPQa0AiSzkBlHo5F1IjJ0Ds9OEFbPeaU5l5bs3VYUvCKPSW4Ch2TgClzpOQJAFipw8vdq3iczpTRbGlMxoUehVQ0msTQKnXRkXGmAgQO314aWoTp9OZKpKTO9l+g711FHoVSNIbEUCpN8JF5mgIGPVVNGMJZCD5JP5DcouisFsNudK7NRQ7Cn0RHN87EUCpd8JH4RAJXOynh9j1oPv87q+zk6AH0KLz1tGOVexVtutG6z9wyr0FWIpUEtiqvMMNCERK4NOWmmrxVcpnQAKRO51ZR/LCg97UuiTWWu1c5rWR3Yq998sE/oeAAwIodQcQqQICEFhPQEy8TtfniP+u9TYno7T/+ECgNwIsv/eGloohAIFLAuLoJ3mlfsmC/yHQJwGUep90qRsCECgITObxO51B1BDwgQBK3Qcp0IdBCWxtMWscFLi4TGXveFDiNJYwAZR6wsJPdejnbjzVm1THP/i4jTkZvE0ahECiBFDqiQo++WFrzYGlgR4CrTL20wdiTTMQQKnzDCRJQOyGj5Ic+AiDzjP200fATpOJEkCpJyr41Idd2A4nbDs9pPw5wzAkbdpKnQBKPfUnIOHxT+Z6r4YLz4QJORn6i1QiszmhRSUQ6EgApd4RIMXDJXB+IlvvhzuCAHpu0onMFoA06GICBFDqCQiZIVYTOHs5O1JGf8OMvZpRpztZWpHZOrGiMAQcEECpO4BIFWETsO47ZSl+Rxnzfdgj8a/34mKfk+/+iYUeRUxAvDfygQAELgnYCG7zidpVeb6rMj1VhGi9RNPq/7NXb/iNaUWOQhBoR4A/uHbcKJUQgS8eT3dkSWtHzOB2tDIyoycWey3xi3XB2cs3u7XykgkCEHBCgChtTjBSScwELkJnLi0jo+g3S1wbfbI5FzkgAAGXBFDqLmlSVzIEail6mdnLrP6zZKCsDNQY9tNXkHAJgd4JsPzeO2IaSJlAsUevZdle/hltdoVFMoqe/fSUn3zGPhYBlPpY5Gk3WQJJKHqxJDh7/XYvWSEzcAiMRAClPhJ4moXAIoElRa9yOZSn5VCeerCYJ6TvJtNfv/vr7CSkPtNXCMRAAKUegxQZQ5QEpjvTu58+qZ0sV7smJEXPqfcon0cGFQYBlHoYcqKXECgIhKDoc61/dXGQEKlBAAIDE0CpDwyc5iDgmsCVop9bW/p8R2nxjqfUE9ft1KlPzNh+8/b17LBOXvJAAALuCaDU3TOlRgh4QeDel9PdbEhFz+E4L+ROJ9ImgFJPW/6MPjECvSl6FHpiTxLD9ZUASt1XydAvCAxEwCp6bdS0lRtcrX7SuT5gyX0gYdEMBDYQQKlvAMRtCKRIYJMbXHkBeJMpfZTdVoez09n7FBkxZghAAAIQgECwBKwtvZ3VBzsAOg4BCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgAAEIQAACEIAABCDgiMD/B+09j3M1DX+IAAAAAElFTkSuQmCC" } ``` Specifying Totals Manually [#specifying-totals-manually] By default, totals are calculated automatically, but you can specify them manually: ```javascript const invoice = { // ... other invoice fields ... totals: { taxExclusiveAmount: "1000.00", taxInclusiveAmount: "1210.00", payableAmount: "1210.00", }, vat: { totalVatAmount: "210.00", subtotals: [ { taxableAmount: "1000.00", vatAmount: "210.00", category: "S", percentage: "21.00", }, ], }, }; ``` Best Practices [#best-practices] 1. **Validate recipient before sending**: Always check if the recipient exists in the Peppol network 2. **Include clear references**: Use clear invoice numbers and references 3. **Set reasonable due dates**: Typically 30 days from issue date 4. **Provide complete information**: Fill in optional fields when available 5. **Handle errors gracefully**: Implement proper error handling 6. **Test with known recipients**: Test your integration before going live Next Steps [#next-steps] Issue credit notes to correct invoices. Create and manage company profiles. Send via email, configure notifications, and connect accounting software. Process incoming documents using webhooks or polling. Explore all endpoints and models. # Suppliers and Labels (/docs/suppliers-and-labels) This guide explains how to use Suppliers (supporting data) together with Labels to build powerful routing and integration workflows. It covers syncing suppliers, managing labels, automatic label propagation to documents, manual labeling, and webhook events you can use to react to changes. Overview [#overview] * **Suppliers**: Your master data for vendors. Suppliers can be created or updated via the API and support `externalId` so you can sync your own IDs without changing existing systems. * **Labels**: Team-level tags you can attach to suppliers and documents. Labels enable flexible routing, categorization and downstream integrations. * **Automatic propagation**: When an incoming document is matched to a supplier, the supplier’s labels are automatically attached to that document. * **Manual labeling**: You can attach or remove labels from documents manually via the API. * **Webhooks**: Label changes and new documents emit webhook events you can consume to drive automations. Common routing patterns: * Apply a label such as `"ERP"` to all invoices from specific suppliers to route them to an internal ERP. * Keep other invoices unlabelled until a human adds e.g. `"Accounting"` or `"ERP"`, then your integration picks them up and forwards them accordingly. Using Suppliers and Labels in the dashboard [#using-suppliers-and-labels-in-the-dashboard] You can also manage suppliers, labels, and document labeling directly from the Recommand dashboard: * **Labels**: Manage team-level labels from `Labels`. * **Suppliers**: View and edit suppliers from `Supporting data > Suppliers`, including their labels. * **Documents**: See and adjust labels on sent and received documents from `Sent and received`. These dashboard views operate on the same **team-scoped suppliers and labels** as the API, so changes made via the UI and via the API stay in sync. Prerequisites [#prerequisites] * A Recommand account with API access * Your API key and secret ```javascript // Shared auth setup used in examples const API_KEY = "your_api_key"; const API_SECRET = "your_api_secret"; export const AUTH = "Basic " + Buffer.from(`${API_KEY}:${API_SECRET}`).toString("base64"); export const BASE_URL = "https://app.recommand.eu/api/v1"; ``` Suppliers [#suppliers] Suppliers are supporting data you can sync from your systems. They support: * `id`: Internal Recommand ID * `externalId`: Your own identifier (optional). If provided, you can upsert by `externalId`. * `name`, `vatNumber`, `peppolAddresses` (array of Peppol IDs), and `labels`. Upsert a Supplier [#upsert-a-supplier] Use the [Upsert Supplier endpoint](/reference/suppliers/upsert-supplier). If `id` is provided, updates by `id`. Otherwise if `externalId` is provided, it updates or creates based on `externalId`; if neither is provided, it creates a new supplier. ```javascript // Create or update a supplier async function upsertSupplier(data) { const res = await fetch(`${BASE_URL}/suppliers`, { method: "POST", headers: { Authorization: AUTH, "Content-Type": "application/json" }, body: JSON.stringify(data), }); return res.json(); } // Examples await upsertSupplier({ name: "Contoso BV", externalId: "sup_12345", // your own ID vatNumber: "BE0123456789", peppolAddresses: ["0208:0123456789"], }); await upsertSupplier({ id: "internal_supplier_id", // update by internal id name: "Contoso BVBA", }); ``` List and Search Suppliers [#list-and-search-suppliers] Use the [List Suppliers endpoint](/reference/suppliers/get-suppliers) with pagination and search. ```javascript async function listSuppliers({ page = 1, limit = 10, search = "" } = {}) { const url = new URL(`${BASE_URL}/suppliers`); url.searchParams.set("page", String(page)); url.searchParams.set("limit", String(limit)); if (search) url.searchParams.set("search", search); const res = await fetch(url, { headers: { Authorization: AUTH } }); return res.json(); } ``` Labels [#labels] Labels are team-level tags you can attach to both suppliers and documents. They are useful for: * Routing (e.g., `"ERP"`, `"Accounting"`) * Categorization (e.g., `"High Value"`, `"Subscription"`) * Filtering and downstream processing Create and Manage Labels [#create-and-manage-labels] * Create: [Create Label](/reference/labels/create-label) * List: [List Labels](/reference/labels/get-labels) * Update/Delete: see Label endpoints under the “Labels” tag. ```javascript async function createLabel(name, colorHex, externalId = null) { const res = await fetch(`${BASE_URL}/labels`, { method: "POST", headers: { Authorization: AUTH, "Content-Type": "application/json" }, body: JSON.stringify({ name, colorHex, externalId }), }); return res.json(); } // Example await createLabel("ERP", "#3B82F6"); await createLabel("Accounting", "#10B981"); ``` Assign/Unassign Labels to Suppliers [#assignunassign-labels-to-suppliers] Use supplier-label endpoints: * Assign: [POST](/reference/suppliers/assign-label-to-supplier) * Unassign: [DELETE](/reference/suppliers/unassign-label-from-supplier) ```javascript async function assignLabelToSupplier(supplierId, labelId) { const res = await fetch( `${BASE_URL}/suppliers/${supplierId}/labels/${labelId}`, { method: "POST", headers: { Authorization: AUTH } } ); return res.json(); } async function unassignLabelFromSupplier(supplierId, labelId) { const res = await fetch( `${BASE_URL}/suppliers/${supplierId}/labels/${labelId}`, { method: "DELETE", headers: { Authorization: AUTH } } ); return res.json(); } ``` Automatic Label Propagation to Documents [#automatic-label-propagation-to-documents] When an incoming document is matched to a supplier, the supplier’s labels are automatically attached to that document. This means you can: * Maintain labeling logic centrally on suppliers * Have documents consistently inherit the correct labels for routing Manually Label Documents [#manually-label-documents] You can also attach or remove labels on specific documents: * Assign: [POST](/reference/documents/assign-label-to-document) * Unassign: [DELETE](/reference/documents/unassign-label-from-document) ```javascript async function assignLabelToDocument(documentId, labelId) { const res = await fetch( `${BASE_URL}/documents/${documentId}/labels/${labelId}`, { method: "POST", headers: { Authorization: AUTH } } ); return res.json(); } async function unassignLabelFromDocument(documentId, labelId) { const res = await fetch( `${BASE_URL}/documents/${documentId}/labels/${labelId}`, { method: "DELETE", headers: { Authorization: AUTH } } ); return res.json(); } ``` Webhook Events for Routing [#webhook-events-for-routing] Use webhooks to react in real-time when labels change. See [Webhooks CRUD](/reference/webhooks/get-webhooks). Relevant label events: * `document.label.assigned` * `document.label.unassigned` For reacting to newly arrived documents, use the `document.received` event documented in the [Working with Webhooks](/docs/working-with-webhooks) guide. Payload basics (label events): ```json { "eventType": "document.label.assigned | document.label.unassigned", "documentId": "doc_123", "teamId": "team_123", "companyId": "c_123", "labelId": "lab_456" // only for label events } ``` Recommendations: * Include a secret token in your webhook URL (e.g., as a path segment or query param) and verify it server-side. * Respond quickly with 200 OK; process work asynchronously. * Implement retry/backoff in your downstream processing. Example: Route by Labels [#example-route-by-labels] ```javascript // Express-style example app.post("/peppol-webhook", async (req, res) => { const event = req.body; // Optional: verify a secret token in the webhook URL res.status(200).send("OK"); try { if (event.eventType?.startsWith("document.label.")) { // Fetch full document to inspect labels const docRes = await fetch(`${BASE_URL}/documents/${event.documentId}`, { headers: { Authorization: AUTH }, }); const { success, document } = await docRes.json(); if (!success) return; const labelNames = new Set((document.labels || []).map((l) => l.name)); if (labelNames.has("ERP")) { await forwardToERP(document); } else if (labelNames.has("Accounting")) { await forwardToAccounting(document); } else { // leave unprocessed for manual review, or notify a queue } } } catch (err) { console.error("Routing error:", err); } }); ``` Best Practices [#best-practices] 1. Model your routing with labels; keep supplier labels as the source of truth where possible. 2. Use `externalId` when syncing suppliers to avoid changing your internal IDs. 3. Prefer webhooks over polling for timely integrations. 4. For manual workflows, let users add labels like `"ERP"` or `"Accounting"` to trigger downstream actions. 5. Implement safe retries and idempotency in your integrations to avoid duplicate processing. Next Steps [#next-steps] Set up webhooks and process document events. Upsert, list, and manage suppliers. Create and manage labels. Label documents, download packages, and more. # Troubleshooting Guide (/docs/troubleshooting-guide) This guide addresses common issues you may encounter when using the Recommand Peppol API and how to resolve them. Authentication Issues [#authentication-issues] 401 Unauthorized Errors [#401-unauthorized-errors] If you receive a `401 Unauthorized` response: ```json { "success": false, "error": "Unauthorized" } ``` **Possible causes and solutions:** 1. **Invalid API credentials** * Verify your API key and secret are correct * Check for extra spaces or special characters in your credentials * Try regenerating your API key in the dashboard 2. **Incorrect authentication format** * Ensure you're using Basic Authentication correctly ```javascript // Correct format const auth = "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"); // Incorrect format (missing 'Basic ' prefix) const auth = Buffer.from("key_xxx:secret_xxx").toString("base64"); ``` 3. **Revoked API key** * Check the API key status in your dashboard * Generate a new API key if necessary Testing Authentication [#testing-authentication] ```javascript async function testAuthentication() { try { const response = await fetch("https://app.recommand.eu/api/v1/companies", { headers: { Authorization: "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"), }, }); const statusCode = response.status; const body = await response.json(); console.log(`Status code: ${statusCode}`); console.log("Response body:", body); return statusCode === 200; } catch (error) { console.error("Authentication test failed:", error); return false; } } ``` Recipient Verification Problems [#recipient-verification-problems] Invalid Recipients [#invalid-recipients] If a recipient verification fails when using the [verify endpoint](/reference/recipients/verify-recipient): ```json { "success": true, "isValid": false } ``` **Possible causes and solutions:** 1. **Incorrect Peppol ID format** * Ensure the format is `schemeID:value` (e.g., `0208:0123456789`) * If no scheme is provided, `0208` (Belgian Enterprise Number) is assumed 2. **Recipient not in Peppol network** * Confirm the organization is registered in Peppol * Try different identifier schemes (0088, 0192, 0210, 9925) ```javascript // Try different schemes const schemes = ["0208", "0088", "0192", "0210", "9925"]; for (const scheme of schemes) { const result = await verifyRecipient(`${scheme}:${identifier}`); if (result.isValid) { console.log(`Found with scheme: ${scheme}`); return result; } } ``` 3. **Network or SML service issues** * Implement retry logic with exponential backoff ```javascript async function verifyWithRetry(peppolAddress, maxRetries = 3) { for (let attempt = 1; attempt <= maxRetries; attempt++) { try { const result = await verifyRecipient(peppolAddress); return result; } catch (error) { console.log(`Attempt ${attempt} failed. Retrying...`); if (attempt < maxRetries) { await new Promise((r) => setTimeout(r, 1000 * attempt)); } else { throw error; } } } } ``` Document Sending Failures [#document-sending-failures] Validation Errors [#validation-errors] If document validation fails when using the [send document endpoint](/reference/sending/send-document), the response is **HTTP 400**. The document is not sent and the attempt does not count toward your usage: ```json { "success": false, "errors": { "root": [ "Document validation failed. Please ensure your document complies with all requirements (e.g. EN16931, PEPPOL BIS 3.0, etc.).", "PEPPOL-EN16931-R020: Seller electronic address MUST be provided." ], "buyer.vatNumber": ["BR-CO-09: The Seller VAT identifier shall have a prefix in accordance with ISO code ISO 3166-1 alpha-2."] } } ``` `errors` is keyed by the field the error maps to; `root` is always present and carries the general message plus every error that has no field mapping. Each message starts with the validation rule identifier when the validator reports one, so you can look the rule up in the Peppol BIS Billing or EN 16931 rule lists. Validation is about structure and rules, not content: a wrong price or a mistyped address passes validation. HTTP 422 is different: the document was valid but could not be delivered (see [delivery errors](#delivery-errors) below). **Possible causes and solutions:** 1. **Missing required fields** * Check that all required fields are provided * Common required fields: invoiceNumber, buyer information, lines, paymentMeans 2. **Invalid data formats** * Ensure dates are in YYYY-MM-DD format * Verify monetary amounts are strings with 2 decimal places (e.g., "100.00") * Check VAT numbers follow country-specific formats 3. **Inconsistent data** * Ensure line totals match invoice totals if manually specified * Verify VAT calculations are correct Debugging Tool: Field Validation [#debugging-tool-field-validation] ```javascript function validateInvoice(invoice) { const requiredFields = ["invoiceNumber", "buyer", "paymentMeans", "lines"]; const errors = {}; // Check required fields for (const field of requiredFields) { if (!invoice[field]) { errors[field] = [`${field} is required`]; } } // Check buyer fields if (invoice.buyer) { const buyerFields = [ "vatNumber", "name", "street", "city", "postalZone", "country", ]; for (const field of buyerFields) { if (!invoice.buyer[field]) { errors[`buyer.${field}`] = [`buyer.${field} is required`]; } } // Validate VAT number format if ( invoice.buyer.vatNumber && !/^[A-Z]{2}[0-9A-Z]{2,12}$/.test(invoice.buyer.vatNumber) ) { errors["buyer.vatNumber"] = ["Invalid VAT number format"]; } } // Check line items if (invoice.lines && invoice.lines.length > 0) { invoice.lines.forEach((line, index) => { if (!line.netPriceAmount) { errors[`lines[${index}].netPriceAmount`] = [ "netPriceAmount is required", ]; } if (!line.vat || !line.vat.percentage) { errors[`lines[${index}].vat.percentage`] = [ "VAT percentage is required", ]; } }); } return { valid: Object.keys(errors).length === 0, errors }; } ``` Delivery Errors [#delivery-errors] If the document is valid but cannot be delivered, the response is **HTTP 422**. The document is not sent and the attempt does not count toward your usage: ```json { "success": false, "errors": { "root": ["Failed to send document over Peppol network. No additional context available, please contact support@recommand.eu if you could use our help."] } } ``` A 422 means Recommand did not get a delivery confirmation from the recipient's access point. The body does not carry the other side's status code: an outage, a timeout or an error response on their side all arrive as the same 422. When the recipient is not registered for the document type you sent, the message says so instead. **Possible causes and solutions:** 1. **Recipient's AP is unavailable** * This is usually temporary; implement retry logic * Configure [email delivery](/reference/sending/send-document) as a fallback so the document still reaches the recipient * If it persists, contact support with the recipient identifier and the time of the attempt 2. **Document size limits** * Reduce attachment sizes or split into multiple documents * Compress attachments before base64 encoding Document Reception Issues [#document-reception-issues] Missing Incoming Documents [#missing-incoming-documents] If expected documents don't appear in your [inbox](/reference/documents/get-inbox): **Possible causes and solutions:** 1. **Documents not directed to your Peppol ID** * Verify your Peppol ID is correctly communicated to senders 2. **Documents processed but not visible** * Check document filters * Verify company ID selection is correct ```javascript // List all documents across all companies const allDocs = await fetch(`https://app.recommand.eu/api/v1/documents`, { headers: { Authorization: AUTH }, }).then((r) => r.json()); // Check documents one by one allDocs.documents.forEach((doc) => { console.log(`Document ${doc.id} to ${doc.receiverId} from ${doc.senderId}`); }); ``` 3. **Webhook processing errors** * Check webhook server logs * Verify webhook endpoint is publicly accessible * Test webhook endpoint manually Webhook Challenges [#webhook-challenges] Webhooks Not Receiving Events [#webhooks-not-receiving-events] When [webhooks](/reference/webhooks/get-webhooks) are not receiving events: **Possible causes and solutions:** 1. **Webhook URL not accessible** * Ensure your endpoint is publicly accessible * Check firewall settings * Verify HTTPS certificate is valid 2. **Webhook server returning errors** * Ensure your endpoint returns 200 OK quickly * Check server logs for exceptions * Implement proper error handling 3. **Webhook registration issues** * Verify webhook is registered with correct URL * Check for typos in the URL Testing Webhook Functionality [#testing-webhook-functionality] ```javascript // Express.js webhook endpoint with logging app.post("/peppol-webhook", (req, res) => { // Log received payload for debugging console.log("Webhook received at:", new Date().toISOString()); console.log("Headers:", req.headers); console.log("Body:", req.body); // Always respond with 200 OK quickly res.status(200).send("Event received"); // Process event asynchronously setTimeout(() => { try { // Process event logic console.log("Processing event:", req.body.eventType); } catch (error) { console.error("Error processing webhook:", error); } }, 10); }); ``` Common Error Codes [#common-error-codes] | Error Code | Description | Solution | | ---------- | --------------------------------------------------------- | ------------------------------------------------------------------------- | | 400 | Bad Request - Invalid input or document validation failed | Check `errors` in the response body | | 401 | Unauthorized | Verify API key and secret | | 403 | Forbidden | Check permissions for the API key | | 404 | Not Found | Verify endpoint path and resource IDs | | 422 | Recipient could not be reached | Retry later; check the recipient's registration; configure email fallback | | 429 | Too Many Requests | Implement rate limiting and backoff strategy | | 500 | Server Error | Contact support if persistent | Debugging Network Issues [#debugging-network-issues] Request-Response Logging [#request-response-logging] Implement detailed logging to troubleshoot API requests: ```javascript async function makeApiRequest(method, url, body = null) { console.log(`${method} ${url}`); if (body) console.log("Request Body:", body); const options = { method, headers: { Authorization: "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"), "Content-Type": "application/json", }, }; if (body) { options.body = JSON.stringify(body); } try { const startTime = Date.now(); const response = await fetch(url, options); const responseTime = Date.now() - startTime; console.log(`Response Status: ${response.status} (${responseTime}ms)`); const responseBody = await response.json(); console.log("Response Body:", responseBody); return responseBody; } catch (error) { console.error("Request Failed:", error); throw error; } } ``` API Response Time Issues [#api-response-time-issues] If the API is responding slowly: 1. **Check your network connection** * Test latency to the API endpoint ```bash ping app.recommand.eu ``` 2. **Optimize request patterns** * Batch requests where possible * Implement caching for verification results * Reduce payload sizes 3. **Implement timeout handling** ```javascript async function fetchWithTimeout(url, options, timeout = 10000) { const controller = new AbortController(); const id = setTimeout(() => controller.abort(), timeout); try { const response = await fetch(url, { ...options, signal: controller.signal, }); clearTimeout(id); return response; } catch (error) { clearTimeout(id); if (error.name === "AbortError") { throw new Error(`Request timed out after ${timeout}ms`); } throw error; } } ``` Document Content Issues [#document-content-issues] If the document content is incorrect: 1. **Preview document before sending** * Consider implementing a preview functionality * Validate totals and calculations client-side 2. **Check decimal handling** * Ensure monetary values use dot as decimal separator * Format numbers with 2 decimal places as strings 3. **Validate dates and identifiers** * Use ISO date format (YYYY-MM-DD) * Ensure invoice numbers follow a consistent pattern Getting Support [#getting-support] If you've tried the troubleshooting steps and still face issues: 1. **Gather debugging information** * API request and response details * Error messages and codes * Steps to reproduce the issue * Timestamps of when issues occurred 2. **Contact Recommand support** * Email: [support@recommand.eu](mailto:support@recommand.eu) * Include your team ID and relevant document IDs * Share the debugging information collected Next Steps [#next-steps] Full reference of all endpoints and models. Create and send your first invoice. Verify recipients and document support. Receive inbound events from the network. Set up and test HTTP Basic authentication. # Understanding Peppol UBL Format (/docs/ubl-format-guide) This guide explains the Universal Business Language (UBL) format used in [Peppol document exchange](/reference). What is UBL? [#what-is-ubl] UBL (Universal Business Language) is an XML-based standard for electronic business documents. In the Peppol network, UBL serves as the foundation for standardized document exchange between businesses across borders and systems. UBL in Peppol [#ubl-in-peppol] Peppol uses specific UBL document formats defined by the EN16931 European standard for electronic invoicing. Documents sent through Peppol must comply with these standards to ensure interoperability across the network. The most common UBL document type in Peppol is: ```text urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1 ``` This identifier specifies that the document is: * A UBL Invoice document (version 2) * Compliant with EN16931:2017 standard * Following Peppol BIS Billing 3.0 specifications * Using syntax version 2.1 Document Structure [#document-structure] A UBL invoice in Peppol contains several key sections: 1. Header Information Contains basic invoice details like number, dates, and references: ```xml INV-2025-001 2024-05-15 2024-06-15 Thank you for your business PO-2024-001 ``` 2. Parties Defines seller and buyer information: ```xml Your Company 0123456789 Your Street 1 Brussels 1000 BE ``` 3. Payment Information Contains payment terms and bank details: ```xml 30 INV-2025-001 BE1234567890 ``` 4. Invoice lines Each product or service line item: ```xml 1 10.00 1000.00 Consulting Services Professional consulting services CS-001 S 21.00 VAT 100.00 ``` 5. Tax Information VAT breakdowns and totals: ```xml 210.00 1000.00 210.00 S 21.00 VAT ``` 6. Monetary Totals Summary of invoice amounts: ```xml 1000.00 1000.00 1210.00 1210.00 ``` VAT Categories [#vat-categories] Peppol UBL supports various VAT categories, including: | Code | Description | | ---- | ----------------------------------------------------------------- | | S | Standard rate | | Z | Zero rated goods | | E | Exempt from tax | | AE | VAT Reverse Charge | | K | VAT exempt for EEA intra-community supply | | G | Free export item, VAT not charged | | O | Services outside scope of tax | | L | Canary Islands general indirect tax | | M | Tax for production, services and importation in Ceuta and Melilla | | B | Transferred (VAT), In Italy | When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Unit Codes [#unit-codes] Common unit codes in Peppol UBL include: | Code | Description | | ---- | ------------- | | C62 | One (unit) | | DAY | Day | | HUR | Hour | | MIN | Minute | | MON | Month | | WEE | Week | | KGM | Kilogram | | LTR | Liter | | MTR | Meter | | KWH | Kilowatt hour | The complete list of unit codes can be found in the [UN/ECE Recommendation 20](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Document Types [#document-types] Common document types in Peppol: | Type | Description | | -------------- | --------------------------------- | | Invoice | Standard invoice | | CreditNote | Credit note correcting an invoice | | Order | Purchase order | | OrderResponse | Response to a purchase order | | Catalogue | Product catalogue | | DespatchAdvice | Shipping notice | Attachments [#attachments] UBL documents can include attachments embedded as base64-encoded content: ```xml ATT-001 Commercial invoice ``` Validation Rules [#validation-rules] Peppol documents must pass several validation layers: 1. XML Schema Validation: Basic XML structure validation 2. Schematron Validation: Business rule validation specific to document type 3. Peppol Validation Artifacts: Additional Peppol-specific rules The Recommand API handles these validations automatically when sending documents. Simplified Approach with Recommand [#simplified-approach-with-recommand] Instead of constructing complex UBL XML manually, you can use Recommand's simplified JSON structure, which is automatically converted to valid UBL. Furthermore, if not provided, Recommand will automatically calculate any necessary totals. ```javascript // Simple JSON structure const invoice = { invoiceNumber: "INV-2025-001", issueDate: "2024-05-15", buyer: { vatNumber: "BE0987654321", name: "Customer Company", // ... }, // ... }; // Send to Recommand API which converts to proper UBL await fetch("https://app.recommand.eu/api/v1/{companyId}/send", { method: "POST", // ... body: JSON.stringify({ recipient: "0208:987654321", documentType: "invoice", document: invoice, }), }); ``` Working with Raw UBL [#working-with-raw-ubl] If you need to work with raw UBL XML: 1. You can send pre-formed XML directly using the [send document endpoint](/reference/sending/send-document): ```javascript await fetch("https://app.recommand.eu/api/v1/{companyId}/send", { method: "POST", // ... body: JSON.stringify({ recipient: "0208:987654321", documentType: "xml", document: "...(UBL XML)...", doctypeId: "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1", }), }); ``` 2. You can retrieve the UBL XML of sent and received documents using the [get document endpoint](/reference/documents/get-document): ```javascript const response = await fetch( "https://app.recommand.eu/api/v1/documents/{documentId}", { // ... } ); const data = await response.json(); const ublXml = data.document.xml; ``` Further Resources [#further-resources] Official BIS Billing 3.0 documentation. UBL 2.1 specification by OASIS. Practical guide to send invoices with JSON or XML. Learn to issue credit notes in Peppol. Explore all endpoints and models. # Verifying Recipients (/docs/verifying-recipients) This guide explains how to verify if recipients exist in the Peppol network and support specific document types using the [Recommand API](/reference/recipients/verify-recipient). Overview [#overview] Before sending documents through Peppol, it's important to verify if: 1. The recipient is registered in the Peppol network 2. The recipient can receive the specific document type you want to send Recommand automatically performs these verifications. In some cases, you may want to ensure a recipient is on the Peppol network before sending documents, you can do this through the verification endpoints. Prerequisites [#prerequisites] * A Recommand account with API access * Your API key and secret Understanding Peppol Addressing [#understanding-peppol-addressing] Peppol participants are identified by a unique Peppol ID, typically structured as: `scheme:identifier`. Common electronic address schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/eas/). If no scheme is specified in your requests, "0208" (Belgian Enterprise Number) is assumed. The identifier is often the company's national identifier, such as a VAT number or enterprise number. Verifying if a Recipient Exists [#verifying-if-a-recipient-exists] To check if a recipient is registered in the Peppol network using the [verify endpoint](/reference/recipients/verify-recipient): ```javascript async function verifyRecipient(peppolAddress) { const response = await fetch("https://app.recommand.eu/api/v1/verify", { method: "POST", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify({ peppolAddress }), }); return response.json(); } // Example usage const result = await verifyRecipient("0208:0123456789"); console.log("Recipient exists:", result.isValid); console.log("SMP URL:", result.smpUrl); ``` Response Structure [#response-structure] ```json { "success": true, "isValid": true, "smpUrl": "https://smp.example.com/..." } ``` * `isValid`: Boolean indicating if the recipient exists in the Peppol network * `smpUrl`: The Service Metadata Publisher URL for the recipient * `serviceMetadataReferences`: The SMP references published for the participant * `smpHostnames`: The hostnames the SMP was resolved on * `supportedDocuments`: The document types the participant is registered to receive, each with a readable `name` and a full `docTypeId` A lookup that fails is not an error. An address that is not registered, or that cannot be resolved for any other reason, comes back as `{ "success": true, "isValid": false }` with none of the other fields. Check `isValid` rather than the HTTP status. Asking for More Detail [#asking-for-more-detail] Two options widen the response: | Option | What it adds | | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `includeEndpointDetails` | Fetches the endpoint metadata for every supported document type, so each entry in `supportedDocuments` also carries `serviceProvider`, `serviceEndpoint`, `technicalContact` and `certificateExpiry` | | `includeBusinessCard` | Fetches the participant's business card from the SMP, adding `companyName` and `countryCode` at the top level | ```javascript const result = await fetch("https://app.recommand.eu/api/v1/verify", { method: "POST", headers: { Authorization: "Basic " + Buffer.from("key_xxx:secret_xxx").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify({ peppolAddress: "0208:0123456789", includeEndpointDetails: true, includeBusinessCard: true, }), }).then((r) => r.json()); console.log(result.companyName, result.countryCode); for (const doc of result.supportedDocuments) { console.log(doc.name, doc.serviceEndpoint, doc.certificateExpiry); } ``` Both options cost extra SMP lookups, so leave them off when all you need to know is whether the address resolves. Verifying Document Type Support [#verifying-document-type-support] To check if a recipient can receive a specific document type using the [verify document support endpoint](/reference/recipients/verify-document-support): ```javascript async function verifyDocumentSupport(peppolAddress, documentType) { const response = await fetch( "https://app.recommand.eu/api/v1/verify-document-support", { method: "POST", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify({ peppolAddress, documentType }), } ); return response.json(); } // Example usage const documentType = "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"; const result = await verifyDocumentSupport("0208:0123456789", documentType); console.log("Document type supported:", result.isValid); ``` Common Document Types [#common-document-types] | Document | Document Type Identifier | | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | Invoice (BIS Billing 3.0) | `urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1` | | Credit Note (BIS Billing 3.0) | `urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2::CreditNote##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1` | | Order (BIS Ordering 3.0) | `urn:oasis:names:specification:ubl:schema:xsd:Order-2::Order##urn:fdc:peppol.eu:2017:poacc:ordering:3.0::2.1` | Response Structure [#response-structure-1] ```json { "success": true, "isValid": true, "smpUrl": "https://smp.example.com/..." } ``` * `isValid`: Boolean indicating if the recipient supports the document type * `smpUrl`: The Service Metadata Publisher URL for the recipient * `serviceProvider`: The service description published on the endpoint * `serviceEndpoint`: The endpoint URL the document would be delivered to * `technicalContact`: The technical contact URL published by the receiving access point * `certificateExpiry`: When the receiving access point's certificate expires, ISO 8601 As with verifying a recipient, a failed lookup is not an error. An address that is registered but not for this document type comes back as `{ "success": true, "isValid": false }` with none of the other fields. Narrowing to One Process [#narrowing-to-one-process] A document type can be published under more than one Peppol process. Pass `processId` to check the combination you are actually going to send, with or without its scheme prefix: ```javascript body: JSON.stringify({ peppolAddress: "0208:0123456789", documentType: "invoice", processId: "urn:fdc:peppol.eu:2017:poacc:billing:01:1.0", }); ``` When you leave `processId` out, any process published for the document type is accepted. Name it when the process matters, for example for French recipients inside the e-invoicing perimeter, who are published under `urn:peppol:france:billing:regulated` rather than the standard billing process. `documentType` also accepts the short names as well as a full document type ID, so `"invoice"`, `"creditNote"`, `"selfBillingInvoice"` and `"selfBillingCreditNote"` all work. Searching the Peppol Directory [#searching-the-peppol-directory] To find recipients in the Peppol directory using the [search Peppol Directory endpoint](/reference/recipients/search-directory): ```javascript async function searchPeppolDirectory(query) { const response = await fetch( "https://app.recommand.eu/api/v1/search-peppol-directory", { method: "POST", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify({ query }), } ); return response.json(); } // Example usage const searchResults = await searchPeppolDirectory("Company Name"); console.log("Search results:", searchResults.results); ``` Response Structure [#response-structure-2] ```json { "success": true, "results": [ { "peppolAddress": "0208:0123456789", "name": "Example Company", "supportedDocumentTypes": [ "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1" ] } ] } ``` Complete Verification Workflow [#complete-verification-workflow] Here's a complete example demonstrating how to implement a verification workflow before sending documents: ```javascript // Setup authentication const API_KEY = "your_api_key"; const API_SECRET = "your_api_secret"; const AUTH = "Basic " + Buffer.from(`${API_KEY}:${API_SECRET}`).toString("base64"); const BASE_URL = "https://app.recommand.eu/api/v1"; /** * Verify if recipient exists and supports invoice documents before sending */ async function verifyAndSendInvoice(companyId, recipientId, invoice) { console.log(`Verifying recipient: ${recipientId}`); // Step 1: Verify if recipient exists in Peppol network const verifyResponse = await fetch(`${BASE_URL}/verify`, { method: "POST", headers: { Authorization: AUTH, "Content-Type": "application/json", }, body: JSON.stringify({ peppolAddress: recipientId }), }); const verifyResult = await verifyResponse.json(); if (!verifyResult.isValid) { console.error( `Recipient ${recipientId} is not registered in the Peppol network` ); return { success: false, error: "Recipient not found in Peppol network", }; } console.log(`Recipient ${recipientId} exists in Peppol network`); // Step 2: Verify if recipient supports invoice document type const documentType = "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"; const supportResponse = await fetch(`${BASE_URL}/verify-document-support`, { method: "POST", headers: { Authorization: AUTH, "Content-Type": "application/json", }, body: JSON.stringify({ peppolAddress: recipientId, documentType, }), }); const supportResult = await supportResponse.json(); if (!supportResult.isValid) { console.error( `Recipient ${recipientId} does not support invoice documents` ); return { success: false, error: "Recipient does not support invoice documents", }; } console.log(`Recipient ${recipientId} supports invoice documents`); // Step 3: Send the invoice const sendResponse = await fetch(`${BASE_URL}/${companyId}/send`, { method: "POST", headers: { Authorization: AUTH, "Content-Type": "application/json", }, body: JSON.stringify({ recipient: recipientId, documentType: "invoice", document: invoice, }), }); const sendResult = await sendResponse.json(); if (!sendResult.success) { console.error("Failed to send invoice:", sendResult.errors); return { success: false, errors: sendResult.errors, }; } console.log("Invoice sent successfully!"); return { success: true, }; } // Example usage const companyId = "your_company_id"; const recipientId = "0208:0123456789"; const invoice = { invoiceNumber: "INV-2024-001", issueDate: "2024-05-15", // ... other invoice fields }; verifyAndSendInvoice(companyId, recipientId, invoice) .then((result) => { if (result.success) { console.log("Invoice process completed successfully"); } else { console.error("Invoice process failed:", result.error || result.errors); } }) .catch((error) => { console.error("Error in verification process:", error); }); ``` Handling Invalid Recipients [#handling-invalid-recipients] When a recipient is not found in the Peppol network, you might want to try different identifier schemes: ```javascript async function verifyRecipientWithMultipleSchemes(identifier) { // Try without scheme (defaults to 0208) let result = await verifyRecipient(identifier); if (result.isValid) return result; console.log("Recipient not found, trying alternative schemes..."); // Try with common schemes const schemes = ["0208", "0088", "0192", "0210", "9925"]; for (const scheme of schemes) { const peppolAddress = `${scheme}:${identifier}`; console.log(`Trying: ${peppolAddress}`); result = await verifyRecipient(peppolAddress); if (result.isValid) { console.log(`Found recipient with scheme ${scheme}`); return result; } } console.log("Recipient not found with any common scheme"); return { success: true, isValid: false }; } // Example usage const result = await verifyRecipientWithMultipleSchemes("0123456789"); ``` Finding Recipients by Name [#finding-recipients-by-name] You can help users find recipients by searching the Peppol directory: ```javascript async function findRecipientByName(name) { const searchResponse = await fetch( `https://app.recommand.eu/api/v1/search-peppol-directory`, { method: "POST", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify({ query: name }), } ); const searchResult = await searchResponse.json(); if (!searchResult.success || !searchResult.results.length) { console.log("No recipients found matching the name"); return []; } console.log( `Found ${searchResult.results.length} recipients matching "${name}"` ); return searchResult.results; } // Example UI integration async function searchAndSelectRecipient(searchTerm) { const recipients = await findRecipientByName(searchTerm); if (recipients.length === 0) { console.log("No recipients found matching the name"); return null; } // Display results to user for selection console.log("Please select a recipient:"); recipients.forEach((recipient, index) => { console.log(`${index + 1}. ${recipient.name} (${recipient.peppolAddress})`); }); // In a real application, you would have UI selection // For this example, we'll just return the first match return recipients[0].peppolAddress; } await searchAndSelectRecipient("BRBX"); ``` Best Practices [#best-practices] 1. **Always verify before sending**: Check recipient existence and document support before sending, either through the Recommand API or by communicating with the recipient directly (out of band) 2. **Cache verification results**: Store verification results temporarily to reduce API calls 3. **Implement fallbacks**: Try different identifier schemes if the initial check fails 4. **Provide search functionality**: Help users find recipients by name or identifier 5. **Handle errors gracefully**: Provide clear error messages when verification fails 6. **Validate identifiers**: Ensure identifiers are in the correct format before verification Common Issues and Solutions [#common-issues-and-solutions] | Issue | Solution | | --------------------------- | ------------------------------------------------------------------------------------ | | Recipient not found | Verify the identifier is correct and try different schemes | | Document type not supported | Check if the recipient supports a different document format or contact them directly | | Network errors | Implement retry logic with exponential backoff | | Invalid identifier format | Validate the format before verification | Next Steps [#next-steps] Send a verified recipient an invoice. Correct invoices for verified recipients. Receive inbound document events after sending. Explore endpoints for verification and sending. # Working with Webhooks (/docs/working-with-webhooks) This guide explains how to set up and use webhooks to receive real-time notifications about Peppol document events using the [Recommand API](/reference/webhooks/get-webhooks). Webhooks are part of Recommand's broader rule system. If you want to filter by event details, send emails, combine multiple actions, or manage delivery retries from one place, see [Working with Rules](/docs/rules). Overview [#overview] Webhooks allow your systems to receive instant notifications when new documents are received or other events occur in the Peppol network. Instead of constantly polling the API for updates, you can have updates pushed to your system as they happen. Prerequisites [#prerequisites] * A Recommand account with API access * Your API key and secret * Your team ID * A publicly accessible URL endpoint on your server to receive webhook events Setting Up a Webhook Endpoint [#setting-up-a-webhook-endpoint] First, you need to create an endpoint on your server to receive the webhook events. Node.js Example [#nodejs-example] ```javascript // Using Express.js const express = require("express"); const bodyParser = require("body-parser"); const app = express(); app.use(bodyParser.json()); app.post("/peppol-webhook", (req, res) => { const event = req.body; // Process the event console.log("Received webhook event:", event); // Process new document const docId = event.documentId; // TODO: Fetch the document, process it, etc. // Always respond with a 200 OK to acknowledge receipt res.status(200).send("Event received"); }); app.listen(3000, () => { console.log("Webhook server listening on port 3000"); }); ``` PHP Example [#php-example] ```php ``` The digest is an HMAC SHA-256 signature of the **exact raw request body**. Verify it before parsing or processing the event. Use a constant-time comparison to avoid timing attacks. ```javascript import crypto from "node:crypto"; import express from "express"; const app = express(); const WEBHOOK_SECRET = process.env.RECOMMAND_WEBHOOK_SECRET; app.post( "/peppol-webhook", express.raw({ type: "application/json" }), (req, res) => { const received = req.get("X-Signature"); const expected = `sha256=${crypto .createHmac("sha256", WEBHOOK_SECRET) .update(req.body) .digest("hex")}`; const receivedBuffer = Buffer.from(received ?? ""); const expectedBuffer = Buffer.from(expected); const valid = receivedBuffer.length === expectedBuffer.length && crypto.timingSafeEqual(receivedBuffer, expectedBuffer); if (!valid) { return res.status(401).send("Invalid signature"); } const event = JSON.parse(req.body.toString("utf8")); // Process the verified event. return res.status(200).send("Event received"); } ); ``` Parsing the JSON and serializing it again can change whitespace or property ordering and make a valid signature fail. Configure your framework to retain the original request bytes. Listing Webhooks [#listing-webhooks] To retrieve all webhooks associated with your team using the [list webhooks endpoint](/reference/webhooks/get-webhooks): ```javascript async function listWebhooks() { const response = await fetch(`https://app.recommand.eu/api/v1/webhooks`, { headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), }, }); const result = await response.json(); return result.webhooks; } // Example usage const webhooks = await listWebhooks(); webhooks.forEach((webhook) => { console.log(`Webhook ID: ${webhook.id}, URL: ${webhook.url}`); }); ``` Updating a Webhook [#updating-a-webhook] To update an existing webhook using the [update webhook endpoint](/reference/webhooks/update-webhook): ```javascript async function updateWebhook(webhookId, updatedData) { const response = await fetch( `https://app.recommand.eu/api/v1/webhooks/${webhookId}`, { method: "PUT", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify(updatedData), } ); return response.json(); } // Example usage const updateResult = await updateWebhook("webhook_id", { url: "https://your-domain.com/updated-webhook-endpoint", companyId: "c_123", // Change to monitor a specific company secret: "your_new_webhook_signing_secret", }); if (updateResult.success) { console.log("Webhook updated successfully"); } else { console.error("Failed to update webhook:", updateResult.errors); } ``` When updating a webhook, omit `secret` to keep the current signing secret. Set it to a new non-empty string to rotate the secret, or to `null` to stop signing deliveries. Deleting a Webhook [#deleting-a-webhook] To delete a webhook using the [delete webhook endpoint](/reference/webhooks/delete-webhook): ```javascript async function deleteWebhook(webhookId) { const response = await fetch( `https://app.recommand.eu/api/v1/webhooks/${webhookId}`, { method: "DELETE", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), }, } ); return response.json(); } // Example usage const deleteResult = await deleteWebhook("webhook_id"); if (deleteResult.success) { console.log("Webhook deleted successfully"); } else { console.error("Failed to delete webhook:", deleteResult.errors); } ``` Webhook Event Types [#webhook-event-types] When a document is received or other events occur, your webhook endpoint will receive a POST request with a JSON payload containing the event details. Document Received Event [#document-received-event] For a complete guide on processing incoming documents (including fetching details, accessing parsed content, and polling as an alternative to webhooks), see the [Receiving Documents](/docs/receiving-documents) guide. ```json { "eventType": "document.received", "documentId": "doc_xxx", "teamId": "team_xxx", "companyId": "c_xxx" } ``` Upon receiving this event, you would typically: 1. Check the `eventType` to ensure it is a document received event 2. Retrieve the full document using the `documentId` via the [get document endpoint](/reference/documents/get-document) 3. Process the document in your system 4. Mark the document as read via the [mark as read endpoint](/reference/documents/mark-as-read) ```javascript // Example of handling a received document event app.post("/peppol-webhook", async (req, res) => { const event = req.body; if (event.eventType === "document.received") { try { // 1. Retrieve the document const document = await fetchDocument(event.documentId); // 2. Process the document in your system await processDocumentInYourSystem(document); // 3. Mark the document as read await markDocumentAsRead(event.documentId); console.log(`Successfully processed document ${event.documentId}`); } catch (error) { console.error(`Error processing document ${event.documentId}:`, error); } } // Always acknowledge receipt res.status(200).send("Event received"); }); // Fetch document function async function fetchDocument(documentId) { const response = await fetch( `https://app.recommand.eu/api/v1/documents/${documentId}`, { headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), }, } ); const result = await response.json(); if (!result.success) { throw new Error( `Failed to fetch document: ${JSON.stringify(result.errors)}` ); } return result.document; } // Mark document as read async function markDocumentAsRead(documentId) { const response = await fetch( `https://app.recommand.eu/api/v1/documents/${documentId}/mark-as-read`, { method: "POST", headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), "Content-Type": "application/json", }, body: JSON.stringify({ read: true }), } ); const result = await response.json(); if (!result.success) { throw new Error( `Failed to mark document as read: ${JSON.stringify(result.errors)}` ); } return result; } ``` Document Sent Event [#document-sent-event] Fired when a company sends a document, whether it went out over the Peppol network or by email. Use it to record in your own system that the document left the platform, without polling the documents endpoint after every send. ```json { "eventType": "document.sent", "documentId": "doc_xxx", "teamId": "team_xxx", "companyId": "c_xxx" } ``` The send call itself already tells you whether delivery succeeded, so this event is most useful when documents are also sent from the dashboard or by another system in your team, and you want one place that sees all of them. Report Status Changed Event [#report-status-changed-event] Fired when a French e-reporting report moves on with the tax administration. A report is filed on a period, and the outcome comes back later, so this event is how you learn where a report ended up without polling the document. ```json { "eventType": "document.reporting_status_changed", "documentId": "doc_xxx", "teamId": "team_xxx", "companyId": "c_xxx", "reportingStatus": "filed", "previousReportingStatus": "accepted", "periodEnd": "2026-09-30", "submissionId": "sub_xxx", "outcomeCode": null } ``` * `reportingStatus` and `previousReportingStatus`: one of * `accepted`: on file, inside its reporting period * `pending_rectificative`: arrived after the period was filed, so a corrective filing will carry it * `filed`: reported to the tax administration * `filed_rectificative`: reported by a corrective filing * `superseded`: replaced by a correction, or cancelled * `rejected`: refused by the tax administration; `outcomeCode` says why * `periodEnd`: the last day of the reporting period the report belongs to * `submissionId`: the period filing the report was carried on * `outcomeCode`: the tax administration's outcome code `periodEnd`, `submissionId` and `outcomeCode` are `null` until they are known, so an early status change carries less detail than a later one. For what these statuses mean in the French reporting flow, see the [France getting started guide](/getting-started/france). Company Verification Event [#company-verification-event] Fired when a company's verification is completed, either successfully or rejected. Use this event to update your system's record of a company's verified status without polling. For a full walkthrough of the verification process, see the [Company Verification](/docs/company-verification) guide. ```json { "eventType": "company.verification", "companyId": "c_xxx", "teamId": "team_xxx", "status": "verified" } ``` * `status`: One of `"verified"`, `"rejected"`, or `"error"` * `"verified"`: identity check passed and the company is active on the Peppol network * `"rejected"`: identity check failed * `"error"`: identity check completed, but a subsequent Peppol network operation failed; the company is not yet active * `errorMessage`: Only present when `status` is `"error"`. Contains a description of what went wrong. ```javascript if (event.eventType === "company.verification") { if (event.status === "verified") { console.log(`Company ${event.companyId} is now verified.`); // e.g. update your local database, enable document sending for this company } else if (event.status === "rejected") { console.log(`Company ${event.companyId} verification was rejected.`); // e.g. notify your team, trigger a new verification attempt } else if (event.status === "error") { console.error(`Company ${event.companyId} verification error: ${event.errorMessage}`); // e.g. alert your team — contact support@recommand.eu for assistance } } ``` Label Events [#label-events] Labels can be attached to or removed from documents manually or via automatic propagation from matched suppliers. These actions trigger label events you can use for routing and integrations (e.g., forward documents with label `"ERP"` or `"Accounting"` to specific systems). For end-to-end usage of suppliers together with labels and label propagation, see the [Suppliers and Labels](/docs/suppliers-and-labels) guide. ```json { "eventType": "document.label.assigned", "documentId": "doc_xxx", "teamId": "team_xxx", "companyId": "c_xxx", "labelId": "lab_yyy" } ``` ```json { "eventType": "document.label.unassigned", "documentId": "doc_xxx", "teamId": "team_xxx", "companyId": "c_xxx", "labelId": "lab_yyy" } ``` When handling these events, fetch the document and inspect its labels to decide how to route it: ```javascript if ( event.eventType === "document.label.assigned" || event.eventType === "document.label.unassigned" ) { const doc = await fetchDocument(event.documentId); const names = new Set((doc.labels || []).map((l) => l.name)); if (names.has("ERP")) { await forwardToERP(doc); } else if (names.has("Accounting")) { await forwardToAccounting(doc); } } ``` Downloading Document Packages [#downloading-document-packages] When processing documents received through webhooks, you may want to download the complete document package, including XML data and any attachments using the [download package endpoint](/reference/documents/download-package). This is particularly useful when debugging and testing. Document packages can also be downloaded manually from the [dashboard](https://app.recommand.eu/transmitted-documents). ```javascript // Download document package as a zip file async function downloadDocumentPackage(documentId) { const response = await fetch( `https://app.recommand.eu/api/v1/documents/${documentId}/download-package`, { headers: { Authorization: "Basic " + Buffer.from("your_api_key:your_api_secret").toString("base64"), }, } ); if (!response.ok) { throw new Error( `Failed to download document package: ${response.statusText}` ); } // Handle the zip file content const packageData = await response.arrayBuffer(); // Example: Save the package to a file (Node.js) const fs = require("fs"); fs.writeFileSync(`document-${documentId}.zip`, Buffer.from(packageData)); return packageData; } ``` The downloaded zip file contains: * The document JSON * The document XML (UBL format) * Any binary attachments referenced in the document (for invoices and credit notes) This is particularly useful when you need to: * Archive complete documents with all attachments * Process attachments that were sent with the document * Access the raw UBL XML for detailed processing (although this is also available in the document JSON) Best Practices [#best-practices] 1. **Respond quickly**: Webhook handlers should acknowledge receipt promptly 2. **Process asynchronously**: Handle complex processing outside the request/response cycle 3. **Implement retry logic**: Be prepared to handle temporary failures 4. **Monitor webhook health**: Keep track of successful and failed webhook deliveries 5. **Verify signatures**: Configure a signing secret and reject deliveries with an invalid signature 6. **Use idempotency**: Process each event exactly once, even if received multiple times 7. **Handle all event types**: Be prepared for new event types in the future Complete Webhook Integration Example [#complete-webhook-integration-example] ```javascript // Setup authentication const API_KEY = "your_api_key"; const API_SECRET = "your_api_secret"; const AUTH = "Basic " + Buffer.from(`${API_KEY}:${API_SECRET}`).toString("base64"); const BASE_URL = "https://app.recommand.eu/api/v1"; const WEBHOOK_SECRET = process.env.RECOMMAND_WEBHOOK_SECRET; // Create a webhook async function setupWebhook() { // 1. Create webhook const createResponse = await fetch(`${BASE_URL}/webhooks`, { method: "POST", headers: { Authorization: AUTH, "Content-Type": "application/json", }, body: JSON.stringify({ url: "https://your-domain.com/peppol-webhook", companyId: null, // For all companies secret: WEBHOOK_SECRET, }), }); const createResult = await createResponse.json(); if (!createResult.success) { console.error("Failed to create webhook:", createResult.errors); return null; } console.log(`Webhook created with ID: ${createResult.webhook.documentId}`); // 2. Verify webhook was created const listResponse = await fetch(`${BASE_URL}/webhooks`, { headers: { Authorization: AUTH }, }); const listResult = await listResponse.json(); if (listResult.success) { console.log("Active webhooks:"); listResult.webhooks.forEach((webhook) => { console.log(`- ID: ${webhook.documentId}, URL: ${webhook.url}`); }); } return createResult.webhook.documentId; } // Example Express.js webhook handler const crypto = require("node:crypto"); const express = require("express"); const app = express(); app.post("/peppol-webhook", express.raw({ type: "application/json" }), async ( req, res ) => { // Verify the signature before parsing the request body const received = Buffer.from(req.get("X-Signature") ?? ""); const expected = Buffer.from( `sha256=${crypto .createHmac("sha256", WEBHOOK_SECRET) .update(req.body) .digest("hex")}` ); if ( received.length !== expected.length || !crypto.timingSafeEqual(received, expected) ) { return res.status(401).send("Invalid signature"); } const event = JSON.parse(req.body.toString("utf8")); console.log("Received webhook event:", event); // Immediately acknowledge the webhook res.status(200).send("Event received"); // Process the event asynchronously try { if (event.eventType === "document.received") { // Get document details const documentResponse = await fetch( `${BASE_URL}/documents/${event.documentId}`, { headers: { Authorization: AUTH } } ); const documentResult = await documentResponse.json(); if (documentResult.success) { const document = documentResult.document; // Process the document in your system await processDocument(document); // Mark as read await fetch(`${BASE_URL}/documents/${event.documentId}/mark-as-read`, { method: "POST", headers: { Authorization: AUTH, "Content-Type": "application/json", }, body: JSON.stringify({ read: true }), }); console.log(`Document ${event.documentId} processed successfully`); } else { console.error("Failed to fetch document:", documentResult.errors); } } } catch (error) { console.error("Error processing webhook event:", error); } }); // Process document function (implement based on your business logic) async function processDocument(document) { // Example: Extract document data and save to your database const { id, direction, senderId, receiverId, type, parsed } = document; console.log( `Processing ${direction} ${type} from ${senderId} to ${receiverId}` ); // Your business logic here... // - Save to database // - Create entry in accounting system // - Notify users // etc. } // Start the server app.listen(3000, () => { console.log("Webhook server listening on port 3000"); }); // Setup the webhook setupWebhook().catch((error) => { console.error("Error setting up webhook:", error); }); ``` Next Steps [#next-steps] Process incoming documents using webhooks or polling. Use suppliers and labels to drive routing via label events. Configure which companies webhooks should monitor. Explore webhooks, documents and related endpoints. # API path updated to /api/v1 (/changelog/2025-11-25-api-path-v1) We updated the base path for the Recommand Peppol API from `peppol` to `v1`. What changed [#what-changed] * All API endpoints now use the `/api/v1/...` path. Backwards compatibility [#backwards-compatibility] * Existing calls to `/api/peppol/...` continue to work. * We recommend migrating to `/api/v1/...` for new and updated integrations to stay aligned with the current documentation. # Document detail page with generated document preview (/changelog/2025-11-28-document-detail-page) We’ve introduced a new **document detail page** in the dashboard so you can better inspect individual transmissions. What changed [#what-changed] * **New document detail view**: * Each transmitted document now has a dedicated page with a clear layout for metadata, sender/receiver information, and delivery status. * You can navigate to this page directly from the transmitted documents table via a shortened document ID link. * **HTML document preview**: * A new internal `/documents/:documentId/render` API endpoint renders a human‑friendly HTML representation of a transmitted document. * The dashboard consumes this endpoint to show a styled billing document preview, making it easier to review invoices and credit notes without leaving Recommand. * **PDF in download package**: * When downloading a document package, Recommand now attempts to generate a `auto-generated.pdf` using the same billing template. * If PDF generation fails, the rest of the package (XML and other artifacts) is still returned. These changes make it much easier to understand, review, and share individual Peppol documents directly from the dashboard. # Inline attachment previews for documents (/changelog/2025-12-01-attachments-and-previews) We’ve expanded the document detail page with attachments and simple inline previews. What changed [#what-changed] * **Attachments in the Send Document UI**: You can now add optional attachments (for example CSV, PDF or images) when sending invoices and credit notes through the Send Document UI. * **Attachment previews on document details**: The transmitted document detail page shows a compact list of attachments, and common types like images, PDFs and CSV files can be previewed inline next to the generated document. These additions make it easier to quickly review supporting files alongside the main Peppol document. # Improved document validation (/changelog/2025-12-01-document-validation-support) We’ve added first‑class document validation to help you catch Peppol compliance issues *before* sending documents. What changed [#what-changed] * **New validation service**: All transmitted documents are now validated via our dedicated validation service, using EN16931 and Peppol BIS 3.0 rules. * **Stored validation results**: Validation output is stored alongside each transmitted document so you can review issues later. * **Outgoing validation enforcement**: Companies now have a new setting `isOutgoingDocumentValidationEnforced` that, when enabled, blocks sending documents that fail validation with clear error messages. * **Incoming documents**: Incoming documents are also validated and their results are stored on the transmitted document record. How validation works [#how-validation-works] * **Automatic XML validation**: When you send or receive a document, its XML is passed to our validation service. * **Result handling**: * If validation succeeds, the document continues to be processed and sent as before. * If validation fails or an error occurs *and* enforcement is enabled for the company, the API returns a `400` response with a structured list of rule codes and human‑readable error messages grouped by field. * **Per‑company control**: * New companies have validation enforcement enabled by default via `isOutgoingDocumentValidationEnforced`. * Existing companies can enable or disable this behaviour in the company settings UI. Dashboard improvements [#dashboard-improvements] * **Transmitted document details**: * A new “Document Validation Issues” panel surfaces validation results whenever a document is not marked as `valid`. * You can inspect the full validation payload, parsed JSON structure, and original XML for each transmission. * **Document list indicators**: * The transmitted documents table now shows a visual indicator next to the document type when validation issues are present. * Hovering the indicator opens a popover with the most important validation errors for quick inspection. These improvements make it easier to keep your Peppol traffic compliant and to diagnose issues quickly when something goes wrong. # Optional PDF and JSON attachments in notification emails (/changelog/2025-12-01-notification-attachments) We’ve made document notification emails more flexible with optional extra attachments. What changed [#what-changed] * **Per-address attachment settings**: For each company notification email address you can now choose whether to receive the auto-generated PDF and/or a `document.json` payload besides the Peppol document XML and its attachments. * **Incoming and outgoing coverage**: Settings are available separately for incoming and outgoing documents, so you can tailor which recipients get which attachments. * **Safer defaults**: Extra attachments are off by default and only added when explicitly enabled for a notification address. This makes it easier to plug notification emails into downstream workflows (for example archiving, accounting or review tools) without changing your core integration. # More payment means options (/changelog/2025-12-02-payment-means) We’ve expanded payment method handling for invoices and credit notes. What changed [#what-changed] * **More payment means**: Documents can now use additional Peppol payment means such as cash, debit transfer, bank card and credit/debit card, not just credit transfer. * **Schema and XML mapping**: The payment means schema and UBL parsing/serialization map between friendly keys (like `credit_card`) and the correct Peppol payment codes. * **Financial institution branch**: Payment details now support an optional financial institution branch identifier (for example BIC or national clearing code) which is round‑tripped in the XML. This makes it easier to represent how an invoice or credit note will actually be paid, while staying aligned with Peppol payment means and banking details. # Peppol Test Network support for playgrounds (/changelog/2025-12-02-playground-test-network) We’ve added optional Peppol Test Network support for playground environments. What changed [#what-changed] * **Test Network playgrounds**: When creating a playground, you can now choose to connect it to the Peppol Test Network, instead of keeping it fully isolated. * **Correct routing and credentials**: Documents sent from a Test Network playground use dedicated AP/SMP endpoints and tokens, and companies/identifiers are registered against the matching test infrastructure. * **Safer separation from production**: Production teams and non‑Test Network playgrounds remain unchanged and do not interact with the Peppol Test Network. This makes it possible to run realistic end‑to‑end Peppol tests while still keeping production traffic fully separated. # Control PDF generation in document package downloads (/changelog/2025-12-03-download-package-generate-pdf) We’ve made the document package download more flexible around including an autogenerated PDF. What changed [#what-changed] * **generatePdf query parameter**: The `download-package` endpoint now accepts a `generatePdf` query parameter with three options: `never`, `always`, or `when_no_pdf_attachment`. * **Smarter PDF inclusion**: When set to `when_no_pdf_attachment`, the API only generates `auto-generated.pdf` if there isn’t already a PDF attachment on the document. * **Dashboard behaviour**: Package downloads triggered from the transmitted documents table and detail page request `generatePdf=always`, so the PDF is always included there. This gives you more control over when PDFs are generated and avoids unnecessary duplicates when a document already includes its own PDF. # Filter companies by enterprise and VAT number (/changelog/2025-12-04-company-filters) We’ve made it easier to look up specific companies via the API. What changed [#what-changed] * **New query filters**: The `GET /companies` endpoint now accepts optional `enterpriseNumber` and `vatNumber` query parameters. This helps you quickly find the right company record without scanning or filtering the full list on the client. # Line-level discounts and surcharges (/changelog/2025-12-04-line-discounts-surcharges) We’ve improved how individual invoice and credit note lines can express discounts and surcharges. What changed [#what-changed] * **Line discounts & surcharges**: Document lines can now include structured `discounts` and `surcharges` with reason codes/text and amounts, following Peppol codelists. * **Parsing, XML & totals**: These values round‑trip through the UBL XML (via `cac:AllowanceCharge`) and are taken into account when calculating line and document totals. * **PDF preview**: The billing document template now shows per‑line discounts (in red) and surcharges (in green) in the rendered preview. This makes line pricing in your Peppol documents more accurate and transparent, especially when you use discounts or extra charges per line. # Line IDs and notes in documents and previews (/changelog/2025-12-04-line-ids-and-notes) We’ve made line identification and free-text notes clearer for invoices and credit notes. What changed [#what-changed] * **Explicit line IDs**: Lines now support an optional `id` that is parsed from and written to UBL; when missing, a sequential number is still generated. * **Line notes**: Each line can include a free-text `note`, which round-trips via `cbc:Note` and appears in the billing PDF as italic text under the description. * **Document-level note**: A top-level document `note` is also supported and rendered as a separate section above the seller/buyer details in the PDF. This makes it easier to match lines to external systems and to communicate extra context directly on specific lines or the whole document. # Global VAT exemption reasons (/changelog/2025-12-07-vat-exemption-reasons) We’ve improved how VAT exemption reasons are modeled and validated. What changed [#what-changed] * **Document-level exemption info**: The send invoice and credit note schemas now support a `vat` object that can either contain full VAT subtotals or just a global `exemptionReason` / `exemptionReasonCode`. * **Automatic VAT calculation**: When only the exemption fields are provided, Recommand calculates VAT subtotals from the lines and applies the same exemption reason to all exempt categories. * **Validation-aware behaviour**: For documents with validation enforcement enabled, required exemption reasons are checked before generating UBL, so missing reasons surface as clear errors instead of only appearing in downstream validators. This makes it easier to send compliant VAT-exempt invoices and credit notes without having to manually build detailed VAT subtotal structures. # Peppol message tracking information for outgoing documents (/changelog/2025-12-11-peppol-message-tracking) We've added detailed Peppol message tracking information to help you monitor document transmission and troubleshoot delivery issues. What changed [#what-changed] * **Message tracking fields**: Sent documents now include `peppolMessageId`, `peppolConversationId`, and `receivedPeppolSignalMessage` fields that capture metadata from the Peppol AS4 network response. * **API response updates**: The transmitted document API response schema now includes these tracking fields, making them available for programmatic access. * **Enhanced UI display**: The document detail page now shows an "Advanced" collapsible section with Peppol tracking information, including the ability to download or copy the received Peppol signal message XML. This provides better visibility into the Peppol network's handling of your documents and helps with debugging delivery problems. # Harvest Integration (/changelog/2025-12-12-harvest-integration) We've just released our integration with Harvest, allowing you to automatically send invoices created in Harvest to your customers via the Peppol network. What's new [#whats-new] * **Automatic invoice sync**: When enabled, the integration periodically checks Harvest for new invoices that have been marked as sent and automatically processes them for Peppol delivery. * **Smart client mapping**: Automatically identifies recipients using Belgian VAT numbers or Peppol identifiers configured in Harvest client addresses. * **Email fallback**: Optional email fallback feature sends invoices via email when Peppol delivery fails, ensuring your invoices always reach your customers. For detailed setup instructions, see our [Harvest integration guide](/integrations/harvest). # Filter documents on read status and date range (/changelog/2025-12-17-document-filtering-read-status-date-range) We've implemented filtering capabilities for documents by read status and date range, making it easier to find and manage your documents. What's new [#whats-new] * **Read status filtering**: You can now filter documents by read status (read or unread) in both the API and dashboard. The dashboard includes a new filter option and the ability to toggle read status directly from the document list. * **Date range filtering**: The API now supports filtering documents by creation date using `from` and `to` parameters in ISO 8601 format. These filtering options help you quickly find specific documents and manage your document workflow more efficiently. More information about these filtering options can be found in the [API reference](/reference/documents/get-documents). # HTML and PDF rendering endpoint for document previews (/changelog/2025-12-17-document-preview-endpoint) We've implemented a new document render endpoint, providing flexible rendering options for document previews. What's new [#whats-new] * **Render endpoint**: We've implemented a new document render endpoint that makes it easy to integrate document previews into your applications. * **PDF rendering support**: The endpoint supports both HTML and PDF rendering through a `type` parameter (`html` or `pdf`). This endpoint makes it easy to render document previews as HTML or as PDF for any transmitted document. More information about the endpoint can be found in the [API reference](/reference/documents/render-document). # Support for line document reference and additional item properties (/changelog/2025-12-17-line-document-reference-item-properties) We've implemented support for document references and additional item properties on invoice, credit note and self billing document lines. What's new [#whats-new] * **Line document reference**: You can now include a document reference on each line item, which is commonly used to reference a related invoice. * **Additional item properties**: Lines now support optional additional item properties as name-value pairs, allowing you to include custom metadata or additional information about items. These fields are optional and will only be included in the UBL document when provided. Both features are supported for both parsing incoming documents and generating outgoing documents. More information about these new fields can be found in the [API reference](/reference/sending/send-document). # Support for sender and buyer contact information (/changelog/2025-12-17-sender-buyer-contact-information) We've implemented support for contact information (email and phone) for both sender and buyer parties in invoices and credit notes. These fields are optional - if not provided, they will not be included in the UBL document. More information about these new fields can be found in the [API reference](/reference/sending/send-document). # Bulk export support for documents (/changelog/2025-12-22-bulk-export-support) We've implemented bulk export support, allowing you to export multiple documents at once within a specified date range. What's new [#whats-new] * **Bulk document export**: Export all documents within a date range (up to 1 month) as a ZIP archive from the dashboard. * **Export formats**: Choose between two output formats: * **Flat format**: All XML files in the root of the ZIP archive * **Nested format**: Document package structure with each document in its own folder, including metadata JSON, XML, and attachments This feature makes it easier to archive, backup, or process multiple documents at once. Or just to hand over all of your documents to a third party like an accountant. # Peppol message tracking information for incoming documents (/changelog/2025-12-23-peppol-message-tracking-incoming) We've extended Peppol message tracking information to incoming documents, providing the same visibility into document transmission for received documents as we already had for outgoing documents. What changed [#what-changed] Incoming documents now include `peppolMessageId` and `peppolConversationId` fields that capture metadata from the Peppol AS4 network. These fields are accessible through the dashboard and the API. This provides better visibility into the Peppol network's handling of your received documents and helps with debugging delivery issues and tracking document flow. # Native Message Level Response support (/changelog/2025-12-24-message-level-response-support) We've implemented JSON support for Message Level Response (MLR) documents, allowing you to easily send and receive acknowledgment responses for Peppol documents. What's new [#whats-new] * **Send Message Level Response**: You can now send Message Level Response documents via the API to acknowledge receipt of invoices and other documents. Response codes include: * **AB**: Message acknowledgement * **AP**: Accepted * **RE**: Rejected * **Receive Message Level Response**: The system now automatically parses and stores incoming Message Level Response documents. * **Document linking**: Message Level Response documents are linked to their original documents via the `envelopeId` field, and the dashboard shows related documents when viewing a Message Level Response. * **Rendering support**: Message Level Response documents can be rendered as HTML or PDF previews, just like other native document types. Message Level Response documents allow recipients to formally acknowledge receipt and acceptance or rejection of invoices and other documents, providing better visibility into document status in the Peppol network. More information about sending Message Level Response documents can be found in the [API reference](/reference/sending/send-document). # Include generated PDF when sending documents (/changelog/2025-12-28-include-generated-pdf-when-sending) You can now include a generated PDF when sending documents, making it easier to provide recipients with a PDF version of the document alongside the Peppol transmission. What's new [#whats-new] * **PDF generation option**: When sending documents, you can now enable PDF generation to automatically create a PDF version of the document and include it as an attachment. * **Automatic filename generation**: The system automatically generates appropriate filenames for PDFs based on the document type and number (e.g., invoice number or credit note number). * **Custom filename support**: You can optionally specify a custom filename for the generated PDF, or let the system generate one automatically. * **Email attachments**: Generated PDFs are automatically included as attachments when sending documents via email, providing recipients with a ready-to-use PDF version. This feature is particularly useful when recipients need a PDF version of the document for their records or accounting systems, while still benefiting from the structured Peppol transmission. # XML file upload zone in Send Document (/changelog/2025-12-28-send-document-xml-upload-zone) We’ve improved the **dashboard** **Send Document** page by adding an optional XML file upload zone. What changed [#what-changed] * **Drag & drop or choose a file**: Upload an `.xml` file directly from the page. This is useful when you receive or export **external UBL/XML files** (for example from an ERP system) and want to **upload and send them** from the dashboard. # Skip default company setup during creation (/changelog/2025-12-29-skip-default-company-setup) You can now skip the automatic setup of company defaults when creating a new company, giving you more control over the company configuration process. What's new [#whats-new] * **skipDefaultCompanySetup option**: When creating a company via the API, you can now set `skipDefaultCompanySetup` to `true` to skip the automatic creation of company identifiers and document types. * **Manual setup control**: This allows you to create company identifiers and document types manually using the respective API endpoints, giving you more granular control over the company configuration. * **Default behavior unchanged**: By default, `skipDefaultCompanySetup` is `false`, so existing behavior is preserved and companies will continue to have their defaults set up automatically unless explicitly skipped. This is particularly useful when you need to customize the company setup process or when integrating with systems that prefer to manage company configuration separately. More information about creating companies can be found in the [API reference](/reference/companies/create-company). # Send Document now includes a billing preview and developer mode (/changelog/2025-12-31-send-document-preview-and-developer-mode) We’ve upgraded the **dashboard** **Send Document** page to better support both billing users and developers. What changed [#what-changed] * **Billing mode (default)**: The page now shows a live **document preview** so you can verify how the generated billing document will look before sending. * **Smart defaults while composing**: The form can suggest the **next document number** (invoice/credit note) and auto-fill the **last used IBAN** to speed up repeated sending flows. * **Developer mode**: Toggle to a developer-oriented view that focuses on the API payload and advanced options during document composition. * **Improved form UX**: Better grouping and progressive disclosure for counterparty details, payment/options, and attachments, making the flow easier to complete without losing context. # Supporting data customers (/changelog/2025-12-31-supporting-data-customers) You can now manage **customers** as supporting data and reuse them while sending invoices and credit notes. What's new [#whats-new] * **Customers API**: Added endpoints to list, retrieve (by internal ID or `externalId`), upsert, and delete customers for a team. * **Dashboard customers page**: Added a dedicated Customers page in the dashboard to create and manage your customer list. * **Send-document autofill**: When sending an invoice or credit note, you can select a customer to auto-populate buyer/seller details (including self-billing flows) and automatically fill the recipient Peppol ID from the customer's saved Peppol addresses. More information can be found in the [API reference](/reference/customers/get-customers). # Outgoing document validation now always enforced (/changelog/2026-01-02-outgoing-validation-always-enforced) Peppol document validation is now **always enforced** for all outgoing documents. The option to disable validation at the company level has been removed as communicated previously. What changed [#what-changed] * **Validation always enforced**: All outgoing documents, including invoices and credit notes, must pass EN16931 / Peppol BIS 3.0 validation before being sent. * **Removed company setting**: The `isOutgoingDocumentValidationEnforced` parameter has been removed from company creation and update endpoints. Validation enforcement can no longer be disabled. * **Clear error messages**: Documents that fail validation will not be sent, and you'll receive detailed error messages indicating what must be corrected. Why this matters [#why-this-matters] Enforcing validation before sending helps: * **Reduce failed deliveries**: Catch compliance issues before documents enter the Peppol network * **Avoid downstream rejections**: Ensure documents meet recipient and access point requirements * **Improve data quality**: Better automation and processing for recipients What you need to do [#what-you-need-to-do] * **If you generate XML yourself**: Ensure your UBL documents comply with EN16931 / Peppol BIS 3.0 standards. * **Review existing documents**: Check the dashboard for any documents marked with "Document Validation Issues" and address the listed errors. This change improves interoperability across the Peppol network and helps ensure reliable document delivery. # Improved document overview UX with saved preferences and extra columns (/changelog/2026-01-09-document-overview-saved-preferences-extra-columns) The document overview page has been enhanced with **saved preferences** and **new optional columns** to improve your workflow. What changed [#what-changed] * **Saved preferences**: Your column filters, page size, and column visibility settings are now automatically saved to your browser and restored when you return to the page. * **New optional columns**: Three new columns are available (hidden by default for now): * **Document Number**: Shows the invoice or credit note number from the document * **Total Excl. VAT**: Displays the total amount excluding VAT * **Total Incl. VAT**: Displays the total amount including VAT * **Column visibility control**: You can show or hide any column, including the new ones, and your preferences will be remembered. This update makes the document overview more flexible and tailored to your needs. # Send documents without Peppol recipient (/changelog/2026-01-14-send-documents-without-recipient) You can now send billing documents (invoices and credit notes) **without a Peppol recipient**, enabling you to use a single API endpoint for all your customers - whether they're on Peppol or not. What changed [#what-changed] * **Null recipient support**: Set `recipient: null` when sending invoices, credit notes, self-billing invoices, or self-billing credit notes * **Email-only delivery**: When recipient is null, documents are sent via email only * **PDF generation**: PDFs are still generated and attached to emails, even without a Peppol recipient * **Unified API**: Use the same send document endpoint for both Peppol and non-Peppol customers Why this matters [#why-this-matters] This feature is especially valuable in **e-commerce and B2C scenarios** where many customers aren't on the Peppol network: * **Unified invoicing workflow**: Send all invoices through the same API endpoint, regardless of whether recipients are on Peppol * **E-commerce integration**: Perfect for online stores that need to invoice both B2B (Peppol) and B2C (email) customers * **International customers**: Send invoices to customers outside countries with Peppol mandates * **Simplified integration**: No need to maintain separate systems or endpoints for Peppol vs. non-Peppol recipients * **Consistent document format**: All invoices use the same structure and PDF generation What you need to do [#what-you-need-to-do] * **Set recipient to null**: When sending to non-Peppol customers, set `recipient: null` in your send document request * **Enable email delivery**: Ensure the `email` field is provided with recipient email addresses * **Use billing document types**: Only invoices, credit notes, self-billing invoices, and self-billing credit notes support null recipients This update makes it easier to handle mixed customer bases and simplifies integration for e-commerce and marketplace scenarios. # Email and phone number in company settings (/changelog/2026-01-20-company-email-phone) Company settings now support **email and phone number** fields, making it easier to include contact information on your invoices and automatically populate sender details when sending documents. This update makes it easier to maintain complete contact information across all your invoices and credit notes. # Commodity classifications support (/changelog/2026-01-26-commodity-classifications-support) You can now include **commodity classifications** on invoice and credit note line items, supporting a wide range of classification schemes for product categorization and compliance. What changed [#what-changed] * **Commodity classifications field**: Added optional `commodityClassifications` array to invoice and credit note line items * **Multiple classification schemes**: Support for 200+ classification schemes including many industry-specific codes * **UBL support**: Commodity classifications are included in the generated UBL XML and parsed from incoming documents * **Bidirectional support**: Works for both sending and receiving documents This update improves compliance capabilities and enables better product categorization across different industries and use cases. # Order line reference support (/changelog/2026-01-26-order-line-reference-support) You can now include **order line references** on invoice and credit note line items, making it easier to track which purchase order lines correspond to each invoice line. What changed [#what-changed] * **Order line reference field**: Added optional `orderLineReference` field to invoice and credit note line items * **UBL support**: Order line references are included in the generated UBL XML and parsed from incoming documents * **Bidirectional support**: Works for both sending and receiving documents Why this matters [#why-this-matters] Order line references are essential for: * **Purchase order tracking**: Link invoice lines back to specific lines in purchase orders * **Better traceability**: Track which order line each invoice line corresponds to * **Automated reconciliation**: Help systems automatically match invoices to purchase orders * **Compliance**: Meet requirements for referencing purchase orders in invoices This update improves traceability and helps with purchase order reconciliation workflows. # Verify endpoint enrichment (/changelog/2026-02-02-verify-endpoint-enrichment) The **verify recipient endpoint** has been extended with richer data about Peppol participants, including which document types they support, their endpoint details, and business card information. What changed [#what-changed] * **Supported documents**: The verify response now includes a `supportedDocuments` array with human-readable names and full Peppol document type identifiers for each document type the participant supports * **Endpoint details**: Set `includeEndpointDetails: true` to fetch service provider, endpoint URL, transport profile, technical contact, and certificate expiry for each supported document type * **Business card**: Set `includeBusinessCard: true` to retrieve the company name and country code from the SMP business card * **Verify document support**: The verify document support endpoint now also returns endpoint details (service provider, endpoint URL, transport profile, technical contact, certificate expiry) Why this matters [#why-this-matters] * **Richer participant insights**: Understand exactly which document types a recipient supports and how they are connected to the Peppol network, all from a single API call * **Backwards compatible**: Existing integrations continue to work without changes. The new fields are additive # Microsoft Business Central Integration Now Public (/changelog/2026-03-17-business-central-integration) Our Microsoft Dynamics 365 Business Central integration is now publicly available. Allowing you to send and receive Peppol e-invoices directly from Business Central using the Recommand E-Document extension. What's included [#whats-included] * **Direct Peppol delivery**: Post a sales invoice or credit note in Business Central and it is automatically sent to your customer via the Peppol network through Recommand. * **Incoming documents**: Receive incoming Peppol documents from your Recommand inbox directly into Business Central's E-Documents page. * **Built on the E-Document framework**: The extension integrates with Business Central's native E-Document module, fitting naturally into your existing posting workflow. The extension is not yet available on Microsoft AppSource. To get access, reach out to us at [support@recommand.eu](mailto:support@recommand.eu). For setup instructions, see our [Business Central integration guide](/integrations/business-central). # Base Quantity Support for Line Items (/changelog/2026-03-24-base-quantity-support) Invoice and credit note line items now support a **base quantity** field, so you can express prices that are based on a batch or pack rather than a single unit. What changed [#what-changed] * **New `baseQuantity` field on line items**: An optional field that indicates how many units the `netPriceAmount` refers to. When omitted or set to `"1"`, behaviour is unchanged: the price is per unit. * **Correct line amount calculation**: When `baseQuantity` is greater than 1, the line amount is calculated as `quantity * (netPriceAmount / baseQuantity)`, following PEPPOL rule EN16931-R120. * **UBL round-trip**: `BaseQuantity` is written into the generated UBL XML when greater than 1, and parsed back from incoming documents. * **Document preview**: The preview renders batch prices clearly, showing the price alongside the pack size (e.g. "51.98 / 10 pieces"). Why this matters [#why-this-matters] Many suppliers, especially in construction, hardware, and wholesale, quote prices per pack rather than per unit. For example, a box of 200 screws might be priced at 51.98 per 10 pieces. Without base quantity support, you'd have to calculate the per-unit price yourself and risk rounding differences that break Peppol validation. With `baseQuantity`, you can now express prices exactly as they appear on the original quote: * A line with `quantity: "2"`, `netPriceAmount: "73.47"`, and `baseQuantity: "10"` means "2 units ordered at a price of 73.47 per 10", giving a line total of 14.69 * A feed supplier invoicing 12000 kg of cow feed priced at 285.00 per 1000 kg: `quantity: "12000"`, `netPriceAmount: "285.00"`, `baseQuantity: "1000"`, giving a line total of 3420.00 * A line with `quantity: "5"`, `netPriceAmount: "10.00"`, and `baseQuantity: "1"` (or omitted) works the same as before: 5 units at 10.00 each, totalling 50.00 This avoids manual per-unit price conversion and ensures your invoices stay compliant with the Peppol calculation rules. # Explicit company verification required (/changelog/2026-04-02-company-verification) Companies on Recommand now go through an explicit verification step before they can send or receive documents on the Peppol network. This replaces the implicit background checks that were previously part of onboarding. What changed [#what-changed] * **New `isVerified` field on company objects**: Indicates whether a company has passed verification. Companies where this is `false` cannot participate in Peppol document exchange. * **`verificationUrl` included in the create company response**: When creating a company, the response now includes a `verificationUrl` to present to your user immediately. From the verification page, they can complete or forward the identity check without any additional API calls. * **New `POST /companies/:companyId/verify` endpoint**: Generates a fresh verification session for an existing company and returns a new `verificationUrl`. Use this if the original link was lost or you want to verify an existing company. See the [API reference](/reference/companies/verify-company). * **Dashboard support**: Verification can be initiated and completed entirely from the [Recommand dashboard](https://app.recommand.eu/companies) without using the API. * **New `company.verification` webhook event**: Fires when verification reaches a final state. `status` is `"verified"`, `"rejected"`, or `"error"` (identity check succeeded but a Peppol network operation failed, and `errorMessage` is included). See [Working with Webhooks](/docs/working-with-webhooks). * **Verification reset on identifier change**: Updating a company's `vatNumber` or `enterpriseNumber` automatically resets `isVerified` to `false`. The company must be reverified before it can participate on the Peppol network again. * **Stricter identifier validation**: VAT numbers and enterprise numbers are now validated against national format rules (e.g. the Belgian modulo-97 check digit) at creation and update time. Why this matters [#why-this-matters] The Peppol network relies on accurate and trustworthy participant registrations. Explicit verification gives a clear, auditable confirmation that companies are registered by people genuinely authorised to act for them, reducing the risk of erroneous registrations. What you need to do [#what-you-need-to-do] Verify your companies before they need to send or receive documents. You can do this from the dashboard or via the API. For the full flow, see the [Company Verification guide](/docs/company-verification). # Search documents by company name and document number (/changelog/2026-04-07-transmitted-document-search) Finding the right transmitted document is now much easier. The existing `search` filter in the API and the search box in the dashboard now include document-aware search fields alongside the existing technical identifiers. What changed [#what-changed] * **Search by sender or receiver name**: For invoices, credit notes, and self-billing documents, search now matches the sender and receiver company names extracted from the document. * **Search by invoice or credit note number**: The same `search` filter now also matches the document number from billing documents. * **Still supports technical identifiers**: Search continues to match the Recommand document ID, sender and receiver Peppol identifiers, document type ID, process ID, and country code. Why this matters [#why-this-matters] Previously, finding a document often meant searching with a Peppol participant ID or a Recommand document ID. You can now search using the invoice number or company names that users actually recognize from the document itself. What you need to do [#what-you-need-to-do] No integration changes are required. Keep using the existing `search` parameter on the [list documents endpoint](/reference/documents/get-documents) or the search box in the [transmitted documents dashboard](https://app.recommand.eu/transmitted-documents). # Bulk actions on selected documents (/changelog/2026-04-21-bulk-document-actions) The transmitted documents dashboard now supports acting on multiple documents at once. Select any combination of documents with the new row checkboxes and apply an action to the entire selection without opening each one individually. What's new [#whats-new] * **Row selection**: Each row in the [transmitted documents dashboard](https://app.recommand.eu/transmitted-documents) now has a checkbox, and a header checkbox for selecting every document on the current page. * **Bulk export**: Export the selected documents as a ZIP archive, with the same flat or nested layout and PDF generation options already available for date-range exports. * **Bulk assign label**: Apply an existing label to every selected document in a single action. * **Bulk mark as read**: Mark many documents as read in a single action. * **Bulk delete**: Delete every selected document in a single action. * **Filter by label**: The document list can now also be filtered by label, making it easy to narrow down a selection before applying a bulk action. Why this matters [#why-this-matters] Previously, archiving a batch of documents, tagging them, or clearing their unread state meant repeating the same action document by document. Bulk actions turn routine housekeeping on dozens of documents into a single click. What you need to do [#what-you-need-to-do] No integration changes are required. Open the [transmitted documents dashboard](https://app.recommand.eu/transmitted-documents), tick the documents you want to act on, and use the bulk action controls that appear. # Create webhook and email automations with rules (/changelog/2026-05-05-webhooks-and-rules) Recommand now includes a unified **Webhooks and rules** experience for Peppol automations. This gives you a more flexible way to react to important events from the dashboard while keeping the existing webhook API available for simpler integrations. What changed [#what-changed] * **New rules model for automations**: You can now create automations that react to supported Peppol events such as document receipt, document sending, label changes, and company verification updates. * **Webhook and email actions**: Rules can send a webhook, send an email, or do both from a single trigger. * **Optional conditions**: Narrow a rule to the events you actually care about, for example by company, document type, sender, label, or verification status. * **Dashboard support**: A new **Webhooks and rules** page lets you create, edit, monitor, and retry automations without leaving the dashboard. * **Rules are currently managed in the UI**: The dedicated rules API is not publicly available yet, giving us time to refine the feature before opening that surface more broadly. * **Webhook security**: Webhook actions can include an optional signing secret for HMAC SHA-256 verification. * **Delivery tracking and retries**: Failed deliveries are visible per rule, retried automatically, and can also be retried manually from the dashboard. * **Existing webhook compatibility**: Classic webhook payloads remain simple and familiar, so existing webhook consumers do not need to adopt a new payload format. Why this matters [#why-this-matters] Many teams start with one webhook endpoint, but eventually need more control. Rules make it easier to build targeted automations without setting up separate infrastructure for every use case, while still keeping the simple webhook flow available for straightforward integrations. What you need to do [#what-you-need-to-do] Nothing if your current webhook integration already does what you need. If you want more control, start with the new [Working with Rules guide](/docs/rules). If you only want the classic setup, continue using [Working with Webhooks](/docs/working-with-webhooks). # Team permission management (/changelog/2026-06-10-permission-management) Recommand now supports granular permission management at the team level. Instead of every team member having the same administrative access, you can control exactly who is allowed to manage the team and its members. What changed [#what-changed] * **Permission management system**: Permissions are assigned per user within a team. Users with the right permissions can grant or revoke access for other members from the dashboard. * \*\*`Manage Team` permission: The first team permission controls administrative actions, including: * Inviting and removing team members * Updating the team name and logo * Deleting the team * Managing permissions for other members * **Team creator gets access automatically**: When you create a team, you receive the `Manage Team` permission immediately. * **New members do not get admin access by default**: Members invited to an existing team can use the team, but cannot manage it unless someone with `Manage Team` grants them the permission. * **Dashboard support**: From the [Team settings page](https://app.recommand.eu/team), open a member's permissions to toggle what they are allowed to do. Why this matters [#why-this-matters] Larger teams often include people who need to view or work with documents without being able to change team membership or settings. Permission management gives you control over who can administer the team, while keeping day-to-day access unchanged for everyone else. What you need to do [#what-you-need-to-do] No integration changes are required. Existing team members retain their previous access. Everyone who could manage a team before this release still has the `Manage Team` permission. Review your team on the [Team settings page](https://app.recommand.eu/team) and adjust permissions for members who should or should not be able to manage the team. # Select ranges of documents with shift-click (/changelog/2026-07-22-shift-click-document-selection) Selecting a batch of documents for a bulk action no longer means clicking every checkbox one by one. What changed [#what-changed] * **Shift-click range selection**: Click one document's checkbox, then shift-click another, and every document in between is selected. * **Works for deselecting too**: Shift-clicking a checked box clears the whole range in the same way. Why this matters [#why-this-matters] Bulk actions such as archiving, exporting, assigning labels, marking as read, and deleting all start with a selection. Picking a contiguous block of documents is now a two-click operation instead of one click per row. What you need to do [#what-you-need-to-do] Nothing. The behaviour is available now in the [transmitted documents dashboard](https://app.recommand.eu/transmitted-documents). # Verify webhooks with HMAC signatures (/changelog/2026-08-10-webhook-hmac-signatures) Webhook subscriptions created through the API can now include an optional signing secret. Recommand uses it to sign the raw request body with HMAC SHA-256 and sends the result in the `X-Signature` header. See [Working with Webhooks](/docs/working-with-webhooks) for setup and verification examples. # Outgoing documents pick a format the recipient accepts (/changelog/2026-08-28-automatic-document-format-routing) Sending a JSON invoice used to always produce Peppol BIS 3 UBL unless you named a `doctypeId`. Recipients who only publish a national format then failed at the far end. The [send document endpoint](/reference/sending/send-document) now looks the recipient up and picks a combination they actually accept. What changed [#what-changed] * **Automatic format selection**: Leave `doctypeId` off and the document is written as the first format, in our order of preference, the recipient is registered to receive. * **Automatic process selection**: Leave `processId` off and the process the recipient registered for that format is preferred, as far as the document itself leaves the choice open. A French invoice only travels over the regulated or non-regulated process its `countrySpecific.businessProcess` names; the other one is not treated as a fallback. * **Overrides still win**: Pass both `doctypeId` and `processId` and they are used as-is, with no lookup. Pass only one and routing happens inside that constraint: a named format still chooses the process the recipient registered, a named process still chooses a format published for it. * **Raw XML and generate-XML remain unchanged**: A document you already supply as XML is one specific format, so it is not rerouted. The [generate XML endpoint](/changelog/2026-08-28-generate-xml-endpoint) still writes the default format, because there is no transmission to route. Why this matters [#why-this-matters] National formats and country-specific processes are now the common case, not an override you have to remember per recipient. You can send the same JSON payload to a Belgian BIS 3 buyer, a Dutch SI-UBL-only buyer and a French regulated recipient, and each document is written as something that recipient published. What you need to do [#what-you-need-to-do] Nothing if you already omit `doctypeId` and `processId`. You can stop hardcoding them for recipients that only accept a national format or a French process. Keep passing both when you need a specific combination regardless of what the recipient publishes. # Dashboard available in Dutch, French and German (/changelog/2026-08-28-dashboard-languages) Every screen in the [Recommand dashboard](https://app.recommand.eu) is now available in Dutch, French and German, alongside English. What changed [#what-changed] * **Fully translated interface** * **Per-user language**: Each user picks their language on the [account page](https://app.recommand.eu/account). New users start in the language their browser asks for, falling back to English. What you need to do [#what-you-need-to-do] Nothing. Change your language on the [account page](https://app.recommand.eu/account); API responses and document content are unaffected. # Check document support per process (/changelog/2026-08-28-document-support-process-check) Some document types are published for more than one process - French invoices, for example, travel over a regulated and a non-regulated process. Recipient checks and receiving registrations now take the process into account. What changed [#what-changed] **`processId` on verify document support**: Pass an optional `processId`, with or without its scheme prefix, to the [verify document support endpoint](/reference/recipients/verify-document-support) to check whether a recipient published that document type for that specific process. When omitted, any published process is accepted, as before. Why this matters [#why-this-matters] Publishing or verifying a document type without its process can send a document over a process the recipient never registered. The additional field makes that check exact. # French regulated invoicing support (/changelog/2026-08-28-france-regulated-invoicing) Recommand now supports the French e-invoicing reform. French companies are onboarded on a French-accredited SMP and access point automatically, and invoices and credit notes can be exchanged in the formats the reform requires. What changed [#what-changed] * **New document formats**: Invoices and credit notes can be generated as French CIUS or Extended UBL, CII D22B (CIUS and Extended), and Factur-X, in addition to the existing Peppol BIS 3 UBL. Select one by passing its `doctypeId` on the send endpoint; without it, Peppol BIS 3 UBL stays the default. * **New `countrySpecific` field on invoices and credit notes**: The `FR` variant carries the information the French formats require - `billingMode` (`B1`, `S1`, `M1`, …, following AFNOR XP Z12-012), the mandatory recovery-cost, late-payment-penalty and early-payment-discount statements, and the `businessProcess`. It is required for the French document types and must be omitted for plain EN 16931 documents. * **Regulated and non-regulated processes**: Set `countrySpecific.businessProcess` to `REGULATED` for transactions inside the French e-invoicing perimeter (the default) or `NON_REGULATED` for transactions outside it. The document is sent over the matching French Peppol process. * **Factur-X in both directions**: Outgoing Factur-X is delivered as a PDF/A-3 with the CII XML embedded. Incoming Factur-X is extracted and parsed like any other document, and the original PDF is kept and included in the document's download package. * **Automatic French routing**: Companies registered in France are published on a French-accredited SMP and exchange documents through the matching access point, with the French document types registered by default. Why this matters [#why-this-matters] French domestic e-invoicing follows its own formats, processes and mandatory content rules. You can now serve French companies through the same API you already use, without building the French specifics yourself. What you need to do [#what-you-need-to-do] Nothing for companies outside France. For French companies, add the `countrySpecific` `FR` block to your invoices and credit notes, and pass the `doctypeId` of the format you want to send. Check what a recipient accepts with the [verify document support endpoint](/reference/recipients/verify-document-support) before sending. # French invoice lifecycle statuses (CDAR) (/changelog/2026-08-28-french-invoicing-cdar) French regulated invoicing requires trading partners to report back on the invoices they receive. Recommand now supports these lifecycle status messages (CDAR) as a first-class document type. What changed [#what-changed] * **New `frenchInvoicingCdar` document type**: Send a lifecycle status for an invoice you received through the [send document endpoint](/reference/sending/send-document), the same way you send a message level response. * **Full status set**: Statuses cover the French lifecycle codes, from `200` (submitted) through `205` (approved), `210` (refused) and `212` (collected), with the coded rejection reasons (`DOUBLON`, `TX_TVA_ERR`, `NON_CONFORME`, …) and an optional free-text note. * **Incoming statuses**: CDAR messages you receive are parsed, stored and shown alongside your other documents, and are delivered through your existing webhooks and notifications. Why this matters [#why-this-matters] Reporting the status of an invoice back to its sender is mandatory inside the French e-invoicing perimeter. Handling it as a document type means you can send and receive these statuses without touching the underlying XML. What you need to do [#what-you-need-to-do] Nothing if you do not exchange French regulated documents. Otherwise, send a `frenchInvoicingCdar` document for the invoices you receive and process, and handle incoming ones in your webhook the way you already handle message level responses. When you receive a French invoice, Recommand automatically sends the `202` (received) and `203` (made available) statuses back to the sender; you still send the later processing statuses yourself. # Generate XML without sending (/changelog/2026-08-28-generate-xml-endpoint) The new `POST /:companyId/generate` endpoint accepts the same body as the [send document endpoint](/reference/sending/send-document) and returns the document that sending it would produce. What changed [#what-changed] * **Same request, no transmission**: The body is identical to the send endpoint, minus the email delivery options and the `xml` document type, which has nothing to generate. Nothing is sent or stored. * **Validated like a real send**: The generated document passes the same document validation as sending, so a document that comes back here is one the Peppol network accepts. * **Response**: Returns the `xml` along with the resolved `documentType`, `doctypeId` and `processId`, so you can see which format and process your payload maps to. * **Not billed**: Documents generated through this endpoint do not count towards your subscription usage. Why this matters [#why-this-matters] Building or migrating an integration usually means inspecting the XML your payload produces. You can now do that as often as you like, without sending test documents to the network or consuming quota. Through this endpoint you can also generate XML for documents that are not sent over the Peppol network but that you would like to make available for your own use. # French e-reporting for B2C and cross-border sales (/changelog/2026-09-08-french-e-reporting) French companies must report the operations that never travel as an e-invoice: sales to private individuals and invoices to businesses outside France. Recommand now files these reports with the French tax administration on the company's behalf. What changed [#what-changed] * **Registration endpoint**: A company is registered for e-reporting once, with its VAT regime and when its VAT becomes due, through `PUT /:companyId/reporting/fr/declarant`. The dashboard offers the same registration on the company page. * **B2C reports**: Daily totals of sales to private individuals, one report per day, category and currency, through `POST /:companyId/reporting/fr/b2c`. Companies whose VAT becomes due on payment also report the payments they receive. * **Cross-border reports**: Every invoice or credit note to a business outside France, and the payments received on it, through `POST /:companyId/reporting/fr/b2bi`. Buyers in the European Union are identified by their VAT number, buyers elsewhere by their country and name. * **Status until filed**: A report is accepted first and filed later, at the end of its reporting period. The `reporting` block on every report in the [documents API](/reference/documents/get-document) shows where it stands, from `accepted` to `filed` or `rejected`, and a `document.reporting_status_changed` webhook event fires on every change. * **Lifecycle statuses and your quota**: French transmission statuses (`200` to `203`, `213`, `501`) no longer count towards your document quota, in either direction. Processing statuses such as approved, refused or collected count as one document each, like any business document. * **Safe retries, explicit corrections**: Retrying a report with the same `reference` returns the report filed the first time. Corrections and cancellations carry a new reference and an `action`, and act on the day or document they name. Why this matters [#why-this-matters] E-reporting is mandatory for French companies from the same dates as e-invoicing. The reports are aggregates and identifiers, not invoices, so there is no XML to build: you send the figures and Recommand handles the regulatory filing and its follow-up. What you need to do [#what-you-need-to-do] Register each French company that sells to consumers or abroad, then submit its reports as the sales happen rather than at the end of the month. Playground and test-network teams can exercise the full flow; their reports are recorded but never filed. The e-reporting section of the [French getting started guides](/getting-started/france) walks through registration, the two report types, corrections and the status lifecycle; the endpoint details are in the Reporting section of the [API reference](/reference). # How can I check if a company is active on the Peppol network? (/faq/addressing-and-delivery/how-can-i-check-if-a-company-is-active-on-peppol) The verify endpoint (/api/v1/verify) checks whether a company is actively registered on Peppol. Use the correct format for Peppol addresses (e.g. 0208:1012081766). A common mistake is passing a VAT number instead of a Peppol ID. A valid call returns `{"isValid": true}`. See [API reference - Verify recipient](/reference/recipients/verify-recipient) For quick checks outside your integration, you can also use our [Peppol search](https://recommand.eu/en/peppol-search). When you try to send a document, we also check if the company is active on Peppol. If it isn't, the send attempt will fail with an error message. # How does Peppol know where to route my invoice? (/faq/addressing-and-delivery/how-does-peppol-know-where-to-route-my-invoice) Every organization has a unique Peppol ID, usually based on its company number (in Belgium `0208:xxxxxxxxxx`). This ensures every invoice automatically reaches the correct company. For Belgian company numbers, the prefix `0208` is used, followed by the full company number. The company number always starts with a `0` or a `1`. For example: `0208:0xxxxxxxxx` or `0208:1xxxxxxxxx`. Some organizations are registered under their GLN (Global Location Number) using scheme `0088` instead of a national company number. This is common in retail, logistics, and healthcare. In that case the Peppol address looks like `0088:5400000000001`. If you cannot reach a recipient via `0208`, they may be registered under `0088`. See [What is a GLN and when should I use it?](/faq/addressing-and-delivery/what-is-a-gln-and-when-should-i-use-it) for more details. # What is a GLN and when should I use it? (/faq/addressing-and-delivery/what-is-a-gln-and-when-should-i-use-it) A Global Location Number (GLN) is a 13-digit identifier issued by GS1 that uniquely identifies a legal entity, a function within an entity, or a physical location such as a warehouse or accounting department. On the Peppol network, GLNs use the scheme code `0088`. A Peppol address based on a GLN looks like `0088:1234567890123`. When to use a GLN [#when-to-use-a-gln] * **Multiple delivery or billing points**: When a company has several locations (e.g. warehouses, branch offices) that each need to receive documents independently, each location can be registered with its own GLN. * **Internal routing**: Large organizations use GLNs to route incoming invoices or orders to the right department automatically. * **Trading partners require it**: Retail, logistics, and healthcare sectors commonly use GLNs as their primary Peppol identifier. If a recipient is registered under `0088` rather than a national scheme like `0208`, you must address them with their GLN. How it relates to other schemes [#how-it-relates-to-other-schemes] Belgian companies are typically registered with scheme `0208` (enterprise number), but some are registered under `0088` (GLN) instead, or under both. If you cannot find a recipient using `0208`, try verifying them with `0088` and their GLN. See [What is the correct format for a Peppol address?](/faq/api-and-development/what-is-the-correct-format-for-a-peppol-address) for more details on schemes. # What is a Peppol Access Point? (/faq/addressing-and-delivery/what-is-a-peppol-access-point) An Access Point is the fixed digital location where your company receives and sends documents on Peppol. Without an active Access Point, a company cannot receive Peppol documents. Recommand acts as both an Access Point and SMP provider (address book). # Why do companies register only as recipients? (/faq/addressing-and-delivery/why-do-companies-register-only-as-recipients) Within Peppol, only recipients are registered on the network. Sending can be done via any certified Access Point without additional registration. This keeps the system simpler and more reliable. This also means you can use different access points for sending. Very useful if you have, for example, a webshop where invoices are created automatically but also create invoices manually with other software. # Can I add an email address to my invoices? (/faq/api-and-development/can-i-add-an-email-address-to-my-invoices) The Peppol UBL format supports a `cac:Contact` element in the `AccountingSupplierParty`. The simplified JSON API of Recommand does not currently expose this field, but when sending your own XML you can add this. See Peppol syntax guide. # Can I send an XML document directly via the API? (/faq/api-and-development/can-i-send-an-xml-document-directly-via-the-api) You can send a complete XML document as a string via `/send`. Ensure that the document type (`doctypeId`) is correctly filled in, for example: ``` urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1 ``` Check the UBL for validity. # Can I view logs of sent documents? (/faq/api-and-development/can-i-view-logs-of-sent-documents) Via the API responses you get status information back; extensive server logs are not made public, but in case of issues, support can help with a trace based on document ID. # How can I download my sent or received documents? (/faq/api-and-development/how-can-i-download-my-documents) When you send or receive an invoice or other document via Recommand, a document package (ZIP) is automatically created. This package contains: * the original UBL XML file, * any attachments (such as a PDF version), * the parsed document in JSON format Download complete package: Via the API endpoint `/api/v1/documents/{documentId}/download-package` or directly from the dashboard. Get only the XML file: Use the endpoint GET `/api/v1/documents/{documentId}` and retrieve the XML file from the xml field. # How can I see feedback when a document is rejected by the recipient? (/faq/api-and-development/how-can-i-see-feedback-when-a-document-is-rejected) Peppol does not require recipients to send notifications when an invoice is rejected. Some accounting packages do send an Invoice Response, but this is optional. If the document was sent via Recommand with `success: true`, it has been technically delivered correctly. # How can I test without sending real invoices? (/faq/api-and-development/how-can-i-test-without-sending-real-invoices) The Playground environment is a completely separate test environment where no documents are sent over the actual Peppol network. You can freely send invoices between test companies within the same team there. # How do I add a structured reference (OGM) correctly? (/faq/api-and-development/how-do-i-add-a-structured-reference-ogm) The structured reference (OGM) is not strictly specified in UBL, but the common practice is to provide only the numeric part, e.g., `"reference": "123456789101"`. The notation `+++123/4567/89101+++` may appear visually on a PDF attachment, but in the UBL only the numeric part is used. # How do I use the Playground environment? (/faq/api-and-development/how-do-i-use-the-playground-environment) Use the Playground to safely test without sending documents over the real Peppol network. When you create a team you can choose between a production team or a playground team. If you choose a playground team, you can freely add test companies and send documents within the same environment. This lets you test the full integration and switch to a production environment once it is set up. You can create playground environments at any time without limitations. For setup instructions, simulated delivery behavior, and test failure addresses, see [Using a playground](/docs#using-a-playground) in the Getting Started guide. # Must I register recipients in my team first to be able to send? (/faq/api-and-development/must-i-register-recipients-in-my-team-to-send) No, you can send to any valid Peppol address. In Recommand you only need to register the companies for which you want to send and/or receive documents. In the playground, external recipients are often registered within the same test environment, because no real Peppol delivery takes place and reception becomes visible within the same team that way. # What is the correct format for a Peppol address? (/faq/api-and-development/what-is-the-correct-format-for-a-peppol-address) A Peppol address consists of two parts: the **scheme** and the **identifier**, separated by a colon. Belgian enterprise number (0208) [#belgian-enterprise-number-0208] For the Belgian company number, the prefix `0208` is used, followed by the full company number. The company number always starts with a `0` or a `1`. For example: `0208:0xxxxxxxxx` or `0208:1xxxxxxxxx`. GLN: Global Location Number (0088) [#gln-global-location-number-0088] Some organizations, especially in retail, logistics, and healthcare, are registered on Peppol under their GLN instead of a national company number. The scheme code for GLN is `0088`, followed by the 13-digit GLN. For example: `0088:5400000000001`. A full list of electronic address schemes is available on the [Peppol EAS code list](https://docs.peppol.eu/poacc/billing/3.0/codelist/eas/). # What is the difference between production and playground? (/faq/api-and-development/what-is-the-difference-between-production-and-playground) In the playground, no real Peppol connections are made. All data remains within your own team environment. In production, documents are actually sent via the Peppol network and registration as a participant is required. # Can a company use multiple Peppol Access Points? (/faq/general-usage/can-a-company-use-multiple-access-points) Within Peppol, a company can have only one active receiving Access Point per document type (such as invoices, credit notes, orders). It is therefore not possible to be registered with multiple providers simultaneously for receiving the same type of document. It is possible, however, to use different Access Points for sending documents or for receiving different document types. This also means that once your company is registered as a receiver with us (or another provider), no one else can register with the same VAT or enterprise number to receive your documents. # Can I manage multiple customers within one account? (/faq/general-usage/can-i-manage-multiple-customers-in-one-account) You can manage multiple companies within a single team. This makes Recommand ideal for software companies, accountants and agencies who want to onboard multiple customers via one platform. There is no fee per company, and the document volume of all companies in the team is pooled into one total for pricing. # Can I see if my invoice was read? (/faq/general-usage/can-i-see-if-my-invoice-was-read) Peppol does not provide receipt or read confirmation from the recipient. In Recommand, you can use the `readAt` field, which indicates when a document was marked as read within your own environment via the `/markAsRead` endpoint. View the endpoint in the [API reference](/reference/documents/mark-as-read) Through the Peppol network, an Invoice Message Response can be used. This allows the invoice recipient to indicate whether the invoice was received correctly, approved or rejected, etc. These types of documents are supported by Recommand, but unfortunately not by all senders or recipients in the network. Therefore, when sending an invoice, you will usually not receive an Invoice Message Response, even if you set this up and the document was delivered correctly. # Can I use Recommand for sending only or also for receiving? (/faq/general-usage/can-i-use-recommand-for-sending-only-or-also-receiving) When registering a company on Recommand, you can indicate whether the company will only send documents, or also wants to receive via Peppol (`isSmpRecipient: true`). Some integrators use Recommand only for sending invoices from their own software, while incoming invoices go through another package. See the company registration endpoint in the [API reference](/reference/companies/create-company). The same option is also available when registering a company in the dashboard. # Can I whitelabel integrate Recommand into my own software? (/faq/general-usage/can-i-whitelabel-integrate-recommand) Recommand is designed as an open API and can be easily integrated into invoicing, ERP or e-commerce platforms. You can fully automate Peppol sending within your software, with your own branding or flow. Contact `info@recommand.eu` to discuss these possibilities further. # How do I get started with Recommand? (/faq/general-usage/how-do-i-get-started-with-recommand) After registering on our website, you can immediately add your company and send an invoice via the dashboard or the API. No contract or technical setup is required. A playground environment is available to set up the integration without actually sending documents over the Peppol network. For the exact steps in your situation, follow the [country-specific getting started guides](/getting-started): pick your country, whether you are setting up a single company or onboarding many, and whether you send documents, receive them, or both. # How does the Recommand API work? (/faq/general-usage/how-does-the-recommand-api-work) The Recommand API supports both sending and receiving Peppol documents. You can choose between providing full UBL XML files or the simpler JSON structure. Documentation: [recommand.eu/docs](/docs) Full API reference: [recommand.eu/reference](/reference) # How long does it take for an invoice to reach the recipient? (/faq/general-usage/how-long-does-delivery-take) Invoices are delivered within Peppol almost in real time, usually within seconds. Some accounting systems process documents in batches, so visibility can vary from minutes to an hour. If the document was successfully sent via `send`, then it has been correctly delivered to the recipient's software. # Is pricing per company or per team? (/faq/general-usage/is-pricing-per-company-or-per-team) Pricing applies per team, not per company. You can add as many companies to your team as you want at no extra cost, and the documents of all those companies count toward one shared volume. That consolidated volume determines your plan tier, so the more companies you manage, the faster you reach a lower price per document. This is how software vendors and accounting firms typically use Recommand. # Is support included? (/faq/general-usage/is-support-included) Email support is included in every paid plan. Professional and Enterprise customers receive priority support and, if desired, a dedicated point of contact. # Must I register as a receiver to receive Peppol invoices? (/faq/general-usage/must-i-register-as-receiver-to-receive-peppol-invoices) Within Peppol, every recipient must be officially registered with an SMP. In Recommand, you can simply indicate this via the field `isSmpRecipient: true` when registering your company. When this is not checked, you can still send, but you will not receive documents via our Access Point over the Peppol network. # What counts as a document? (/faq/general-usage/what-counts-as-a-document) Every document stored for one of your companies counts towards your volume, whether you sent it or received it. An invoice you send and an invoice that arrives for you are each one document. On top of that: * **Each email delivery counts.** If a document goes to three email recipients as well as over Peppol, that is the Peppol transmission plus three email deliveries. * **Each e-reporting submission counts.** A French B2C or cross-border report is one document when it is filed. * **French lifecycle statuses count when they carry a decision.** Status codes 204 to 212 and 214 belong to the processing phase, where a buyer or a seller decided something about the invoice: taken in charge, approved, disputed, refused, paid, collected. Those count, in both directions. The following never count: * **Message level responses.** They are transport receipts, not business documents, so you can acknowledge everything you receive for free. * **French transmission statuses.** Status codes 200, 201, 202, 203, 213 and 501 record that a file was submitted, issued, received, made available or technically rejected. Most of them are generated by a platform without anyone deciding anything, so they are the French counterpart of a message level response. * **XML produced by the generate endpoint.** Generating a document is not sending it, so it is not billed. You are billed when you send it. The rule behind all of this is that you pay for documents and for the business answers to them, not for the messages that platforms and the network exchange to move them around. # What is Recommand and what can I use it for? (/faq/general-usage/what-is-recommand) Recommand is a certified Peppol Access Point designed to make Peppol integration accessible for businesses and developers. It supports e-invoices, orders and other documents via API or dashboard, with a focus on simplicity, openness and control over your data. Recommand provides both an API (for integration in your own software) and a dashboard (for manual sending or follow-up). Read more in the [documentation](/docs) # Where can I get help? (/faq/general-usage/where-can-i-get-help) For support, you can use several channels: Email: [support@recommand.eu](mailto:support@recommand.eu) * for general or technical questions. Discord: [discord.com/invite/a2tcQYA3ew](https://discord.com/invite/a2tcQYA3ew) * for quick help, announcements and community discussions. GitHub: [github.com/brbxai/recommand-peppol](https://github.com/brbxai/recommand-peppol) * for source code, issues and contributions. # Does the government automatically receive documents sent over Peppol? (/faq/peppol-basics/does-the-government-receive-documents-sent-over-peppol) No. The Peppol network is not a central government hub. Documents are exchanged point-to-point between the sender and the verified recipient via their Access Points. The government does not receive a copy unless it is itself the addressed recipient (e.g. a government department). In countries with VAT or reporting requirements (e.g. e-reporting/e-invoicing regimes), that reporting is done via the designated channels and rules. Peppol can be a transport channel there, but sharing with the government does not happen automatically. # What is Peppol? (/faq/peppol-basics/what-is-peppol) Peppol (Pan-European Public Procurement Online) is an international standard for e-invoicing and e-procurement. From 1 January 2026, e-invoicing via Peppol will be mandatory in Belgium for all VAT-registered companies. Peppol enables invoices, orders and credit notes to be sent directly and securely between companies, without email or PDFs. # Which documents can be sent over the Peppol network? (/faq/peppol-basics/which-documents-are-supported-on-peppol) Although e-invoicing is the most well-known use case, Peppol supports a wide range of structured business documents. These documents are based on the **Peppol BIS specifications (Business Interoperability Specifications)**. Below are some of the most common documents that can be sent over the Peppol network. | Document type | Description | BIS specification | Typical use case | | --------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------- | -------------------------------------------------- | | **Invoice (BIS Billing 3.0)** | Electronic invoice in structured UBL format | `BIS Billing 3.0` | Sales invoices to customers or governments | | **Credit Note (BIS Billing 3.0)** | Structured credit note, often linked to an invoice reference | `BIS Billing 3.0` | Correction of previously invoiced amounts | | **Order (BIS Order 3.0)** | Official purchase order from a customer to a supplier | `BIS Order 3.0` | Procurement orders, especially in e-procurement | | **Order Response (BIS Order Agreement 3.0)** | Confirmation or adjustment of a received order | `BIS Order Agreement 3.0` | Approval, rejection or modification of orders | | **Despatch Advice (BIS Despatch Advice 3.0)** | Shipping notice with details about the goods sent | `BIS Despatch Advice 3.0` | Confirmation of shipment or delivery | | **Receipt Advice (BIS Despatch Advice 3.0)** | Message confirming the goods have been received | `BIS Despatch Advice 3.0` | Receipt confirmation after delivery | | **Catalogue (BIS Catalogue 3.0)** | Product catalogue with prices, references and descriptions | `BIS Catalogue 3.0` | Synchronizing product information between systems | | **Self-Billing Invoice** | Invoice created by the customer on behalf of the supplier | `BIS Billing 3.0 (Self Billing variant)` | Common in agriculture, retail and platform economy | | **Reminder / Statement** *(in development)* | Overview or reminder of outstanding documents | Not yet defined | Expected in future Peppol extensions | **In short:** Peppol is evolving from an invoicing network into a **fully interoperable business communication network**. This allows companies to fully automate their **purchase-to-pay (P2P)** or **order-to-cash (O2C)** processes in a secure and structured way, without manual processing. # Are documents sent via Peppol publicly visible? (/faq/security-and-certification/are-documents-on-peppol-publicly-visible) Documents sent via the Peppol network are not publicly visible. The exchange takes place exclusively between the sender and the verified recipient, via their recognized Access Points. During transport, the messages are encrypted and the identity of both parties is cryptographically secured. # Is Peppol more secure than email? (/faq/security-and-certification/is-peppol-more-secure-than-email) Every company on Peppol is verified and registered. All documents are transmitted encrypted between certified Access Points. This reduces the risk of fraud, misdelivery or interception. # Is Recommand secure and certified? (/faq/security-and-certification/is-recommand-secure-and-certified) Recommand is an officially recognized Peppol Access Point and SMP. All communication takes place over secure connections and only you have access to your data. You can find Recommand (BRBX BV) in the official [list of certified Peppol service providers](https://peppol.org/members/peppol-certified-service-providers/). # Can I upload my own UBL XML? (/faq/sending-and-error-handling/can-i-upload-my-own-ubl-xml) You can add your own UBL XML in the API call. Set `documentType` to `xml` and paste the UBL as a string in the `document` field. See API reference: [recommand.eu/reference](/reference/sending/send-document) # What happens after an invoice is successfully delivered? (/faq/sending-and-error-handling/what-happens-after-an-invoice-is-delivered) A successfully sent invoice becomes immediately visible in the recipient's software. The data is structured, correctly mapped and ready for processing. # What if I don't switch to Peppol by 2026 as a Belgian company? (/faq/sending-and-error-handling/what-if-i-dont-switch-to-peppol-by-2026) From January 1, 2026, all Belgian companies must be able to receive and send electronic invoices via the Peppol network. Those who don't will face not only fines but also operational constraints. Legal implications [#legal-implications] The Belgian tax administration provides administrative fines for non-compliant companies: * €1,500 for the first offense * €3,000 for the second offense * €5,000 from the third offense onwards There is a three-month buffer period between each offense to become compliant. Existing fines for incorrect or incomplete invoices remain in effect. Practical implications [#practical-implications] * Suppliers will no longer be able to deliver their invoices in the legally required manner. Invoices sent outside Peppol will not be considered valid e-invoices. * Your own invoices to Belgian business customers will no longer be legally accepted if they are not sent via Peppol. This can lead to payment delays, administrative rejections or invoices not being received in accounting software. # What happens if the recipient is unreachable? (/faq/sending-and-error-handling/what-if-the-recipient-is-unreachable) If the receiving Access Point is temporarily unavailable or the recipient is not actively registered, you will receive an error message. You can then contact your customer to resolve the issue. # What is the difference between an e-invoice and a PDF invoice? (/faq/sending-and-error-handling/what-is-the-difference-between-an-e-invoice-and-a-pdf-invoice) E-invoices are sent in a standardized UBL format, allowing accounting or ERP software to process them immediately. PDFs require manual processing and do not meet the new legal standards. # Do I need to report B2C sales in France? (/faq/vat-and-accounting/do-i-need-to-report-b2c-sales-in-france) Yes. The French reform has two halves, and they cover different transactions. **E-invoicing** covers invoices between businesses established in France. Those invoices travel as electronic invoices, and the invoice itself is what the tax administration sees. **E-reporting** covers everything else you sell: * sales to private individuals, which are reported as daily totals per category and currency rather than invoice by invoice * invoices to businesses abroad, which are reported per invoice So a French company that sells to consumers, or that invoices customers outside France, still has an obligation even though no French e-invoice is involved. That obligation is the report. Recommand files these reports for you. You submit the sales and the payments through the API, and Recommand assembles them into the periodic filings the tax administration expects and follows each report until it is filed. For registration, the two report types, corrections and the status lifecycle, see the e-reporting section of the [French getting started guide](/getting-started/france). # What is self-billing and how does it work? (/faq/vat-and-accounting/what-is-self-billing) In self-billing (also known as 'purchase orders'), the buyer creates the invoice for the delivered goods or services on behalf of the supplier. This can be useful when the buyer determines consumption/volume (e.g., marketplaces, platforms, utilities) or to standardize processes. Important considerations: * The supplier must explicitly agree to self-billing. * VAT rules still apply: the correct VAT codes, rates and obligations remain applicable. * Both parties keep the invoice in their administration. Self-billing via Peppol: * Self-billing documents use an adapted UBL format (EN16931) that closely resembles that of regular e-invoices. * The buyer sends the document via their Access Point to the supplier on Peppol. * The supplier can automatically process the document in their accounting/ERP system. When to use? * Recurring purchases with variable volumes or prices. * Platform or marketplace models with many suppliers. * Situations where the buyer manages the source data (meters, reports, consumption, commissions). Note: Always check national legislation for specific requirements regarding consent, disclosure and archiving. Recommand supports self-billing via Peppol. # Which VAT codes do I use? (/faq/vat-and-accounting/which-vat-codes-do-i-use) The main Peppol VAT categories are: | Code | Meaning | Usage | | ---- | ------------------ | --------------------------- | | S | Standard rate | Within the same country | | AE | VAT Reverse Charge | Sales to another EU country | | G | Export outside EU | No VAT | | E | VAT Exempt | Certain sectors | | O | Outside scope | Services outside VAT | Use G for export outside the EU and O for services outside the VAT scope. # Send Document `POST /api/v1/{companyId}/send` Send a document to a customer over the Peppol network, by email, or both. The document type identifier and process are resolved against the recipient unless you name both yourself. The document is stored under the company and returned document ID, and it counts towards your subscription usage. When Peppol delivery fails and no email fallback applies, the request fails with a 422 and nothing is stored. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company sending the document. The document is sent from this company's Peppol identifier. | ## Request Body **One of:** #### Invoice | Name | Type | Required | Description | |------|------|----------|-------------| | `recipient` | string \| null | Yes | The Peppol address of the recipient. If null, the document will be sent via email only (requires `email.to`). Example: `"0208:987654321"` | | `email` | object | No | Email delivery options. When Peppol recipient is provided, email is optional and you can choose to always send the email, or only when Peppol delivery fails. When Peppol recipient is null, email becomes the primary delivery method and `email.to` is required. Each sent email is counted towards your document quota | | `pdfGeneration` | object | No | Optionally generate a PDF of the document and include it as an embedded attachment (also included in email attachments when email sending is enabled). Not supported for message level responses, French Invoicing CDAR messages, or raw XML documents | | `doctypeId` | string | No | The document type identifier. For JSON documents it is selected automatically: the recipient is looked up and the document is sent as the first format, in our order of preference, the recipient is registered to receive it in, falling back to the standard Peppol BIS 3 UBL document type for the selected documentType. For raw XML documents it can be detected automatically where supported. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | No | Optional process identifier override. It is detected automatically for supported JSON and XML document types. For JSON documents the process the recipient is registered for is preferred, as far as the document itself leaves the choice open. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `documentType` | string | Yes | The type of document. Example: `"invoice"`. Value: `invoice` | | `document` | object | Yes | Invoice to send to a recipient | **`email`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `when` | `always` \| `on_peppol_failure` | No | When to send the email. If the provided Peppol recipient is null, email becomes the primary delivery method and emails are always sent. Default: `on_peppol_failure`. Values: `always`, `on_peppol_failure` | | `to` | string[] | Yes | The email addresses to send the document to. Example: `["support@recommand.eu"]` | | `subject` | string | No | The subject of the email. If not provided, the subject will be autogenerated based on the document type. Example: `"Invoice SI-001"` | | `htmlBody` | string | No | The HTML body of the email. If not provided, the body will be autogenerated based on the document type. Example: `"Dear customer, you can find your invoice attached."` | **`pdfGeneration`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `enabled` | boolean | No | Whether to generate a PDF of the document and include it as an embedded attachment. Default: `false` | | `filename` | string | No | Optional filename to use for the generated PDF attachment. Defaults to a filename derived from the document number (e.g. invoice-001.pdf). Example: `"INV-2024-001.pdf"` | **`document`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `invoiceNumber` | string | Yes | The number the seller assigned to the invoice. Example: `"INV-2024-001"` | | `issueDate` | string \| null | No | If not provided, the issue date will be the current date. Example: `"2024-03-20"`. Format: date | | `dueDate` | string \| null | No | If not provided, the due date will be 1 month from the issue date. Example: `"2024-04-20"`. Format: date | | `note` | string \| null | No | A free text note about the invoice as a whole. Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | A reference the buyer asked you to put on the invoice so they can route it internally. If neither this nor `purchaseOrderReference` is provided, the invoice number is used. Example: `"PO-2024-001"` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | `seller` | Party | null | No | If not provided, the seller will be the company that is sending the invoice | | `buyer` | object | Yes | | | `delivery` | Delivery | null | No | Optional delivery information | | `paymentMeans` | object[] \| null | No | Optional payment information. For most invoices, this should be provided. For prepaid invoices, this could be omitted | | `paymentTerms` | object \| null | No | Optional payment terms | | `lines` | object[] | Yes | The invoice lines. At least one line is required. Min items: 1 | | `discounts` | object[] \| null | No | Optional global discounts | | `surcharges` | object[] \| null | No | Optional global surcharges | | `totals` | Totals | null | No | | | `vat` | Provided VAT totals | VAT totals auto calculation | null | No | If not provided, the VAT totals will be calculated from the document lines | | `attachments` | object[] \| null | No | Optional attachments to the invoice | | `currency` | string (enum) | No | The currency of the invoice. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `countrySpecific` | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | **`seller`** (One of): #### Party | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | #### Variant 2 Type: `null` **`buyer`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`delivery`** (One of): #### Delivery | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | `locationIdentifier` | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | `location` | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | **`locationIdentifier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | **`location`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | #### Variant 2 Type: `null` **`paymentMeans`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | **`paymentTerms`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | The payment terms as free text. Example: `"Net 30"` | **`lines`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | `standardId` | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | `commodityClassifications` | object[] \| null | No | Optional commodity classifications | | `additionalItemProperties` | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | `discounts` | object[] \| null | No | Optional discounts for the line | | `surcharges` | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | `vat` | object | Yes | | **`standardId`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | **`commodityClassifications`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | **`additionalItemProperties`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`totals`** (One of): #### Totals | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | #### Variant 2 Type: `null` **`vat`** (Any of): #### Provided VAT totals | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | `subtotals` | object[] | Yes | One entry for every combination of VAT category and rate used in the document | **`subtotals`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### VAT totals auto calculation | Name | Type | Required | Description | |------|------|----------|-------------| | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### Variant 3 Type: `null` **`attachments`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | **`countrySpecific`** (One of): #### Country Specific Billing **One of:** #### French Country Specific Billing | Name | Type | Required | Description | |------|------|----------|-------------| | `country` | string | Yes | Identifies this as the French regulatory extension. This is independent from seller, buyer, delivery, and origin country codes. Value: `FR` | | `billingMode` | string (enum) | Yes | Required only for French regulated UBL, CII, and Factur-X. Select the invoicing framework that matches the invoice. \| Mode \| Description \| \| --- \| --- \| \| `B1` \| Goods invoice. \| \| `S1` \| Services invoice. \| \| `M1` \| Mixed invoice containing goods and services that are not ancillary to each other. \| \| `B2` \| Goods invoice that has already been paid. \| \| `S2` \| Services invoice that has already been paid. \| \| `M2` \| Mixed invoice that has already been paid. \| \| `S3` \| B2G subcontractor payment request with direct payment. \| \| `B4` \| Final goods invoice after an advance payment. \| \| `S4` \| Final services invoice after an advance payment. \| \| `M4` \| Final mixed invoice after an advance payment. \| \| `S5` \| Invoice submitted by a subcontractor for services rendered. \| \| `S6` \| Invoice submitted by a co-contractor for services rendered. \| \| `B7` \| Goods invoice that has already been e-reported and for which VAT has already been collected. \| \| `S7` \| Services invoice that has already been e-reported and for which VAT has already been collected. \| \| `B8` \| Multi-seller goods invoice. \| \| `S8` \| Multi-seller services invoice. \| \| `M8` \| Multi-seller mixed invoice whose individual invoices are not all goods invoices or all services invoices. \| . Example: `"S1"`. Values: `B1`, `S1`, `M1`, `B2`, `S2`, `M2`, `S3`, `B4`, `S4`, `M4`, `S5`, `S6`, `B7`, `S7`, `B8`, `S8`, `M8`, `B9`, `S9`, `M9` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` | No | Determines which French Peppol process the document is sent over. Defaults to `REGULATED`. \| Value \| Description \| \| --- \| --- \| \| `REGULATED` \| Transaction inside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:regulated`. \| \| `NON_REGULATED` \| Transaction outside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:non-regulated`. \| The recipient must have registered the matching process for the document type in its SMP. Default: `REGULATED`. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED` | | `recoveryCostsNote` | string | Yes | The mandatory French recovery-cost indemnity statement, written as an IncludedNote with subject code PMT. Example: `"Indemnite forfaitaire de 40 EUR pour frais de recouvrement."` | | `latePaymentPenaltiesNote` | string | Yes | The mandatory French late-payment penalties statement, written as an IncludedNote with subject code PMD. Example: `"Penalites de retard exigibles au taux prevu dans les conditions generales de vente."` | | `earlyPaymentDiscountNote` | string | Yes | The mandatory French early-payment discount statement, written as an IncludedNote with subject code AAB. State either the offered discount terms or explicitly that no early-payment discount applies. Example: `"Aucun escompte accorde pour paiement anticipe."` | #### Variant 2 Type: `null` #### Credit Note | Name | Type | Required | Description | |------|------|----------|-------------| | `recipient` | string \| null | Yes | The Peppol address of the recipient. If null, the document will be sent via email only (requires `email.to`). Example: `"0208:987654321"` | | `email` | object | No | Email delivery options. When Peppol recipient is provided, email is optional and you can choose to always send the email, or only when Peppol delivery fails. When Peppol recipient is null, email becomes the primary delivery method and `email.to` is required. Each sent email is counted towards your document quota | | `pdfGeneration` | object | No | Optionally generate a PDF of the document and include it as an embedded attachment (also included in email attachments when email sending is enabled). Not supported for message level responses, French Invoicing CDAR messages, or raw XML documents | | `doctypeId` | string | No | The document type identifier. For JSON documents it is selected automatically: the recipient is looked up and the document is sent as the first format, in our order of preference, the recipient is registered to receive it in, falling back to the standard Peppol BIS 3 UBL document type for the selected documentType. For raw XML documents it can be detected automatically where supported. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | No | Optional process identifier override. It is detected automatically for supported JSON and XML document types. For JSON documents the process the recipient is registered for is preferred, as far as the document itself leaves the choice open. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `documentType` | string | Yes | The type of document. Example: `"creditNote"`. Value: `creditNote` | | `document` | object | Yes | Credit note to send to a recipient | **`email`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `when` | `always` \| `on_peppol_failure` | No | When to send the email. If the provided Peppol recipient is null, email becomes the primary delivery method and emails are always sent. Default: `on_peppol_failure`. Values: `always`, `on_peppol_failure` | | `to` | string[] | Yes | The email addresses to send the document to. Example: `["support@recommand.eu"]` | | `subject` | string | No | The subject of the email. If not provided, the subject will be autogenerated based on the document type. Example: `"Invoice SI-001"` | | `htmlBody` | string | No | The HTML body of the email. If not provided, the body will be autogenerated based on the document type. Example: `"Dear customer, you can find your invoice attached."` | **`pdfGeneration`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `enabled` | boolean | No | Whether to generate a PDF of the document and include it as an embedded attachment. Default: `false` | | `filename` | string | No | Optional filename to use for the generated PDF attachment. Defaults to a filename derived from the document number (e.g. invoice-001.pdf). Example: `"INV-2024-001.pdf"` | **`document`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `creditNoteNumber` | string | Yes | Example: `"CN-2024-001"` | | `issueDate` | string \| null | No | If not provided, the issue date will be the current date. Example: `"2024-03-20"`. Format: date | | `note` | string \| null | No | Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | Example: `"PO-2024-001"` | | `invoiceReferences` | object[] | No | References to one or more invoices that are being credited. Default: `` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | `seller` | Party | null | No | If not provided, the seller will be the company that is sending the credit note | | `buyer` | object | Yes | | | `delivery` | Delivery | null | No | Optional delivery information | | `paymentMeans` | object[] \| null | No | | | `paymentTerms` | object \| null | No | | | `lines` | object[] | Yes | Min items: 1 | | `discounts` | object[] \| null | No | Optional global discounts | | `surcharges` | object[] \| null | No | Optional global surcharges | | `totals` | Totals | null | No | | | `vat` | Provided VAT totals | VAT totals auto calculation | null | No | If not provided, the VAT totals will be calculated from the document lines | | `attachments` | object[] \| null | No | Optional attachments to the credit note | | `currency` | string (enum) | No | The currency of the credit note. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `countrySpecific` | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | | `dueDate` | string \| null | No | If not provided, the due date will be 1 month from the issue date. Example: `"2024-04-20"`. Format: date | **`invoiceReferences`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The reference to the invoice that is being credited. Example: `"INV-2024-001"` | | `issueDate` | string \| null | No | The issue date of the invoice that is being credited. Example: `"2024-03-20"`. Format: date | **`seller`** (One of): #### Party | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | #### Variant 2 Type: `null` **`buyer`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`delivery`** (One of): #### Delivery | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | `locationIdentifier` | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | `location` | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | **`locationIdentifier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | **`location`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | #### Variant 2 Type: `null` **`paymentMeans`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | **`paymentTerms`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | Example: `"Net 30"` | **`lines`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | `standardId` | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | `commodityClassifications` | object[] \| null | No | Optional commodity classifications | | `additionalItemProperties` | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | `discounts` | object[] \| null | No | Optional discounts for the line | | `surcharges` | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | `vat` | object | Yes | | **`standardId`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | **`commodityClassifications`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | **`additionalItemProperties`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`totals`** (One of): #### Totals | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | #### Variant 2 Type: `null` **`vat`** (Any of): #### Provided VAT totals | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | `subtotals` | object[] | Yes | One entry for every combination of VAT category and rate used in the document | **`subtotals`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### VAT totals auto calculation | Name | Type | Required | Description | |------|------|----------|-------------| | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### Variant 3 Type: `null` **`attachments`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | **`countrySpecific`** (One of): #### Country Specific Billing **One of:** #### French Country Specific Billing | Name | Type | Required | Description | |------|------|----------|-------------| | `country` | string | Yes | Identifies this as the French regulatory extension. This is independent from seller, buyer, delivery, and origin country codes. Value: `FR` | | `billingMode` | string (enum) | Yes | Required only for French regulated UBL, CII, and Factur-X. Select the invoicing framework that matches the invoice. \| Mode \| Description \| \| --- \| --- \| \| `B1` \| Goods invoice. \| \| `S1` \| Services invoice. \| \| `M1` \| Mixed invoice containing goods and services that are not ancillary to each other. \| \| `B2` \| Goods invoice that has already been paid. \| \| `S2` \| Services invoice that has already been paid. \| \| `M2` \| Mixed invoice that has already been paid. \| \| `S3` \| B2G subcontractor payment request with direct payment. \| \| `B4` \| Final goods invoice after an advance payment. \| \| `S4` \| Final services invoice after an advance payment. \| \| `M4` \| Final mixed invoice after an advance payment. \| \| `S5` \| Invoice submitted by a subcontractor for services rendered. \| \| `S6` \| Invoice submitted by a co-contractor for services rendered. \| \| `B7` \| Goods invoice that has already been e-reported and for which VAT has already been collected. \| \| `S7` \| Services invoice that has already been e-reported and for which VAT has already been collected. \| \| `B8` \| Multi-seller goods invoice. \| \| `S8` \| Multi-seller services invoice. \| \| `M8` \| Multi-seller mixed invoice whose individual invoices are not all goods invoices or all services invoices. \| . Example: `"S1"`. Values: `B1`, `S1`, `M1`, `B2`, `S2`, `M2`, `S3`, `B4`, `S4`, `M4`, `S5`, `S6`, `B7`, `S7`, `B8`, `S8`, `M8`, `B9`, `S9`, `M9` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` | No | Determines which French Peppol process the document is sent over. Defaults to `REGULATED`. \| Value \| Description \| \| --- \| --- \| \| `REGULATED` \| Transaction inside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:regulated`. \| \| `NON_REGULATED` \| Transaction outside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:non-regulated`. \| The recipient must have registered the matching process for the document type in its SMP. Default: `REGULATED`. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED` | | `recoveryCostsNote` | string | Yes | The mandatory French recovery-cost indemnity statement, written as an IncludedNote with subject code PMT. Example: `"Indemnite forfaitaire de 40 EUR pour frais de recouvrement."` | | `latePaymentPenaltiesNote` | string | Yes | The mandatory French late-payment penalties statement, written as an IncludedNote with subject code PMD. Example: `"Penalites de retard exigibles au taux prevu dans les conditions generales de vente."` | | `earlyPaymentDiscountNote` | string | Yes | The mandatory French early-payment discount statement, written as an IncludedNote with subject code AAB. State either the offered discount terms or explicitly that no early-payment discount applies. Example: `"Aucun escompte accorde pour paiement anticipe."` | #### Variant 2 Type: `null` #### Self Billing Invoice | Name | Type | Required | Description | |------|------|----------|-------------| | `recipient` | string \| null | Yes | The Peppol address of the recipient. If null, the document will be sent via email only (requires `email.to`). Example: `"0208:987654321"` | | `email` | object | No | Email delivery options. When Peppol recipient is provided, email is optional and you can choose to always send the email, or only when Peppol delivery fails. When Peppol recipient is null, email becomes the primary delivery method and `email.to` is required. Each sent email is counted towards your document quota | | `pdfGeneration` | object | No | Optionally generate a PDF of the document and include it as an embedded attachment (also included in email attachments when email sending is enabled). Not supported for message level responses, French Invoicing CDAR messages, or raw XML documents | | `doctypeId` | string | No | The document type identifier. For JSON documents it is selected automatically: the recipient is looked up and the document is sent as the first format, in our order of preference, the recipient is registered to receive it in, falling back to the standard Peppol BIS 3 UBL document type for the selected documentType. For raw XML documents it can be detected automatically where supported. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | No | Optional process identifier override. It is detected automatically for supported JSON and XML document types. For JSON documents the process the recipient is registered for is preferred, as far as the document itself leaves the choice open. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `documentType` | string | Yes | The type of document. Example: `"selfBillingInvoice"`. Value: `selfBillingInvoice` | | `document` | object | Yes | Self billing invoice to send to a recipient | **`email`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `when` | `always` \| `on_peppol_failure` | No | When to send the email. If the provided Peppol recipient is null, email becomes the primary delivery method and emails are always sent. Default: `on_peppol_failure`. Values: `always`, `on_peppol_failure` | | `to` | string[] | Yes | The email addresses to send the document to. Example: `["support@recommand.eu"]` | | `subject` | string | No | The subject of the email. If not provided, the subject will be autogenerated based on the document type. Example: `"Invoice SI-001"` | | `htmlBody` | string | No | The HTML body of the email. If not provided, the body will be autogenerated based on the document type. Example: `"Dear customer, you can find your invoice attached."` | **`pdfGeneration`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `enabled` | boolean | No | Whether to generate a PDF of the document and include it as an embedded attachment. Default: `false` | | `filename` | string | No | Optional filename to use for the generated PDF attachment. Defaults to a filename derived from the document number (e.g. invoice-001.pdf). Example: `"INV-2024-001.pdf"` | **`document`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `invoiceNumber` | string | Yes | The number the seller assigned to the invoice. Example: `"INV-2024-001"` | | `issueDate` | string \| null | No | If not provided, the issue date will be the current date. Example: `"2024-03-20"`. Format: date | | `dueDate` | string \| null | No | If not provided, the due date will be 1 month from the issue date. Example: `"2024-04-20"`. Format: date | | `note` | string \| null | No | A free text note about the invoice as a whole. Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | A reference the buyer asked you to put on the invoice so they can route it internally. If neither this nor `purchaseOrderReference` is provided, the invoice number is used. Example: `"PO-2024-001"` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | `seller` | object | Yes | | | `buyer` | Party | null | No | If not provided, the buyer will be the company that is sending the self billing invoice | | `delivery` | Delivery | null | No | Optional delivery information | | `paymentMeans` | object[] \| null | No | Optional payment information. For most invoices, this should be provided. For prepaid invoices, this could be omitted | | `paymentTerms` | object \| null | No | Optional payment terms | | `lines` | object[] | Yes | The invoice lines. At least one line is required. Min items: 1 | | `discounts` | object[] \| null | No | Optional global discounts | | `surcharges` | object[] \| null | No | Optional global surcharges | | `totals` | Totals | null | No | | | `vat` | Provided VAT totals | VAT totals auto calculation | null | No | If not provided, the VAT totals will be calculated from the document lines | | `attachments` | object[] \| null | No | Optional attachments to the invoice | | `currency` | string (enum) | No | The currency of the invoice. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `countrySpecific` | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | **`seller`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`buyer`** (One of): #### Party | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | #### Variant 2 Type: `null` **`delivery`** (One of): #### Delivery | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | `locationIdentifier` | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | `location` | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | **`locationIdentifier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | **`location`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | #### Variant 2 Type: `null` **`paymentMeans`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | **`paymentTerms`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | The payment terms as free text. Example: `"Net 30"` | **`lines`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | `standardId` | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | `commodityClassifications` | object[] \| null | No | Optional commodity classifications | | `additionalItemProperties` | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | `discounts` | object[] \| null | No | Optional discounts for the line | | `surcharges` | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | `vat` | object | Yes | | **`standardId`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | **`commodityClassifications`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | **`additionalItemProperties`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`totals`** (One of): #### Totals | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | #### Variant 2 Type: `null` **`vat`** (Any of): #### Provided VAT totals | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | `subtotals` | object[] | Yes | One entry for every combination of VAT category and rate used in the document | **`subtotals`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### VAT totals auto calculation | Name | Type | Required | Description | |------|------|----------|-------------| | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### Variant 3 Type: `null` **`attachments`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | **`countrySpecific`** (One of): #### Country Specific Billing **One of:** #### French Country Specific Billing | Name | Type | Required | Description | |------|------|----------|-------------| | `country` | string | Yes | Identifies this as the French regulatory extension. This is independent from seller, buyer, delivery, and origin country codes. Value: `FR` | | `billingMode` | string (enum) | Yes | Required only for French regulated UBL, CII, and Factur-X. Select the invoicing framework that matches the invoice. \| Mode \| Description \| \| --- \| --- \| \| `B1` \| Goods invoice. \| \| `S1` \| Services invoice. \| \| `M1` \| Mixed invoice containing goods and services that are not ancillary to each other. \| \| `B2` \| Goods invoice that has already been paid. \| \| `S2` \| Services invoice that has already been paid. \| \| `M2` \| Mixed invoice that has already been paid. \| \| `S3` \| B2G subcontractor payment request with direct payment. \| \| `B4` \| Final goods invoice after an advance payment. \| \| `S4` \| Final services invoice after an advance payment. \| \| `M4` \| Final mixed invoice after an advance payment. \| \| `S5` \| Invoice submitted by a subcontractor for services rendered. \| \| `S6` \| Invoice submitted by a co-contractor for services rendered. \| \| `B7` \| Goods invoice that has already been e-reported and for which VAT has already been collected. \| \| `S7` \| Services invoice that has already been e-reported and for which VAT has already been collected. \| \| `B8` \| Multi-seller goods invoice. \| \| `S8` \| Multi-seller services invoice. \| \| `M8` \| Multi-seller mixed invoice whose individual invoices are not all goods invoices or all services invoices. \| . Example: `"S1"`. Values: `B1`, `S1`, `M1`, `B2`, `S2`, `M2`, `S3`, `B4`, `S4`, `M4`, `S5`, `S6`, `B7`, `S7`, `B8`, `S8`, `M8`, `B9`, `S9`, `M9` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` | No | Determines which French Peppol process the document is sent over. Defaults to `REGULATED`. \| Value \| Description \| \| --- \| --- \| \| `REGULATED` \| Transaction inside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:regulated`. \| \| `NON_REGULATED` \| Transaction outside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:non-regulated`. \| The recipient must have registered the matching process for the document type in its SMP. Default: `REGULATED`. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED` | | `recoveryCostsNote` | string | Yes | The mandatory French recovery-cost indemnity statement, written as an IncludedNote with subject code PMT. Example: `"Indemnite forfaitaire de 40 EUR pour frais de recouvrement."` | | `latePaymentPenaltiesNote` | string | Yes | The mandatory French late-payment penalties statement, written as an IncludedNote with subject code PMD. Example: `"Penalites de retard exigibles au taux prevu dans les conditions generales de vente."` | | `earlyPaymentDiscountNote` | string | Yes | The mandatory French early-payment discount statement, written as an IncludedNote with subject code AAB. State either the offered discount terms or explicitly that no early-payment discount applies. Example: `"Aucun escompte accorde pour paiement anticipe."` | #### Variant 2 Type: `null` #### Self Billing Credit Note | Name | Type | Required | Description | |------|------|----------|-------------| | `recipient` | string \| null | Yes | The Peppol address of the recipient. If null, the document will be sent via email only (requires `email.to`). Example: `"0208:987654321"` | | `email` | object | No | Email delivery options. When Peppol recipient is provided, email is optional and you can choose to always send the email, or only when Peppol delivery fails. When Peppol recipient is null, email becomes the primary delivery method and `email.to` is required. Each sent email is counted towards your document quota | | `pdfGeneration` | object | No | Optionally generate a PDF of the document and include it as an embedded attachment (also included in email attachments when email sending is enabled). Not supported for message level responses, French Invoicing CDAR messages, or raw XML documents | | `doctypeId` | string | No | The document type identifier. For JSON documents it is selected automatically: the recipient is looked up and the document is sent as the first format, in our order of preference, the recipient is registered to receive it in, falling back to the standard Peppol BIS 3 UBL document type for the selected documentType. For raw XML documents it can be detected automatically where supported. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | No | Optional process identifier override. It is detected automatically for supported JSON and XML document types. For JSON documents the process the recipient is registered for is preferred, as far as the document itself leaves the choice open. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `documentType` | string | Yes | The type of document. Example: `"selfBillingCreditNote"`. Value: `selfBillingCreditNote` | | `document` | object | Yes | Self billing credit note to send to a recipient | **`email`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `when` | `always` \| `on_peppol_failure` | No | When to send the email. If the provided Peppol recipient is null, email becomes the primary delivery method and emails are always sent. Default: `on_peppol_failure`. Values: `always`, `on_peppol_failure` | | `to` | string[] | Yes | The email addresses to send the document to. Example: `["support@recommand.eu"]` | | `subject` | string | No | The subject of the email. If not provided, the subject will be autogenerated based on the document type. Example: `"Invoice SI-001"` | | `htmlBody` | string | No | The HTML body of the email. If not provided, the body will be autogenerated based on the document type. Example: `"Dear customer, you can find your invoice attached."` | **`pdfGeneration`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `enabled` | boolean | No | Whether to generate a PDF of the document and include it as an embedded attachment. Default: `false` | | `filename` | string | No | Optional filename to use for the generated PDF attachment. Defaults to a filename derived from the document number (e.g. invoice-001.pdf). Example: `"INV-2024-001.pdf"` | **`document`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `creditNoteNumber` | string | Yes | Example: `"CN-2024-001"` | | `issueDate` | string \| null | No | If not provided, the issue date will be the current date. Example: `"2024-03-20"`. Format: date | | `note` | string \| null | No | Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | Example: `"PO-2024-001"` | | `invoiceReferences` | object[] | No | References to one or more invoices that are being credited. Default: `` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | `seller` | object | Yes | | | `buyer` | Party | null | No | If not provided, the buyer will be the company that is sending the self billing credit note | | `delivery` | Delivery | null | No | Optional delivery information | | `paymentMeans` | object[] \| null | No | | | `paymentTerms` | object \| null | No | | | `lines` | object[] | Yes | Min items: 1 | | `discounts` | object[] \| null | No | Optional global discounts | | `surcharges` | object[] \| null | No | Optional global surcharges | | `totals` | Totals | null | No | | | `vat` | Provided VAT totals | VAT totals auto calculation | null | No | If not provided, the VAT totals will be calculated from the document lines | | `attachments` | object[] \| null | No | Optional attachments to the credit note | | `currency` | string (enum) | No | The currency of the credit note. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `countrySpecific` | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | | `dueDate` | string \| null | No | If not provided, the due date will be 1 month from the issue date. Example: `"2024-04-20"`. Format: date | **`invoiceReferences`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The reference to the invoice that is being credited. Example: `"INV-2024-001"` | | `issueDate` | string \| null | No | The issue date of the invoice that is being credited. Example: `"2024-03-20"`. Format: date | **`seller`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`buyer`** (One of): #### Party | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | #### Variant 2 Type: `null` **`delivery`** (One of): #### Delivery | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | `locationIdentifier` | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | `location` | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | **`locationIdentifier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | **`location`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | #### Variant 2 Type: `null` **`paymentMeans`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | **`paymentTerms`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | Example: `"Net 30"` | **`lines`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | `standardId` | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | `commodityClassifications` | object[] \| null | No | Optional commodity classifications | | `additionalItemProperties` | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | `discounts` | object[] \| null | No | Optional discounts for the line | | `surcharges` | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | `vat` | object | Yes | | **`standardId`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | **`commodityClassifications`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | **`additionalItemProperties`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`totals`** (One of): #### Totals | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | #### Variant 2 Type: `null` **`vat`** (Any of): #### Provided VAT totals | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | `subtotals` | object[] | Yes | One entry for every combination of VAT category and rate used in the document | **`subtotals`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### VAT totals auto calculation | Name | Type | Required | Description | |------|------|----------|-------------| | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### Variant 3 Type: `null` **`attachments`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | **`countrySpecific`** (One of): #### Country Specific Billing **One of:** #### French Country Specific Billing | Name | Type | Required | Description | |------|------|----------|-------------| | `country` | string | Yes | Identifies this as the French regulatory extension. This is independent from seller, buyer, delivery, and origin country codes. Value: `FR` | | `billingMode` | string (enum) | Yes | Required only for French regulated UBL, CII, and Factur-X. Select the invoicing framework that matches the invoice. \| Mode \| Description \| \| --- \| --- \| \| `B1` \| Goods invoice. \| \| `S1` \| Services invoice. \| \| `M1` \| Mixed invoice containing goods and services that are not ancillary to each other. \| \| `B2` \| Goods invoice that has already been paid. \| \| `S2` \| Services invoice that has already been paid. \| \| `M2` \| Mixed invoice that has already been paid. \| \| `S3` \| B2G subcontractor payment request with direct payment. \| \| `B4` \| Final goods invoice after an advance payment. \| \| `S4` \| Final services invoice after an advance payment. \| \| `M4` \| Final mixed invoice after an advance payment. \| \| `S5` \| Invoice submitted by a subcontractor for services rendered. \| \| `S6` \| Invoice submitted by a co-contractor for services rendered. \| \| `B7` \| Goods invoice that has already been e-reported and for which VAT has already been collected. \| \| `S7` \| Services invoice that has already been e-reported and for which VAT has already been collected. \| \| `B8` \| Multi-seller goods invoice. \| \| `S8` \| Multi-seller services invoice. \| \| `M8` \| Multi-seller mixed invoice whose individual invoices are not all goods invoices or all services invoices. \| . Example: `"S1"`. Values: `B1`, `S1`, `M1`, `B2`, `S2`, `M2`, `S3`, `B4`, `S4`, `M4`, `S5`, `S6`, `B7`, `S7`, `B8`, `S8`, `M8`, `B9`, `S9`, `M9` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` | No | Determines which French Peppol process the document is sent over. Defaults to `REGULATED`. \| Value \| Description \| \| --- \| --- \| \| `REGULATED` \| Transaction inside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:regulated`. \| \| `NON_REGULATED` \| Transaction outside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:non-regulated`. \| The recipient must have registered the matching process for the document type in its SMP. Default: `REGULATED`. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED` | | `recoveryCostsNote` | string | Yes | The mandatory French recovery-cost indemnity statement, written as an IncludedNote with subject code PMT. Example: `"Indemnite forfaitaire de 40 EUR pour frais de recouvrement."` | | `latePaymentPenaltiesNote` | string | Yes | The mandatory French late-payment penalties statement, written as an IncludedNote with subject code PMD. Example: `"Penalites de retard exigibles au taux prevu dans les conditions generales de vente."` | | `earlyPaymentDiscountNote` | string | Yes | The mandatory French early-payment discount statement, written as an IncludedNote with subject code AAB. State either the offered discount terms or explicitly that no early-payment discount applies. Example: `"Aucun escompte accorde pour paiement anticipe."` | #### Variant 2 Type: `null` #### Message Level Response | Name | Type | Required | Description | |------|------|----------|-------------| | `recipient` | string \| null | Yes | The Peppol address of the recipient. If null, the document will be sent via email only (requires `email.to`). Example: `"0208:987654321"` | | `email` | object | No | Email delivery options. When Peppol recipient is provided, email is optional and you can choose to always send the email, or only when Peppol delivery fails. When Peppol recipient is null, email becomes the primary delivery method and `email.to` is required. Each sent email is counted towards your document quota | | `pdfGeneration` | object | No | Optionally generate a PDF of the document and include it as an embedded attachment (also included in email attachments when email sending is enabled). Not supported for message level responses, French Invoicing CDAR messages, or raw XML documents | | `doctypeId` | string | No | The document type identifier. For JSON documents it is selected automatically: the recipient is looked up and the document is sent as the first format, in our order of preference, the recipient is registered to receive it in, falling back to the standard Peppol BIS 3 UBL document type for the selected documentType. For raw XML documents it can be detected automatically where supported. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | No | Optional process identifier override. It is detected automatically for supported JSON and XML document types. For JSON documents the process the recipient is registered for is preferred, as far as the document itself leaves the choice open. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `documentType` | string | Yes | The type of document. Example: `"messageLevelResponse"`. Value: `messageLevelResponse` | | `document` | object | Yes | Message Level Response to send to a recipient | **`email`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `when` | `always` \| `on_peppol_failure` | No | When to send the email. If the provided Peppol recipient is null, email becomes the primary delivery method and emails are always sent. Default: `on_peppol_failure`. Values: `always`, `on_peppol_failure` | | `to` | string[] | Yes | The email addresses to send the document to. Example: `["support@recommand.eu"]` | | `subject` | string | No | The subject of the email. If not provided, the subject will be autogenerated based on the document type. Example: `"Invoice SI-001"` | | `htmlBody` | string | No | The HTML body of the email. If not provided, the body will be autogenerated based on the document type. Example: `"Dear customer, you can find your invoice attached."` | **`pdfGeneration`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `enabled` | boolean | No | Whether to generate a PDF of the document and include it as an embedded attachment. Default: `false` | | `filename` | string | No | Optional filename to use for the generated PDF attachment. Defaults to a filename derived from the document number (e.g. invoice-001.pdf). Example: `"INV-2024-001.pdf"` | **`document`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | No | The ID of the message level response. If not provided, the ID will be autogenerated | | `issueDate` | string (date) | No | If not provided, the issue date will be the current date. Example: `"2024-03-20"`. Format: date | | `responseCode` | `AB` \| `AP` \| `RE` | Yes | The response code of the message level response (AB: Message acknowledgement, AP: Accepted, RE: Rejected). Example: `"AB"`. Values: `AB`, `AP`, `RE` | | `envelopeId` | string | Yes | Identifies the document on which the message level response is based | #### French Invoicing CDAR | Name | Type | Required | Description | |------|------|----------|-------------| | `recipient` | string \| null | Yes | The Peppol address of the recipient. If null, the document will be sent via email only (requires `email.to`). Example: `"0208:987654321"` | | `email` | object | No | Email delivery options. When Peppol recipient is provided, email is optional and you can choose to always send the email, or only when Peppol delivery fails. When Peppol recipient is null, email becomes the primary delivery method and `email.to` is required. Each sent email is counted towards your document quota | | `pdfGeneration` | object | No | Optionally generate a PDF of the document and include it as an embedded attachment (also included in email attachments when email sending is enabled). Not supported for message level responses, French Invoicing CDAR messages, or raw XML documents | | `doctypeId` | string | No | The document type identifier. For JSON documents it is selected automatically: the recipient is looked up and the document is sent as the first format, in our order of preference, the recipient is registered to receive it in, falling back to the standard Peppol BIS 3 UBL document type for the selected documentType. For raw XML documents it can be detected automatically where supported. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | No | Optional process identifier override. It is detected automatically for supported JSON and XML document types. For JSON documents the process the recipient is registered for is preferred, as far as the document itself leaves the choice open. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `documentType` | string | Yes | The type of document. Example: `"frenchInvoicingCdar"`. Value: `frenchInvoicingCdar` | | `document` | object | Yes | French invoice lifecycle status to send. The recipient electronic address is derived from the top-level Peppol recipient | **`email`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `when` | `always` \| `on_peppol_failure` | No | When to send the email. If the provided Peppol recipient is null, email becomes the primary delivery method and emails are always sent. Default: `on_peppol_failure`. Values: `always`, `on_peppol_failure` | | `to` | string[] | Yes | The email addresses to send the document to. Example: `["support@recommand.eu"]` | | `subject` | string | No | The subject of the email. If not provided, the subject will be autogenerated based on the document type. Example: `"Invoice SI-001"` | | `htmlBody` | string | No | The HTML body of the email. If not provided, the body will be autogenerated based on the document type. Example: `"Dear customer, you can find your invoice attached."` | **`pdfGeneration`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `enabled` | boolean | No | Whether to generate a PDF of the document and include it as an embedded attachment. Default: `false` | | `filename` | string | No | Optional filename to use for the generated PDF attachment. Defaults to a filename derived from the document number (e.g. invoice-001.pdf). Example: `"INV-2024-001.pdf"` | **`document`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | No | The ID of the CDAR. If not provided, the ID will be autogenerated | | `issueDate` | string (date-time) | No | If not provided, the issue date and time will be the current local date and time. Example: `"2024-03-20T14:05:09"`. Format: date-time | | `businessProcess` | `REGULATED` \| `NON_REGULATED` \| `B2C` \| `B2CINT` \| `B2BINT` \| `OUTOFSCOPE` | Yes | Flow classification. \| Value \| Meaning \| \| --- \| --- \| \| `REGULATED` \| Regulated French domestic e-invoicing \| \| `NON_REGULATED` \| Outside the regulated French e-invoicing perimeter \| \| `B2C` \| B2C sales e-reporting \| \| `B2CINT` \| International B2C sales e-reporting \| \| `B2BINT` \| International B2B sales e-reporting \| \| `OUTOFSCOPE` \| Outside the French e-invoicing and e-reporting reform \|. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED`, `B2C`, `B2CINT`, `B2BINT`, `OUTOFSCOPE` | | `phase` | `23` \| `305` | No | CDAR phase. \| Value \| Meaning \| \| --- \| --- \| \| `23` \| Processing phase \| \| `305` \| Transmission phase \| Defaults to `305` for statuses `200`, `201`, `202`, `203`, `213`, and `501`; otherwise defaults to `23`. Example: `"23"`. Values: `23`, `305` | | `senderRole` | string (enum) | Yes | Role of the CDAR sender. CDAR party role code (UNCL 3035). \| Value \| Meaning \| \| --- \| --- \| \| `BY` \| Buyer \| \| `AB` \| Buyer's agent or representative \| \| `DL` \| Factor \| \| `SE` \| Seller \| \| `SR` \| Seller's agent \| \| `WK` \| Platform or dematerialisation operator \| \| `DFH` \| French public invoicing portal (PPF) \| \| `PE` \| Payee \| \| `PR` \| Payer \| \| `II` \| Invoicer (invoice issuer) \| \| `IV` \| Invoicee (party invoiced) \|. Example: `"WK"`. Values: `BY`, `AB`, `DL`, `SE`, `SR`, `WK`, `DFH`, `PE`, `PR`, `II`, `IV` | | `issuerRole` | string (enum) | Yes | Role of the party that creates and issues the invoice lifecycle status. This is independent from the CDAR sender role. CDAR party role code (UNCL 3035). \| Value \| Meaning \| \| --- \| --- \| \| `BY` \| Buyer \| \| `AB` \| Buyer's agent or representative \| \| `DL` \| Factor \| \| `SE` \| Seller \| \| `SR` \| Seller's agent \| \| `WK` \| Platform or dematerialisation operator \| \| `DFH` \| French public invoicing portal (PPF) \| \| `PE` \| Payee \| \| `PR` \| Payer \| \| `II` \| Invoicer (invoice issuer) \| \| `IV` \| Invoicee (party invoiced) \|. Example: `"BY"`. Values: `BY`, `AB`, `DL`, `SE`, `SR`, `WK`, `DFH`, `PE`, `PR`, `II`, `IV` | | `issuerLegalId` | string | No | Legal identifier of the party setting the status. Required when phase is 23; must be omitted when phase is 305 unless recipientRole is DFH. Example: `"200000008"` | | `issuerLegalIdScheme` | string | No | ISO 6523 ICD scheme of the party-setting-status legal identifier. Required together with issuerLegalId. Example: `"0002"` | | `recipientRole` | string (enum) | Yes | Role of the CDAR recipient. CDAR party role code (UNCL 3035). \| Value \| Meaning \| \| --- \| --- \| \| `BY` \| Buyer \| \| `AB` \| Buyer's agent or representative \| \| `DL` \| Factor \| \| `SE` \| Seller \| \| `SR` \| Seller's agent \| \| `WK` \| Platform or dematerialisation operator \| \| `DFH` \| French public invoicing portal (PPF) \| \| `PE` \| Payee \| \| `PR` \| Payer \| \| `II` \| Invoicer (invoice issuer) \| \| `IV` \| Invoicee (party invoiced) \|. Example: `"SE"`. Values: `BY`, `AB`, `DL`, `SE`, `SR`, `WK`, `DFH`, `PE`, `PR`, `II`, `IV` | | `recipientLegalId` | string | No | Legal identifier of the CDAR recipient. Example: `"200000008"` | | `recipientLegalIdScheme` | string | No | ISO 6523 ICD scheme of the CDAR recipient legal identifier. Required together with recipientLegalId. Example: `"0002"` | | `statusCode` | string (enum) | Yes | French invoice lifecycle status. \| Value \| Meaning \| \| --- \| --- \| \| `200` \| Submitted \| \| `201` \| Issued \| \| `202` \| Received \| \| `203` \| Made available \| \| `204` \| Taken in charge (processing started) \| \| `205` \| Approved \| \| `206` \| Partially approved \| \| `207` \| In dispute \| \| `208` \| Suspended \| \| `209` \| Completed \| \| `210` \| Refused \| \| `211` \| Payment sent \| \| `212` \| Collected (cashed) \| \| `213` \| Rejected \| \| `214` \| Validated or pre-validated ("Visée") \| \| `501` \| Inadmissible file \|. Example: `"200"`. Values: `200`, `201`, `202`, `203`, `204`, `205`, `206`, `207`, `208`, `209`, `210`, `211`, `212`, `213`, `214`, `501` | | `statusDate` | string (date-time) | No | Date and time at which the status was set. If not provided, the issue date and time of the CDAR is used. Example: `"2024-03-20T14:05:09"`. Format: date-time | | `invoiceId` | string | Yes | Number of the invoice this status relates to. For status 501, this is the filename of the inadmissible file | | `invoiceTypeCode` | string (enum) | No | Type of the referenced invoice. Type of the referenced invoice (UNTDID 1001, restricted to the values allowed by BR-FR-04). \| Value \| Meaning \| \| --- \| --- \| \| `380` \| Commercial invoice \| \| `389` \| Self-billed invoice \| \| `393` \| Factored invoice \| \| `501` \| Self-billed factored invoice \| \| `386` \| Advance payment invoice \| \| `500` \| Self-billed advance payment invoice \| \| `384` \| Corrective invoice \| \| `471` \| Self-billed corrective invoice \| \| `472` \| Factored corrective invoice \| \| `473` \| Self-billed factored corrective invoice \| \| `261` \| Self-billed credit note \| \| `262` \| Global rebate credit note \| \| `381` \| Credit note \| \| `396` \| Factored credit note \| \| `502` \| Self-billed factored credit note \| \| `503` \| Credit note for an advance payment invoice \|. Example: `"380"`. Values: `380`, `389`, `393`, `501`, `386`, `500`, `384`, `471`, `472`, `473`, `261`, `262`, `381`, `396`, `502`, `503` | | `invoiceIssueDate` | string (date) | No | Issue date of the referenced invoice. Required unless statusCode is 501. Example: `"2024-03-15"`. Format: date | | `sellerLegalId` | string | No | Legal identifier (e.g. SIREN) of the invoice seller. Required unless statusCode is 501. Example: `"123456789"` | | `sellerLegalIdScheme` | string | No | ISO 6523 ICD scheme of the referenced invoice seller legal identifier. Required together with sellerLegalId. Example: `"0002"` | | `reasonCode` | string (enum) | No | Coded reason for the invoice lifecycle status. \| Value \| Meaning \| \| --- \| --- \| \| `JUSTIF_ABS` \| Supporting document missing or insufficient \| \| `ROUTAGE_ERR` \| Routing error \| \| `AUTRE` \| Other reason; provide an explanation in `reasonNote` \| \| `COORD_BANC_ERR` \| Incorrect bank details \| \| `TX_TVA_ERR` \| Incorrect VAT rate \| \| `MONTANTTOTAL_ERR` \| Incorrect invoice total \| \| `CALCUL_ERR` \| Invoice calculation error \| \| `NON_CONFORME` \| Missing legal information \| \| `DOUBLON` \| Duplicate invoice \| \| `DEST_INC` \| Unknown recipient \| \| `DEST_ERR` \| Incorrect recipient \| \| `TRANSAC_INC` \| Unknown transaction \| \| `EMMET_INC` \| Unknown issuer \| \| `CONTRAT_TERM` \| Contract ended \| \| `DOUBLE_FACT` \| Supply or service already invoiced on another invoice \| \| `CMD_ERR` \| Incorrect or missing order number \| \| `ADR_ERR` \| Incorrect electronic invoicing address \| \| `SIRET_ERR` \| Incorrect or missing SIRET \| \| `CODE_ROUTAGE_ERR` \| Incorrect or missing routing code \| \| `REF_CT_ABSENT` \| Required contractual reference missing \| \| `REF_ERR` \| Incorrect reference \| \| `PU_ERR` \| Incorrect unit price \| \| `REM_ERR` \| Incorrect discount \| \| `QTE_ERR` \| Incorrect invoiced quantity \| \| `ART_ERR` \| Incorrect invoiced item \| \| `MODPAI_ERR` \| Incorrect payment terms \| \| `QUALITE_ERR` \| Incorrect quality of delivered item \| \| `LIVR_INCOMP` \| Incomplete or non-compliant delivery \| \| `REJ_SEMAN` \| Rejected because of a semantic error \| \| `REJ_UNI` \| Rejected by uniqueness control \| \| `REJ_COH` \| Rejected by data-consistency control \| \| `REJ_ADR` \| Rejected by addressing control \| \| `REJ_CONT_B2G` \| Rejected by B2G business controls \| \| `REJ_REF_PJ` \| Rejected because of an attachment-reference error \| \| `REJ_ASS_PJ` \| Rejected because of an attachment-association error \| \| `NON_TRANSMISE` \| Submitted but not transmitted because the recipient has no receiving platform \|. Values: `JUSTIF_ABS`, `ROUTAGE_ERR`, `AUTRE`, `COORD_BANC_ERR`, `TX_TVA_ERR`, `MONTANTTOTAL_ERR`, `CALCUL_ERR`, `NON_CONFORME`, `DOUBLON`, `DEST_INC`, `DEST_ERR`, `TRANSAC_INC`, `EMMET_INC`, `CONTRAT_TERM`, `DOUBLE_FACT`, `CMD_ERR`, `ADR_ERR`, `SIRET_ERR`, `CODE_ROUTAGE_ERR`, `REF_CT_ABSENT`, `REF_ERR`, `PU_ERR`, `REM_ERR`, `QTE_ERR`, `ART_ERR`, `MODPAI_ERR`, `QUALITE_ERR`, `LIVR_INCOMP`, `REJ_SEMAN`, `REJ_UNI`, `REJ_COH`, `REJ_ADR`, `REJ_CONT_B2G`, `REJ_REF_PJ`, `REJ_ASS_PJ`, `NON_TRANSMISE` | | `reason` | string | No | Optional free-text status reason. This is distinct from the IncludedNote explanation required for reasonCode AUTRE | | `reasonNote` | string | No | Free-text comment in the status detail IncludedNote. Required when reasonCode is AUTRE. Example: `"The invoice needs manual review."` | | `collectedAmounts` | object[] | No | Collected amounts with VAT rates (TypeCode MEN). Required for status 212; at least one entry | **`collectedAmounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `amount` | string | Yes | Net collected amount (positive) or disbursed amount (negative), for status 212. Example: `"12000.00"` | | `currency` | string (enum) | Yes | ISO 4217 currency code of the collected amount. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `vatPercent` | string | Yes | VAT rate applicable to the collected amount. Example: `"20.00"` | #### XML | Name | Type | Required | Description | |------|------|----------|-------------| | `recipient` | string \| null | Yes | The Peppol address of the recipient. If null, the document will be sent via email only (requires `email.to`). Example: `"0208:987654321"` | | `email` | object | No | Email delivery options. When Peppol recipient is provided, email is optional and you can choose to always send the email, or only when Peppol delivery fails. When Peppol recipient is null, email becomes the primary delivery method and `email.to` is required. Each sent email is counted towards your document quota | | `pdfGeneration` | object | No | Optionally generate a PDF of the document and include it as an embedded attachment (also included in email attachments when email sending is enabled). Not supported for message level responses, French Invoicing CDAR messages, or raw XML documents | | `doctypeId` | string | No | The document type identifier. For JSON documents it is selected automatically: the recipient is looked up and the document is sent as the first format, in our order of preference, the recipient is registered to receive it in, falling back to the standard Peppol BIS 3 UBL document type for the selected documentType. For raw XML documents it can be detected automatically where supported. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | No | Optional process identifier override. It is detected automatically for supported JSON and XML document types. For JSON documents the process the recipient is registered for is preferred, as far as the document itself leaves the choice open. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `documentType` | string | Yes | The type of document. Example: `"xml"`. Value: `xml` | | `document` | string | Yes | A complete Peppol UBL or CII document as a string. Set `doctypeId` yourself when it cannot be detected | **`email`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `when` | `always` \| `on_peppol_failure` | No | When to send the email. If the provided Peppol recipient is null, email becomes the primary delivery method and emails are always sent. Default: `on_peppol_failure`. Values: `always`, `on_peppol_failure` | | `to` | string[] | Yes | The email addresses to send the document to. Example: `["support@recommand.eu"]` | | `subject` | string | No | The subject of the email. If not provided, the subject will be autogenerated based on the document type. Example: `"Invoice SI-001"` | | `htmlBody` | string | No | The HTML body of the email. If not provided, the body will be autogenerated based on the document type. Example: `"Dear customer, you can find your invoice attached."` | **`pdfGeneration`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `enabled` | boolean | No | Whether to generate a PDF of the document and include it as an embedded attachment. Default: `false` | | `filename` | string | No | Optional filename to use for the generated PDF attachment. Defaults to a filename derived from the document number (e.g. invoice-001.pdf). Example: `"INV-2024-001.pdf"` | ## Responses ### 200 Successfully sent document | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `sentOverPeppol` | boolean | Yes | Whether the recipient's access point accepted the document over Peppol. False when the document could not be routed or the access point refused it, in which case it was delivered by email instead. Example: `true` | | `sentOverEmail` | boolean | Yes | Whether the document was also delivered by email. Email delivery happens when you configure it, either always or only as a fallback when Peppol delivery fails. Example: `false` | | `emailRecipients` | string[] | Yes | The email addresses the document was delivered to. Empty when it was not sent by email; an address the email failed for is left out. Example: `[]` | | `teamId` | string | Yes | The ID of the team the document was sent from. Example: `"team_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string | Yes | The ID of the company the document was sent for. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `id` | string | Yes | The Recommand document ID of the stored document. Use it with the documents endpoints to fetch, render or download what was sent. Example: `"doc_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `peppolMessageId` | string \| null | Yes | The AS4 message ID of the transmission. Null when the document was not transmitted over Peppol, and for playground teams, whose transmissions are simulated. Example: `"b7c2f0a4-3d1e-4a58-9c6d-0f2e8a1b4c73@recommand.eu"` | | `envelopeId` | string \| null | Yes | The envelope ID of the transmission, also known as the SBDH instance identifier (Standard Business Document Header Instance Identifier). Null when the document was not transmitted over Peppol, and for playground teams, whose transmissions are simulated. Example: `"9f1b3c7e-52a4-4d68-8b0f-6c9d2e4a17b5"` | ### 400 Invalid document data provided | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | | `invalidInputDetails` | object[] | No | Present when the request body or query did not match the schema | **`invalidInputDetails`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `path` | string | No | Dotted path of the field the message applies to | | `message` | string | No | | | `unionErrors` | object[][] | No | For a union of schemas, the failures of every variant, in the order the variants are declared | ### 422 Recipient could not be reached and no email fallback was configured or possible | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Generate Document `POST /api/v1/{companyId}/generate` Generate the XML document that would be written for the given payload, without sending or storing it. Accepts the same body as the send document endpoint, minus the email delivery options and the raw XML document type. The document type identifier and process are resolved against the recipient exactly as they are when sending, so leaving them out returns the document written as the format the recipient is registered to receive; naming both yourself skips that lookup, again exactly as sending does. This endpoint does not check that the recipient can receive the document. The generated document is validated exactly as it is when sending. Documents generated through this endpoint do not count towards your Recommand subscription usage. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company the document is generated for. Its Peppol identifier is written into the document as the sender. | ## Request Body **One of:** #### Invoice | Name | Type | Required | Description | |------|------|----------|-------------| | `recipient` | string | Yes | The Peppol address of the recipient the document is generated for. Example: `"0208:987654321"` | | `pdfGeneration` | object | No | Optionally generate a PDF of the document and include it as an embedded attachment (also included in email attachments when email sending is enabled). Not supported for message level responses, French Invoicing CDAR messages, or raw XML documents | | `doctypeId` | string | No | The document type identifier. For JSON documents it is selected automatically: the recipient is looked up and the document is sent as the first format, in our order of preference, the recipient is registered to receive it in, falling back to the standard Peppol BIS 3 UBL document type for the selected documentType. For raw XML documents it can be detected automatically where supported. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | No | Optional process identifier override. It is detected automatically for supported JSON and XML document types. For JSON documents the process the recipient is registered for is preferred, as far as the document itself leaves the choice open. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `documentType` | string | Yes | The type of document. Example: `"invoice"`. Value: `invoice` | | `document` | object | Yes | Invoice to send to a recipient | **`pdfGeneration`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `enabled` | boolean | No | Whether to generate a PDF of the document and include it as an embedded attachment. Default: `false` | | `filename` | string | No | Optional filename to use for the generated PDF attachment. Defaults to a filename derived from the document number (e.g. invoice-001.pdf). Example: `"INV-2024-001.pdf"` | **`document`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `invoiceNumber` | string | Yes | The number the seller assigned to the invoice. Example: `"INV-2024-001"` | | `issueDate` | string \| null | No | If not provided, the issue date will be the current date. Example: `"2024-03-20"`. Format: date | | `dueDate` | string \| null | No | If not provided, the due date will be 1 month from the issue date. Example: `"2024-04-20"`. Format: date | | `note` | string \| null | No | A free text note about the invoice as a whole. Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | A reference the buyer asked you to put on the invoice so they can route it internally. If neither this nor `purchaseOrderReference` is provided, the invoice number is used. Example: `"PO-2024-001"` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | `seller` | Party | null | No | If not provided, the seller will be the company that is sending the invoice | | `buyer` | object | Yes | | | `delivery` | Delivery | null | No | Optional delivery information | | `paymentMeans` | object[] \| null | No | Optional payment information. For most invoices, this should be provided. For prepaid invoices, this could be omitted | | `paymentTerms` | object \| null | No | Optional payment terms | | `lines` | object[] | Yes | The invoice lines. At least one line is required. Min items: 1 | | `discounts` | object[] \| null | No | Optional global discounts | | `surcharges` | object[] \| null | No | Optional global surcharges | | `totals` | Totals | null | No | | | `vat` | Provided VAT totals | VAT totals auto calculation | null | No | If not provided, the VAT totals will be calculated from the document lines | | `attachments` | object[] \| null | No | Optional attachments to the invoice | | `currency` | string (enum) | No | The currency of the invoice. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `countrySpecific` | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | **`seller`** (One of): #### Party | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | #### Variant 2 Type: `null` **`buyer`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`delivery`** (One of): #### Delivery | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | `locationIdentifier` | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | `location` | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | **`locationIdentifier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | **`location`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | #### Variant 2 Type: `null` **`paymentMeans`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | **`paymentTerms`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | The payment terms as free text. Example: `"Net 30"` | **`lines`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | `standardId` | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | `commodityClassifications` | object[] \| null | No | Optional commodity classifications | | `additionalItemProperties` | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | `discounts` | object[] \| null | No | Optional discounts for the line | | `surcharges` | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | `vat` | object | Yes | | **`standardId`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | **`commodityClassifications`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | **`additionalItemProperties`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`totals`** (One of): #### Totals | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | #### Variant 2 Type: `null` **`vat`** (Any of): #### Provided VAT totals | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | `subtotals` | object[] | Yes | One entry for every combination of VAT category and rate used in the document | **`subtotals`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### VAT totals auto calculation | Name | Type | Required | Description | |------|------|----------|-------------| | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### Variant 3 Type: `null` **`attachments`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | **`countrySpecific`** (One of): #### Country Specific Billing **One of:** #### French Country Specific Billing | Name | Type | Required | Description | |------|------|----------|-------------| | `country` | string | Yes | Identifies this as the French regulatory extension. This is independent from seller, buyer, delivery, and origin country codes. Value: `FR` | | `billingMode` | string (enum) | Yes | Required only for French regulated UBL, CII, and Factur-X. Select the invoicing framework that matches the invoice. \| Mode \| Description \| \| --- \| --- \| \| `B1` \| Goods invoice. \| \| `S1` \| Services invoice. \| \| `M1` \| Mixed invoice containing goods and services that are not ancillary to each other. \| \| `B2` \| Goods invoice that has already been paid. \| \| `S2` \| Services invoice that has already been paid. \| \| `M2` \| Mixed invoice that has already been paid. \| \| `S3` \| B2G subcontractor payment request with direct payment. \| \| `B4` \| Final goods invoice after an advance payment. \| \| `S4` \| Final services invoice after an advance payment. \| \| `M4` \| Final mixed invoice after an advance payment. \| \| `S5` \| Invoice submitted by a subcontractor for services rendered. \| \| `S6` \| Invoice submitted by a co-contractor for services rendered. \| \| `B7` \| Goods invoice that has already been e-reported and for which VAT has already been collected. \| \| `S7` \| Services invoice that has already been e-reported and for which VAT has already been collected. \| \| `B8` \| Multi-seller goods invoice. \| \| `S8` \| Multi-seller services invoice. \| \| `M8` \| Multi-seller mixed invoice whose individual invoices are not all goods invoices or all services invoices. \| . Example: `"S1"`. Values: `B1`, `S1`, `M1`, `B2`, `S2`, `M2`, `S3`, `B4`, `S4`, `M4`, `S5`, `S6`, `B7`, `S7`, `B8`, `S8`, `M8`, `B9`, `S9`, `M9` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` | No | Determines which French Peppol process the document is sent over. Defaults to `REGULATED`. \| Value \| Description \| \| --- \| --- \| \| `REGULATED` \| Transaction inside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:regulated`. \| \| `NON_REGULATED` \| Transaction outside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:non-regulated`. \| The recipient must have registered the matching process for the document type in its SMP. Default: `REGULATED`. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED` | | `recoveryCostsNote` | string | Yes | The mandatory French recovery-cost indemnity statement, written as an IncludedNote with subject code PMT. Example: `"Indemnite forfaitaire de 40 EUR pour frais de recouvrement."` | | `latePaymentPenaltiesNote` | string | Yes | The mandatory French late-payment penalties statement, written as an IncludedNote with subject code PMD. Example: `"Penalites de retard exigibles au taux prevu dans les conditions generales de vente."` | | `earlyPaymentDiscountNote` | string | Yes | The mandatory French early-payment discount statement, written as an IncludedNote with subject code AAB. State either the offered discount terms or explicitly that no early-payment discount applies. Example: `"Aucun escompte accorde pour paiement anticipe."` | #### Variant 2 Type: `null` #### Credit Note | Name | Type | Required | Description | |------|------|----------|-------------| | `recipient` | string | Yes | The Peppol address of the recipient the document is generated for. Example: `"0208:987654321"` | | `pdfGeneration` | object | No | Optionally generate a PDF of the document and include it as an embedded attachment (also included in email attachments when email sending is enabled). Not supported for message level responses, French Invoicing CDAR messages, or raw XML documents | | `doctypeId` | string | No | The document type identifier. For JSON documents it is selected automatically: the recipient is looked up and the document is sent as the first format, in our order of preference, the recipient is registered to receive it in, falling back to the standard Peppol BIS 3 UBL document type for the selected documentType. For raw XML documents it can be detected automatically where supported. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | No | Optional process identifier override. It is detected automatically for supported JSON and XML document types. For JSON documents the process the recipient is registered for is preferred, as far as the document itself leaves the choice open. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `documentType` | string | Yes | The type of document. Example: `"creditNote"`. Value: `creditNote` | | `document` | object | Yes | Credit note to send to a recipient | **`pdfGeneration`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `enabled` | boolean | No | Whether to generate a PDF of the document and include it as an embedded attachment. Default: `false` | | `filename` | string | No | Optional filename to use for the generated PDF attachment. Defaults to a filename derived from the document number (e.g. invoice-001.pdf). Example: `"INV-2024-001.pdf"` | **`document`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `creditNoteNumber` | string | Yes | Example: `"CN-2024-001"` | | `issueDate` | string \| null | No | If not provided, the issue date will be the current date. Example: `"2024-03-20"`. Format: date | | `note` | string \| null | No | Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | Example: `"PO-2024-001"` | | `invoiceReferences` | object[] | No | References to one or more invoices that are being credited. Default: `` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | `seller` | Party | null | No | If not provided, the seller will be the company that is sending the credit note | | `buyer` | object | Yes | | | `delivery` | Delivery | null | No | Optional delivery information | | `paymentMeans` | object[] \| null | No | | | `paymentTerms` | object \| null | No | | | `lines` | object[] | Yes | Min items: 1 | | `discounts` | object[] \| null | No | Optional global discounts | | `surcharges` | object[] \| null | No | Optional global surcharges | | `totals` | Totals | null | No | | | `vat` | Provided VAT totals | VAT totals auto calculation | null | No | If not provided, the VAT totals will be calculated from the document lines | | `attachments` | object[] \| null | No | Optional attachments to the credit note | | `currency` | string (enum) | No | The currency of the credit note. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `countrySpecific` | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | | `dueDate` | string \| null | No | If not provided, the due date will be 1 month from the issue date. Example: `"2024-04-20"`. Format: date | **`invoiceReferences`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The reference to the invoice that is being credited. Example: `"INV-2024-001"` | | `issueDate` | string \| null | No | The issue date of the invoice that is being credited. Example: `"2024-03-20"`. Format: date | **`seller`** (One of): #### Party | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | #### Variant 2 Type: `null` **`buyer`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`delivery`** (One of): #### Delivery | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | `locationIdentifier` | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | `location` | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | **`locationIdentifier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | **`location`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | #### Variant 2 Type: `null` **`paymentMeans`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | **`paymentTerms`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | Example: `"Net 30"` | **`lines`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | `standardId` | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | `commodityClassifications` | object[] \| null | No | Optional commodity classifications | | `additionalItemProperties` | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | `discounts` | object[] \| null | No | Optional discounts for the line | | `surcharges` | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | `vat` | object | Yes | | **`standardId`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | **`commodityClassifications`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | **`additionalItemProperties`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`totals`** (One of): #### Totals | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | #### Variant 2 Type: `null` **`vat`** (Any of): #### Provided VAT totals | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | `subtotals` | object[] | Yes | One entry for every combination of VAT category and rate used in the document | **`subtotals`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### VAT totals auto calculation | Name | Type | Required | Description | |------|------|----------|-------------| | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### Variant 3 Type: `null` **`attachments`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | **`countrySpecific`** (One of): #### Country Specific Billing **One of:** #### French Country Specific Billing | Name | Type | Required | Description | |------|------|----------|-------------| | `country` | string | Yes | Identifies this as the French regulatory extension. This is independent from seller, buyer, delivery, and origin country codes. Value: `FR` | | `billingMode` | string (enum) | Yes | Required only for French regulated UBL, CII, and Factur-X. Select the invoicing framework that matches the invoice. \| Mode \| Description \| \| --- \| --- \| \| `B1` \| Goods invoice. \| \| `S1` \| Services invoice. \| \| `M1` \| Mixed invoice containing goods and services that are not ancillary to each other. \| \| `B2` \| Goods invoice that has already been paid. \| \| `S2` \| Services invoice that has already been paid. \| \| `M2` \| Mixed invoice that has already been paid. \| \| `S3` \| B2G subcontractor payment request with direct payment. \| \| `B4` \| Final goods invoice after an advance payment. \| \| `S4` \| Final services invoice after an advance payment. \| \| `M4` \| Final mixed invoice after an advance payment. \| \| `S5` \| Invoice submitted by a subcontractor for services rendered. \| \| `S6` \| Invoice submitted by a co-contractor for services rendered. \| \| `B7` \| Goods invoice that has already been e-reported and for which VAT has already been collected. \| \| `S7` \| Services invoice that has already been e-reported and for which VAT has already been collected. \| \| `B8` \| Multi-seller goods invoice. \| \| `S8` \| Multi-seller services invoice. \| \| `M8` \| Multi-seller mixed invoice whose individual invoices are not all goods invoices or all services invoices. \| . Example: `"S1"`. Values: `B1`, `S1`, `M1`, `B2`, `S2`, `M2`, `S3`, `B4`, `S4`, `M4`, `S5`, `S6`, `B7`, `S7`, `B8`, `S8`, `M8`, `B9`, `S9`, `M9` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` | No | Determines which French Peppol process the document is sent over. Defaults to `REGULATED`. \| Value \| Description \| \| --- \| --- \| \| `REGULATED` \| Transaction inside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:regulated`. \| \| `NON_REGULATED` \| Transaction outside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:non-regulated`. \| The recipient must have registered the matching process for the document type in its SMP. Default: `REGULATED`. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED` | | `recoveryCostsNote` | string | Yes | The mandatory French recovery-cost indemnity statement, written as an IncludedNote with subject code PMT. Example: `"Indemnite forfaitaire de 40 EUR pour frais de recouvrement."` | | `latePaymentPenaltiesNote` | string | Yes | The mandatory French late-payment penalties statement, written as an IncludedNote with subject code PMD. Example: `"Penalites de retard exigibles au taux prevu dans les conditions generales de vente."` | | `earlyPaymentDiscountNote` | string | Yes | The mandatory French early-payment discount statement, written as an IncludedNote with subject code AAB. State either the offered discount terms or explicitly that no early-payment discount applies. Example: `"Aucun escompte accorde pour paiement anticipe."` | #### Variant 2 Type: `null` #### Self Billing Invoice | Name | Type | Required | Description | |------|------|----------|-------------| | `recipient` | string | Yes | The Peppol address of the recipient the document is generated for. Example: `"0208:987654321"` | | `pdfGeneration` | object | No | Optionally generate a PDF of the document and include it as an embedded attachment (also included in email attachments when email sending is enabled). Not supported for message level responses, French Invoicing CDAR messages, or raw XML documents | | `doctypeId` | string | No | The document type identifier. For JSON documents it is selected automatically: the recipient is looked up and the document is sent as the first format, in our order of preference, the recipient is registered to receive it in, falling back to the standard Peppol BIS 3 UBL document type for the selected documentType. For raw XML documents it can be detected automatically where supported. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | No | Optional process identifier override. It is detected automatically for supported JSON and XML document types. For JSON documents the process the recipient is registered for is preferred, as far as the document itself leaves the choice open. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `documentType` | string | Yes | The type of document. Example: `"selfBillingInvoice"`. Value: `selfBillingInvoice` | | `document` | object | Yes | Self billing invoice to send to a recipient | **`pdfGeneration`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `enabled` | boolean | No | Whether to generate a PDF of the document and include it as an embedded attachment. Default: `false` | | `filename` | string | No | Optional filename to use for the generated PDF attachment. Defaults to a filename derived from the document number (e.g. invoice-001.pdf). Example: `"INV-2024-001.pdf"` | **`document`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `invoiceNumber` | string | Yes | The number the seller assigned to the invoice. Example: `"INV-2024-001"` | | `issueDate` | string \| null | No | If not provided, the issue date will be the current date. Example: `"2024-03-20"`. Format: date | | `dueDate` | string \| null | No | If not provided, the due date will be 1 month from the issue date. Example: `"2024-04-20"`. Format: date | | `note` | string \| null | No | A free text note about the invoice as a whole. Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | A reference the buyer asked you to put on the invoice so they can route it internally. If neither this nor `purchaseOrderReference` is provided, the invoice number is used. Example: `"PO-2024-001"` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | `seller` | object | Yes | | | `buyer` | Party | null | No | If not provided, the buyer will be the company that is sending the self billing invoice | | `delivery` | Delivery | null | No | Optional delivery information | | `paymentMeans` | object[] \| null | No | Optional payment information. For most invoices, this should be provided. For prepaid invoices, this could be omitted | | `paymentTerms` | object \| null | No | Optional payment terms | | `lines` | object[] | Yes | The invoice lines. At least one line is required. Min items: 1 | | `discounts` | object[] \| null | No | Optional global discounts | | `surcharges` | object[] \| null | No | Optional global surcharges | | `totals` | Totals | null | No | | | `vat` | Provided VAT totals | VAT totals auto calculation | null | No | If not provided, the VAT totals will be calculated from the document lines | | `attachments` | object[] \| null | No | Optional attachments to the invoice | | `currency` | string (enum) | No | The currency of the invoice. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `countrySpecific` | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | **`seller`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`buyer`** (One of): #### Party | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | #### Variant 2 Type: `null` **`delivery`** (One of): #### Delivery | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | `locationIdentifier` | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | `location` | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | **`locationIdentifier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | **`location`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | #### Variant 2 Type: `null` **`paymentMeans`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | **`paymentTerms`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | The payment terms as free text. Example: `"Net 30"` | **`lines`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | `standardId` | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | `commodityClassifications` | object[] \| null | No | Optional commodity classifications | | `additionalItemProperties` | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | `discounts` | object[] \| null | No | Optional discounts for the line | | `surcharges` | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | `vat` | object | Yes | | **`standardId`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | **`commodityClassifications`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | **`additionalItemProperties`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`totals`** (One of): #### Totals | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | #### Variant 2 Type: `null` **`vat`** (Any of): #### Provided VAT totals | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | `subtotals` | object[] | Yes | One entry for every combination of VAT category and rate used in the document | **`subtotals`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### VAT totals auto calculation | Name | Type | Required | Description | |------|------|----------|-------------| | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### Variant 3 Type: `null` **`attachments`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | **`countrySpecific`** (One of): #### Country Specific Billing **One of:** #### French Country Specific Billing | Name | Type | Required | Description | |------|------|----------|-------------| | `country` | string | Yes | Identifies this as the French regulatory extension. This is independent from seller, buyer, delivery, and origin country codes. Value: `FR` | | `billingMode` | string (enum) | Yes | Required only for French regulated UBL, CII, and Factur-X. Select the invoicing framework that matches the invoice. \| Mode \| Description \| \| --- \| --- \| \| `B1` \| Goods invoice. \| \| `S1` \| Services invoice. \| \| `M1` \| Mixed invoice containing goods and services that are not ancillary to each other. \| \| `B2` \| Goods invoice that has already been paid. \| \| `S2` \| Services invoice that has already been paid. \| \| `M2` \| Mixed invoice that has already been paid. \| \| `S3` \| B2G subcontractor payment request with direct payment. \| \| `B4` \| Final goods invoice after an advance payment. \| \| `S4` \| Final services invoice after an advance payment. \| \| `M4` \| Final mixed invoice after an advance payment. \| \| `S5` \| Invoice submitted by a subcontractor for services rendered. \| \| `S6` \| Invoice submitted by a co-contractor for services rendered. \| \| `B7` \| Goods invoice that has already been e-reported and for which VAT has already been collected. \| \| `S7` \| Services invoice that has already been e-reported and for which VAT has already been collected. \| \| `B8` \| Multi-seller goods invoice. \| \| `S8` \| Multi-seller services invoice. \| \| `M8` \| Multi-seller mixed invoice whose individual invoices are not all goods invoices or all services invoices. \| . Example: `"S1"`. Values: `B1`, `S1`, `M1`, `B2`, `S2`, `M2`, `S3`, `B4`, `S4`, `M4`, `S5`, `S6`, `B7`, `S7`, `B8`, `S8`, `M8`, `B9`, `S9`, `M9` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` | No | Determines which French Peppol process the document is sent over. Defaults to `REGULATED`. \| Value \| Description \| \| --- \| --- \| \| `REGULATED` \| Transaction inside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:regulated`. \| \| `NON_REGULATED` \| Transaction outside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:non-regulated`. \| The recipient must have registered the matching process for the document type in its SMP. Default: `REGULATED`. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED` | | `recoveryCostsNote` | string | Yes | The mandatory French recovery-cost indemnity statement, written as an IncludedNote with subject code PMT. Example: `"Indemnite forfaitaire de 40 EUR pour frais de recouvrement."` | | `latePaymentPenaltiesNote` | string | Yes | The mandatory French late-payment penalties statement, written as an IncludedNote with subject code PMD. Example: `"Penalites de retard exigibles au taux prevu dans les conditions generales de vente."` | | `earlyPaymentDiscountNote` | string | Yes | The mandatory French early-payment discount statement, written as an IncludedNote with subject code AAB. State either the offered discount terms or explicitly that no early-payment discount applies. Example: `"Aucun escompte accorde pour paiement anticipe."` | #### Variant 2 Type: `null` #### Self Billing Credit Note | Name | Type | Required | Description | |------|------|----------|-------------| | `recipient` | string | Yes | The Peppol address of the recipient the document is generated for. Example: `"0208:987654321"` | | `pdfGeneration` | object | No | Optionally generate a PDF of the document and include it as an embedded attachment (also included in email attachments when email sending is enabled). Not supported for message level responses, French Invoicing CDAR messages, or raw XML documents | | `doctypeId` | string | No | The document type identifier. For JSON documents it is selected automatically: the recipient is looked up and the document is sent as the first format, in our order of preference, the recipient is registered to receive it in, falling back to the standard Peppol BIS 3 UBL document type for the selected documentType. For raw XML documents it can be detected automatically where supported. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | No | Optional process identifier override. It is detected automatically for supported JSON and XML document types. For JSON documents the process the recipient is registered for is preferred, as far as the document itself leaves the choice open. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `documentType` | string | Yes | The type of document. Example: `"selfBillingCreditNote"`. Value: `selfBillingCreditNote` | | `document` | object | Yes | Self billing credit note to send to a recipient | **`pdfGeneration`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `enabled` | boolean | No | Whether to generate a PDF of the document and include it as an embedded attachment. Default: `false` | | `filename` | string | No | Optional filename to use for the generated PDF attachment. Defaults to a filename derived from the document number (e.g. invoice-001.pdf). Example: `"INV-2024-001.pdf"` | **`document`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `creditNoteNumber` | string | Yes | Example: `"CN-2024-001"` | | `issueDate` | string \| null | No | If not provided, the issue date will be the current date. Example: `"2024-03-20"`. Format: date | | `note` | string \| null | No | Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | Example: `"PO-2024-001"` | | `invoiceReferences` | object[] | No | References to one or more invoices that are being credited. Default: `` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | `seller` | object | Yes | | | `buyer` | Party | null | No | If not provided, the buyer will be the company that is sending the self billing credit note | | `delivery` | Delivery | null | No | Optional delivery information | | `paymentMeans` | object[] \| null | No | | | `paymentTerms` | object \| null | No | | | `lines` | object[] | Yes | Min items: 1 | | `discounts` | object[] \| null | No | Optional global discounts | | `surcharges` | object[] \| null | No | Optional global surcharges | | `totals` | Totals | null | No | | | `vat` | Provided VAT totals | VAT totals auto calculation | null | No | If not provided, the VAT totals will be calculated from the document lines | | `attachments` | object[] \| null | No | Optional attachments to the credit note | | `currency` | string (enum) | No | The currency of the credit note. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `countrySpecific` | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | | `dueDate` | string \| null | No | If not provided, the due date will be 1 month from the issue date. Example: `"2024-04-20"`. Format: date | **`invoiceReferences`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The reference to the invoice that is being credited. Example: `"INV-2024-001"` | | `issueDate` | string \| null | No | The issue date of the invoice that is being credited. Example: `"2024-03-20"`. Format: date | **`seller`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`buyer`** (One of): #### Party | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | #### Variant 2 Type: `null` **`delivery`** (One of): #### Delivery | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | `locationIdentifier` | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | `location` | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | **`locationIdentifier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | **`location`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | #### Variant 2 Type: `null` **`paymentMeans`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | **`paymentTerms`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | Example: `"Net 30"` | **`lines`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | `standardId` | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | `commodityClassifications` | object[] \| null | No | Optional commodity classifications | | `additionalItemProperties` | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | `discounts` | object[] \| null | No | Optional discounts for the line | | `surcharges` | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | `vat` | object | Yes | | **`standardId`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | **`commodityClassifications`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | **`additionalItemProperties`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`totals`** (One of): #### Totals | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | #### Variant 2 Type: `null` **`vat`** (Any of): #### Provided VAT totals | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | `subtotals` | object[] | Yes | One entry for every combination of VAT category and rate used in the document | **`subtotals`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### VAT totals auto calculation | Name | Type | Required | Description | |------|------|----------|-------------| | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### Variant 3 Type: `null` **`attachments`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | **`countrySpecific`** (One of): #### Country Specific Billing **One of:** #### French Country Specific Billing | Name | Type | Required | Description | |------|------|----------|-------------| | `country` | string | Yes | Identifies this as the French regulatory extension. This is independent from seller, buyer, delivery, and origin country codes. Value: `FR` | | `billingMode` | string (enum) | Yes | Required only for French regulated UBL, CII, and Factur-X. Select the invoicing framework that matches the invoice. \| Mode \| Description \| \| --- \| --- \| \| `B1` \| Goods invoice. \| \| `S1` \| Services invoice. \| \| `M1` \| Mixed invoice containing goods and services that are not ancillary to each other. \| \| `B2` \| Goods invoice that has already been paid. \| \| `S2` \| Services invoice that has already been paid. \| \| `M2` \| Mixed invoice that has already been paid. \| \| `S3` \| B2G subcontractor payment request with direct payment. \| \| `B4` \| Final goods invoice after an advance payment. \| \| `S4` \| Final services invoice after an advance payment. \| \| `M4` \| Final mixed invoice after an advance payment. \| \| `S5` \| Invoice submitted by a subcontractor for services rendered. \| \| `S6` \| Invoice submitted by a co-contractor for services rendered. \| \| `B7` \| Goods invoice that has already been e-reported and for which VAT has already been collected. \| \| `S7` \| Services invoice that has already been e-reported and for which VAT has already been collected. \| \| `B8` \| Multi-seller goods invoice. \| \| `S8` \| Multi-seller services invoice. \| \| `M8` \| Multi-seller mixed invoice whose individual invoices are not all goods invoices or all services invoices. \| . Example: `"S1"`. Values: `B1`, `S1`, `M1`, `B2`, `S2`, `M2`, `S3`, `B4`, `S4`, `M4`, `S5`, `S6`, `B7`, `S7`, `B8`, `S8`, `M8`, `B9`, `S9`, `M9` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` | No | Determines which French Peppol process the document is sent over. Defaults to `REGULATED`. \| Value \| Description \| \| --- \| --- \| \| `REGULATED` \| Transaction inside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:regulated`. \| \| `NON_REGULATED` \| Transaction outside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:non-regulated`. \| The recipient must have registered the matching process for the document type in its SMP. Default: `REGULATED`. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED` | | `recoveryCostsNote` | string | Yes | The mandatory French recovery-cost indemnity statement, written as an IncludedNote with subject code PMT. Example: `"Indemnite forfaitaire de 40 EUR pour frais de recouvrement."` | | `latePaymentPenaltiesNote` | string | Yes | The mandatory French late-payment penalties statement, written as an IncludedNote with subject code PMD. Example: `"Penalites de retard exigibles au taux prevu dans les conditions generales de vente."` | | `earlyPaymentDiscountNote` | string | Yes | The mandatory French early-payment discount statement, written as an IncludedNote with subject code AAB. State either the offered discount terms or explicitly that no early-payment discount applies. Example: `"Aucun escompte accorde pour paiement anticipe."` | #### Variant 2 Type: `null` #### Message Level Response | Name | Type | Required | Description | |------|------|----------|-------------| | `recipient` | string | Yes | The Peppol address of the recipient the document is generated for. Example: `"0208:987654321"` | | `pdfGeneration` | object | No | Optionally generate a PDF of the document and include it as an embedded attachment (also included in email attachments when email sending is enabled). Not supported for message level responses, French Invoicing CDAR messages, or raw XML documents | | `doctypeId` | string | No | The document type identifier. For JSON documents it is selected automatically: the recipient is looked up and the document is sent as the first format, in our order of preference, the recipient is registered to receive it in, falling back to the standard Peppol BIS 3 UBL document type for the selected documentType. For raw XML documents it can be detected automatically where supported. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | No | Optional process identifier override. It is detected automatically for supported JSON and XML document types. For JSON documents the process the recipient is registered for is preferred, as far as the document itself leaves the choice open. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `documentType` | string | Yes | The type of document. Example: `"messageLevelResponse"`. Value: `messageLevelResponse` | | `document` | object | Yes | Message Level Response to send to a recipient | **`pdfGeneration`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `enabled` | boolean | No | Whether to generate a PDF of the document and include it as an embedded attachment. Default: `false` | | `filename` | string | No | Optional filename to use for the generated PDF attachment. Defaults to a filename derived from the document number (e.g. invoice-001.pdf). Example: `"INV-2024-001.pdf"` | **`document`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | No | The ID of the message level response. If not provided, the ID will be autogenerated | | `issueDate` | string (date) | No | If not provided, the issue date will be the current date. Example: `"2024-03-20"`. Format: date | | `responseCode` | `AB` \| `AP` \| `RE` | Yes | The response code of the message level response (AB: Message acknowledgement, AP: Accepted, RE: Rejected). Example: `"AB"`. Values: `AB`, `AP`, `RE` | | `envelopeId` | string | Yes | Identifies the document on which the message level response is based | #### French Invoicing CDAR | Name | Type | Required | Description | |------|------|----------|-------------| | `recipient` | string | Yes | The Peppol address of the recipient the document is generated for. Example: `"0208:987654321"` | | `pdfGeneration` | object | No | Optionally generate a PDF of the document and include it as an embedded attachment (also included in email attachments when email sending is enabled). Not supported for message level responses, French Invoicing CDAR messages, or raw XML documents | | `doctypeId` | string | No | The document type identifier. For JSON documents it is selected automatically: the recipient is looked up and the document is sent as the first format, in our order of preference, the recipient is registered to receive it in, falling back to the standard Peppol BIS 3 UBL document type for the selected documentType. For raw XML documents it can be detected automatically where supported. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | No | Optional process identifier override. It is detected automatically for supported JSON and XML document types. For JSON documents the process the recipient is registered for is preferred, as far as the document itself leaves the choice open. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `documentType` | string | Yes | The type of document. Example: `"frenchInvoicingCdar"`. Value: `frenchInvoicingCdar` | | `document` | object | Yes | French invoice lifecycle status to send. The recipient electronic address is derived from the top-level Peppol recipient | **`pdfGeneration`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `enabled` | boolean | No | Whether to generate a PDF of the document and include it as an embedded attachment. Default: `false` | | `filename` | string | No | Optional filename to use for the generated PDF attachment. Defaults to a filename derived from the document number (e.g. invoice-001.pdf). Example: `"INV-2024-001.pdf"` | **`document`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | No | The ID of the CDAR. If not provided, the ID will be autogenerated | | `issueDate` | string (date-time) | No | If not provided, the issue date and time will be the current local date and time. Example: `"2024-03-20T14:05:09"`. Format: date-time | | `businessProcess` | `REGULATED` \| `NON_REGULATED` \| `B2C` \| `B2CINT` \| `B2BINT` \| `OUTOFSCOPE` | Yes | Flow classification. \| Value \| Meaning \| \| --- \| --- \| \| `REGULATED` \| Regulated French domestic e-invoicing \| \| `NON_REGULATED` \| Outside the regulated French e-invoicing perimeter \| \| `B2C` \| B2C sales e-reporting \| \| `B2CINT` \| International B2C sales e-reporting \| \| `B2BINT` \| International B2B sales e-reporting \| \| `OUTOFSCOPE` \| Outside the French e-invoicing and e-reporting reform \|. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED`, `B2C`, `B2CINT`, `B2BINT`, `OUTOFSCOPE` | | `phase` | `23` \| `305` | No | CDAR phase. \| Value \| Meaning \| \| --- \| --- \| \| `23` \| Processing phase \| \| `305` \| Transmission phase \| Defaults to `305` for statuses `200`, `201`, `202`, `203`, `213`, and `501`; otherwise defaults to `23`. Example: `"23"`. Values: `23`, `305` | | `senderRole` | string (enum) | Yes | Role of the CDAR sender. CDAR party role code (UNCL 3035). \| Value \| Meaning \| \| --- \| --- \| \| `BY` \| Buyer \| \| `AB` \| Buyer's agent or representative \| \| `DL` \| Factor \| \| `SE` \| Seller \| \| `SR` \| Seller's agent \| \| `WK` \| Platform or dematerialisation operator \| \| `DFH` \| French public invoicing portal (PPF) \| \| `PE` \| Payee \| \| `PR` \| Payer \| \| `II` \| Invoicer (invoice issuer) \| \| `IV` \| Invoicee (party invoiced) \|. Example: `"WK"`. Values: `BY`, `AB`, `DL`, `SE`, `SR`, `WK`, `DFH`, `PE`, `PR`, `II`, `IV` | | `issuerRole` | string (enum) | Yes | Role of the party that creates and issues the invoice lifecycle status. This is independent from the CDAR sender role. CDAR party role code (UNCL 3035). \| Value \| Meaning \| \| --- \| --- \| \| `BY` \| Buyer \| \| `AB` \| Buyer's agent or representative \| \| `DL` \| Factor \| \| `SE` \| Seller \| \| `SR` \| Seller's agent \| \| `WK` \| Platform or dematerialisation operator \| \| `DFH` \| French public invoicing portal (PPF) \| \| `PE` \| Payee \| \| `PR` \| Payer \| \| `II` \| Invoicer (invoice issuer) \| \| `IV` \| Invoicee (party invoiced) \|. Example: `"BY"`. Values: `BY`, `AB`, `DL`, `SE`, `SR`, `WK`, `DFH`, `PE`, `PR`, `II`, `IV` | | `issuerLegalId` | string | No | Legal identifier of the party setting the status. Required when phase is 23; must be omitted when phase is 305 unless recipientRole is DFH. Example: `"200000008"` | | `issuerLegalIdScheme` | string | No | ISO 6523 ICD scheme of the party-setting-status legal identifier. Required together with issuerLegalId. Example: `"0002"` | | `recipientRole` | string (enum) | Yes | Role of the CDAR recipient. CDAR party role code (UNCL 3035). \| Value \| Meaning \| \| --- \| --- \| \| `BY` \| Buyer \| \| `AB` \| Buyer's agent or representative \| \| `DL` \| Factor \| \| `SE` \| Seller \| \| `SR` \| Seller's agent \| \| `WK` \| Platform or dematerialisation operator \| \| `DFH` \| French public invoicing portal (PPF) \| \| `PE` \| Payee \| \| `PR` \| Payer \| \| `II` \| Invoicer (invoice issuer) \| \| `IV` \| Invoicee (party invoiced) \|. Example: `"SE"`. Values: `BY`, `AB`, `DL`, `SE`, `SR`, `WK`, `DFH`, `PE`, `PR`, `II`, `IV` | | `recipientLegalId` | string | No | Legal identifier of the CDAR recipient. Example: `"200000008"` | | `recipientLegalIdScheme` | string | No | ISO 6523 ICD scheme of the CDAR recipient legal identifier. Required together with recipientLegalId. Example: `"0002"` | | `statusCode` | string (enum) | Yes | French invoice lifecycle status. \| Value \| Meaning \| \| --- \| --- \| \| `200` \| Submitted \| \| `201` \| Issued \| \| `202` \| Received \| \| `203` \| Made available \| \| `204` \| Taken in charge (processing started) \| \| `205` \| Approved \| \| `206` \| Partially approved \| \| `207` \| In dispute \| \| `208` \| Suspended \| \| `209` \| Completed \| \| `210` \| Refused \| \| `211` \| Payment sent \| \| `212` \| Collected (cashed) \| \| `213` \| Rejected \| \| `214` \| Validated or pre-validated ("Visée") \| \| `501` \| Inadmissible file \|. Example: `"200"`. Values: `200`, `201`, `202`, `203`, `204`, `205`, `206`, `207`, `208`, `209`, `210`, `211`, `212`, `213`, `214`, `501` | | `statusDate` | string (date-time) | No | Date and time at which the status was set. If not provided, the issue date and time of the CDAR is used. Example: `"2024-03-20T14:05:09"`. Format: date-time | | `invoiceId` | string | Yes | Number of the invoice this status relates to. For status 501, this is the filename of the inadmissible file | | `invoiceTypeCode` | string (enum) | No | Type of the referenced invoice. Type of the referenced invoice (UNTDID 1001, restricted to the values allowed by BR-FR-04). \| Value \| Meaning \| \| --- \| --- \| \| `380` \| Commercial invoice \| \| `389` \| Self-billed invoice \| \| `393` \| Factored invoice \| \| `501` \| Self-billed factored invoice \| \| `386` \| Advance payment invoice \| \| `500` \| Self-billed advance payment invoice \| \| `384` \| Corrective invoice \| \| `471` \| Self-billed corrective invoice \| \| `472` \| Factored corrective invoice \| \| `473` \| Self-billed factored corrective invoice \| \| `261` \| Self-billed credit note \| \| `262` \| Global rebate credit note \| \| `381` \| Credit note \| \| `396` \| Factored credit note \| \| `502` \| Self-billed factored credit note \| \| `503` \| Credit note for an advance payment invoice \|. Example: `"380"`. Values: `380`, `389`, `393`, `501`, `386`, `500`, `384`, `471`, `472`, `473`, `261`, `262`, `381`, `396`, `502`, `503` | | `invoiceIssueDate` | string (date) | No | Issue date of the referenced invoice. Required unless statusCode is 501. Example: `"2024-03-15"`. Format: date | | `sellerLegalId` | string | No | Legal identifier (e.g. SIREN) of the invoice seller. Required unless statusCode is 501. Example: `"123456789"` | | `sellerLegalIdScheme` | string | No | ISO 6523 ICD scheme of the referenced invoice seller legal identifier. Required together with sellerLegalId. Example: `"0002"` | | `reasonCode` | string (enum) | No | Coded reason for the invoice lifecycle status. \| Value \| Meaning \| \| --- \| --- \| \| `JUSTIF_ABS` \| Supporting document missing or insufficient \| \| `ROUTAGE_ERR` \| Routing error \| \| `AUTRE` \| Other reason; provide an explanation in `reasonNote` \| \| `COORD_BANC_ERR` \| Incorrect bank details \| \| `TX_TVA_ERR` \| Incorrect VAT rate \| \| `MONTANTTOTAL_ERR` \| Incorrect invoice total \| \| `CALCUL_ERR` \| Invoice calculation error \| \| `NON_CONFORME` \| Missing legal information \| \| `DOUBLON` \| Duplicate invoice \| \| `DEST_INC` \| Unknown recipient \| \| `DEST_ERR` \| Incorrect recipient \| \| `TRANSAC_INC` \| Unknown transaction \| \| `EMMET_INC` \| Unknown issuer \| \| `CONTRAT_TERM` \| Contract ended \| \| `DOUBLE_FACT` \| Supply or service already invoiced on another invoice \| \| `CMD_ERR` \| Incorrect or missing order number \| \| `ADR_ERR` \| Incorrect electronic invoicing address \| \| `SIRET_ERR` \| Incorrect or missing SIRET \| \| `CODE_ROUTAGE_ERR` \| Incorrect or missing routing code \| \| `REF_CT_ABSENT` \| Required contractual reference missing \| \| `REF_ERR` \| Incorrect reference \| \| `PU_ERR` \| Incorrect unit price \| \| `REM_ERR` \| Incorrect discount \| \| `QTE_ERR` \| Incorrect invoiced quantity \| \| `ART_ERR` \| Incorrect invoiced item \| \| `MODPAI_ERR` \| Incorrect payment terms \| \| `QUALITE_ERR` \| Incorrect quality of delivered item \| \| `LIVR_INCOMP` \| Incomplete or non-compliant delivery \| \| `REJ_SEMAN` \| Rejected because of a semantic error \| \| `REJ_UNI` \| Rejected by uniqueness control \| \| `REJ_COH` \| Rejected by data-consistency control \| \| `REJ_ADR` \| Rejected by addressing control \| \| `REJ_CONT_B2G` \| Rejected by B2G business controls \| \| `REJ_REF_PJ` \| Rejected because of an attachment-reference error \| \| `REJ_ASS_PJ` \| Rejected because of an attachment-association error \| \| `NON_TRANSMISE` \| Submitted but not transmitted because the recipient has no receiving platform \|. Values: `JUSTIF_ABS`, `ROUTAGE_ERR`, `AUTRE`, `COORD_BANC_ERR`, `TX_TVA_ERR`, `MONTANTTOTAL_ERR`, `CALCUL_ERR`, `NON_CONFORME`, `DOUBLON`, `DEST_INC`, `DEST_ERR`, `TRANSAC_INC`, `EMMET_INC`, `CONTRAT_TERM`, `DOUBLE_FACT`, `CMD_ERR`, `ADR_ERR`, `SIRET_ERR`, `CODE_ROUTAGE_ERR`, `REF_CT_ABSENT`, `REF_ERR`, `PU_ERR`, `REM_ERR`, `QTE_ERR`, `ART_ERR`, `MODPAI_ERR`, `QUALITE_ERR`, `LIVR_INCOMP`, `REJ_SEMAN`, `REJ_UNI`, `REJ_COH`, `REJ_ADR`, `REJ_CONT_B2G`, `REJ_REF_PJ`, `REJ_ASS_PJ`, `NON_TRANSMISE` | | `reason` | string | No | Optional free-text status reason. This is distinct from the IncludedNote explanation required for reasonCode AUTRE | | `reasonNote` | string | No | Free-text comment in the status detail IncludedNote. Required when reasonCode is AUTRE. Example: `"The invoice needs manual review."` | | `collectedAmounts` | object[] | No | Collected amounts with VAT rates (TypeCode MEN). Required for status 212; at least one entry | **`collectedAmounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `amount` | string | Yes | Net collected amount (positive) or disbursed amount (negative), for status 212. Example: `"12000.00"` | | `currency` | string (enum) | Yes | ISO 4217 currency code of the collected amount. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `vatPercent` | string | Yes | VAT rate applicable to the collected amount. Example: `"20.00"` | ## Responses ### 200 Successfully generated document | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `xml` | string | Yes | The generated XML document | | `documentType` | string | Yes | The type of the generated document. Example: `"invoice"` | | `doctypeId` | string | Yes | The document type identifier the document was generated for. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | Yes | The process identifier the document was generated for. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | ### 400 Invalid document data provided, or the generated document failed validation | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | | `invalidInputDetails` | object[] | No | Present when the request body or query did not match the schema | **`invalidInputDetails`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `path` | string | No | Dotted path of the field the message applies to | | `message` | string | No | | | `unionErrors` | object[][] | No | For a union of schemas, the failures of every variant, in the order the variants are declared | # List Companies `GET /api/v1/companies` List every company registered under the team, with its verification and SMP registration status. This response is not paginated. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Query Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `enterpriseNumber` | string | No | Filter companies by enterprise number | | `vatNumber` | string | No | Filter companies by VAT number | ## Responses ### 200 Successfully retrieved companies | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `companies` | object[] | Yes | | **`companies`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the company. Use it wherever an endpoint takes a companyId. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `teamId` | string | Yes | The ID of the team the company belongs to. Example: `"team_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `name` | string | Yes | The legal name of the company, as it is written on the documents it sends. Example: `"Recommand BV"` | | `address` | string | Yes | Street name and number of the company's registered address. Example: `"Kortrijksesteenweg 1092"` | | `postalCode` | string | Yes | Postal code of the company's registered address. Example: `"9051"` | | `city` | string | Yes | City of the company's registered address. Example: `"Gent"` | | `country` | string | Yes | The country the company is registered in, in ISO 3166-1 alpha-2 format. Example: `"BE"` | | `enterpriseNumberScheme` | string \| null | Yes | The Peppol scheme the enterprise number belongs to, for example `0208` for the Belgian enterprise number register. Null when no scheme was recorded. Example: `"0208"` | | `enterpriseNumber` | string | Yes | The company's registration number in its national business register, without the scheme prefix. Example: `"1012081766"` | | `vatNumber` | string | Yes | The company's VAT number, including its country prefix. Example: `"BE1012081766"` | | `email` | string \| null | Yes | Contact email address recorded for the company. This is not where document notifications go; those are configured per address through the notification email address endpoints. Example: `"billing@example.com"` | | `phone` | string \| null | Yes | Contact phone number recorded for the company. Example: `"+32 9 396 20 39"` | | `isSmpRecipient` | boolean | Yes | Whether the company is registered in the SMP to receive documents. Set it to false for a company that only sends. Registration also requires the company to be verified when your team's verification requirements are strict, and never happens for playground teams. Example: `true` | | `isVerified` | boolean | Yes | Whether an authorised representative completed the identity check, which is needed before exchanging documents. Start the check with the verify company endpoint. Example: `true` | | `createdAt` | string (date-time) | Yes | When the company was created. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the company was last changed. Format: date-time | ### 500 Failed to fetch companies | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Create Company `POST /api/v1/companies` Register a business you want to send or receive Peppol documents for. Unless `skipDefaultCompanySetup` is set, the company is given the default Peppol identifiers and document types for its country, and is registered in the SMP so it can receive documents. The response carries a `verificationUrl`: a company has to pass the identity check before it can exchange documents. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | | | `address` | string | Yes | | | `postalCode` | string | Yes | | | `city` | string | Yes | | | `country` | string (enum) | Yes | The country the company is registered in, in ISO 3166-1 alpha-2 format. Only countries Recommand supports are accepted; any other country is rejected with a 400. Example: `"BE"`. Values: `AU`, `AT`, `BE`, `BG`, `CA`, `HR`, `DK`, `EE`, `FI`, `FR`, `DE`, `GR`, `HK`, `HU`, `IS`, `IE`, `IT`, `JP`, `LV`, `LU`, `MY`, `NL`, `NZ`, `NO`, `PL`, `PT`, `RO`, `SG`, `SK`, `SI`, `ES`, `SE`, `AE`, `GB`, `US` | | `enterpriseNumberScheme` | string (enum) | No | Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The enterprise number of the company. Can only contain alphanumeric characters. For Belgian businesses it will be inferred from the VAT number if not provided | | `vatNumber` | string \| null | No | | | `email` | string (email) | string | null | No | | | `phone` | string \| null | No | | | `isSmpRecipient` | boolean | No | Default: `true` | | `skipDefaultCompanySetup` | boolean | No | If true, the automatic creation of company identifiers and document types will be skipped. You will need to create them afterwards using the company identifier creation endpoint and company document type creation endpoint. Default: `false` | **`email`** (Any of): #### Variant 1 Type: `string (email)` #### Variant 2 Type: `string` #### Variant 3 Type: `null` ## Responses ### 200 Successfully created company | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `company` | object | Yes | | | `verificationUrl` | string | Yes | A one-time URL where an authorised representative completes the company's identity check. Present it to your user immediately. Call the verify company endpoint if you need a fresh one | **`company`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the company. Use it wherever an endpoint takes a companyId. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `teamId` | string | Yes | The ID of the team the company belongs to. Example: `"team_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `name` | string | Yes | The legal name of the company, as it is written on the documents it sends. Example: `"Recommand BV"` | | `address` | string | Yes | Street name and number of the company's registered address. Example: `"Kortrijksesteenweg 1092"` | | `postalCode` | string | Yes | Postal code of the company's registered address. Example: `"9051"` | | `city` | string | Yes | City of the company's registered address. Example: `"Gent"` | | `country` | string | Yes | The country the company is registered in, in ISO 3166-1 alpha-2 format. Example: `"BE"` | | `enterpriseNumberScheme` | string \| null | Yes | The Peppol scheme the enterprise number belongs to, for example `0208` for the Belgian enterprise number register. Null when no scheme was recorded. Example: `"0208"` | | `enterpriseNumber` | string | Yes | The company's registration number in its national business register, without the scheme prefix. Example: `"1012081766"` | | `vatNumber` | string | Yes | The company's VAT number, including its country prefix. Example: `"BE1012081766"` | | `email` | string \| null | Yes | Contact email address recorded for the company. This is not where document notifications go; those are configured per address through the notification email address endpoints. Example: `"billing@example.com"` | | `phone` | string \| null | Yes | Contact phone number recorded for the company. Example: `"+32 9 396 20 39"` | | `isSmpRecipient` | boolean | Yes | Whether the company is registered in the SMP to receive documents. Set it to false for a company that only sends. Registration also requires the company to be verified when your team's verification requirements are strict, and never happens for playground teams. Example: `true` | | `isVerified` | boolean | Yes | Whether an authorised representative completed the identity check, which is needed before exchanging documents. Start the check with the verify company endpoint. Example: `true` | | `createdAt` | string (date-time) | Yes | When the company was created. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the company was last changed. Format: date-time | ### 400 Invalid request data | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | | `invalidInputDetails` | object[] | No | Present when the request body or query did not match the schema | **`invalidInputDetails`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `path` | string | No | Dotted path of the field the message applies to | | `message` | string | No | | | `unionErrors` | object[][] | No | For a union of schemas, the failures of every variant, in the order the variants are declared | ### 500 Failed to create company | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Get Company `GET /api/v1/companies/{companyId}` Get one company, including whether it has been verified and whether it is registered in the SMP to receive documents. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company to retrieve | ## Responses ### 200 Successfully retrieved company | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `company` | object | Yes | | **`company`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the company. Use it wherever an endpoint takes a companyId. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `teamId` | string | Yes | The ID of the team the company belongs to. Example: `"team_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `name` | string | Yes | The legal name of the company, as it is written on the documents it sends. Example: `"Recommand BV"` | | `address` | string | Yes | Street name and number of the company's registered address. Example: `"Kortrijksesteenweg 1092"` | | `postalCode` | string | Yes | Postal code of the company's registered address. Example: `"9051"` | | `city` | string | Yes | City of the company's registered address. Example: `"Gent"` | | `country` | string | Yes | The country the company is registered in, in ISO 3166-1 alpha-2 format. Example: `"BE"` | | `enterpriseNumberScheme` | string \| null | Yes | The Peppol scheme the enterprise number belongs to, for example `0208` for the Belgian enterprise number register. Null when no scheme was recorded. Example: `"0208"` | | `enterpriseNumber` | string | Yes | The company's registration number in its national business register, without the scheme prefix. Example: `"1012081766"` | | `vatNumber` | string | Yes | The company's VAT number, including its country prefix. Example: `"BE1012081766"` | | `email` | string \| null | Yes | Contact email address recorded for the company. This is not where document notifications go; those are configured per address through the notification email address endpoints. Example: `"billing@example.com"` | | `phone` | string \| null | Yes | Contact phone number recorded for the company. Example: `"+32 9 396 20 39"` | | `isSmpRecipient` | boolean | Yes | Whether the company is registered in the SMP to receive documents. Set it to false for a company that only sends. Registration also requires the company to be verified when your team's verification requirements are strict, and never happens for playground teams. Example: `true` | | `isVerified` | boolean | Yes | Whether an authorised representative completed the identity check, which is needed before exchanging documents. Start the check with the verify company endpoint. Example: `true` | | `createdAt` | string (date-time) | Yes | When the company was created. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the company was last changed. Format: date-time | ### 404 Company not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to fetch company | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Update Company `PUT /api/v1/companies/{companyId}` Update an existing company. Changing the VAT number or enterprise number revokes any open verification sessions for the company. If the company was already verified, its verification status is also revoked and the company must be verified again. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company to update | ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | No | | | `address` | string | No | | | `postalCode` | string | No | | | `city` | string | No | | | `country` | string (enum) | No | Values: `AU`, `AT`, `BE`, `BG`, `CA`, `HR`, `DK`, `EE`, `FI`, `FR`, `DE`, `GR`, `HK`, `HU`, `IS`, `IE`, `IT`, `JP`, `LV`, `LU`, `MY`, `NL`, `NZ`, `NO`, `PL`, `PT`, `RO`, `SG`, `SK`, `SI`, `ES`, `SE`, `AE`, `GB`, `US` | | `enterpriseNumberScheme` | string (enum) | No | Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The enterprise number of the company. Changing its value revokes open verification sessions, and also revokes verification status if the company was verified | | `vatNumber` | string \| null | No | The VAT number of the company. Changing its value revokes open verification sessions, and also revokes verification status if the company was verified | | `email` | string (email) | string | null | No | | | `phone` | string \| null | No | | | `isSmpRecipient` | boolean | No | | **`email`** (Any of): #### Variant 1 Type: `string (email)` #### Variant 2 Type: `string` #### Variant 3 Type: `null` ## Responses ### 200 Successfully updated company | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `company` | object | Yes | | **`company`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the company. Use it wherever an endpoint takes a companyId. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `teamId` | string | Yes | The ID of the team the company belongs to. Example: `"team_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `name` | string | Yes | The legal name of the company, as it is written on the documents it sends. Example: `"Recommand BV"` | | `address` | string | Yes | Street name and number of the company's registered address. Example: `"Kortrijksesteenweg 1092"` | | `postalCode` | string | Yes | Postal code of the company's registered address. Example: `"9051"` | | `city` | string | Yes | City of the company's registered address. Example: `"Gent"` | | `country` | string | Yes | The country the company is registered in, in ISO 3166-1 alpha-2 format. Example: `"BE"` | | `enterpriseNumberScheme` | string \| null | Yes | The Peppol scheme the enterprise number belongs to, for example `0208` for the Belgian enterprise number register. Null when no scheme was recorded. Example: `"0208"` | | `enterpriseNumber` | string | Yes | The company's registration number in its national business register, without the scheme prefix. Example: `"1012081766"` | | `vatNumber` | string | Yes | The company's VAT number, including its country prefix. Example: `"BE1012081766"` | | `email` | string \| null | Yes | Contact email address recorded for the company. This is not where document notifications go; those are configured per address through the notification email address endpoints. Example: `"billing@example.com"` | | `phone` | string \| null | Yes | Contact phone number recorded for the company. Example: `"+32 9 396 20 39"` | | `isSmpRecipient` | boolean | Yes | Whether the company is registered in the SMP to receive documents. Set it to false for a company that only sends. Registration also requires the company to be verified when your team's verification requirements are strict, and never happens for playground teams. Example: `true` | | `isVerified` | boolean | Yes | Whether an authorised representative completed the identity check, which is needed before exchanging documents. Start the check with the verify company endpoint. Example: `true` | | `createdAt` | string (date-time) | Yes | When the company was created. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the company was last changed. Format: date-time | ### 400 Invalid request data | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | | `invalidInputDetails` | object[] | No | Present when the request body or query did not match the schema | **`invalidInputDetails`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `path` | string | No | Dotted path of the field the message applies to | | `message` | string | No | | | `unionErrors` | object[][] | No | For a union of schemas, the failures of every variant, in the order the variants are declared | ### 404 Company not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to update company | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Delete Company `DELETE /api/v1/companies/{companyId}` Permanently delete a company. If the company was registered in the SMP, its registration is removed first, so the Peppol network stops routing documents to it. Every document sent or received for the company is deleted with it, along with the stored XML, attachments and payloads; this cannot be undone. Set `isSmpRecipient` to false with the update company endpoint instead if you only want to stop receiving documents while keeping the history. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company to delete | ## Responses ### 200 Successfully deleted company | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `true` | ### 500 Failed to delete company | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Verify Company `POST /api/v1/companies/{companyId}/verify` To send or receive documents on behalf of a company, you must first verify your identity to confirm you are authorized to act for that company. This endpoint initiates a verification session and returns a URL. The URL leads to a secure form where an official company representative can provide proof of identity. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company to verify | ## Responses ### 200 Successfully created verification session | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `verificationUrl` | string | Yes | | ### 400 Invalid request data | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 404 Company not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to create verification session | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # List Company Identifiers `GET /api/v1/companies/{companyId}/identifiers` List the Peppol identifiers registered for a company. Each identifier is an address other participants can send documents to, written as `scheme:identifier`. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company to get identifiers for | ## Responses ### 200 Successfully retrieved company identifiers | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `identifiers` | object[] | Yes | | **`identifiers`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the identifier record. Use it with the get, update and delete identifier endpoints. Example: `"ci_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string | Yes | The ID of the company this identifier belongs to. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `scheme` | string | Yes | The Peppol identifier scheme, an ISO/IEC 6523 ICD code. It says which register the identifier comes from, for example `0208` for the Belgian enterprise number register. Example: `"0208"` | | `identifier` | string | Yes | The value within the scheme. Together with the scheme it forms the company's Peppol address, written as `scheme:identifier`. Example: `"1012081766"` | | `createdAt` | string (date-time) | Yes | When the identifier was added to the company. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the identifier was last changed. Format: date-time | ### 500 Failed to fetch company identifiers | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Create Company Identifier `POST /api/v1/companies/{companyId}/identifiers` Add a Peppol identifier the company can be addressed by. When the company is registered as an SMP recipient, the identifier is registered in the SMP as well, which is what makes the address reachable on the network. A company created without `skipDefaultCompanySetup` already has the default identifiers for its country, so use this to add an extra address, for example a GLN alongside a national registration number. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company to create an identifier for | ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | The scheme of the identifier | | `identifier` | string | Yes | The value of the identifier | ## Responses ### 200 Successfully created company identifier | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `identifier` | object | Yes | | **`identifier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the identifier record. Use it with the get, update and delete identifier endpoints. Example: `"ci_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string | Yes | The ID of the company this identifier belongs to. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `scheme` | string | Yes | The Peppol identifier scheme, an ISO/IEC 6523 ICD code. It says which register the identifier comes from, for example `0208` for the Belgian enterprise number register. Example: `"0208"` | | `identifier` | string | Yes | The value within the scheme. Together with the scheme it forms the company's Peppol address, written as `scheme:identifier`. Example: `"1012081766"` | | `createdAt` | string (date-time) | Yes | When the identifier was added to the company. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the identifier was last changed. Format: date-time | ### 400 Invalid request data | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to create company identifier | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Get Company Identifier `GET /api/v1/companies/{companyId}/identifiers/{identifierId}` Get one of a company's Peppol identifiers. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `identifierId` | string | Yes | The ID of the identifier to retrieve | | `companyId` | string | Yes | | ## Responses ### 200 Successfully retrieved company identifier | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `identifier` | object | Yes | | **`identifier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the identifier record. Use it with the get, update and delete identifier endpoints. Example: `"ci_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string | Yes | The ID of the company this identifier belongs to. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `scheme` | string | Yes | The Peppol identifier scheme, an ISO/IEC 6523 ICD code. It says which register the identifier comes from, for example `0208` for the Belgian enterprise number register. Example: `"0208"` | | `identifier` | string | Yes | The value within the scheme. Together with the scheme it forms the company's Peppol address, written as `scheme:identifier`. Example: `"1012081766"` | | `createdAt` | string (date-time) | Yes | When the identifier was added to the company. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the identifier was last changed. Format: date-time | ### 404 Company identifier not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to fetch company identifier | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Update Company Identifier `PUT /api/v1/companies/{companyId}/identifiers/{identifierId}` Change the scheme or value of an identifier. The old address is unregistered from the SMP and the new one registered in its place, so anything routed to the old address stops arriving. Senders who stored the old address will have to be told. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company to update an identifier for | | `identifierId` | string | Yes | The ID of the identifier to update | ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | The scheme of the identifier | | `identifier` | string | Yes | The value of the identifier | ## Responses ### 200 Successfully updated company identifier | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `identifier` | object | Yes | | **`identifier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the identifier record. Use it with the get, update and delete identifier endpoints. Example: `"ci_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string | Yes | The ID of the company this identifier belongs to. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `scheme` | string | Yes | The Peppol identifier scheme, an ISO/IEC 6523 ICD code. It says which register the identifier comes from, for example `0208` for the Belgian enterprise number register. Example: `"0208"` | | `identifier` | string | Yes | The value within the scheme. Together with the scheme it forms the company's Peppol address, written as `scheme:identifier`. Example: `"1012081766"` | | `createdAt` | string (date-time) | Yes | When the identifier was added to the company. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the identifier was last changed. Format: date-time | ### 404 Company identifier not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to update company identifier | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Delete Company Identifier `DELETE /api/v1/companies/{companyId}/identifiers/{identifierId}` Remove an identifier from the company and unregister it from the SMP, so documents can no longer be routed to that address. Documents already received under it are kept. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company to delete an identifier for | | `identifierId` | string | Yes | The ID of the identifier to delete | ## Responses ### 200 Successfully deleted company identifier | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | ### 404 Company identifier not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to delete company identifier | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # List Company Document Types `GET /api/v1/companies/{companyId}/document-types` List the Peppol document types the company is registered to receive. Senders look this up in the SMP to decide what they may send you. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company to get document types for | ## Responses ### 200 Successfully retrieved company document types | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `documentTypes` | object[] | Yes | | **`documentTypes`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the document type record. Use it with the get, update and delete document type endpoints. Example: `"cdt_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string | Yes | The ID of the company this document type belongs to. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `docTypeId` | string | Yes | The full Peppol document type identifier the company accepts. It names the syntax and the customization a sender has to follow. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | Yes | The Peppol process identifier the document type is accepted under. It names the business process the document type is used in. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `createdAt` | string (date-time) | Yes | When the document type was added to the company. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the document type was last changed. Format: date-time | ### 500 Failed to fetch company document types | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Create Company Document Type `POST /api/v1/companies/{companyId}/document-types` Declare that the company can receive a document type, under a given process. When the company is registered as an SMP recipient, the document type is published in the SMP, which is what lets senders address it. A company created without `skipDefaultCompanySetup` already has the default document types for its country; use this to accept something beyond them, and only for document types you can actually process. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company to create a document type for | ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `docTypeId` | string | Yes | The ID of the document type to create | | `processId` | string | Yes | The ID of the process to create | ## Responses ### 200 Successfully created company document type | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `documentType` | object | Yes | | **`documentType`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the document type record. Use it with the get, update and delete document type endpoints. Example: `"cdt_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string | Yes | The ID of the company this document type belongs to. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `docTypeId` | string | Yes | The full Peppol document type identifier the company accepts. It names the syntax and the customization a sender has to follow. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | Yes | The Peppol process identifier the document type is accepted under. It names the business process the document type is used in. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `createdAt` | string (date-time) | Yes | When the document type was added to the company. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the document type was last changed. Format: date-time | ### 400 Invalid request data | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to create company document type | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Get Company Document Type `GET /api/v1/companies/{companyId}/document-types/{documentTypeId}` Get one of the document types the company is registered to receive. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company to get a document type for | | `documentTypeId` | string | Yes | The ID of the document type to retrieve | ## Responses ### 200 Successfully retrieved company document type | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `documentType` | object | Yes | | **`documentType`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the document type record. Use it with the get, update and delete document type endpoints. Example: `"cdt_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string | Yes | The ID of the company this document type belongs to. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `docTypeId` | string | Yes | The full Peppol document type identifier the company accepts. It names the syntax and the customization a sender has to follow. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | Yes | The Peppol process identifier the document type is accepted under. It names the business process the document type is used in. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `createdAt` | string (date-time) | Yes | When the document type was added to the company. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the document type was last changed. Format: date-time | ### 404 Company document type not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to fetch company document type | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Update Company Document Type `PUT /api/v1/companies/{companyId}/document-types/{documentTypeId}` Change the document type identifier or the process it is accepted under. The old combination is withdrawn from the SMP and the new one published, so senders stop being able to address the old one. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company to update a document type for | | `documentTypeId` | string | Yes | The ID of the document type to update | ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `docTypeId` | string | Yes | The ID of the document type to update | | `processId` | string | Yes | The ID of the process to update | ## Responses ### 200 Successfully updated company document type | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `documentType` | object | Yes | | **`documentType`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the document type record. Use it with the get, update and delete document type endpoints. Example: `"cdt_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string | Yes | The ID of the company this document type belongs to. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `docTypeId` | string | Yes | The full Peppol document type identifier the company accepts. It names the syntax and the customization a sender has to follow. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | Yes | The Peppol process identifier the document type is accepted under. It names the business process the document type is used in. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `createdAt` | string (date-time) | Yes | When the document type was added to the company. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the document type was last changed. Format: date-time | ### 400 Invalid request data | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 404 Company document type not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to update company document type | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Delete Company Document Type `DELETE /api/v1/companies/{companyId}/document-types/{documentTypeId}` Stop accepting a document type. It is withdrawn from the SMP, so senders can no longer address the company for it and their transmissions will fail. Documents already received under it are kept. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company to delete a document type for | | `documentTypeId` | string | Yes | The ID of the document type to delete | ## Responses ### 200 Successfully deleted company document type | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | ### 404 Company document type not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to delete company document type | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # List Company Notification Email Addresses `GET /api/v1/companies/{companyId}/notification-email-addresses` List the addresses that are emailed when the company sends or receives a document, and what each of them gets. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company to get notification email addresses for | ## Responses ### 200 Successfully retrieved company notification email addresses | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `notificationEmailAddresses` | object[] | Yes | | **`notificationEmailAddresses`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the notification email address record. Use it with the get, update and delete notification email address endpoints. Example: `"cnea_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string | Yes | The ID of the company these notifications are sent for. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `email` | string | Yes | The address the notifications are sent to. Example: `"billing@example.com"` | | `notifyIncoming` | boolean | Yes | Whether this address is notified when the company receives a document. Example: `true` | | `notifyOutgoing` | boolean | Yes | Whether this address is notified when the company sends a document. Example: `false` | | `includeAutoGeneratedPdfIncoming` | boolean | Yes | Whether the notification for an incoming document carries a PDF rendering of it as an attachment. Example: `true` | | `includeAutoGeneratedPdfOutgoing` | boolean | Yes | Whether the notification for an outgoing document carries a PDF rendering of it as an attachment. Example: `false` | | `includeDocumentJsonIncoming` | boolean | Yes | Whether the notification for an incoming document carries the document's JSON representation as an attachment. Example: `false` | | `includeDocumentJsonOutgoing` | boolean | Yes | Whether the notification for an outgoing document carries the document's JSON representation as an attachment. Example: `false` | | `createdAt` | string (date-time) | Yes | When the address was added to the company. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the address was last changed. Format: date-time | ### 500 Failed to fetch company notification email addresses | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Create Company Notification Email Address `POST /api/v1/companies/{companyId}/notification-email-addresses` Have a person or a shared mailbox emailed whenever the company sends or receives a document. Choose the directions to notify, and whether each notification carries a rendered PDF and the document as JSON. These emails are for people; use a webhook to drive an integration. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company to create a notification email address for | ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `email` | string (email) | Yes | The email address to create. Format: email | | `notifyIncoming` | boolean | Yes | Whether to notify on incoming documents | | `notifyOutgoing` | boolean | Yes | Whether to notify on outgoing documents | | `includeAutoGeneratedPdfIncoming` | boolean | No | Whether to include the auto-generated PDF attachment for incoming document notifications | | `includeAutoGeneratedPdfOutgoing` | boolean | No | Whether to include the auto-generated PDF attachment for outgoing document notifications | | `includeDocumentJsonIncoming` | boolean | No | Whether to include the document.json attachment for incoming document notifications | | `includeDocumentJsonOutgoing` | boolean | No | Whether to include the document.json attachment for outgoing document notifications | ## Responses ### 200 Successfully created company notification email address | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `notificationEmailAddress` | object | Yes | | **`notificationEmailAddress`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the notification email address record. Use it with the get, update and delete notification email address endpoints. Example: `"cnea_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string | Yes | The ID of the company these notifications are sent for. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `email` | string | Yes | The address the notifications are sent to. Example: `"billing@example.com"` | | `notifyIncoming` | boolean | Yes | Whether this address is notified when the company receives a document. Example: `true` | | `notifyOutgoing` | boolean | Yes | Whether this address is notified when the company sends a document. Example: `false` | | `includeAutoGeneratedPdfIncoming` | boolean | Yes | Whether the notification for an incoming document carries a PDF rendering of it as an attachment. Example: `true` | | `includeAutoGeneratedPdfOutgoing` | boolean | Yes | Whether the notification for an outgoing document carries a PDF rendering of it as an attachment. Example: `false` | | `includeDocumentJsonIncoming` | boolean | Yes | Whether the notification for an incoming document carries the document's JSON representation as an attachment. Example: `false` | | `includeDocumentJsonOutgoing` | boolean | Yes | Whether the notification for an outgoing document carries the document's JSON representation as an attachment. Example: `false` | | `createdAt` | string (date-time) | Yes | When the address was added to the company. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the address was last changed. Format: date-time | ### 400 Invalid request data | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 404 Company not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to create company notification email address | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Get Company Notification Email Address `GET /api/v1/companies/{companyId}/notification-email-addresses/{notificationEmailAddressId}` Get one notification email address and its settings. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company to get a notification email address for | | `notificationEmailAddressId` | string | Yes | The ID of the notification email address to retrieve | ## Responses ### 200 Successfully retrieved company notification email address | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `notificationEmailAddress` | object | Yes | | **`notificationEmailAddress`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the notification email address record. Use it with the get, update and delete notification email address endpoints. Example: `"cnea_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string | Yes | The ID of the company these notifications are sent for. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `email` | string | Yes | The address the notifications are sent to. Example: `"billing@example.com"` | | `notifyIncoming` | boolean | Yes | Whether this address is notified when the company receives a document. Example: `true` | | `notifyOutgoing` | boolean | Yes | Whether this address is notified when the company sends a document. Example: `false` | | `includeAutoGeneratedPdfIncoming` | boolean | Yes | Whether the notification for an incoming document carries a PDF rendering of it as an attachment. Example: `true` | | `includeAutoGeneratedPdfOutgoing` | boolean | Yes | Whether the notification for an outgoing document carries a PDF rendering of it as an attachment. Example: `false` | | `includeDocumentJsonIncoming` | boolean | Yes | Whether the notification for an incoming document carries the document's JSON representation as an attachment. Example: `false` | | `includeDocumentJsonOutgoing` | boolean | Yes | Whether the notification for an outgoing document carries the document's JSON representation as an attachment. Example: `false` | | `createdAt` | string (date-time) | Yes | When the address was added to the company. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the address was last changed. Format: date-time | ### 404 Company notification email address not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to fetch company notification email address | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Update Company Notification Email Address `PUT /api/v1/companies/{companyId}/notification-email-addresses/{notificationEmailAddressId}` Change which documents an address is notified about and what its notifications carry. Set both `notifyIncoming` and `notifyOutgoing` to false to silence it without removing it. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company to update a notification email address for | | `notificationEmailAddressId` | string | Yes | The ID of the notification email address to update | ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `email` | string (email) | Yes | The email address to update. Format: email | | `notifyIncoming` | boolean | Yes | Whether to notify on incoming documents | | `notifyOutgoing` | boolean | Yes | Whether to notify on outgoing documents | | `includeAutoGeneratedPdfIncoming` | boolean | No | Whether to include the auto-generated PDF attachment for incoming document notifications | | `includeAutoGeneratedPdfOutgoing` | boolean | No | Whether to include the auto-generated PDF attachment for outgoing document notifications | | `includeDocumentJsonIncoming` | boolean | No | Whether to include the document.json attachment for incoming document notifications | | `includeDocumentJsonOutgoing` | boolean | No | Whether to include the document.json attachment for outgoing document notifications | ## Responses ### 200 Successfully updated company notification email address | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `notificationEmailAddress` | object | Yes | | **`notificationEmailAddress`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the notification email address record. Use it with the get, update and delete notification email address endpoints. Example: `"cnea_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string | Yes | The ID of the company these notifications are sent for. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `email` | string | Yes | The address the notifications are sent to. Example: `"billing@example.com"` | | `notifyIncoming` | boolean | Yes | Whether this address is notified when the company receives a document. Example: `true` | | `notifyOutgoing` | boolean | Yes | Whether this address is notified when the company sends a document. Example: `false` | | `includeAutoGeneratedPdfIncoming` | boolean | Yes | Whether the notification for an incoming document carries a PDF rendering of it as an attachment. Example: `true` | | `includeAutoGeneratedPdfOutgoing` | boolean | Yes | Whether the notification for an outgoing document carries a PDF rendering of it as an attachment. Example: `false` | | `includeDocumentJsonIncoming` | boolean | Yes | Whether the notification for an incoming document carries the document's JSON representation as an attachment. Example: `false` | | `includeDocumentJsonOutgoing` | boolean | Yes | Whether the notification for an outgoing document carries the document's JSON representation as an attachment. Example: `false` | | `createdAt` | string (date-time) | Yes | When the address was added to the company. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the address was last changed. Format: date-time | ### 400 Invalid request data | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 404 Company notification email address not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to update company notification email address | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Delete Company Notification Email Address `DELETE /api/v1/companies/{companyId}/notification-email-addresses/{notificationEmailAddressId}` Stop emailing this address about the company's documents and remove it. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | The ID of the company to delete a notification email address for | | `notificationEmailAddressId` | string | Yes | The ID of the notification email address to delete | ## Responses ### 200 Successfully deleted company notification email address | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | ### 404 Company notification email address not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to delete company notification email address | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # List Documents `GET /api/v1/documents` Get a list of transmitted documents with pagination ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Query Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `page` | number | No | The page number to retrieve | | `limit` | number | No | The number of items per page | | `companyId` | string | string[] | No | Filter documents by company ID | | `labelId` | string | string[] | No | Filter documents by label ID | | `direction` | `incoming` \| `outgoing` | No | Filter documents by direction (incoming or outgoing) | | `search` | string | No | Search term to filter documents | | `type` | string (enum) | No | Filter documents by type | | `from` | string | No | Filter documents created from this timestamp (inclusive). ISO 8601 format. | | `to` | string | No | Filter documents created until this timestamp (exclusive). ISO 8601 format. | | `isUnread` | `true` \| `false` | No | Filter documents by read status: true for unread documents (readAt is null), false for read documents. | | `envelopeId` | string | No | Filter documents by envelope ID (Standard Business Document Header Instance Identifier) | | `excludeAttachments` | boolean | No | When true, excludes attachments from the parsed object to reduce payload size. Can be passed as a flag without a value (e.g. ?excludeAttachments). | ## Responses ### 200 Successfully retrieved transmitted documents | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `documents` | object[] | Yes | | | `pagination` | object | Yes | | **`documents`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The Recommand document ID. Use it with the other document endpoints. Example: `"doc_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `teamId` | string | Yes | The ID of the team the document belongs to. Example: `"team_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string | Yes | The ID of the company the document was sent for or received by. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `direction` | `incoming` \| `outgoing` | Yes | Whether the document was received by this company (`incoming`) or sent by it (`outgoing`). Example: `"incoming"`. Values: `incoming`, `outgoing` | | `senderId` | string | Yes | The Peppol address of the sender, as `scheme:identifier`. Example: `"0208:1012081766"` | | `receiverId` | string \| null | Yes | The Peppol address of the receiver, as `scheme:identifier`. Null for documents that were never addressed on the network, such as email-only sends and French e-reporting reports. Example: `"0208:0428643097"` | | `docTypeId` | string | Yes | The full Peppol document type identifier the document was exchanged under. It names the syntax and the customization the document follows. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | Yes | The Peppol process identifier the document was exchanged under. It names the business process the document type is used in. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `countryC1` | string | Yes | The country of the originating sender (Peppol corner 1), in ISO 3166-1 alpha-2 format. Peppol requires it on every transmission so receivers can apply country-specific rules. Example: `"BE"` | | `type` | string (enum) | Yes | What kind of document this is. `unknown` means the document could not be recognised as one of the supported types, in which case `parsed` is null and only the XML is available. Example: `"invoice"`. Values: `invoice`, `creditNote`, `selfBillingInvoice`, `selfBillingCreditNote`, `messageLevelResponse`, `frenchInvoicingCdar`, `frenchB2CSalesReport`, `frenchB2CPaymentReport`, `frenchB2BiInvoiceReport`, `frenchB2BiPaymentReport`, `unknown` | | `readAt` | string \| null | Yes | When the document was marked as read. Null while it is unread, which is what puts an incoming document in the inbox | | `createdAt` | string | Yes | When the document was sent or received | | `updatedAt` | string | Yes | When the document record last changed | | `parsed` | Invoice | Credit Note | Self Billing Invoice | Self Billing Credit Note | Message Level Response | French Invoicing CDAR | French B2C reporting request | French cross-border reporting request | null | Yes | The document read into the JSON shape of its type, so you do not have to parse the XML yourself. Null when the type is `unknown` or the payload was not kept | | `validation` | object \| null | Yes | The outcome of validating the document against the rules of its document type. Null when the document was not validated | | `sentOverPeppol` | boolean | Yes | Whether the document travelled over the Peppol network. False for a document that was only delivered by email. Example: `true` | | `sentOverEmail` | boolean | Yes | Whether the document was delivered by email, either as the only channel or alongside Peppol. Example: `false` | | `emailRecipients` | string[] | Yes | The email addresses the document was delivered to. Empty when it was not sent by email. Example: `[]` | | `labels` | object[] | Yes | The labels assigned to this document. Manage them with the assign and unassign label endpoints | | `peppolMessageId` | string \| null | Yes | The AS4 message ID of the transmission. Null when the document did not travel over Peppol, and for playground teams, whose transmissions are simulated | | `peppolConversationId` | string \| null | Yes | The AS4 conversation ID the transmission belongs to. It ties a document to the responses that follow it | | `receivedPeppolSignalMessage` | string \| null | Yes | The AS4 signal message the receiving access point returned to acknowledge an outgoing transmission. Null for incoming documents and when the access point returned none | | `envelopeId` | string \| null | Yes | The envelope ID of the document, also known as the SBDH instance identifier (Standard Business Document Header Instance Identifier) | | `reporting` | French Reporting Status | null | Yes | Where a French e-reporting report stands with the tax administration. Null for documents that are not reports | **`parsed`** (Any of): #### Invoice | Name | Type | Required | Description | |------|------|----------|-------------| | `invoiceNumber` | string | Yes | The number the seller assigned to the invoice. Example: `"INV-2024-001"` | | `issueDate` | string (date) | Yes | The date the invoice was issued, as YYYY-MM-DD. Example: `"2024-03-20"`. Format: date | | `dueDate` | string \| null | No | The date the payment is due, as YYYY-MM-DD. Example: `"2024-04-20"`. Format: date | | `note` | string \| null | No | A free text note about the invoice as a whole. Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | A reference the buyer asked you to put on the invoice so they can route it internally. If neither this nor `purchaseOrderReference` is provided, the invoice number is used. Example: `"PO-2024-001"` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | `seller` | object | Yes | | | `buyer` | object | Yes | | | `delivery` | Delivery | null | No | Optional delivery information | | `paymentMeans` | object[] \| null | No | Optional payment information. For most invoices, this should be provided. For prepaid invoices, this could be omitted | | `paymentTerms` | object \| null | No | Optional payment terms | | `lines` | object[] | Yes | The invoice lines. At least one line is required. Min items: 1 | | `discounts` | object[] \| null | No | Optional global discounts | | `surcharges` | object[] \| null | No | Optional global surcharges | | `totals` | Totals | null | No | | | `vat` | Provided VAT totals | null | No | The VAT totals of the invoice, broken down per VAT category and rate | | `attachments` | object[] \| null | No | Optional attachments to the invoice | | `currency` | string (enum) | No | The currency of the invoice. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `countrySpecific` | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | **`seller`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`buyer`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`delivery`** (One of): #### Delivery | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | `locationIdentifier` | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | `location` | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | **`locationIdentifier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | **`location`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | #### Variant 2 Type: `null` **`paymentMeans`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | **`paymentTerms`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | The payment terms as free text. Example: `"Net 30"` | **`lines`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | `standardId` | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | `commodityClassifications` | object[] \| null | No | Optional commodity classifications | | `additionalItemProperties` | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | `discounts` | object[] \| null | No | Optional discounts for the line | | `surcharges` | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | `vat` | object | Yes | | **`standardId`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | **`commodityClassifications`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | **`additionalItemProperties`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`totals`** (One of): #### Totals | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | #### Variant 2 Type: `null` **`vat`** (One of): #### Provided VAT totals | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | `subtotals` | object[] | Yes | One entry for every combination of VAT category and rate used in the document | **`subtotals`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### Variant 2 Type: `null` **`attachments`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | **`countrySpecific`** (One of): #### Country Specific Billing **One of:** #### French Country Specific Billing | Name | Type | Required | Description | |------|------|----------|-------------| | `country` | string | Yes | Identifies this as the French regulatory extension. This is independent from seller, buyer, delivery, and origin country codes. Value: `FR` | | `billingMode` | string (enum) | Yes | Required only for French regulated UBL, CII, and Factur-X. Select the invoicing framework that matches the invoice. \| Mode \| Description \| \| --- \| --- \| \| `B1` \| Goods invoice. \| \| `S1` \| Services invoice. \| \| `M1` \| Mixed invoice containing goods and services that are not ancillary to each other. \| \| `B2` \| Goods invoice that has already been paid. \| \| `S2` \| Services invoice that has already been paid. \| \| `M2` \| Mixed invoice that has already been paid. \| \| `S3` \| B2G subcontractor payment request with direct payment. \| \| `B4` \| Final goods invoice after an advance payment. \| \| `S4` \| Final services invoice after an advance payment. \| \| `M4` \| Final mixed invoice after an advance payment. \| \| `S5` \| Invoice submitted by a subcontractor for services rendered. \| \| `S6` \| Invoice submitted by a co-contractor for services rendered. \| \| `B7` \| Goods invoice that has already been e-reported and for which VAT has already been collected. \| \| `S7` \| Services invoice that has already been e-reported and for which VAT has already been collected. \| \| `B8` \| Multi-seller goods invoice. \| \| `S8` \| Multi-seller services invoice. \| \| `M8` \| Multi-seller mixed invoice whose individual invoices are not all goods invoices or all services invoices. \| . Example: `"S1"`. Values: `B1`, `S1`, `M1`, `B2`, `S2`, `M2`, `S3`, `B4`, `S4`, `M4`, `S5`, `S6`, `B7`, `S7`, `B8`, `S8`, `M8`, `B9`, `S9`, `M9` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` | No | Determines which French Peppol process the document is sent over. Defaults to `REGULATED`. \| Value \| Description \| \| --- \| --- \| \| `REGULATED` \| Transaction inside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:regulated`. \| \| `NON_REGULATED` \| Transaction outside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:non-regulated`. \| The recipient must have registered the matching process for the document type in its SMP. Default: `REGULATED`. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED` | | `recoveryCostsNote` | string | Yes | The mandatory French recovery-cost indemnity statement, written as an IncludedNote with subject code PMT. Example: `"Indemnite forfaitaire de 40 EUR pour frais de recouvrement."` | | `latePaymentPenaltiesNote` | string | Yes | The mandatory French late-payment penalties statement, written as an IncludedNote with subject code PMD. Example: `"Penalites de retard exigibles au taux prevu dans les conditions generales de vente."` | | `earlyPaymentDiscountNote` | string | Yes | The mandatory French early-payment discount statement, written as an IncludedNote with subject code AAB. State either the offered discount terms or explicitly that no early-payment discount applies. Example: `"Aucun escompte accorde pour paiement anticipe."` | #### Variant 2 Type: `null` #### Credit Note | Name | Type | Required | Description | |------|------|----------|-------------| | `creditNoteNumber` | string | Yes | Example: `"CN-2024-001"` | | `issueDate` | string (date) | Yes | Example: `"2024-03-20"`. Format: date | | `note` | string \| null | No | Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | Example: `"PO-2024-001"` | | `invoiceReferences` | object[] | No | References to one or more invoices that are being credited. Default: `` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | `seller` | object | Yes | | | `buyer` | object | Yes | | | `delivery` | Delivery | null | No | Optional delivery information | | `paymentMeans` | object[] \| null | No | | | `paymentTerms` | object \| null | No | | | `lines` | object[] | Yes | Min items: 1 | | `discounts` | object[] \| null | No | Optional global discounts | | `surcharges` | object[] \| null | No | Optional global surcharges | | `totals` | Totals | null | No | | | `vat` | Provided VAT totals | null | No | | | `attachments` | object[] \| null | No | Optional attachments to the credit note | | `currency` | string (enum) | No | The currency of the credit note. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `countrySpecific` | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | **`invoiceReferences`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The reference to the invoice that is being credited. Example: `"INV-2024-001"` | | `issueDate` | string \| null | No | The issue date of the invoice that is being credited. Example: `"2024-03-20"`. Format: date | **`seller`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`buyer`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`delivery`** (One of): #### Delivery | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | `locationIdentifier` | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | `location` | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | **`locationIdentifier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | **`location`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | #### Variant 2 Type: `null` **`paymentMeans`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | **`paymentTerms`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | Example: `"Net 30"` | **`lines`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | `standardId` | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | `commodityClassifications` | object[] \| null | No | Optional commodity classifications | | `additionalItemProperties` | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | `discounts` | object[] \| null | No | Optional discounts for the line | | `surcharges` | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | `vat` | object | Yes | | **`standardId`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | **`commodityClassifications`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | **`additionalItemProperties`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`totals`** (One of): #### Totals | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | #### Variant 2 Type: `null` **`vat`** (One of): #### Provided VAT totals | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | `subtotals` | object[] | Yes | One entry for every combination of VAT category and rate used in the document | **`subtotals`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### Variant 2 Type: `null` **`attachments`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | **`countrySpecific`** (One of): #### Country Specific Billing **One of:** #### French Country Specific Billing | Name | Type | Required | Description | |------|------|----------|-------------| | `country` | string | Yes | Identifies this as the French regulatory extension. This is independent from seller, buyer, delivery, and origin country codes. Value: `FR` | | `billingMode` | string (enum) | Yes | Required only for French regulated UBL, CII, and Factur-X. Select the invoicing framework that matches the invoice. \| Mode \| Description \| \| --- \| --- \| \| `B1` \| Goods invoice. \| \| `S1` \| Services invoice. \| \| `M1` \| Mixed invoice containing goods and services that are not ancillary to each other. \| \| `B2` \| Goods invoice that has already been paid. \| \| `S2` \| Services invoice that has already been paid. \| \| `M2` \| Mixed invoice that has already been paid. \| \| `S3` \| B2G subcontractor payment request with direct payment. \| \| `B4` \| Final goods invoice after an advance payment. \| \| `S4` \| Final services invoice after an advance payment. \| \| `M4` \| Final mixed invoice after an advance payment. \| \| `S5` \| Invoice submitted by a subcontractor for services rendered. \| \| `S6` \| Invoice submitted by a co-contractor for services rendered. \| \| `B7` \| Goods invoice that has already been e-reported and for which VAT has already been collected. \| \| `S7` \| Services invoice that has already been e-reported and for which VAT has already been collected. \| \| `B8` \| Multi-seller goods invoice. \| \| `S8` \| Multi-seller services invoice. \| \| `M8` \| Multi-seller mixed invoice whose individual invoices are not all goods invoices or all services invoices. \| . Example: `"S1"`. Values: `B1`, `S1`, `M1`, `B2`, `S2`, `M2`, `S3`, `B4`, `S4`, `M4`, `S5`, `S6`, `B7`, `S7`, `B8`, `S8`, `M8`, `B9`, `S9`, `M9` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` | No | Determines which French Peppol process the document is sent over. Defaults to `REGULATED`. \| Value \| Description \| \| --- \| --- \| \| `REGULATED` \| Transaction inside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:regulated`. \| \| `NON_REGULATED` \| Transaction outside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:non-regulated`. \| The recipient must have registered the matching process for the document type in its SMP. Default: `REGULATED`. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED` | | `recoveryCostsNote` | string | Yes | The mandatory French recovery-cost indemnity statement, written as an IncludedNote with subject code PMT. Example: `"Indemnite forfaitaire de 40 EUR pour frais de recouvrement."` | | `latePaymentPenaltiesNote` | string | Yes | The mandatory French late-payment penalties statement, written as an IncludedNote with subject code PMD. Example: `"Penalites de retard exigibles au taux prevu dans les conditions generales de vente."` | | `earlyPaymentDiscountNote` | string | Yes | The mandatory French early-payment discount statement, written as an IncludedNote with subject code AAB. State either the offered discount terms or explicitly that no early-payment discount applies. Example: `"Aucun escompte accorde pour paiement anticipe."` | #### Variant 2 Type: `null` #### Self Billing Invoice | Name | Type | Required | Description | |------|------|----------|-------------| | `invoiceNumber` | string | Yes | The number the seller assigned to the invoice. Example: `"INV-2024-001"` | | `issueDate` | string (date) | Yes | The date the invoice was issued, as YYYY-MM-DD. Example: `"2024-03-20"`. Format: date | | `dueDate` | string \| null | No | The date the payment is due, as YYYY-MM-DD. Example: `"2024-04-20"`. Format: date | | `note` | string \| null | No | A free text note about the invoice as a whole. Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | A reference the buyer asked you to put on the invoice so they can route it internally. If neither this nor `purchaseOrderReference` is provided, the invoice number is used. Example: `"PO-2024-001"` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | `seller` | object | Yes | | | `buyer` | object | Yes | | | `delivery` | Delivery | null | No | Optional delivery information | | `paymentMeans` | object[] \| null | No | Optional payment information. For most invoices, this should be provided. For prepaid invoices, this could be omitted | | `paymentTerms` | object \| null | No | Optional payment terms | | `lines` | object[] | Yes | The invoice lines. At least one line is required. Min items: 1 | | `discounts` | object[] \| null | No | Optional global discounts | | `surcharges` | object[] \| null | No | Optional global surcharges | | `totals` | Totals | null | No | | | `vat` | Provided VAT totals | null | No | The VAT totals of the invoice, broken down per VAT category and rate | | `attachments` | object[] \| null | No | Optional attachments to the invoice | | `currency` | string (enum) | Yes | The currency of the invoice. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `countrySpecific` | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | **`seller`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`buyer`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`delivery`** (One of): #### Delivery | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | `locationIdentifier` | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | `location` | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | **`locationIdentifier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | **`location`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | #### Variant 2 Type: `null` **`paymentMeans`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | **`paymentTerms`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | The payment terms as free text. Example: `"Net 30"` | **`lines`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | `standardId` | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | `commodityClassifications` | object[] \| null | No | Optional commodity classifications | | `additionalItemProperties` | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | `discounts` | object[] \| null | No | Optional discounts for the line | | `surcharges` | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | `vat` | object | Yes | | **`standardId`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | **`commodityClassifications`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | **`additionalItemProperties`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`totals`** (One of): #### Totals | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | #### Variant 2 Type: `null` **`vat`** (One of): #### Provided VAT totals | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | `subtotals` | object[] | Yes | One entry for every combination of VAT category and rate used in the document | **`subtotals`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### Variant 2 Type: `null` **`attachments`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | **`countrySpecific`** (One of): #### Country Specific Billing **One of:** #### French Country Specific Billing | Name | Type | Required | Description | |------|------|----------|-------------| | `country` | string | Yes | Identifies this as the French regulatory extension. This is independent from seller, buyer, delivery, and origin country codes. Value: `FR` | | `billingMode` | string (enum) | Yes | Required only for French regulated UBL, CII, and Factur-X. Select the invoicing framework that matches the invoice. \| Mode \| Description \| \| --- \| --- \| \| `B1` \| Goods invoice. \| \| `S1` \| Services invoice. \| \| `M1` \| Mixed invoice containing goods and services that are not ancillary to each other. \| \| `B2` \| Goods invoice that has already been paid. \| \| `S2` \| Services invoice that has already been paid. \| \| `M2` \| Mixed invoice that has already been paid. \| \| `S3` \| B2G subcontractor payment request with direct payment. \| \| `B4` \| Final goods invoice after an advance payment. \| \| `S4` \| Final services invoice after an advance payment. \| \| `M4` \| Final mixed invoice after an advance payment. \| \| `S5` \| Invoice submitted by a subcontractor for services rendered. \| \| `S6` \| Invoice submitted by a co-contractor for services rendered. \| \| `B7` \| Goods invoice that has already been e-reported and for which VAT has already been collected. \| \| `S7` \| Services invoice that has already been e-reported and for which VAT has already been collected. \| \| `B8` \| Multi-seller goods invoice. \| \| `S8` \| Multi-seller services invoice. \| \| `M8` \| Multi-seller mixed invoice whose individual invoices are not all goods invoices or all services invoices. \| . Example: `"S1"`. Values: `B1`, `S1`, `M1`, `B2`, `S2`, `M2`, `S3`, `B4`, `S4`, `M4`, `S5`, `S6`, `B7`, `S7`, `B8`, `S8`, `M8`, `B9`, `S9`, `M9` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` | No | Determines which French Peppol process the document is sent over. Defaults to `REGULATED`. \| Value \| Description \| \| --- \| --- \| \| `REGULATED` \| Transaction inside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:regulated`. \| \| `NON_REGULATED` \| Transaction outside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:non-regulated`. \| The recipient must have registered the matching process for the document type in its SMP. Default: `REGULATED`. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED` | | `recoveryCostsNote` | string | Yes | The mandatory French recovery-cost indemnity statement, written as an IncludedNote with subject code PMT. Example: `"Indemnite forfaitaire de 40 EUR pour frais de recouvrement."` | | `latePaymentPenaltiesNote` | string | Yes | The mandatory French late-payment penalties statement, written as an IncludedNote with subject code PMD. Example: `"Penalites de retard exigibles au taux prevu dans les conditions generales de vente."` | | `earlyPaymentDiscountNote` | string | Yes | The mandatory French early-payment discount statement, written as an IncludedNote with subject code AAB. State either the offered discount terms or explicitly that no early-payment discount applies. Example: `"Aucun escompte accorde pour paiement anticipe."` | #### Variant 2 Type: `null` #### Self Billing Credit Note | Name | Type | Required | Description | |------|------|----------|-------------| | `creditNoteNumber` | string | Yes | Example: `"CN-2024-001"` | | `issueDate` | string (date) | Yes | Example: `"2024-03-20"`. Format: date | | `note` | string \| null | No | Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | Example: `"PO-2024-001"` | | `invoiceReferences` | object[] | Yes | References to one or more invoices that are being credited. Default: `` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | `seller` | object | Yes | | | `buyer` | object | Yes | | | `delivery` | Delivery | null | No | Optional delivery information | | `paymentMeans` | object[] \| null | No | | | `paymentTerms` | object \| null | No | | | `lines` | object[] | Yes | Min items: 1 | | `discounts` | object[] \| null | No | Optional global discounts | | `surcharges` | object[] \| null | No | Optional global surcharges | | `totals` | Totals | null | No | | | `vat` | Provided VAT totals | null | No | | | `attachments` | object[] \| null | No | Optional attachments to the credit note | | `currency` | string (enum) | Yes | The currency of the credit note. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `countrySpecific` | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | **`invoiceReferences`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The reference to the invoice that is being credited. Example: `"INV-2024-001"` | | `issueDate` | string \| null | No | The issue date of the invoice that is being credited. Example: `"2024-03-20"`. Format: date | **`seller`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`buyer`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`delivery`** (One of): #### Delivery | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | `locationIdentifier` | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | `location` | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | **`locationIdentifier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | **`location`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | #### Variant 2 Type: `null` **`paymentMeans`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | **`paymentTerms`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | Example: `"Net 30"` | **`lines`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | `standardId` | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | `commodityClassifications` | object[] \| null | No | Optional commodity classifications | | `additionalItemProperties` | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | `discounts` | object[] \| null | No | Optional discounts for the line | | `surcharges` | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | `vat` | object | Yes | | **`standardId`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | **`commodityClassifications`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | **`additionalItemProperties`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`totals`** (One of): #### Totals | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | #### Variant 2 Type: `null` **`vat`** (One of): #### Provided VAT totals | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | `subtotals` | object[] | Yes | One entry for every combination of VAT category and rate used in the document | **`subtotals`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### Variant 2 Type: `null` **`attachments`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | **`countrySpecific`** (One of): #### Country Specific Billing **One of:** #### French Country Specific Billing | Name | Type | Required | Description | |------|------|----------|-------------| | `country` | string | Yes | Identifies this as the French regulatory extension. This is independent from seller, buyer, delivery, and origin country codes. Value: `FR` | | `billingMode` | string (enum) | Yes | Required only for French regulated UBL, CII, and Factur-X. Select the invoicing framework that matches the invoice. \| Mode \| Description \| \| --- \| --- \| \| `B1` \| Goods invoice. \| \| `S1` \| Services invoice. \| \| `M1` \| Mixed invoice containing goods and services that are not ancillary to each other. \| \| `B2` \| Goods invoice that has already been paid. \| \| `S2` \| Services invoice that has already been paid. \| \| `M2` \| Mixed invoice that has already been paid. \| \| `S3` \| B2G subcontractor payment request with direct payment. \| \| `B4` \| Final goods invoice after an advance payment. \| \| `S4` \| Final services invoice after an advance payment. \| \| `M4` \| Final mixed invoice after an advance payment. \| \| `S5` \| Invoice submitted by a subcontractor for services rendered. \| \| `S6` \| Invoice submitted by a co-contractor for services rendered. \| \| `B7` \| Goods invoice that has already been e-reported and for which VAT has already been collected. \| \| `S7` \| Services invoice that has already been e-reported and for which VAT has already been collected. \| \| `B8` \| Multi-seller goods invoice. \| \| `S8` \| Multi-seller services invoice. \| \| `M8` \| Multi-seller mixed invoice whose individual invoices are not all goods invoices or all services invoices. \| . Example: `"S1"`. Values: `B1`, `S1`, `M1`, `B2`, `S2`, `M2`, `S3`, `B4`, `S4`, `M4`, `S5`, `S6`, `B7`, `S7`, `B8`, `S8`, `M8`, `B9`, `S9`, `M9` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` | No | Determines which French Peppol process the document is sent over. Defaults to `REGULATED`. \| Value \| Description \| \| --- \| --- \| \| `REGULATED` \| Transaction inside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:regulated`. \| \| `NON_REGULATED` \| Transaction outside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:non-regulated`. \| The recipient must have registered the matching process for the document type in its SMP. Default: `REGULATED`. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED` | | `recoveryCostsNote` | string | Yes | The mandatory French recovery-cost indemnity statement, written as an IncludedNote with subject code PMT. Example: `"Indemnite forfaitaire de 40 EUR pour frais de recouvrement."` | | `latePaymentPenaltiesNote` | string | Yes | The mandatory French late-payment penalties statement, written as an IncludedNote with subject code PMD. Example: `"Penalites de retard exigibles au taux prevu dans les conditions generales de vente."` | | `earlyPaymentDiscountNote` | string | Yes | The mandatory French early-payment discount statement, written as an IncludedNote with subject code AAB. State either the offered discount terms or explicitly that no early-payment discount applies. Example: `"Aucun escompte accorde pour paiement anticipe."` | #### Variant 2 Type: `null` #### Message Level Response | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | | | `issueDate` | string (date) | Yes | Example: `"2024-03-20"`. Format: date | | `responseCode` | `AB` \| `AP` \| `RE` | Yes | The response code of the message level response (AB: Message acknowledgement, AP: Accepted, RE: Rejected). Example: `"AB"`. Values: `AB`, `AP`, `RE` | | `envelopeId` | string | Yes | Identifies the document on which the message level response is based | #### French Invoicing CDAR | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | | | `issueDate` | string (date-time) | string (date) | Yes | Creation date and time of the CDAR, without a timezone and with second precision. Date-only values are accepted for incoming format-102 documents. Example: `"2024-03-20T14:05:09"` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` \| `B2C` \| `B2CINT` \| `B2BINT` \| `OUTOFSCOPE` | Yes | Flow classification. \| Value \| Meaning \| \| --- \| --- \| \| `REGULATED` \| Regulated French domestic e-invoicing \| \| `NON_REGULATED` \| Outside the regulated French e-invoicing perimeter \| \| `B2C` \| B2C sales e-reporting \| \| `B2CINT` \| International B2C sales e-reporting \| \| `B2BINT` \| International B2B sales e-reporting \| \| `OUTOFSCOPE` \| Outside the French e-invoicing and e-reporting reform \|. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED`, `B2C`, `B2CINT`, `B2BINT`, `OUTOFSCOPE` | | `phase` | `23` \| `305` | Yes | CDAR phase. \| Value \| Meaning \| \| --- \| --- \| \| `23` \| Processing phase \| \| `305` \| Transmission phase \|. Example: `"23"`. Values: `23`, `305` | | `senderRole` | string (enum) | Yes | Role of the CDAR sender. CDAR party role code (UNCL 3035). \| Value \| Meaning \| \| --- \| --- \| \| `BY` \| Buyer \| \| `AB` \| Buyer's agent or representative \| \| `DL` \| Factor \| \| `SE` \| Seller \| \| `SR` \| Seller's agent \| \| `WK` \| Platform or dematerialisation operator \| \| `DFH` \| French public invoicing portal (PPF) \| \| `PE` \| Payee \| \| `PR` \| Payer \| \| `II` \| Invoicer (invoice issuer) \| \| `IV` \| Invoicee (party invoiced) \|. Example: `"WK"`. Values: `BY`, `AB`, `DL`, `SE`, `SR`, `WK`, `DFH`, `PE`, `PR`, `II`, `IV` | | `issuerRole` | string (enum) | Yes | Role of the party that creates and issues the invoice lifecycle status. This is independent from the CDAR sender role. CDAR party role code (UNCL 3035). \| Value \| Meaning \| \| --- \| --- \| \| `BY` \| Buyer \| \| `AB` \| Buyer's agent or representative \| \| `DL` \| Factor \| \| `SE` \| Seller \| \| `SR` \| Seller's agent \| \| `WK` \| Platform or dematerialisation operator \| \| `DFH` \| French public invoicing portal (PPF) \| \| `PE` \| Payee \| \| `PR` \| Payer \| \| `II` \| Invoicer (invoice issuer) \| \| `IV` \| Invoicee (party invoiced) \|. Example: `"BY"`. Values: `BY`, `AB`, `DL`, `SE`, `SR`, `WK`, `DFH`, `PE`, `PR`, `II`, `IV` | | `issuerLegalId` | string | No | Legal identifier of the party setting the status. Required when phase is 23; must be omitted when phase is 305 unless recipientRole is DFH. Example: `"200000008"` | | `issuerLegalIdScheme` | string | No | ISO 6523 ICD scheme of the party-setting-status legal identifier. Required together with issuerLegalId. Example: `"0002"` | | `recipientRole` | string (enum) | Yes | Role of the CDAR recipient. CDAR party role code (UNCL 3035). \| Value \| Meaning \| \| --- \| --- \| \| `BY` \| Buyer \| \| `AB` \| Buyer's agent or representative \| \| `DL` \| Factor \| \| `SE` \| Seller \| \| `SR` \| Seller's agent \| \| `WK` \| Platform or dematerialisation operator \| \| `DFH` \| French public invoicing portal (PPF) \| \| `PE` \| Payee \| \| `PR` \| Payer \| \| `II` \| Invoicer (invoice issuer) \| \| `IV` \| Invoicee (party invoiced) \|. Example: `"SE"`. Values: `BY`, `AB`, `DL`, `SE`, `SR`, `WK`, `DFH`, `PE`, `PR`, `II`, `IV` | | `recipientLegalId` | string | No | Legal identifier of the CDAR recipient. Example: `"200000008"` | | `recipientLegalIdScheme` | string | No | ISO 6523 ICD scheme of the CDAR recipient legal identifier. Required together with recipientLegalId. Example: `"0002"` | | `recipientElectronicAddress` | string | No | Electronic address of the CDAR recipient. Required when recipientRole is not WK or DFH. Example: `"100000009"` | | `recipientElectronicAddressScheme` | string | No | Electronic Address Scheme (EAS) code of the CDAR recipient electronic address. Required together with recipientElectronicAddress. Example: `"0225"` | | `statusCode` | string (enum) | Yes | French invoice lifecycle status. \| Value \| Meaning \| \| --- \| --- \| \| `200` \| Submitted \| \| `201` \| Issued \| \| `202` \| Received \| \| `203` \| Made available \| \| `204` \| Taken in charge (processing started) \| \| `205` \| Approved \| \| `206` \| Partially approved \| \| `207` \| In dispute \| \| `208` \| Suspended \| \| `209` \| Completed \| \| `210` \| Refused \| \| `211` \| Payment sent \| \| `212` \| Collected (cashed) \| \| `213` \| Rejected \| \| `214` \| Validated or pre-validated ("Visée") \| \| `501` \| Inadmissible file \|. Example: `"200"`. Values: `200`, `201`, `202`, `203`, `204`, `205`, `206`, `207`, `208`, `209`, `210`, `211`, `212`, `213`, `214`, `501` | | `statusDate` | string (date-time) | string (date) | Yes | Date and time at which the status itself was set, without a timezone and with second precision. This is distinct from issueDate, which is the creation date and time of the CDAR message. Date-only values are accepted for incoming format-102 documents. Example: `"2024-03-20T14:05:09"` | | `invoiceId` | string | Yes | Number of the invoice this status relates to. For status 501, this is the filename of the inadmissible file | | `invoiceTypeCode` | string (enum) | No | Type of the referenced invoice. Type of the referenced invoice (UNTDID 1001, restricted to the values allowed by BR-FR-04). \| Value \| Meaning \| \| --- \| --- \| \| `380` \| Commercial invoice \| \| `389` \| Self-billed invoice \| \| `393` \| Factored invoice \| \| `501` \| Self-billed factored invoice \| \| `386` \| Advance payment invoice \| \| `500` \| Self-billed advance payment invoice \| \| `384` \| Corrective invoice \| \| `471` \| Self-billed corrective invoice \| \| `472` \| Factored corrective invoice \| \| `473` \| Self-billed factored corrective invoice \| \| `261` \| Self-billed credit note \| \| `262` \| Global rebate credit note \| \| `381` \| Credit note \| \| `396` \| Factored credit note \| \| `502` \| Self-billed factored credit note \| \| `503` \| Credit note for an advance payment invoice \|. Example: `"380"`. Values: `380`, `389`, `393`, `501`, `386`, `500`, `384`, `471`, `472`, `473`, `261`, `262`, `381`, `396`, `502`, `503` | | `invoiceIssueDate` | string (date) | No | Issue date of the referenced invoice. Required unless statusCode is 501. Example: `"2024-03-15"`. Format: date | | `sellerLegalId` | string | No | Legal identifier (e.g. SIREN) of the invoice seller. Required unless statusCode is 501. Example: `"123456789"` | | `sellerLegalIdScheme` | string | No | ISO 6523 ICD scheme of the referenced invoice seller legal identifier. Required together with sellerLegalId. Example: `"0002"` | | `reasonCode` | string (enum) | No | Coded reason for the invoice lifecycle status. \| Value \| Meaning \| \| --- \| --- \| \| `JUSTIF_ABS` \| Supporting document missing or insufficient \| \| `ROUTAGE_ERR` \| Routing error \| \| `AUTRE` \| Other reason; provide an explanation in `reasonNote` \| \| `COORD_BANC_ERR` \| Incorrect bank details \| \| `TX_TVA_ERR` \| Incorrect VAT rate \| \| `MONTANTTOTAL_ERR` \| Incorrect invoice total \| \| `CALCUL_ERR` \| Invoice calculation error \| \| `NON_CONFORME` \| Missing legal information \| \| `DOUBLON` \| Duplicate invoice \| \| `DEST_INC` \| Unknown recipient \| \| `DEST_ERR` \| Incorrect recipient \| \| `TRANSAC_INC` \| Unknown transaction \| \| `EMMET_INC` \| Unknown issuer \| \| `CONTRAT_TERM` \| Contract ended \| \| `DOUBLE_FACT` \| Supply or service already invoiced on another invoice \| \| `CMD_ERR` \| Incorrect or missing order number \| \| `ADR_ERR` \| Incorrect electronic invoicing address \| \| `SIRET_ERR` \| Incorrect or missing SIRET \| \| `CODE_ROUTAGE_ERR` \| Incorrect or missing routing code \| \| `REF_CT_ABSENT` \| Required contractual reference missing \| \| `REF_ERR` \| Incorrect reference \| \| `PU_ERR` \| Incorrect unit price \| \| `REM_ERR` \| Incorrect discount \| \| `QTE_ERR` \| Incorrect invoiced quantity \| \| `ART_ERR` \| Incorrect invoiced item \| \| `MODPAI_ERR` \| Incorrect payment terms \| \| `QUALITE_ERR` \| Incorrect quality of delivered item \| \| `LIVR_INCOMP` \| Incomplete or non-compliant delivery \| \| `REJ_SEMAN` \| Rejected because of a semantic error \| \| `REJ_UNI` \| Rejected by uniqueness control \| \| `REJ_COH` \| Rejected by data-consistency control \| \| `REJ_ADR` \| Rejected by addressing control \| \| `REJ_CONT_B2G` \| Rejected by B2G business controls \| \| `REJ_REF_PJ` \| Rejected because of an attachment-reference error \| \| `REJ_ASS_PJ` \| Rejected because of an attachment-association error \| \| `NON_TRANSMISE` \| Submitted but not transmitted because the recipient has no receiving platform \|. Values: `JUSTIF_ABS`, `ROUTAGE_ERR`, `AUTRE`, `COORD_BANC_ERR`, `TX_TVA_ERR`, `MONTANTTOTAL_ERR`, `CALCUL_ERR`, `NON_CONFORME`, `DOUBLON`, `DEST_INC`, `DEST_ERR`, `TRANSAC_INC`, `EMMET_INC`, `CONTRAT_TERM`, `DOUBLE_FACT`, `CMD_ERR`, `ADR_ERR`, `SIRET_ERR`, `CODE_ROUTAGE_ERR`, `REF_CT_ABSENT`, `REF_ERR`, `PU_ERR`, `REM_ERR`, `QTE_ERR`, `ART_ERR`, `MODPAI_ERR`, `QUALITE_ERR`, `LIVR_INCOMP`, `REJ_SEMAN`, `REJ_UNI`, `REJ_COH`, `REJ_ADR`, `REJ_CONT_B2G`, `REJ_REF_PJ`, `REJ_ASS_PJ`, `NON_TRANSMISE` | | `reason` | string | No | Optional free-text status reason. This is distinct from the IncludedNote explanation required for reasonCode AUTRE | | `reasonNote` | string | No | Free-text comment in the status detail IncludedNote. Required when reasonCode is AUTRE. Example: `"The invoice needs manual review."` | | `collectedAmounts` | object[] | No | Collected amounts with VAT rates (TypeCode MEN). Required for status 212; at least one entry | **`issueDate`** (Any of): #### Variant 1 Type: `string (date-time)` #### Variant 2 Type: `string (date)` **`statusDate`** (Any of): #### Variant 1 Type: `string (date-time)` #### Variant 2 Type: `string (date)` **`collectedAmounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `amount` | string | Yes | Net collected amount (positive) or disbursed amount (negative), for status 212. Example: `"12000.00"` | | `currency` | string (enum) | Yes | ISO 4217 currency code of the collected amount. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `vatPercent` | string | Yes | VAT rate applicable to the collected amount. Example: `"20.00"` | #### French B2C reporting request **One of:** #### French B2C sales report | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"SALES-2026-07-01-GOODS"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `sales` to report transactions with private individuals. Send one sales report per day, category and currency, regardless of when customers pay. Value: `sales` | | `date` | string (date) | Yes | Day on which the reported sales took place. Example: `"2026-07-01"`. Format: date | | `category` | `goods` \| `services` | Yes | Whether this daily total covers taxable goods or taxable services. Use a separate report when both were sold on the same day. These are the two categories currently supported by this API. Example: `"goods"`. Values: `goods`, `services` | | `currency` | string (enum) | No | Three-letter currency code for the sales amounts excluding VAT. EUR is used when this field is omitted. French VAT amounts are always reported in EUR, including when this field uses another currency. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `taxExclusiveAmount` | string | Yes | Total sales amount excluding VAT for this day and category. Example: `"10000.00"` | | `taxAmount` | string | Yes | Total VAT amount for this day and category, expressed in EUR even when the sales currency is different. Example: `"2000.00"` | | `transactionCount` | integer | Yes | Number of individual sales included in this daily total. At least 1; a day without sales is not reported. Example: `42` | | `vatBreakdown` | object[] | Yes | Breakdown of the daily sales total by VAT rate. Include one entry for every VAT rate used. Min items: 1 | **`vatBreakdown`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate applied to these sales. Example: `"20.00"` | | `taxableAmount` | string | Yes | Sales amount excluding VAT for this VAT rate, expressed in the report's sales currency. Example: `"10000.00"` | | `taxAmount` | string | Yes | VAT amount for this VAT rate, expressed in EUR even when the sales currency is different. Example: `"2000.00"` | #### French B2C payment report | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"SALES-2026-07-01-GOODS"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `payments` only to additionally report payments received for services using cash-basis VAT (`TVA sur les encaissements`). Value: `payments` | | `date` | string (date) | Yes | Day on which the reported payments were received. Example: `"2026-07-01"`. Format: date | | `currency` | string (enum) | No | Three-letter currency code of the received amounts. EUR is used when this field is omitted. One report covers one day in one currency. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `vatBreakdown` | object[] | Yes | Payments received, grouped by VAT rate. Amounts include VAT. Min items: 1 | **`vatBreakdown`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate that applies to the received amount. Example: `"20.00"` | | `amount` | string | Yes | Amount received including VAT for this VAT rate, expressed in the report's currency. Example: `"12000.00"` | #### French cross-border reporting request **One of:** #### French cross-border invoice report | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"EREPORT-INV-2026-000431"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `invoice` to report a single cross-border invoice or credit note issued to a business. Value: `invoice` | | `documentNumber` | string | Yes | The number of the invoice or credit note being reported. A payment report refers back to it, and a correction or cancellation is matched on it. Example: `"INV-2026-000431"` | | `documentType` | `invoice` \| `creditNote` | No | Whether the reported document is an invoice or a credit note. Defaults to `invoice`. Default: `invoice`. Example: `"invoice"`. Values: `invoice`, `creditNote` | | `issueDate` | string (date) | Yes | Date on which the document was issued. Example: `"2026-01-15"`. Format: date | | `dueDate` | string \| null | No | Date on which the amount is due, when the document names one. Example: `"2026-02-14"`. Format: date | | `currency` | string (enum) | No | Three-letter currency code of the reported amounts. EUR is used when this field is omitted. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `buyer` | object | Yes | The foreign business the reported operation was invoiced to | | `taxExclusiveAmount` | string | Yes | Total amount of the document excluding VAT. Example: `"10000.00"` | | `taxAmount` | string | Yes | Total VAT amount of the document. Example: `"0.00"` | | `vatBreakdown` | object[] | Yes | Breakdown of the document total by VAT rate. Include one entry for every VAT rate used. Min items: 1 | **`buyer`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | The buyer's legal name. Example: `"Rossi Forniture S.r.l."` | | `country` | string | Yes | The country the buyer is established in, in ISO 3166-1:Alpha2 format. Must not be `FR`: invoices to French buyers are exchanged over the e-invoicing network instead of being reported. Example: `"IT"` | | `vatNumber` | string \| null | No | The buyer's intra-community VAT number. Required for buyers established in the European Union; it is how the tax administration identifies them. Leave it off for buyers outside the European Union, who are identified by their country and name instead. Example: `"IT00987654321"` | | `enterpriseNumber` | string \| null | No | The buyer's company registration number. Used for buyers in Nouvelle-Calédonie (RIDET) and Polynésie française (TAHITI); optional elsewhere. Example: `"0123456"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme the buyer's company registration number belongs to. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0223"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | **`vatBreakdown`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate applied to this part of the invoice. Example: `"0.00"` | | `taxableAmount` | string | Yes | Amount excluding VAT taxed at this rate. Example: `"10000.00"` | | `taxAmount` | string | Yes | VAT amount for this rate. Example: `"0.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code for this rate. Cross-border operations are typically exempt or reverse charged rather than taxed. Example: `"K"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `exemptionReason` | string \| null | No | Why no VAT is charged. Required, together with or instead of `exemptionReasonCode`, whenever the VAT category is an exempt one. Example: `"Intra-Community supply"` | | `exemptionReasonCode` | string \| null | No | The exemption reason code, from the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/). Example: `"VATEX-EU-IC"` | #### French cross-border payment report | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"EREPORT-INV-2026-000431"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `payment` to report a payment received on a cross-border invoice you reported earlier. Value: `payment` | | `invoiceNumber` | string | Yes | The `documentNumber` of the invoice report this payment belongs to. The invoice must have been reported before its payment can be. Example: `"INV-2026-000431"` | | `issueDate` | string (date) | Yes | Date on which the invoice was issued. Example: `"2026-01-15"`. Format: date | | `date` | string (date) | Yes | Date on which the payment was received. Example: `"2026-02-10"`. Format: date | | `currency` | string (enum) | No | Three-letter currency code of the received amounts. EUR is used when this field is omitted. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `vatBreakdown` | object[] | Yes | Amounts received, grouped by VAT rate. Amounts include VAT. Min items: 1 | **`vatBreakdown`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate that applies to the received amount. Example: `"20.00"` | | `amount` | string | Yes | Amount received including VAT for this VAT rate. Example: `"12000.00"` | #### Variant 9 Type: `null` **`validation`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `result` | `valid` \| `invalid` \| `not_supported` \| `error` | Yes | `valid`: the document passed every rule that applies to it. `invalid`: at least one rule was violated; see `errors`. `not_supported`: no ruleset is available for this document type, so nothing was checked. `error`: the validation service could not be reached or its answer could not be read. Example: `"valid"`. Values: `valid`, `invalid`, `not_supported`, `error` | | `errors` | object[] | Yes | The findings the validation produced. Empty when the document is valid, and also when the result is `not_supported` or `error` | **`errors`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `ruleCode` | string \| null | No | The identifier of the rule that was violated, for example an EN 16931 or Peppol BIS business rule code. Null for findings that come from something other than a coded rule, such as a schema error. Example: `"PEPPOL-EN16931-R010"` | | `errorMessage` | string | Yes | What the rule expected, in the words of the ruleset that raised it | | `errorLevel` | string | Yes | How serious the finding is. Only findings the ruleset treats as errors make a document invalid. Example: `"ERROR"` | | `fieldName` | string \| null | No | Where in the document the finding applies, usually as an XPath. Null when the finding is not tied to one place | | `source` | string | No | Which ruleset produced the finding, for example the syntax schema or a Peppol business rule set | **`labels`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The label's identifier, used wherever a label is assigned or unassigned. Example: `"lbl_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `externalId` | string \| null | Yes | Your own identifier for the label, if you set one. It is unique within the team, so you can address a label by the id your system already uses. Example: `"erp-routing-inbox"` | | `name` | string | Yes | The label's name, as it is shown in the dashboard and returned on the documents and suppliers it is assigned to. Example: `"ERP"` | | `colorHex` | string | Yes | The colour the label is shown in, as a hex code. Example: `"#3B82F6"` | **`reporting`** (One of): #### French Reporting Status | Name | Type | Required | Description | |------|------|----------|-------------| | `reportingStatus` | `accepted` \| `pending_rectificative` \| `filed` \| `filed_rectificative` \| `superseded` \| `rejected` | Yes | `accepted`: on file, inside its reporting period. `pending_rectificative`: arrived after the period was filed and will be carried by a corrective filing. `filed` / `filed_rectificative`: reported to the tax administration. `superseded`: replaced by a correction or cancelled. `rejected`: refused by the tax administration; see `outcomeCode`. Values: `accepted`, `pending_rectificative`, `filed`, `filed_rectificative`, `superseded`, `rejected` | | `receivedAt` | string \| null | Yes | When the report reached the reporting service | | `periodStart` | string \| null | Yes | First day of the reporting period the report belongs to | | `periodEnd` | string \| null | Yes | Last day of the reporting period; the cutoff for on-time filing | | `submissionId` | string \| null | Yes | The period filing the report was carried on, once assembled | | `outcomeCode` | string \| null | Yes | The tax administration's outcome code, once known | | `outcomeAt` | string \| null | Yes | When the tax administration returned its outcome | | `checkedAt` | string \| null | Yes | When the status was last refreshed from the reporting service | | `simulated` | boolean | Yes | True for playground and test-network reports, which are recorded but never filed | #### Variant 2 Type: `null` **`pagination`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `total` | number | Yes | | | `page` | number | Yes | | | `limit` | number | Yes | | | `totalPages` | number | Yes | | ### 500 Failed to fetch transmitted documents | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Get Document `GET /api/v1/documents/{documentId}` Get a single transmitted document by ID ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `documentId` | string | Yes | The ID of the document to retrieve | ## Responses ### 200 Successfully retrieved the document | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `document` | object | Yes | | **`document`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The Recommand document ID. Use it with the other document endpoints. Example: `"doc_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `teamId` | string | Yes | The ID of the team the document belongs to. Example: `"team_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string | Yes | The ID of the company the document was sent for or received by. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `direction` | `incoming` \| `outgoing` | Yes | Whether the document was received by this company (`incoming`) or sent by it (`outgoing`). Example: `"incoming"`. Values: `incoming`, `outgoing` | | `senderId` | string | Yes | The Peppol address of the sender, as `scheme:identifier`. Example: `"0208:1012081766"` | | `receiverId` | string \| null | Yes | The Peppol address of the receiver, as `scheme:identifier`. Null for documents that were never addressed on the network, such as email-only sends and French e-reporting reports. Example: `"0208:0428643097"` | | `docTypeId` | string | Yes | The full Peppol document type identifier the document was exchanged under. It names the syntax and the customization the document follows. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | Yes | The Peppol process identifier the document was exchanged under. It names the business process the document type is used in. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `countryC1` | string | Yes | The country of the originating sender (Peppol corner 1), in ISO 3166-1 alpha-2 format. Peppol requires it on every transmission so receivers can apply country-specific rules. Example: `"BE"` | | `type` | string (enum) | Yes | What kind of document this is. `unknown` means the document could not be recognised as one of the supported types, in which case `parsed` is null and only the XML is available. Example: `"invoice"`. Values: `invoice`, `creditNote`, `selfBillingInvoice`, `selfBillingCreditNote`, `messageLevelResponse`, `frenchInvoicingCdar`, `frenchB2CSalesReport`, `frenchB2CPaymentReport`, `frenchB2BiInvoiceReport`, `frenchB2BiPaymentReport`, `unknown` | | `readAt` | string \| null | Yes | When the document was marked as read. Null while it is unread, which is what puts an incoming document in the inbox | | `createdAt` | string | Yes | When the document was sent or received | | `updatedAt` | string | Yes | When the document record last changed | | `xml` | string \| null | Yes | The document as XML, exactly as it went over the network. Null for documents that have no XML body, such as French e-reporting reports | | `parsed` | Invoice | Credit Note | Self Billing Invoice | Self Billing Credit Note | Message Level Response | French Invoicing CDAR | French B2C reporting request | French cross-border reporting request | null | Yes | The document read into the JSON shape of its type, so you do not have to parse the XML yourself. Null when the type is `unknown` or the payload was not kept | | `validation` | object \| null | Yes | The outcome of validating the document against the rules of its document type. Null when the document was not validated | | `sentOverPeppol` | boolean | Yes | Whether the document travelled over the Peppol network. False for a document that was only delivered by email. Example: `true` | | `sentOverEmail` | boolean | Yes | Whether the document was delivered by email, either as the only channel or alongside Peppol. Example: `false` | | `emailRecipients` | string[] | Yes | The email addresses the document was delivered to. Empty when it was not sent by email. Example: `[]` | | `labels` | object[] | Yes | The labels assigned to this document. Manage them with the assign and unassign label endpoints | | `peppolMessageId` | string \| null | Yes | The AS4 message ID of the transmission. Null when the document did not travel over Peppol, and for playground teams, whose transmissions are simulated | | `peppolConversationId` | string \| null | Yes | The AS4 conversation ID the transmission belongs to. It ties a document to the responses that follow it | | `receivedPeppolSignalMessage` | string \| null | Yes | The AS4 signal message the receiving access point returned to acknowledge an outgoing transmission. Null for incoming documents and when the access point returned none | | `envelopeId` | string \| null | Yes | The envelope ID of the document, also known as the SBDH instance identifier (Standard Business Document Header Instance Identifier) | | `reporting` | French Reporting Status | null | Yes | Where a French e-reporting report stands with the tax administration. Null for documents that are not reports | **`parsed`** (Any of): #### Invoice | Name | Type | Required | Description | |------|------|----------|-------------| | `invoiceNumber` | string | Yes | The number the seller assigned to the invoice. Example: `"INV-2024-001"` | | `issueDate` | string (date) | Yes | The date the invoice was issued, as YYYY-MM-DD. Example: `"2024-03-20"`. Format: date | | `dueDate` | string \| null | No | The date the payment is due, as YYYY-MM-DD. Example: `"2024-04-20"`. Format: date | | `note` | string \| null | No | A free text note about the invoice as a whole. Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | A reference the buyer asked you to put on the invoice so they can route it internally. If neither this nor `purchaseOrderReference` is provided, the invoice number is used. Example: `"PO-2024-001"` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | `seller` | object | Yes | | | `buyer` | object | Yes | | | `delivery` | Delivery | null | No | Optional delivery information | | `paymentMeans` | object[] \| null | No | Optional payment information. For most invoices, this should be provided. For prepaid invoices, this could be omitted | | `paymentTerms` | object \| null | No | Optional payment terms | | `lines` | object[] | Yes | The invoice lines. At least one line is required. Min items: 1 | | `discounts` | object[] \| null | No | Optional global discounts | | `surcharges` | object[] \| null | No | Optional global surcharges | | `totals` | Totals | null | No | | | `vat` | Provided VAT totals | null | No | The VAT totals of the invoice, broken down per VAT category and rate | | `attachments` | object[] \| null | No | Optional attachments to the invoice | | `currency` | string (enum) | No | The currency of the invoice. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `countrySpecific` | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | **`seller`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`buyer`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`delivery`** (One of): #### Delivery | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | `locationIdentifier` | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | `location` | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | **`locationIdentifier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | **`location`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | #### Variant 2 Type: `null` **`paymentMeans`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | **`paymentTerms`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | The payment terms as free text. Example: `"Net 30"` | **`lines`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | `standardId` | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | `commodityClassifications` | object[] \| null | No | Optional commodity classifications | | `additionalItemProperties` | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | `discounts` | object[] \| null | No | Optional discounts for the line | | `surcharges` | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | `vat` | object | Yes | | **`standardId`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | **`commodityClassifications`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | **`additionalItemProperties`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`totals`** (One of): #### Totals | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | #### Variant 2 Type: `null` **`vat`** (One of): #### Provided VAT totals | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | `subtotals` | object[] | Yes | One entry for every combination of VAT category and rate used in the document | **`subtotals`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### Variant 2 Type: `null` **`attachments`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | **`countrySpecific`** (One of): #### Country Specific Billing **One of:** #### French Country Specific Billing | Name | Type | Required | Description | |------|------|----------|-------------| | `country` | string | Yes | Identifies this as the French regulatory extension. This is independent from seller, buyer, delivery, and origin country codes. Value: `FR` | | `billingMode` | string (enum) | Yes | Required only for French regulated UBL, CII, and Factur-X. Select the invoicing framework that matches the invoice. \| Mode \| Description \| \| --- \| --- \| \| `B1` \| Goods invoice. \| \| `S1` \| Services invoice. \| \| `M1` \| Mixed invoice containing goods and services that are not ancillary to each other. \| \| `B2` \| Goods invoice that has already been paid. \| \| `S2` \| Services invoice that has already been paid. \| \| `M2` \| Mixed invoice that has already been paid. \| \| `S3` \| B2G subcontractor payment request with direct payment. \| \| `B4` \| Final goods invoice after an advance payment. \| \| `S4` \| Final services invoice after an advance payment. \| \| `M4` \| Final mixed invoice after an advance payment. \| \| `S5` \| Invoice submitted by a subcontractor for services rendered. \| \| `S6` \| Invoice submitted by a co-contractor for services rendered. \| \| `B7` \| Goods invoice that has already been e-reported and for which VAT has already been collected. \| \| `S7` \| Services invoice that has already been e-reported and for which VAT has already been collected. \| \| `B8` \| Multi-seller goods invoice. \| \| `S8` \| Multi-seller services invoice. \| \| `M8` \| Multi-seller mixed invoice whose individual invoices are not all goods invoices or all services invoices. \| . Example: `"S1"`. Values: `B1`, `S1`, `M1`, `B2`, `S2`, `M2`, `S3`, `B4`, `S4`, `M4`, `S5`, `S6`, `B7`, `S7`, `B8`, `S8`, `M8`, `B9`, `S9`, `M9` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` | No | Determines which French Peppol process the document is sent over. Defaults to `REGULATED`. \| Value \| Description \| \| --- \| --- \| \| `REGULATED` \| Transaction inside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:regulated`. \| \| `NON_REGULATED` \| Transaction outside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:non-regulated`. \| The recipient must have registered the matching process for the document type in its SMP. Default: `REGULATED`. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED` | | `recoveryCostsNote` | string | Yes | The mandatory French recovery-cost indemnity statement, written as an IncludedNote with subject code PMT. Example: `"Indemnite forfaitaire de 40 EUR pour frais de recouvrement."` | | `latePaymentPenaltiesNote` | string | Yes | The mandatory French late-payment penalties statement, written as an IncludedNote with subject code PMD. Example: `"Penalites de retard exigibles au taux prevu dans les conditions generales de vente."` | | `earlyPaymentDiscountNote` | string | Yes | The mandatory French early-payment discount statement, written as an IncludedNote with subject code AAB. State either the offered discount terms or explicitly that no early-payment discount applies. Example: `"Aucun escompte accorde pour paiement anticipe."` | #### Variant 2 Type: `null` #### Credit Note | Name | Type | Required | Description | |------|------|----------|-------------| | `creditNoteNumber` | string | Yes | Example: `"CN-2024-001"` | | `issueDate` | string (date) | Yes | Example: `"2024-03-20"`. Format: date | | `note` | string \| null | No | Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | Example: `"PO-2024-001"` | | `invoiceReferences` | object[] | No | References to one or more invoices that are being credited. Default: `` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | `seller` | object | Yes | | | `buyer` | object | Yes | | | `delivery` | Delivery | null | No | Optional delivery information | | `paymentMeans` | object[] \| null | No | | | `paymentTerms` | object \| null | No | | | `lines` | object[] | Yes | Min items: 1 | | `discounts` | object[] \| null | No | Optional global discounts | | `surcharges` | object[] \| null | No | Optional global surcharges | | `totals` | Totals | null | No | | | `vat` | Provided VAT totals | null | No | | | `attachments` | object[] \| null | No | Optional attachments to the credit note | | `currency` | string (enum) | No | The currency of the credit note. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `countrySpecific` | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | **`invoiceReferences`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The reference to the invoice that is being credited. Example: `"INV-2024-001"` | | `issueDate` | string \| null | No | The issue date of the invoice that is being credited. Example: `"2024-03-20"`. Format: date | **`seller`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`buyer`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`delivery`** (One of): #### Delivery | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | `locationIdentifier` | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | `location` | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | **`locationIdentifier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | **`location`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | #### Variant 2 Type: `null` **`paymentMeans`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | **`paymentTerms`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | Example: `"Net 30"` | **`lines`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | `standardId` | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | `commodityClassifications` | object[] \| null | No | Optional commodity classifications | | `additionalItemProperties` | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | `discounts` | object[] \| null | No | Optional discounts for the line | | `surcharges` | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | `vat` | object | Yes | | **`standardId`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | **`commodityClassifications`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | **`additionalItemProperties`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`totals`** (One of): #### Totals | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | #### Variant 2 Type: `null` **`vat`** (One of): #### Provided VAT totals | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | `subtotals` | object[] | Yes | One entry for every combination of VAT category and rate used in the document | **`subtotals`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### Variant 2 Type: `null` **`attachments`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | **`countrySpecific`** (One of): #### Country Specific Billing **One of:** #### French Country Specific Billing | Name | Type | Required | Description | |------|------|----------|-------------| | `country` | string | Yes | Identifies this as the French regulatory extension. This is independent from seller, buyer, delivery, and origin country codes. Value: `FR` | | `billingMode` | string (enum) | Yes | Required only for French regulated UBL, CII, and Factur-X. Select the invoicing framework that matches the invoice. \| Mode \| Description \| \| --- \| --- \| \| `B1` \| Goods invoice. \| \| `S1` \| Services invoice. \| \| `M1` \| Mixed invoice containing goods and services that are not ancillary to each other. \| \| `B2` \| Goods invoice that has already been paid. \| \| `S2` \| Services invoice that has already been paid. \| \| `M2` \| Mixed invoice that has already been paid. \| \| `S3` \| B2G subcontractor payment request with direct payment. \| \| `B4` \| Final goods invoice after an advance payment. \| \| `S4` \| Final services invoice after an advance payment. \| \| `M4` \| Final mixed invoice after an advance payment. \| \| `S5` \| Invoice submitted by a subcontractor for services rendered. \| \| `S6` \| Invoice submitted by a co-contractor for services rendered. \| \| `B7` \| Goods invoice that has already been e-reported and for which VAT has already been collected. \| \| `S7` \| Services invoice that has already been e-reported and for which VAT has already been collected. \| \| `B8` \| Multi-seller goods invoice. \| \| `S8` \| Multi-seller services invoice. \| \| `M8` \| Multi-seller mixed invoice whose individual invoices are not all goods invoices or all services invoices. \| . Example: `"S1"`. Values: `B1`, `S1`, `M1`, `B2`, `S2`, `M2`, `S3`, `B4`, `S4`, `M4`, `S5`, `S6`, `B7`, `S7`, `B8`, `S8`, `M8`, `B9`, `S9`, `M9` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` | No | Determines which French Peppol process the document is sent over. Defaults to `REGULATED`. \| Value \| Description \| \| --- \| --- \| \| `REGULATED` \| Transaction inside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:regulated`. \| \| `NON_REGULATED` \| Transaction outside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:non-regulated`. \| The recipient must have registered the matching process for the document type in its SMP. Default: `REGULATED`. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED` | | `recoveryCostsNote` | string | Yes | The mandatory French recovery-cost indemnity statement, written as an IncludedNote with subject code PMT. Example: `"Indemnite forfaitaire de 40 EUR pour frais de recouvrement."` | | `latePaymentPenaltiesNote` | string | Yes | The mandatory French late-payment penalties statement, written as an IncludedNote with subject code PMD. Example: `"Penalites de retard exigibles au taux prevu dans les conditions generales de vente."` | | `earlyPaymentDiscountNote` | string | Yes | The mandatory French early-payment discount statement, written as an IncludedNote with subject code AAB. State either the offered discount terms or explicitly that no early-payment discount applies. Example: `"Aucun escompte accorde pour paiement anticipe."` | #### Variant 2 Type: `null` #### Self Billing Invoice | Name | Type | Required | Description | |------|------|----------|-------------| | `invoiceNumber` | string | Yes | The number the seller assigned to the invoice. Example: `"INV-2024-001"` | | `issueDate` | string (date) | Yes | The date the invoice was issued, as YYYY-MM-DD. Example: `"2024-03-20"`. Format: date | | `dueDate` | string \| null | No | The date the payment is due, as YYYY-MM-DD. Example: `"2024-04-20"`. Format: date | | `note` | string \| null | No | A free text note about the invoice as a whole. Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | A reference the buyer asked you to put on the invoice so they can route it internally. If neither this nor `purchaseOrderReference` is provided, the invoice number is used. Example: `"PO-2024-001"` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | `seller` | object | Yes | | | `buyer` | object | Yes | | | `delivery` | Delivery | null | No | Optional delivery information | | `paymentMeans` | object[] \| null | No | Optional payment information. For most invoices, this should be provided. For prepaid invoices, this could be omitted | | `paymentTerms` | object \| null | No | Optional payment terms | | `lines` | object[] | Yes | The invoice lines. At least one line is required. Min items: 1 | | `discounts` | object[] \| null | No | Optional global discounts | | `surcharges` | object[] \| null | No | Optional global surcharges | | `totals` | Totals | null | No | | | `vat` | Provided VAT totals | null | No | The VAT totals of the invoice, broken down per VAT category and rate | | `attachments` | object[] \| null | No | Optional attachments to the invoice | | `currency` | string (enum) | Yes | The currency of the invoice. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `countrySpecific` | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | **`seller`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`buyer`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`delivery`** (One of): #### Delivery | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | `locationIdentifier` | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | `location` | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | **`locationIdentifier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | **`location`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | #### Variant 2 Type: `null` **`paymentMeans`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | **`paymentTerms`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | The payment terms as free text. Example: `"Net 30"` | **`lines`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | `standardId` | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | `commodityClassifications` | object[] \| null | No | Optional commodity classifications | | `additionalItemProperties` | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | `discounts` | object[] \| null | No | Optional discounts for the line | | `surcharges` | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | `vat` | object | Yes | | **`standardId`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | **`commodityClassifications`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | **`additionalItemProperties`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`totals`** (One of): #### Totals | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | #### Variant 2 Type: `null` **`vat`** (One of): #### Provided VAT totals | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | `subtotals` | object[] | Yes | One entry for every combination of VAT category and rate used in the document | **`subtotals`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### Variant 2 Type: `null` **`attachments`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | **`countrySpecific`** (One of): #### Country Specific Billing **One of:** #### French Country Specific Billing | Name | Type | Required | Description | |------|------|----------|-------------| | `country` | string | Yes | Identifies this as the French regulatory extension. This is independent from seller, buyer, delivery, and origin country codes. Value: `FR` | | `billingMode` | string (enum) | Yes | Required only for French regulated UBL, CII, and Factur-X. Select the invoicing framework that matches the invoice. \| Mode \| Description \| \| --- \| --- \| \| `B1` \| Goods invoice. \| \| `S1` \| Services invoice. \| \| `M1` \| Mixed invoice containing goods and services that are not ancillary to each other. \| \| `B2` \| Goods invoice that has already been paid. \| \| `S2` \| Services invoice that has already been paid. \| \| `M2` \| Mixed invoice that has already been paid. \| \| `S3` \| B2G subcontractor payment request with direct payment. \| \| `B4` \| Final goods invoice after an advance payment. \| \| `S4` \| Final services invoice after an advance payment. \| \| `M4` \| Final mixed invoice after an advance payment. \| \| `S5` \| Invoice submitted by a subcontractor for services rendered. \| \| `S6` \| Invoice submitted by a co-contractor for services rendered. \| \| `B7` \| Goods invoice that has already been e-reported and for which VAT has already been collected. \| \| `S7` \| Services invoice that has already been e-reported and for which VAT has already been collected. \| \| `B8` \| Multi-seller goods invoice. \| \| `S8` \| Multi-seller services invoice. \| \| `M8` \| Multi-seller mixed invoice whose individual invoices are not all goods invoices or all services invoices. \| . Example: `"S1"`. Values: `B1`, `S1`, `M1`, `B2`, `S2`, `M2`, `S3`, `B4`, `S4`, `M4`, `S5`, `S6`, `B7`, `S7`, `B8`, `S8`, `M8`, `B9`, `S9`, `M9` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` | No | Determines which French Peppol process the document is sent over. Defaults to `REGULATED`. \| Value \| Description \| \| --- \| --- \| \| `REGULATED` \| Transaction inside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:regulated`. \| \| `NON_REGULATED` \| Transaction outside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:non-regulated`. \| The recipient must have registered the matching process for the document type in its SMP. Default: `REGULATED`. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED` | | `recoveryCostsNote` | string | Yes | The mandatory French recovery-cost indemnity statement, written as an IncludedNote with subject code PMT. Example: `"Indemnite forfaitaire de 40 EUR pour frais de recouvrement."` | | `latePaymentPenaltiesNote` | string | Yes | The mandatory French late-payment penalties statement, written as an IncludedNote with subject code PMD. Example: `"Penalites de retard exigibles au taux prevu dans les conditions generales de vente."` | | `earlyPaymentDiscountNote` | string | Yes | The mandatory French early-payment discount statement, written as an IncludedNote with subject code AAB. State either the offered discount terms or explicitly that no early-payment discount applies. Example: `"Aucun escompte accorde pour paiement anticipe."` | #### Variant 2 Type: `null` #### Self Billing Credit Note | Name | Type | Required | Description | |------|------|----------|-------------| | `creditNoteNumber` | string | Yes | Example: `"CN-2024-001"` | | `issueDate` | string (date) | Yes | Example: `"2024-03-20"`. Format: date | | `note` | string \| null | No | Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | Example: `"PO-2024-001"` | | `invoiceReferences` | object[] | Yes | References to one or more invoices that are being credited. Default: `` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | `seller` | object | Yes | | | `buyer` | object | Yes | | | `delivery` | Delivery | null | No | Optional delivery information | | `paymentMeans` | object[] \| null | No | | | `paymentTerms` | object \| null | No | | | `lines` | object[] | Yes | Min items: 1 | | `discounts` | object[] \| null | No | Optional global discounts | | `surcharges` | object[] \| null | No | Optional global surcharges | | `totals` | Totals | null | No | | | `vat` | Provided VAT totals | null | No | | | `attachments` | object[] \| null | No | Optional attachments to the credit note | | `currency` | string (enum) | Yes | The currency of the credit note. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `countrySpecific` | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | **`invoiceReferences`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The reference to the invoice that is being credited. Example: `"INV-2024-001"` | | `issueDate` | string \| null | No | The issue date of the invoice that is being credited. Example: `"2024-03-20"`. Format: date | **`seller`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`buyer`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | **`delivery`** (One of): #### Delivery | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | `locationIdentifier` | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | `location` | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | **`locationIdentifier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | **`location`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | #### Variant 2 Type: `null` **`paymentMeans`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | **`paymentTerms`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | Example: `"Net 30"` | **`lines`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | `standardId` | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | `commodityClassifications` | object[] \| null | No | Optional commodity classifications | | `additionalItemProperties` | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | `discounts` | object[] \| null | No | Optional discounts for the line | | `surcharges` | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | `vat` | object | Yes | | **`standardId`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | **`commodityClassifications`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | **`additionalItemProperties`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`discounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`surcharges`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | `vat` | object | Yes | | **`vat`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | **`totals`** (One of): #### Totals | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | #### Variant 2 Type: `null` **`vat`** (One of): #### Provided VAT totals | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | `subtotals` | object[] | Yes | One entry for every combination of VAT category and rate used in the document | **`subtotals`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | #### Variant 2 Type: `null` **`attachments`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | **`countrySpecific`** (One of): #### Country Specific Billing **One of:** #### French Country Specific Billing | Name | Type | Required | Description | |------|------|----------|-------------| | `country` | string | Yes | Identifies this as the French regulatory extension. This is independent from seller, buyer, delivery, and origin country codes. Value: `FR` | | `billingMode` | string (enum) | Yes | Required only for French regulated UBL, CII, and Factur-X. Select the invoicing framework that matches the invoice. \| Mode \| Description \| \| --- \| --- \| \| `B1` \| Goods invoice. \| \| `S1` \| Services invoice. \| \| `M1` \| Mixed invoice containing goods and services that are not ancillary to each other. \| \| `B2` \| Goods invoice that has already been paid. \| \| `S2` \| Services invoice that has already been paid. \| \| `M2` \| Mixed invoice that has already been paid. \| \| `S3` \| B2G subcontractor payment request with direct payment. \| \| `B4` \| Final goods invoice after an advance payment. \| \| `S4` \| Final services invoice after an advance payment. \| \| `M4` \| Final mixed invoice after an advance payment. \| \| `S5` \| Invoice submitted by a subcontractor for services rendered. \| \| `S6` \| Invoice submitted by a co-contractor for services rendered. \| \| `B7` \| Goods invoice that has already been e-reported and for which VAT has already been collected. \| \| `S7` \| Services invoice that has already been e-reported and for which VAT has already been collected. \| \| `B8` \| Multi-seller goods invoice. \| \| `S8` \| Multi-seller services invoice. \| \| `M8` \| Multi-seller mixed invoice whose individual invoices are not all goods invoices or all services invoices. \| . Example: `"S1"`. Values: `B1`, `S1`, `M1`, `B2`, `S2`, `M2`, `S3`, `B4`, `S4`, `M4`, `S5`, `S6`, `B7`, `S7`, `B8`, `S8`, `M8`, `B9`, `S9`, `M9` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` | No | Determines which French Peppol process the document is sent over. Defaults to `REGULATED`. \| Value \| Description \| \| --- \| --- \| \| `REGULATED` \| Transaction inside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:regulated`. \| \| `NON_REGULATED` \| Transaction outside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:non-regulated`. \| The recipient must have registered the matching process for the document type in its SMP. Default: `REGULATED`. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED` | | `recoveryCostsNote` | string | Yes | The mandatory French recovery-cost indemnity statement, written as an IncludedNote with subject code PMT. Example: `"Indemnite forfaitaire de 40 EUR pour frais de recouvrement."` | | `latePaymentPenaltiesNote` | string | Yes | The mandatory French late-payment penalties statement, written as an IncludedNote with subject code PMD. Example: `"Penalites de retard exigibles au taux prevu dans les conditions generales de vente."` | | `earlyPaymentDiscountNote` | string | Yes | The mandatory French early-payment discount statement, written as an IncludedNote with subject code AAB. State either the offered discount terms or explicitly that no early-payment discount applies. Example: `"Aucun escompte accorde pour paiement anticipe."` | #### Variant 2 Type: `null` #### Message Level Response | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | | | `issueDate` | string (date) | Yes | Example: `"2024-03-20"`. Format: date | | `responseCode` | `AB` \| `AP` \| `RE` | Yes | The response code of the message level response (AB: Message acknowledgement, AP: Accepted, RE: Rejected). Example: `"AB"`. Values: `AB`, `AP`, `RE` | | `envelopeId` | string | Yes | Identifies the document on which the message level response is based | #### French Invoicing CDAR | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | | | `issueDate` | string (date-time) | string (date) | Yes | Creation date and time of the CDAR, without a timezone and with second precision. Date-only values are accepted for incoming format-102 documents. Example: `"2024-03-20T14:05:09"` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` \| `B2C` \| `B2CINT` \| `B2BINT` \| `OUTOFSCOPE` | Yes | Flow classification. \| Value \| Meaning \| \| --- \| --- \| \| `REGULATED` \| Regulated French domestic e-invoicing \| \| `NON_REGULATED` \| Outside the regulated French e-invoicing perimeter \| \| `B2C` \| B2C sales e-reporting \| \| `B2CINT` \| International B2C sales e-reporting \| \| `B2BINT` \| International B2B sales e-reporting \| \| `OUTOFSCOPE` \| Outside the French e-invoicing and e-reporting reform \|. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED`, `B2C`, `B2CINT`, `B2BINT`, `OUTOFSCOPE` | | `phase` | `23` \| `305` | Yes | CDAR phase. \| Value \| Meaning \| \| --- \| --- \| \| `23` \| Processing phase \| \| `305` \| Transmission phase \|. Example: `"23"`. Values: `23`, `305` | | `senderRole` | string (enum) | Yes | Role of the CDAR sender. CDAR party role code (UNCL 3035). \| Value \| Meaning \| \| --- \| --- \| \| `BY` \| Buyer \| \| `AB` \| Buyer's agent or representative \| \| `DL` \| Factor \| \| `SE` \| Seller \| \| `SR` \| Seller's agent \| \| `WK` \| Platform or dematerialisation operator \| \| `DFH` \| French public invoicing portal (PPF) \| \| `PE` \| Payee \| \| `PR` \| Payer \| \| `II` \| Invoicer (invoice issuer) \| \| `IV` \| Invoicee (party invoiced) \|. Example: `"WK"`. Values: `BY`, `AB`, `DL`, `SE`, `SR`, `WK`, `DFH`, `PE`, `PR`, `II`, `IV` | | `issuerRole` | string (enum) | Yes | Role of the party that creates and issues the invoice lifecycle status. This is independent from the CDAR sender role. CDAR party role code (UNCL 3035). \| Value \| Meaning \| \| --- \| --- \| \| `BY` \| Buyer \| \| `AB` \| Buyer's agent or representative \| \| `DL` \| Factor \| \| `SE` \| Seller \| \| `SR` \| Seller's agent \| \| `WK` \| Platform or dematerialisation operator \| \| `DFH` \| French public invoicing portal (PPF) \| \| `PE` \| Payee \| \| `PR` \| Payer \| \| `II` \| Invoicer (invoice issuer) \| \| `IV` \| Invoicee (party invoiced) \|. Example: `"BY"`. Values: `BY`, `AB`, `DL`, `SE`, `SR`, `WK`, `DFH`, `PE`, `PR`, `II`, `IV` | | `issuerLegalId` | string | No | Legal identifier of the party setting the status. Required when phase is 23; must be omitted when phase is 305 unless recipientRole is DFH. Example: `"200000008"` | | `issuerLegalIdScheme` | string | No | ISO 6523 ICD scheme of the party-setting-status legal identifier. Required together with issuerLegalId. Example: `"0002"` | | `recipientRole` | string (enum) | Yes | Role of the CDAR recipient. CDAR party role code (UNCL 3035). \| Value \| Meaning \| \| --- \| --- \| \| `BY` \| Buyer \| \| `AB` \| Buyer's agent or representative \| \| `DL` \| Factor \| \| `SE` \| Seller \| \| `SR` \| Seller's agent \| \| `WK` \| Platform or dematerialisation operator \| \| `DFH` \| French public invoicing portal (PPF) \| \| `PE` \| Payee \| \| `PR` \| Payer \| \| `II` \| Invoicer (invoice issuer) \| \| `IV` \| Invoicee (party invoiced) \|. Example: `"SE"`. Values: `BY`, `AB`, `DL`, `SE`, `SR`, `WK`, `DFH`, `PE`, `PR`, `II`, `IV` | | `recipientLegalId` | string | No | Legal identifier of the CDAR recipient. Example: `"200000008"` | | `recipientLegalIdScheme` | string | No | ISO 6523 ICD scheme of the CDAR recipient legal identifier. Required together with recipientLegalId. Example: `"0002"` | | `recipientElectronicAddress` | string | No | Electronic address of the CDAR recipient. Required when recipientRole is not WK or DFH. Example: `"100000009"` | | `recipientElectronicAddressScheme` | string | No | Electronic Address Scheme (EAS) code of the CDAR recipient electronic address. Required together with recipientElectronicAddress. Example: `"0225"` | | `statusCode` | string (enum) | Yes | French invoice lifecycle status. \| Value \| Meaning \| \| --- \| --- \| \| `200` \| Submitted \| \| `201` \| Issued \| \| `202` \| Received \| \| `203` \| Made available \| \| `204` \| Taken in charge (processing started) \| \| `205` \| Approved \| \| `206` \| Partially approved \| \| `207` \| In dispute \| \| `208` \| Suspended \| \| `209` \| Completed \| \| `210` \| Refused \| \| `211` \| Payment sent \| \| `212` \| Collected (cashed) \| \| `213` \| Rejected \| \| `214` \| Validated or pre-validated ("Visée") \| \| `501` \| Inadmissible file \|. Example: `"200"`. Values: `200`, `201`, `202`, `203`, `204`, `205`, `206`, `207`, `208`, `209`, `210`, `211`, `212`, `213`, `214`, `501` | | `statusDate` | string (date-time) | string (date) | Yes | Date and time at which the status itself was set, without a timezone and with second precision. This is distinct from issueDate, which is the creation date and time of the CDAR message. Date-only values are accepted for incoming format-102 documents. Example: `"2024-03-20T14:05:09"` | | `invoiceId` | string | Yes | Number of the invoice this status relates to. For status 501, this is the filename of the inadmissible file | | `invoiceTypeCode` | string (enum) | No | Type of the referenced invoice. Type of the referenced invoice (UNTDID 1001, restricted to the values allowed by BR-FR-04). \| Value \| Meaning \| \| --- \| --- \| \| `380` \| Commercial invoice \| \| `389` \| Self-billed invoice \| \| `393` \| Factored invoice \| \| `501` \| Self-billed factored invoice \| \| `386` \| Advance payment invoice \| \| `500` \| Self-billed advance payment invoice \| \| `384` \| Corrective invoice \| \| `471` \| Self-billed corrective invoice \| \| `472` \| Factored corrective invoice \| \| `473` \| Self-billed factored corrective invoice \| \| `261` \| Self-billed credit note \| \| `262` \| Global rebate credit note \| \| `381` \| Credit note \| \| `396` \| Factored credit note \| \| `502` \| Self-billed factored credit note \| \| `503` \| Credit note for an advance payment invoice \|. Example: `"380"`. Values: `380`, `389`, `393`, `501`, `386`, `500`, `384`, `471`, `472`, `473`, `261`, `262`, `381`, `396`, `502`, `503` | | `invoiceIssueDate` | string (date) | No | Issue date of the referenced invoice. Required unless statusCode is 501. Example: `"2024-03-15"`. Format: date | | `sellerLegalId` | string | No | Legal identifier (e.g. SIREN) of the invoice seller. Required unless statusCode is 501. Example: `"123456789"` | | `sellerLegalIdScheme` | string | No | ISO 6523 ICD scheme of the referenced invoice seller legal identifier. Required together with sellerLegalId. Example: `"0002"` | | `reasonCode` | string (enum) | No | Coded reason for the invoice lifecycle status. \| Value \| Meaning \| \| --- \| --- \| \| `JUSTIF_ABS` \| Supporting document missing or insufficient \| \| `ROUTAGE_ERR` \| Routing error \| \| `AUTRE` \| Other reason; provide an explanation in `reasonNote` \| \| `COORD_BANC_ERR` \| Incorrect bank details \| \| `TX_TVA_ERR` \| Incorrect VAT rate \| \| `MONTANTTOTAL_ERR` \| Incorrect invoice total \| \| `CALCUL_ERR` \| Invoice calculation error \| \| `NON_CONFORME` \| Missing legal information \| \| `DOUBLON` \| Duplicate invoice \| \| `DEST_INC` \| Unknown recipient \| \| `DEST_ERR` \| Incorrect recipient \| \| `TRANSAC_INC` \| Unknown transaction \| \| `EMMET_INC` \| Unknown issuer \| \| `CONTRAT_TERM` \| Contract ended \| \| `DOUBLE_FACT` \| Supply or service already invoiced on another invoice \| \| `CMD_ERR` \| Incorrect or missing order number \| \| `ADR_ERR` \| Incorrect electronic invoicing address \| \| `SIRET_ERR` \| Incorrect or missing SIRET \| \| `CODE_ROUTAGE_ERR` \| Incorrect or missing routing code \| \| `REF_CT_ABSENT` \| Required contractual reference missing \| \| `REF_ERR` \| Incorrect reference \| \| `PU_ERR` \| Incorrect unit price \| \| `REM_ERR` \| Incorrect discount \| \| `QTE_ERR` \| Incorrect invoiced quantity \| \| `ART_ERR` \| Incorrect invoiced item \| \| `MODPAI_ERR` \| Incorrect payment terms \| \| `QUALITE_ERR` \| Incorrect quality of delivered item \| \| `LIVR_INCOMP` \| Incomplete or non-compliant delivery \| \| `REJ_SEMAN` \| Rejected because of a semantic error \| \| `REJ_UNI` \| Rejected by uniqueness control \| \| `REJ_COH` \| Rejected by data-consistency control \| \| `REJ_ADR` \| Rejected by addressing control \| \| `REJ_CONT_B2G` \| Rejected by B2G business controls \| \| `REJ_REF_PJ` \| Rejected because of an attachment-reference error \| \| `REJ_ASS_PJ` \| Rejected because of an attachment-association error \| \| `NON_TRANSMISE` \| Submitted but not transmitted because the recipient has no receiving platform \|. Values: `JUSTIF_ABS`, `ROUTAGE_ERR`, `AUTRE`, `COORD_BANC_ERR`, `TX_TVA_ERR`, `MONTANTTOTAL_ERR`, `CALCUL_ERR`, `NON_CONFORME`, `DOUBLON`, `DEST_INC`, `DEST_ERR`, `TRANSAC_INC`, `EMMET_INC`, `CONTRAT_TERM`, `DOUBLE_FACT`, `CMD_ERR`, `ADR_ERR`, `SIRET_ERR`, `CODE_ROUTAGE_ERR`, `REF_CT_ABSENT`, `REF_ERR`, `PU_ERR`, `REM_ERR`, `QTE_ERR`, `ART_ERR`, `MODPAI_ERR`, `QUALITE_ERR`, `LIVR_INCOMP`, `REJ_SEMAN`, `REJ_UNI`, `REJ_COH`, `REJ_ADR`, `REJ_CONT_B2G`, `REJ_REF_PJ`, `REJ_ASS_PJ`, `NON_TRANSMISE` | | `reason` | string | No | Optional free-text status reason. This is distinct from the IncludedNote explanation required for reasonCode AUTRE | | `reasonNote` | string | No | Free-text comment in the status detail IncludedNote. Required when reasonCode is AUTRE. Example: `"The invoice needs manual review."` | | `collectedAmounts` | object[] | No | Collected amounts with VAT rates (TypeCode MEN). Required for status 212; at least one entry | **`issueDate`** (Any of): #### Variant 1 Type: `string (date-time)` #### Variant 2 Type: `string (date)` **`statusDate`** (Any of): #### Variant 1 Type: `string (date-time)` #### Variant 2 Type: `string (date)` **`collectedAmounts`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `amount` | string | Yes | Net collected amount (positive) or disbursed amount (negative), for status 212. Example: `"12000.00"` | | `currency` | string (enum) | Yes | ISO 4217 currency code of the collected amount. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `vatPercent` | string | Yes | VAT rate applicable to the collected amount. Example: `"20.00"` | #### French B2C reporting request **One of:** #### French B2C sales report | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"SALES-2026-07-01-GOODS"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `sales` to report transactions with private individuals. Send one sales report per day, category and currency, regardless of when customers pay. Value: `sales` | | `date` | string (date) | Yes | Day on which the reported sales took place. Example: `"2026-07-01"`. Format: date | | `category` | `goods` \| `services` | Yes | Whether this daily total covers taxable goods or taxable services. Use a separate report when both were sold on the same day. These are the two categories currently supported by this API. Example: `"goods"`. Values: `goods`, `services` | | `currency` | string (enum) | No | Three-letter currency code for the sales amounts excluding VAT. EUR is used when this field is omitted. French VAT amounts are always reported in EUR, including when this field uses another currency. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `taxExclusiveAmount` | string | Yes | Total sales amount excluding VAT for this day and category. Example: `"10000.00"` | | `taxAmount` | string | Yes | Total VAT amount for this day and category, expressed in EUR even when the sales currency is different. Example: `"2000.00"` | | `transactionCount` | integer | Yes | Number of individual sales included in this daily total. At least 1; a day without sales is not reported. Example: `42` | | `vatBreakdown` | object[] | Yes | Breakdown of the daily sales total by VAT rate. Include one entry for every VAT rate used. Min items: 1 | **`vatBreakdown`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate applied to these sales. Example: `"20.00"` | | `taxableAmount` | string | Yes | Sales amount excluding VAT for this VAT rate, expressed in the report's sales currency. Example: `"10000.00"` | | `taxAmount` | string | Yes | VAT amount for this VAT rate, expressed in EUR even when the sales currency is different. Example: `"2000.00"` | #### French B2C payment report | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"SALES-2026-07-01-GOODS"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `payments` only to additionally report payments received for services using cash-basis VAT (`TVA sur les encaissements`). Value: `payments` | | `date` | string (date) | Yes | Day on which the reported payments were received. Example: `"2026-07-01"`. Format: date | | `currency` | string (enum) | No | Three-letter currency code of the received amounts. EUR is used when this field is omitted. One report covers one day in one currency. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `vatBreakdown` | object[] | Yes | Payments received, grouped by VAT rate. Amounts include VAT. Min items: 1 | **`vatBreakdown`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate that applies to the received amount. Example: `"20.00"` | | `amount` | string | Yes | Amount received including VAT for this VAT rate, expressed in the report's currency. Example: `"12000.00"` | #### French cross-border reporting request **One of:** #### French cross-border invoice report | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"EREPORT-INV-2026-000431"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `invoice` to report a single cross-border invoice or credit note issued to a business. Value: `invoice` | | `documentNumber` | string | Yes | The number of the invoice or credit note being reported. A payment report refers back to it, and a correction or cancellation is matched on it. Example: `"INV-2026-000431"` | | `documentType` | `invoice` \| `creditNote` | No | Whether the reported document is an invoice or a credit note. Defaults to `invoice`. Default: `invoice`. Example: `"invoice"`. Values: `invoice`, `creditNote` | | `issueDate` | string (date) | Yes | Date on which the document was issued. Example: `"2026-01-15"`. Format: date | | `dueDate` | string \| null | No | Date on which the amount is due, when the document names one. Example: `"2026-02-14"`. Format: date | | `currency` | string (enum) | No | Three-letter currency code of the reported amounts. EUR is used when this field is omitted. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `buyer` | object | Yes | The foreign business the reported operation was invoiced to | | `taxExclusiveAmount` | string | Yes | Total amount of the document excluding VAT. Example: `"10000.00"` | | `taxAmount` | string | Yes | Total VAT amount of the document. Example: `"0.00"` | | `vatBreakdown` | object[] | Yes | Breakdown of the document total by VAT rate. Include one entry for every VAT rate used. Min items: 1 | **`buyer`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | The buyer's legal name. Example: `"Rossi Forniture S.r.l."` | | `country` | string | Yes | The country the buyer is established in, in ISO 3166-1:Alpha2 format. Must not be `FR`: invoices to French buyers are exchanged over the e-invoicing network instead of being reported. Example: `"IT"` | | `vatNumber` | string \| null | No | The buyer's intra-community VAT number. Required for buyers established in the European Union; it is how the tax administration identifies them. Leave it off for buyers outside the European Union, who are identified by their country and name instead. Example: `"IT00987654321"` | | `enterpriseNumber` | string \| null | No | The buyer's company registration number. Used for buyers in Nouvelle-Calédonie (RIDET) and Polynésie française (TAHITI); optional elsewhere. Example: `"0123456"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme the buyer's company registration number belongs to. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0223"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | **`vatBreakdown`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate applied to this part of the invoice. Example: `"0.00"` | | `taxableAmount` | string | Yes | Amount excluding VAT taxed at this rate. Example: `"10000.00"` | | `taxAmount` | string | Yes | VAT amount for this rate. Example: `"0.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code for this rate. Cross-border operations are typically exempt or reverse charged rather than taxed. Example: `"K"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `exemptionReason` | string \| null | No | Why no VAT is charged. Required, together with or instead of `exemptionReasonCode`, whenever the VAT category is an exempt one. Example: `"Intra-Community supply"` | | `exemptionReasonCode` | string \| null | No | The exemption reason code, from the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/). Example: `"VATEX-EU-IC"` | #### French cross-border payment report | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"EREPORT-INV-2026-000431"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `payment` to report a payment received on a cross-border invoice you reported earlier. Value: `payment` | | `invoiceNumber` | string | Yes | The `documentNumber` of the invoice report this payment belongs to. The invoice must have been reported before its payment can be. Example: `"INV-2026-000431"` | | `issueDate` | string (date) | Yes | Date on which the invoice was issued. Example: `"2026-01-15"`. Format: date | | `date` | string (date) | Yes | Date on which the payment was received. Example: `"2026-02-10"`. Format: date | | `currency` | string (enum) | No | Three-letter currency code of the received amounts. EUR is used when this field is omitted. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `vatBreakdown` | object[] | Yes | Amounts received, grouped by VAT rate. Amounts include VAT. Min items: 1 | **`vatBreakdown`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate that applies to the received amount. Example: `"20.00"` | | `amount` | string | Yes | Amount received including VAT for this VAT rate. Example: `"12000.00"` | #### Variant 9 Type: `null` **`validation`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `result` | `valid` \| `invalid` \| `not_supported` \| `error` | Yes | `valid`: the document passed every rule that applies to it. `invalid`: at least one rule was violated; see `errors`. `not_supported`: no ruleset is available for this document type, so nothing was checked. `error`: the validation service could not be reached or its answer could not be read. Example: `"valid"`. Values: `valid`, `invalid`, `not_supported`, `error` | | `errors` | object[] | Yes | The findings the validation produced. Empty when the document is valid, and also when the result is `not_supported` or `error` | **`errors`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `ruleCode` | string \| null | No | The identifier of the rule that was violated, for example an EN 16931 or Peppol BIS business rule code. Null for findings that come from something other than a coded rule, such as a schema error. Example: `"PEPPOL-EN16931-R010"` | | `errorMessage` | string | Yes | What the rule expected, in the words of the ruleset that raised it | | `errorLevel` | string | Yes | How serious the finding is. Only findings the ruleset treats as errors make a document invalid. Example: `"ERROR"` | | `fieldName` | string \| null | No | Where in the document the finding applies, usually as an XPath. Null when the finding is not tied to one place | | `source` | string | No | Which ruleset produced the finding, for example the syntax schema or a Peppol business rule set | **`labels`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The label's identifier, used wherever a label is assigned or unassigned. Example: `"lbl_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `externalId` | string \| null | Yes | Your own identifier for the label, if you set one. It is unique within the team, so you can address a label by the id your system already uses. Example: `"erp-routing-inbox"` | | `name` | string | Yes | The label's name, as it is shown in the dashboard and returned on the documents and suppliers it is assigned to. Example: `"ERP"` | | `colorHex` | string | Yes | The colour the label is shown in, as a hex code. Example: `"#3B82F6"` | **`reporting`** (One of): #### French Reporting Status | Name | Type | Required | Description | |------|------|----------|-------------| | `reportingStatus` | `accepted` \| `pending_rectificative` \| `filed` \| `filed_rectificative` \| `superseded` \| `rejected` | Yes | `accepted`: on file, inside its reporting period. `pending_rectificative`: arrived after the period was filed and will be carried by a corrective filing. `filed` / `filed_rectificative`: reported to the tax administration. `superseded`: replaced by a correction or cancelled. `rejected`: refused by the tax administration; see `outcomeCode`. Values: `accepted`, `pending_rectificative`, `filed`, `filed_rectificative`, `superseded`, `rejected` | | `receivedAt` | string \| null | Yes | When the report reached the reporting service | | `periodStart` | string \| null | Yes | First day of the reporting period the report belongs to | | `periodEnd` | string \| null | Yes | Last day of the reporting period; the cutoff for on-time filing | | `submissionId` | string \| null | Yes | The period filing the report was carried on, once assembled | | `outcomeCode` | string \| null | Yes | The tax administration's outcome code, once known | | `outcomeAt` | string \| null | Yes | When the tax administration returned its outcome | | `checkedAt` | string \| null | Yes | When the status was last refreshed from the reporting service | | `simulated` | boolean | Yes | True for playground and test-network reports, which are recorded but never filed | #### Variant 2 Type: `null` ### 404 Document not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to fetch document | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Delete Document `DELETE /api/v1/documents/{documentId}` Permanently delete a document and everything stored with it: its XML, its attachments and its original payload. This cannot be undone, and the document disappears from the list, inbox and export endpoints. Deleting a document does not withdraw anything from the Peppol network; a document that was transmitted has already reached its recipient. Deleting an ID that does not exist, or that was deleted before, also succeeds, so a retried delete is safe. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `documentId` | string | Yes | The ID of the document to delete | ## Responses ### 200 Successfully deleted the document | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `true` | ### 500 Failed to delete document | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Inbox `GET /api/v1/inbox` List the incoming documents that have not been marked as read. Use it as a work queue: process a document, then mark it as read so the next call no longer returns it. This response is not paginated and carries every unread incoming document, so keeping up with the marking is what keeps it a reasonable size. It differs from `GET /documents?isUnread=true&direction=incoming` in two ways: that endpoint is paginated and filterable, and it returns the parsed document body, which the inbox leaves out to stay cheap. Fetch a document by its ID when you need its contents. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Query Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | No | Optionally filter documents by company ID | ## Responses ### 200 Successfully retrieved inbox documents | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `documents` | object[] | Yes | | **`documents`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The Recommand document ID. Use it with the other document endpoints. Example: `"doc_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `teamId` | string | Yes | The ID of the team the document belongs to. Example: `"team_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string | Yes | The ID of the company the document was sent for or received by. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `direction` | `incoming` \| `outgoing` | Yes | Whether the document was received by this company (`incoming`) or sent by it (`outgoing`). Example: `"incoming"`. Values: `incoming`, `outgoing` | | `senderId` | string | Yes | The Peppol address of the sender, as `scheme:identifier`. Example: `"0208:1012081766"` | | `receiverId` | string \| null | Yes | The Peppol address of the receiver, as `scheme:identifier`. Null for documents that were never addressed on the network, such as email-only sends and French e-reporting reports. Example: `"0208:0428643097"` | | `docTypeId` | string | Yes | The full Peppol document type identifier the document was exchanged under. It names the syntax and the customization the document follows. Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | Yes | The Peppol process identifier the document was exchanged under. It names the business process the document type is used in. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | | `countryC1` | string | Yes | The country of the originating sender (Peppol corner 1), in ISO 3166-1 alpha-2 format. Peppol requires it on every transmission so receivers can apply country-specific rules. Example: `"BE"` | | `type` | string (enum) | Yes | What kind of document this is. `unknown` means the document could not be recognised as one of the supported types, in which case `parsed` is null and only the XML is available. Example: `"invoice"`. Values: `invoice`, `creditNote`, `selfBillingInvoice`, `selfBillingCreditNote`, `messageLevelResponse`, `frenchInvoicingCdar`, `frenchB2CSalesReport`, `frenchB2CPaymentReport`, `frenchB2BiInvoiceReport`, `frenchB2BiPaymentReport`, `unknown` | | `readAt` | string \| null | Yes | When the document was marked as read. Null while it is unread, which is what puts an incoming document in the inbox | | `createdAt` | string | Yes | When the document was sent or received | | `updatedAt` | string | Yes | When the document record last changed | | `validation` | object \| null | Yes | The outcome of validating the document against the rules of its document type. Null when the document was not validated | | `sentOverPeppol` | boolean | Yes | Whether the document travelled over the Peppol network. False for a document that was only delivered by email. Example: `true` | | `sentOverEmail` | boolean | Yes | Whether the document was delivered by email, either as the only channel or alongside Peppol. Example: `false` | | `emailRecipients` | string[] | Yes | The email addresses the document was delivered to. Empty when it was not sent by email. Example: `[]` | | `labels` | object[] | Yes | The labels assigned to this document. Manage them with the assign and unassign label endpoints | | `peppolMessageId` | string \| null | Yes | The AS4 message ID of the transmission. Null when the document did not travel over Peppol, and for playground teams, whose transmissions are simulated | | `peppolConversationId` | string \| null | Yes | The AS4 conversation ID the transmission belongs to. It ties a document to the responses that follow it | | `receivedPeppolSignalMessage` | string \| null | Yes | The AS4 signal message the receiving access point returned to acknowledge an outgoing transmission. Null for incoming documents and when the access point returned none | | `envelopeId` | string \| null | Yes | The envelope ID of the document, also known as the SBDH instance identifier (Standard Business Document Header Instance Identifier) | **`validation`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `result` | `valid` \| `invalid` \| `not_supported` \| `error` | Yes | `valid`: the document passed every rule that applies to it. `invalid`: at least one rule was violated; see `errors`. `not_supported`: no ruleset is available for this document type, so nothing was checked. `error`: the validation service could not be reached or its answer could not be read. Example: `"valid"`. Values: `valid`, `invalid`, `not_supported`, `error` | | `errors` | object[] | Yes | The findings the validation produced. Empty when the document is valid, and also when the result is `not_supported` or `error` | **`errors`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `ruleCode` | string \| null | No | The identifier of the rule that was violated, for example an EN 16931 or Peppol BIS business rule code. Null for findings that come from something other than a coded rule, such as a schema error. Example: `"PEPPOL-EN16931-R010"` | | `errorMessage` | string | Yes | What the rule expected, in the words of the ruleset that raised it | | `errorLevel` | string | Yes | How serious the finding is. Only findings the ruleset treats as errors make a document invalid. Example: `"ERROR"` | | `fieldName` | string \| null | No | Where in the document the finding applies, usually as an XPath. Null when the finding is not tied to one place | | `source` | string | No | Which ruleset produced the finding, for example the syntax schema or a Peppol business rule set | **`labels`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The label's identifier, used wherever a label is assigned or unassigned. Example: `"lbl_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `externalId` | string \| null | Yes | Your own identifier for the label, if you set one. It is unique within the team, so you can address a label by the id your system already uses. Example: `"erp-routing-inbox"` | | `name` | string | Yes | The label's name, as it is shown in the dashboard and returned on the documents and suppliers it is assigned to. Example: `"ERP"` | | `colorHex` | string | Yes | The colour the label is shown in, as a hex code. Example: `"#3B82F6"` | ### 500 Failed to fetch inbox documents | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Mark Document as Read `POST /api/v1/documents/{documentId}/mark-as-read` Mark a document as read, which is what takes it out of the inbox, or send `read: false` to put it back. Calling it again with the same value is harmless. Reading a document through the other endpoints does not mark it: this endpoint is the only thing that does, so an integration decides for itself when a document is done. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `documentId` | string | Yes | The ID of the document to mark as read or unread | ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `read` | boolean | No | Whether to mark the document as read (true) or unread (false). If not provided, defaults to true. Default: `true`. Example: `true` | ## Responses ### 200 Successfully updated document read status | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `true` | ### 404 Document not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to update document read status | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Download Document Package `GET /api/v1/documents/{documentId}/download-package` Download everything stored for one document as a zip: `document.json` with its metadata and parsed contents, `document.xml` with the document as it went over the network, the original payload it was sent as when there was one, and one file per binary attachment. Use `generatePdf` to add a rendered `auto-generated.pdf`, either always or only when the document carries no PDF attachment of its own. The response is `application/zip`, not JSON. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `documentId` | string | Yes | The ID of the document to download | ### Query Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `generatePdf` | `never` \| `always` \| `when_no_pdf_attachment` | No | When to include the autogenerated PDF in the package | ## Responses ### 200 Successfully downloaded the document Type: `string (binary)` ### 404 Document not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to download document | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Assign Label to Document `POST /api/v1/documents/{documentId}/labels/{labelId}` Attach one of the team's labels to a document, so you can filter for it later with the `labelId` parameter of the list documents endpoint. Assigning a label that is already on the document changes nothing and still succeeds. Both the document and the label have to belong to the calling team. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `documentId` | string | Yes | The ID of the document | | `labelId` | string | Yes | The ID of the label to assign | ## Responses ### 200 Successfully assigned label to document | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | ### 400 Invalid request data | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 404 Document or label not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to assign label | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Unassign Label from Document `DELETE /api/v1/documents/{documentId}/labels/{labelId}` Remove a label from a document. The label itself is left alone and stays available for other documents; use the delete label endpoint to remove it from the team. Removing a label that is not on the document also succeeds. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `documentId` | string | Yes | The ID of the document | | `labelId` | string | Yes | The ID of the label to unassign | ## Responses ### 200 Successfully unassigned label from document | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | ### 404 Document or label not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to unassign label | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Render Document Preview `GET /api/v1/documents/{documentId}/render/{type}` Render a stored document as a human-readable page. Ask for `html` to embed the preview in your own interface, or `pdf` to hand the recipient something to file or print. The rendering is generated from the document's contents, so it is a readable presentation of the data rather than the sender's own layout; a document the sender attached a PDF to carries that PDF as an attachment instead. Document types that have no rendering, and documents whose contents could not be parsed, fail with a 500. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `documentId` | string | Yes | The ID of the document to render | | `type` | `html` \| `pdf` | Yes | The type of the document to render | ## Responses ### 200 Successfully rendered the document Type: `string` Type: `string (binary)` ### 404 Document not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to render document | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Verify Recipient `POST /api/v1/verify` Look a Peppol address up in the SMP and report what the participant behind it is registered to receive. Use it before sending to check that an address exists and to see its document types. A lookup that fails, including for an address that is not registered at all, is not an error: the response is `{ isValid: false }` with no further fields. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `peppolAddress` | string | Yes | The Peppol address of the recipient to verify | | `includeEndpointDetails` | boolean | No | If true, fetches endpoint details for all supported document types | | `includeBusinessCard` | boolean | No | If true, fetches the business card from the SMP for company name and country | ## Responses ### 200 Successfully verified recipient | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `isValid` | boolean | Yes | Whether the recipient could be resolved in the Peppol network. A lookup failure also returns false | | `smpUrl` | string | No | The SMP URL of the recipient. Absent when the lookup failed | | `serviceMetadataReferences` | string[] | No | The service metadata references of the recipient. Absent when the lookup failed | | `smpHostnames` | string[] | No | The SMP hostnames of the recipient. Absent when the lookup failed | | `supportedDocuments` | object[] | No | Document types supported by this participant. Includes endpoint details when includeEndpointDetails is true. Absent when the lookup failed | | `companyName` | string \| null | No | Company name from SMP business card | | `countryCode` | string \| null | No | Country code from SMP business card | **`supportedDocuments`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Human-readable document type name | | `docTypeId` | string | Yes | Full Peppol document type identifier | | `serviceProvider` | string \| null | No | Service description from the endpoint metadata | | `serviceEndpoint` | string \| null | No | The endpoint URL | | `technicalContact` | string \| null | No | Technical contact URL | | `certificateExpiry` | string \| null | No | Certificate expiry date (ISO 8601) | # Verify Document Support `POST /api/v1/verify-document-support` Check whether a Peppol address is registered to receive one specific document type, optionally under one specific process. Use it before sending a document type the recipient may not accept. A lookup that fails, including an address that is registered but not for this document type, is not an error: the response is `{ isValid: false }` with no further fields. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `peppolAddress` | string | Yes | The Peppol address of the recipient to verify. Example: `"0208:987654321"` | | `documentType` | string | Yes | The document type to verify. You can use a full document type ID, or the simplified versions (e.g. "invoice", "creditNote", "selfBillingInvoice", "selfBillingCreditNote", ...). Example: `"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"` | | `processId` | string | No | Optional process to verify the document type against, with or without its scheme prefix. When omitted, any process published for the document type is accepted. Example: `"urn:fdc:peppol.eu:2017:poacc:billing:01:1.0"` | ## Responses ### 200 Successfully verified document support | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `isValid` | boolean | Yes | Whether the recipient could be resolved in the Peppol network for this document type. A lookup failure also returns false | | `smpUrl` | string | No | The SMP URL of the recipient. Absent when the lookup failed | | `serviceProvider` | string \| null | No | Service description from the endpoint metadata. Absent when the lookup failed | | `serviceEndpoint` | string \| null | No | The endpoint URL the document would be delivered to. Absent when the lookup failed | | `technicalContact` | string \| null | No | Technical contact URL published by the receiving access point. Absent when the lookup failed | | `certificateExpiry` | string \| null | No | Expiry date of the receiving access point's certificate (ISO 8601). Absent when the lookup failed | # Search Directory `POST /api/v1/search-peppol-directory` Run a free-text search against the Peppol Directory and get back the participants that match, with the document types each is registered to receive. Use it to find a recipient's Peppol address when you only know who they are, then pass that address to the verify recipient endpoint. The Peppol Directory only lists participants that publish a directory entry, so a recipient that is reachable on the network can still be missing here. Returns a 503 when the directory itself cannot be reached. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `query` | string | Yes | The search query to find recipients. Example: `"Company Name"` | ## Responses ### 200 Successfully searched directory | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `results` | object[] | Yes | The matching participants, in the order the Peppol Directory returned them | **`results`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `peppolAddress` | string | Yes | The participant's Peppol address, as `scheme:identifier`. Pass it as the recipient when sending. Example: `"0208:1012081766"` | | `name` | string | Yes | The participant's name as published in its Peppol Directory entry. Empty when the entry carries no name. Example: `"Recommand BV"` | | `supportedDocumentTypes` | string[] | Yes | The full Peppol document type identifiers the participant is registered to receive | ### 503 Peppol directory is currently unavailable | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # List Webhooks `GET /api/v1/webhooks` List the webhooks configured for the team, with their signing secrets. Use it to check what is subscribed before adding another endpoint. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Query Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string \| null | No | Return the webhooks that deliver this company's events: the ones limited to it, plus the team-wide webhooks that receive every company's events. Leave it out to list all of the team's webhooks. | ## Responses ### 200 Successfully retrieved webhooks | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `webhooks` | object[] | Yes | | **`webhooks`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the webhook. Use it with the get, update and delete webhook endpoints. Example: `"wh_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `teamId` | string | Yes | The ID of the team whose events this webhook receives. Example: `"team_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string \| null | Yes | The company this webhook is limited to. Null means it receives the events of every company in the team. Example: `null` | | `url` | string (uri) | Yes | The HTTPS endpoint events are delivered to, as a JSON POST body. Example: `"https://example.com/hooks/recommand"`. Format: uri | | `secret` | string \| null | Yes | The signing secret, returned in full on every read. Null when signing is off. When it is set, each delivery carries an `X-Signature: sha256=` header, an HMAC-SHA256 of the raw request body; recompute it to confirm the request came from us | | `createdAt` | string (date-time) | Yes | When the webhook was created. Format: date-time | | `updatedAt` | string \| null | Yes | When the webhook was last changed. Null when it has not changed since it was created. Format: date-time | ### 500 Failed to fetch webhooks | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Create Webhook `POST /api/v1/webhooks` Register an HTTPS endpoint that Recommand posts events to as they happen, so you do not have to poll the documents endpoints. It receives every peppol event for the team: `document.received`, `document.sent`, `document.label.assigned`, `document.label.unassigned`, `document.reporting_status_changed` and `company.verification`. There is no per-event subscription. Set a `secret` to have every delivery signed, and check that signature before acting on a request. Deliveries are retried for a while on a timeout or a 5xx; any other response is treated as final. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `url` | string (uri) | Yes | The HTTPS endpoint to deliver events to. Each delivery is a JSON POST carrying the event, with an `X-Idempotency-Key` header you can use to discard a redelivery. Answer with a 2xx once you have accepted the event; a timeout or a 5xx is retried, anything else is not. Example: `"https://example.com/hooks/recommand"`. Format: uri | | `companyId` | string \| null | No | Limit the webhook to one company's events. Leave it out to receive the events of every company in the team. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `secret` | string \| null | No | Optional secret used to send X-Signature: sha256=, computed with HMAC-SHA256 over the raw request body. Leave it out to have deliveries sent unsigned | ## Responses ### 200 Successfully created webhook | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `webhook` | object | Yes | | **`webhook`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the webhook. Use it with the get, update and delete webhook endpoints. Example: `"wh_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `teamId` | string | Yes | The ID of the team whose events this webhook receives. Example: `"team_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string \| null | Yes | The company this webhook is limited to. Null means it receives the events of every company in the team. Example: `null` | | `url` | string (uri) | Yes | The HTTPS endpoint events are delivered to, as a JSON POST body. Example: `"https://example.com/hooks/recommand"`. Format: uri | | `secret` | string \| null | Yes | The signing secret, returned in full on every read. Null when signing is off. When it is set, each delivery carries an `X-Signature: sha256=` header, an HMAC-SHA256 of the raw request body; recompute it to confirm the request came from us | | `createdAt` | string (date-time) | Yes | When the webhook was created. Format: date-time | | `updatedAt` | string \| null | Yes | When the webhook was last changed. Null when it has not changed since it was created. Format: date-time | ### 400 Invalid request data | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to create webhook | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Get Webhook `GET /api/v1/webhooks/{webhookId}` Get one webhook, including its signing secret. Use it to read back the secret you need to verify deliveries. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `webhookId` | string | Yes | The ID of the webhook to retrieve | ## Responses ### 200 Successfully retrieved webhook | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `webhook` | object | Yes | | **`webhook`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the webhook. Use it with the get, update and delete webhook endpoints. Example: `"wh_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `teamId` | string | Yes | The ID of the team whose events this webhook receives. Example: `"team_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string \| null | Yes | The company this webhook is limited to. Null means it receives the events of every company in the team. Example: `null` | | `url` | string (uri) | Yes | The HTTPS endpoint events are delivered to, as a JSON POST body. Example: `"https://example.com/hooks/recommand"`. Format: uri | | `secret` | string \| null | Yes | The signing secret, returned in full on every read. Null when signing is off. When it is set, each delivery carries an `X-Signature: sha256=` header, an HMAC-SHA256 of the raw request body; recompute it to confirm the request came from us | | `createdAt` | string (date-time) | Yes | When the webhook was created. Format: date-time | | `updatedAt` | string \| null | Yes | When the webhook was last changed. Null when it has not changed since it was created. Format: date-time | ### 404 Webhook not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to fetch webhook | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Update Webhook `PUT /api/v1/webhooks/{webhookId}` Replace a webhook's configuration. `url` is required, so send the current value for anything you are not changing. The secret is the exception: omit it to keep the one in place, or send null to stop signing deliveries. Events already queued for delivery are sent to the new URL. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `webhookId` | string | Yes | The ID of the webhook to update | ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `url` | string (uri) | Yes | The HTTPS endpoint to deliver events to. Example: `"https://example.com/hooks/recommand"`. Format: uri | | `companyId` | string \| null | No | Limit the webhook to one company's events. Leave it out to receive the events of every company in the team. Example: `"c_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `secret` | string \| null | No | New secret for the HMAC-SHA256 X-Signature header. Omit to preserve it or use null to disable signing | ## Responses ### 200 Successfully updated webhook | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `webhook` | object | Yes | | **`webhook`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The ID of the webhook. Use it with the get, update and delete webhook endpoints. Example: `"wh_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `teamId` | string | Yes | The ID of the team whose events this webhook receives. Example: `"team_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `companyId` | string \| null | Yes | The company this webhook is limited to. Null means it receives the events of every company in the team. Example: `null` | | `url` | string (uri) | Yes | The HTTPS endpoint events are delivered to, as a JSON POST body. Example: `"https://example.com/hooks/recommand"`. Format: uri | | `secret` | string \| null | Yes | The signing secret, returned in full on every read. Null when signing is off. When it is set, each delivery carries an `X-Signature: sha256=` header, an HMAC-SHA256 of the raw request body; recompute it to confirm the request came from us | | `createdAt` | string (date-time) | Yes | When the webhook was created. Format: date-time | | `updatedAt` | string \| null | Yes | When the webhook was last changed. Null when it has not changed since it was created. Format: date-time | ### 400 Invalid request data | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 404 Webhook not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to update webhook | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Delete Webhook `DELETE /api/v1/webhooks/{webhookId}` Stop delivering events to this endpoint and remove it. Deleting an ID that does not exist also succeeds, so the call is safe to repeat. Deliveries already in flight may still arrive. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `webhookId` | string | Yes | The ID of the webhook to delete | ## Responses ### 200 Successfully deleted webhook | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `true` | ### 500 Failed to delete webhook | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Get Playground `GET /api/v1/playgrounds/current` Get the playground settings of the current team, including whether it sends over the Peppol test network. Returns a 404 for a team that is not a playground, which is how you tell the two apart. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Responses ### 200 Successfully retrieved playground | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `true` | | `playground` | object | No | | **`playground`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | No | Team ID | | `name` | string | No | Team name | | `teamDescription` | string | No | Team description | | `isPlayground` | boolean | No | Whether the team is a playground | | `useTestNetwork` | boolean | No | Whether to use the Peppol Test Network | | `createdAt` | string (date-time) | No | Format: date-time | | `updatedAt` | string (date-time) | No | Format: date-time | ### 404 Playground not found for this team | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to fetch playground | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Create Playground `POST /api/v1/playgrounds` Create a playground team to develop against and add the calling user to it. A playground behaves like a normal team, but nothing it sends leaves Recommand: transmissions are simulated, no company is registered in the SMP, and usage is free. Set `useTestNetwork` to send over the Peppol test network instead of simulating, which is what you want to exchange documents with another provider before going live. Switch to the playground team to use its API keys. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Playground name | | `useTestNetwork` | boolean | No | Whether to use the Peppol Test Network. Default: `false` | ## Responses ### 200 Successfully created playground | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `true` | | `playground` | object | No | | **`playground`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | No | Team ID | | `name` | string | No | Team name | | `teamDescription` | string | No | Team description | | `isPlayground` | boolean | No | Whether the team is a playground | | `useTestNetwork` | boolean | No | Whether to use the Peppol Test Network | | `createdAt` | string (date-time) | No | Format: date-time | | `updatedAt` | string (date-time) | No | Format: date-time | ### 400 Invalid request data | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 401 Unauthorized | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to create playground | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # List Suppliers `GET /api/v1/suppliers` Get a list of suppliers with pagination ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Query Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `page` | number | No | The page number to retrieve | | `limit` | number | No | The number of items per page | | `search` | string | No | Search term to filter suppliers | ## Responses ### 200 Successfully retrieved suppliers | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `suppliers` | object[] | Yes | | | `pagination` | object | Yes | | **`suppliers`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | | | `teamId` | string | Yes | | | `externalId` | string \| null | Yes | | | `name` | string | Yes | | | `vatNumber` | string \| null | Yes | | | `peppolAddresses` | string[] | Yes | | | `createdAt` | string | Yes | | | `updatedAt` | string | Yes | | | `labels` | object[] | No | | **`labels`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | | | `externalId` | string \| null | Yes | | | `name` | string | Yes | | | `colorHex` | string | Yes | | **`pagination`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `total` | number | Yes | | | `page` | number | Yes | | | `limit` | number | Yes | | | `totalPages` | number | Yes | | ### 500 Failed to fetch suppliers | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Upsert Supplier `POST /api/v1/suppliers` Create or update a supplier. If id is provided, updates by id. Otherwise, if externalId is provided, finds by externalId and updates or creates if not found. If neither is provided, creates a new supplier. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | No | The internal ID of the supplier to update. If provided, updates by id | | `name` | string | Yes | The name of the supplier | | `externalId` | string \| null | No | The external ID of the supplier. If provided without id, finds by externalId and updates or creates if not found | | `vatNumber` | string \| null | No | The VAT number of the supplier | | `peppolAddresses` | string[] | No | The Peppol addresses of the supplier. Default: `` | ## Responses ### 200 Successfully upserted supplier | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `supplier` | object | Yes | | **`supplier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | | | `teamId` | string | Yes | | | `externalId` | string \| null | Yes | | | `name` | string | Yes | | | `vatNumber` | string \| null | Yes | | | `peppolAddresses` | string[] | Yes | | | `createdAt` | string | Yes | | | `updatedAt` | string | Yes | | | `labels` | object[] | No | | **`labels`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | | | `externalId` | string \| null | Yes | | | `name` | string | Yes | | | `colorHex` | string | Yes | | ### 400 Invalid request data | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to upsert supplier | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Get Supplier `GET /api/v1/suppliers/{supplierId}` Get a supplier by ID or external ID. The supplierId parameter works with both internal and external IDs. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `supplierId` | string | Yes | The internal ID or external ID of the supplier | ## Responses ### 200 Successfully retrieved supplier | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `supplier` | object | Yes | | **`supplier`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | | | `teamId` | string | Yes | | | `externalId` | string \| null | Yes | | | `name` | string | Yes | | | `vatNumber` | string \| null | Yes | | | `peppolAddresses` | string[] | Yes | | | `createdAt` | string | Yes | | | `updatedAt` | string | Yes | | | `labels` | object[] | No | | **`labels`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | | | `externalId` | string \| null | Yes | | | `name` | string | Yes | | | `colorHex` | string | Yes | | ### 404 Supplier not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to fetch supplier | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Delete Supplier `DELETE /api/v1/suppliers/{supplierId}` Delete a supplier ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `supplierId` | string | Yes | The internal ID or external ID of the supplier | ## Responses ### 200 Successfully deleted supplier | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `true` | ### 400 Invalid request data | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to delete supplier | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Assign Label to Supplier `POST /api/v1/suppliers/{supplierId}/labels/{labelId}` Assign a label to a supplier ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `supplierId` | string | Yes | The internal ID or external ID of the supplier | | `labelId` | string | Yes | The ID of the label to assign | ## Responses ### 200 Successfully assigned label to supplier | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | ### 400 Invalid request data | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 404 Supplier or label not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to assign label | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Unassign Label from Supplier `DELETE /api/v1/suppliers/{supplierId}/labels/{labelId}` Unassign a label from a supplier ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `supplierId` | string | Yes | The internal ID or external ID of the supplier | | `labelId` | string | Yes | The ID of the label to unassign | ## Responses ### 200 Successfully unassigned label from supplier | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | ### 404 Supplier or label not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to unassign label | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # List Customers `GET /api/v1/customers` Get a list of customers with pagination ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Query Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `page` | number | No | The page number to retrieve | | `limit` | number | No | The number of items per page | | `search` | string | No | Search term to filter customers | ## Responses ### 200 Successfully retrieved customers | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `customers` | object[] | Yes | | | `pagination` | object | Yes | | **`customers`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | | | `teamId` | string | Yes | | | `externalId` | string \| null | Yes | | | `name` | string | Yes | | | `vatNumber` | string \| null | Yes | | | `enterpriseNumber` | string \| null | Yes | | | `peppolAddresses` | string[] | Yes | | | `address` | string | Yes | | | `city` | string | Yes | | | `postalCode` | string | Yes | | | `country` | string | Yes | | | `email` | string \| null | Yes | | | `phone` | string \| null | Yes | | | `createdAt` | string | Yes | | | `updatedAt` | string | Yes | | **`pagination`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `total` | number | Yes | | | `page` | number | Yes | | | `limit` | number | Yes | | | `totalPages` | number | Yes | | ### 500 Failed to fetch customers | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Upsert Customer `POST /api/v1/customers` Create or update a customer. If id is provided, updates by id. Otherwise, if externalId is provided, finds by externalId and updates or creates if not found. If neither is provided, creates a new customer. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | No | The internal ID of the customer to update. If provided, updates by id | | `name` | string | Yes | The name of the customer | | `externalId` | string \| null | No | The external ID of the customer. If provided without id, finds by externalId and updates or creates if not found | | `vatNumber` | string \| null | No | The VAT number of the customer | | `enterpriseNumber` | string \| null | No | The enterprise number of the customer | | `peppolAddresses` | string[] | No | The Peppol addresses of the customer. Default: `` | | `address` | string | Yes | The street address of the customer | | `city` | string | Yes | The city of the customer | | `postalCode` | string | Yes | The postal code of the customer | | `country` | string | Yes | The country code (ISO 3166-1 alpha-2) of the customer. Example: `"BE"` | | `email` | string \| null | No | The email address of the customer | | `phone` | string \| null | No | The phone number of the customer | ## Responses ### 200 Successfully upserted customer | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `customer` | object | Yes | | **`customer`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | | | `teamId` | string | Yes | | | `externalId` | string \| null | Yes | | | `name` | string | Yes | | | `vatNumber` | string \| null | Yes | | | `enterpriseNumber` | string \| null | Yes | | | `peppolAddresses` | string[] | Yes | | | `address` | string | Yes | | | `city` | string | Yes | | | `postalCode` | string | Yes | | | `country` | string | Yes | | | `email` | string \| null | Yes | | | `phone` | string \| null | Yes | | | `createdAt` | string | Yes | | | `updatedAt` | string | Yes | | ### 400 Invalid request data | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to upsert customer | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Get Customer `GET /api/v1/customers/{customerId}` Get a customer by ID or external ID. The customerId parameter works with both internal and external IDs. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `customerId` | string | Yes | The internal ID or external ID of the customer | ## Responses ### 200 Successfully retrieved customer | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `customer` | object | Yes | | **`customer`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | | | `teamId` | string | Yes | | | `externalId` | string \| null | Yes | | | `name` | string | Yes | | | `vatNumber` | string \| null | Yes | | | `enterpriseNumber` | string \| null | Yes | | | `peppolAddresses` | string[] | Yes | | | `address` | string | Yes | | | `city` | string | Yes | | | `postalCode` | string | Yes | | | `country` | string | Yes | | | `email` | string \| null | Yes | | | `phone` | string \| null | Yes | | | `createdAt` | string | Yes | | | `updatedAt` | string | Yes | | ### 404 Customer not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to fetch customer | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Delete Customer `DELETE /api/v1/customers/{customerId}` Delete a customer ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `customerId` | string | Yes | The internal ID or external ID of the customer | ## Responses ### 200 Successfully deleted customer | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `true` | ### 400 Invalid request data | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to delete customer | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # List Labels `GET /api/v1/labels` Returns every label in the team, unpaginated. Labels are few by design, so this is the call to make once and keep, rather than looking a label up per document. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Responses ### 200 Successfully retrieved labels | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `labels` | object[] | Yes | | **`labels`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The label's identifier, used wherever a label is assigned or unassigned. Example: `"lbl_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `teamId` | string | Yes | The team the label belongs to. Labels are team-wide, not per company | | `externalId` | string \| null | Yes | Your own identifier for the label, if you set one. It is unique within the team, so you can address a label by the id your system already uses. Example: `"erp-routing-inbox"` | | `name` | string | Yes | The label's name, as it is shown in the dashboard and returned on the documents and suppliers it is assigned to. Example: `"ERP"` | | `colorHex` | string | Yes | The colour the label is shown in, as a hex code. Example: `"#3B82F6"` | | `createdAt` | string (date-time) | Yes | When the label was created. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the label was last changed. Format: date-time | ### 500 Failed to fetch labels | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Create Label `POST /api/v1/labels` Creates a label for the team. Labels are the routing primitive: assign one to a supplier and every document matched to that supplier inherits it, or assign one to a document directly. They are team-wide, so a label created here is available to every company in the team. Set `externalId` to the identifier your own system uses, so you can address the label without storing ours. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | The label's name. Keep it short: it is what you match on in your own routing code. Example: `"ERP"` | | `colorHex` | string | Yes | The colour the label is shown in, as a hex code such as `#3B82F6`. Example: `"#3B82F6"` | | `externalId` | string \| null | No | Your own identifier for the label. It must be unique within the team. Example: `"erp-routing-inbox"` | ## Responses ### 200 Successfully created label | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `label` | object | Yes | | **`label`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The label's identifier, used wherever a label is assigned or unassigned. Example: `"lbl_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `teamId` | string | Yes | The team the label belongs to. Labels are team-wide, not per company | | `externalId` | string \| null | Yes | Your own identifier for the label, if you set one. It is unique within the team, so you can address a label by the id your system already uses. Example: `"erp-routing-inbox"` | | `name` | string | Yes | The label's name, as it is shown in the dashboard and returned on the documents and suppliers it is assigned to. Example: `"ERP"` | | `colorHex` | string | Yes | The colour the label is shown in, as a hex code. Example: `"#3B82F6"` | | `createdAt` | string (date-time) | Yes | When the label was created. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the label was last changed. Format: date-time | ### 400 Invalid request data | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to create label | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Get Label `GET /api/v1/labels/{labelId}` Returns one label. Use it to resolve a label id you got back on a document or a supplier into its name and colour. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `labelId` | string | Yes | The ID of the label to retrieve | ## Responses ### 200 Successfully retrieved label | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `label` | object | Yes | | **`label`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The label's identifier, used wherever a label is assigned or unassigned. Example: `"lbl_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `teamId` | string | Yes | The team the label belongs to. Labels are team-wide, not per company | | `externalId` | string \| null | Yes | Your own identifier for the label, if you set one. It is unique within the team, so you can address a label by the id your system already uses. Example: `"erp-routing-inbox"` | | `name` | string | Yes | The label's name, as it is shown in the dashboard and returned on the documents and suppliers it is assigned to. Example: `"ERP"` | | `colorHex` | string | Yes | The colour the label is shown in, as a hex code. Example: `"#3B82F6"` | | `createdAt` | string (date-time) | Yes | When the label was created. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the label was last changed. Format: date-time | ### 404 Label not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to fetch label | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Update Label `PUT /api/v1/labels/{labelId}` Changes a label's name, colour or external id. The label keeps its id, so everything it is already assigned to keeps the label; only how it is shown changes. Fields you leave out are left as they are. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `labelId` | string | Yes | The ID of the label to update | ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | No | The label's new name. Left as it is when omitted. Example: `"ERP"` | | `colorHex` | string | No | The label's new colour, as a hex code. Left as it is when omitted. Example: `"#3B82F6"` | | `externalId` | string \| null | No | Your own identifier for the label. It must be unique within the team. Left as it is when omitted; pass `null` to clear it. Example: `"erp-routing-inbox"` | ## Responses ### 200 Successfully updated label | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `label` | object | Yes | | **`label`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The label's identifier, used wherever a label is assigned or unassigned. Example: `"lbl_01JQZ8X0M4T7RB6K9V2NDHW3PA"` | | `teamId` | string | Yes | The team the label belongs to. Labels are team-wide, not per company | | `externalId` | string \| null | Yes | Your own identifier for the label, if you set one. It is unique within the team, so you can address a label by the id your system already uses. Example: `"erp-routing-inbox"` | | `name` | string | Yes | The label's name, as it is shown in the dashboard and returned on the documents and suppliers it is assigned to. Example: `"ERP"` | | `colorHex` | string | Yes | The colour the label is shown in, as a hex code. Example: `"#3B82F6"` | | `createdAt` | string (date-time) | Yes | When the label was created. Format: date-time | | `updatedAt` | string (date-time) | Yes | When the label was last changed. Format: date-time | ### 400 Invalid request data | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 404 Label not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to update label | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Delete Label `DELETE /api/v1/labels/{labelId}` Deletes the label and removes it from every document and supplier it was assigned to. The documents and suppliers themselves are untouched. There is no undo, and a rule or integration that routes on this label stops matching, so unassign it first if you want to check what depends on it. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `labelId` | string | Yes | The ID of the label to delete | ## Responses ### 200 Successfully deleted label | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `true` | ### 404 Label not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Failed to delete label | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Get the French e-reporting registration `GET /api/v1/{companyId}/reporting/fr/declarant` Returns the company's French e-reporting registration, or `null` when the company has not been registered yet. Reports can be submitted once the state is `registered`. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | | ## Responses ### 200 The registration, or null when there is none | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `declarant` | French e-reporting registration | null | Yes | | **`declarant`** (One of): #### French e-reporting registration | Name | Type | Required | Description | |------|------|----------|-------------| | `environment` | `PROD` \| `TEST` | Yes | The reporting environment this registration belongs to. Teams on the test network are registered in `TEST`, all other teams in `PROD`. Values: `PROD`, `TEST` | | `siren` | string | Yes | The SIREN the company reports under, derived from its enterprise number. Example: `"123456789"` | | `issuerName` | string | Yes | The legal name carried as the issuer on every report filed for the company | | `vatRegime` | `REEL_NORMAL_MENSUEL` \| `REEL_SIMPLIFIE` \| `FRANCHISE_EN_BASE` | Yes | The company's French VAT regime. It determines how often its reports are filed with the tax administration. Values: `REEL_NORMAL_MENSUEL`, `REEL_SIMPLIFIE`, `FRANCHISE_EN_BASE` | | `vatExigibility` | `ENCAISSEMENTS` \| `DEBITS` | Yes | When VAT becomes due for the company. Payment reports are only accepted under `ENCAISSEMENTS`; under `DEBITS` they are out of scope. Values: `ENCAISSEMENTS`, `DEBITS` | | `enabled` | boolean | Yes | Whether reports are currently accepted. A suspended registration keeps its registered state but refuses reports with a 400 until support re-enables it | | `state` | `pending` \| `registered` \| `blocked` | Yes | `pending` while the registration is being completed, `registered` once reports can be submitted, `blocked` when the registration needs support. Values: `pending`, `registered`, `blocked` | | `simulated` | boolean | Yes | True for playground and test-network teams, whose registration and reports are simulated instead of filed | | `lastError` | string \| null | Yes | The reason the last registration attempt failed, if any | | `registeredAt` | string \| null | Yes | When the registration was accepted. The company's reporting periods run from this moment. Null while the state is still `pending` | | `createdAt` | string | Yes | When the registration was first requested | | `updatedAt` | string | Yes | When the registration last changed, including a background retry of a `pending` registration | #### Variant 2 Type: `null` ### 404 Company not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Register a company for French e-reporting `PUT /api/v1/{companyId}/reporting/fr/declarant` Registers the company as a declarant for French e-reporting, so its B2C and cross-border reports can be filed with the French tax administration on its behalf. Registration is an explicit step: it starts the company's reporting periods, so only register companies that will actually submit reports. The company must be registered in France with a valid SIREN or SIRET, and must be verified with a signed French mandate. The registration is usually completed immediately; when the state stays `pending`, it is retried in the background. A `blocked` state means support has to intervene, for example because the SIREN is already registered by another platform. Calling this endpoint again updates the VAT regime and exigibility. Changing the regime mid-period can leave that period unfiled, so coordinate such a change with support. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | | ## Request Body | Name | Type | Required | Description | |------|------|----------|-------------| | `vatRegime` | `REEL_NORMAL_MENSUEL` \| `REEL_SIMPLIFIE` \| `FRANCHISE_EN_BASE` | Yes | The company's French VAT regime: `REEL_NORMAL_MENSUEL` (régime réel normal), `REEL_SIMPLIFIE` (régime réel simplifié) or `FRANCHISE_EN_BASE` (franchise en base de TVA). Changing it after registration can leave the current reporting period unfiled; contact support before changing it. Example: `"REEL_NORMAL_MENSUEL"`. Values: `REEL_NORMAL_MENSUEL`, `REEL_SIMPLIFIE`, `FRANCHISE_EN_BASE` | | `vatExigibility` | `ENCAISSEMENTS` \| `DEBITS` | Yes | When VAT becomes due: `ENCAISSEMENTS` (on payment, typical for services) or `DEBITS` (on invoicing, typical for goods). Payment reports can only be submitted under `ENCAISSEMENTS`. Example: `"DEBITS"`. Values: `ENCAISSEMENTS`, `DEBITS` | ## Responses ### 200 The registration as it stands after this request | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `declarant` | object | Yes | | **`declarant`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `environment` | `PROD` \| `TEST` | Yes | The reporting environment this registration belongs to. Teams on the test network are registered in `TEST`, all other teams in `PROD`. Values: `PROD`, `TEST` | | `siren` | string | Yes | The SIREN the company reports under, derived from its enterprise number. Example: `"123456789"` | | `issuerName` | string | Yes | The legal name carried as the issuer on every report filed for the company | | `vatRegime` | `REEL_NORMAL_MENSUEL` \| `REEL_SIMPLIFIE` \| `FRANCHISE_EN_BASE` | Yes | The company's French VAT regime. It determines how often its reports are filed with the tax administration. Values: `REEL_NORMAL_MENSUEL`, `REEL_SIMPLIFIE`, `FRANCHISE_EN_BASE` | | `vatExigibility` | `ENCAISSEMENTS` \| `DEBITS` | Yes | When VAT becomes due for the company. Payment reports are only accepted under `ENCAISSEMENTS`; under `DEBITS` they are out of scope. Values: `ENCAISSEMENTS`, `DEBITS` | | `enabled` | boolean | Yes | Whether reports are currently accepted. A suspended registration keeps its registered state but refuses reports with a 400 until support re-enables it | | `state` | `pending` \| `registered` \| `blocked` | Yes | `pending` while the registration is being completed, `registered` once reports can be submitted, `blocked` when the registration needs support. Values: `pending`, `registered`, `blocked` | | `simulated` | boolean | Yes | True for playground and test-network teams, whose registration and reports are simulated instead of filed | | `lastError` | string \| null | Yes | The reason the last registration attempt failed, if any | | `registeredAt` | string \| null | Yes | When the registration was accepted. The company's reporting periods run from this moment. Null while the state is still `pending` | | `createdAt` | string | Yes | When the registration was first requested | | `updatedAt` | string | Yes | When the registration last changed, including a background retry of a `pending` registration | ### 400 The company is not registered in France, has no valid SIREN or SIRET as enterprise number, is not verified, or was verified without a signed French mandate. | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | | `invalidInputDetails` | object[] | No | Present when the request body or query did not match the schema | **`invalidInputDetails`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `path` | string | No | Dotted path of the field the message applies to | | `message` | string | No | | | `unionErrors` | object[][] | No | For a union of schemas, the failures of every variant, in the order the variants are declared | ### 404 Company not found | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 The registration could not be requested | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Submit a French B2C report `POST /api/v1/{companyId}/reporting/fr/b2c` Submit French daily sales or payment totals for transactions with private individuals. You do not need to create or submit a regulatory file yourself. Use a sales report for the normal daily transaction totals, regardless of when customers pay. This endpoint accepts one sales summary per day, category and currency. The current integration supports taxable goods and taxable services. Use a payment report only as an additional report for services using cash-basis VAT (`TVA sur les encaissements`), where VAT becomes due when the customer pays. Submit the sales report as usual, then submit the payment report for the day payment is received. Payment reports are only accepted for companies registered with VAT due on payment. The company must be registered for French e-reporting first, through `PUT /:companyId/reporting/fr/declarant`. Reports for playground and test-network teams are recorded but not filed. Choose a new, unique `reference` for every report, including corrections and cancellations. Retrying the exact same request with the same reference is safe: it returns the report filed the first time instead of filing a second one. A correction or cancellation acts on the report identified by the data in the request (the day and category of a daily total, or the document number of an invoice) and carries the optional `action` field. A submitted report is recorded alongside your sent documents and counts towards your document quota. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | | ## Request Body **One of:** #### French B2C sales report | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"SALES-2026-07-01-GOODS"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `sales` to report transactions with private individuals. Send one sales report per day, category and currency, regardless of when customers pay. Value: `sales` | | `date` | string (date) | Yes | Day on which the reported sales took place. Example: `"2026-07-01"`. Format: date | | `category` | `goods` \| `services` | Yes | Whether this daily total covers taxable goods or taxable services. Use a separate report when both were sold on the same day. These are the two categories currently supported by this API. Example: `"goods"`. Values: `goods`, `services` | | `currency` | string (enum) | No | Three-letter currency code for the sales amounts excluding VAT. EUR is used when this field is omitted. French VAT amounts are always reported in EUR, including when this field uses another currency. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `taxExclusiveAmount` | string | Yes | Total sales amount excluding VAT for this day and category. Example: `"10000.00"` | | `taxAmount` | string | Yes | Total VAT amount for this day and category, expressed in EUR even when the sales currency is different. Example: `"2000.00"` | | `transactionCount` | integer | Yes | Number of individual sales included in this daily total. At least 1; a day without sales is not reported. Example: `42` | | `vatBreakdown` | object[] | Yes | Breakdown of the daily sales total by VAT rate. Include one entry for every VAT rate used. Min items: 1 | **`vatBreakdown`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate applied to these sales. Example: `"20.00"` | | `taxableAmount` | string | Yes | Sales amount excluding VAT for this VAT rate, expressed in the report's sales currency. Example: `"10000.00"` | | `taxAmount` | string | Yes | VAT amount for this VAT rate, expressed in EUR even when the sales currency is different. Example: `"2000.00"` | #### French B2C payment report | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"SALES-2026-07-01-GOODS"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `payments` only to additionally report payments received for services using cash-basis VAT (`TVA sur les encaissements`). Value: `payments` | | `date` | string (date) | Yes | Day on which the reported payments were received. Example: `"2026-07-01"`. Format: date | | `currency` | string (enum) | No | Three-letter currency code of the received amounts. EUR is used when this field is omitted. One report covers one day in one currency. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `vatBreakdown` | object[] | Yes | Payments received, grouped by VAT rate. Amounts include VAT. Min items: 1 | **`vatBreakdown`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate that applies to the received amount. Example: `"20.00"` | | `amount` | string | Yes | Amount received including VAT for this VAT rate, expressed in the report's currency. Example: `"12000.00"` | ## Responses ### 200 The report was accepted for processing | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `id` | string | Yes | The identifier of the document this report was recorded as. Pass it to the get document endpoint to follow the report's `reporting` block until it is filed | | `duplicate` | boolean | Yes | True when this reference was already filed, in which case the identifier of the existing report is returned and nothing was filed again | ### 400 Invalid reporting data; the company is not registered for e-reporting, its registration is not yet registered, or it is suspended; the company is not registered in France or lacks the identifiers a report needs; a payment report was sent for a company whose VAT is due on invoicing; or the reporting service refused the report. | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | | `invalidInputDetails` | object[] | No | Present when the request body or query did not match the schema | **`invalidInputDetails`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `path` | string | No | Dotted path of the field the message applies to | | `message` | string | No | | | `unionErrors` | object[][] | No | For a union of schemas, the failures of every variant, in the order the variants are declared | ### 409 The report conflicts with what was filed before | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 502 The reporting service could not accept the report; retry with the same reference | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Submit a French cross-border report `POST /api/v1/{companyId}/reporting/fr/b2bi` Submit a French e-reporting declaration for an operation with a business established outside France. These invoices are not exchanged over the French e-invoicing network, so their data is reported to the French tax administration instead. You do not need to create or submit a regulatory file yourself. Use an invoice report for a single cross-border invoice or credit note. Report every such document; the buyer must not be established in France. Buyers in the European Union are identified by their VAT number, buyers elsewhere by their country and name. Use a payment report for a payment received on a cross-border invoice. The invoice has to be reported before its payment can be, and the payment report refers back to it by `invoiceNumber`. Amounts on a payment report include VAT. Payment reports are only accepted for companies registered with VAT due on payment. The company must be registered for French e-reporting first, through `PUT /:companyId/reporting/fr/declarant`. Reports for playground and test-network teams are recorded but not filed. Choose a new, unique `reference` for every report, including corrections and cancellations. Retrying the exact same request with the same reference is safe: it returns the report filed the first time instead of filing a second one. A correction or cancellation acts on the report identified by the data in the request (the day and category of a daily total, or the document number of an invoice) and carries the optional `action` field. A submitted report is recorded alongside your sent documents and counts towards your document quota. ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Parameters ### Path Parameters | Name | Type | Required | Description | |------|------|----------|-------------| | `companyId` | string | Yes | | ## Request Body **One of:** #### French cross-border invoice report | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"EREPORT-INV-2026-000431"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `invoice` to report a single cross-border invoice or credit note issued to a business. Value: `invoice` | | `documentNumber` | string | Yes | The number of the invoice or credit note being reported. A payment report refers back to it, and a correction or cancellation is matched on it. Example: `"INV-2026-000431"` | | `documentType` | `invoice` \| `creditNote` | No | Whether the reported document is an invoice or a credit note. Defaults to `invoice`. Default: `invoice`. Example: `"invoice"`. Values: `invoice`, `creditNote` | | `issueDate` | string (date) | Yes | Date on which the document was issued. Example: `"2026-01-15"`. Format: date | | `dueDate` | string \| null | No | Date on which the amount is due, when the document names one. Example: `"2026-02-14"`. Format: date | | `currency` | string (enum) | No | Three-letter currency code of the reported amounts. EUR is used when this field is omitted. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `buyer` | object | Yes | The foreign business the reported operation was invoiced to | | `taxExclusiveAmount` | string | Yes | Total amount of the document excluding VAT. Example: `"10000.00"` | | `taxAmount` | string | Yes | Total VAT amount of the document. Example: `"0.00"` | | `vatBreakdown` | object[] | Yes | Breakdown of the document total by VAT rate. Include one entry for every VAT rate used. Min items: 1 | **`buyer`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | The buyer's legal name. Example: `"Rossi Forniture S.r.l."` | | `country` | string | Yes | The country the buyer is established in, in ISO 3166-1:Alpha2 format. Must not be `FR`: invoices to French buyers are exchanged over the e-invoicing network instead of being reported. Example: `"IT"` | | `vatNumber` | string \| null | No | The buyer's intra-community VAT number. Required for buyers established in the European Union; it is how the tax administration identifies them. Leave it off for buyers outside the European Union, who are identified by their country and name instead. Example: `"IT00987654321"` | | `enterpriseNumber` | string \| null | No | The buyer's company registration number. Used for buyers in Nouvelle-Calédonie (RIDET) and Polynésie française (TAHITI); optional elsewhere. Example: `"0123456"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme the buyer's company registration number belongs to. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0223"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | **`vatBreakdown`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate applied to this part of the invoice. Example: `"0.00"` | | `taxableAmount` | string | Yes | Amount excluding VAT taxed at this rate. Example: `"10000.00"` | | `taxAmount` | string | Yes | VAT amount for this rate. Example: `"0.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code for this rate. Cross-border operations are typically exempt or reverse charged rather than taxed. Example: `"K"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `exemptionReason` | string \| null | No | Why no VAT is charged. Required, together with or instead of `exemptionReasonCode`, whenever the VAT category is an exempt one. Example: `"Intra-Community supply"` | | `exemptionReasonCode` | string \| null | No | The exemption reason code, from the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/). Example: `"VATEX-EU-IC"` | #### French cross-border payment report | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"EREPORT-INV-2026-000431"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `payment` to report a payment received on a cross-border invoice you reported earlier. Value: `payment` | | `invoiceNumber` | string | Yes | The `documentNumber` of the invoice report this payment belongs to. The invoice must have been reported before its payment can be. Example: `"INV-2026-000431"` | | `issueDate` | string (date) | Yes | Date on which the invoice was issued. Example: `"2026-01-15"`. Format: date | | `date` | string (date) | Yes | Date on which the payment was received. Example: `"2026-02-10"`. Format: date | | `currency` | string (enum) | No | Three-letter currency code of the received amounts. EUR is used when this field is omitted. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `vatBreakdown` | object[] | Yes | Amounts received, grouped by VAT rate. Amounts include VAT. Min items: 1 | **`vatBreakdown`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate that applies to the received amount. Example: `"20.00"` | | `amount` | string | Yes | Amount received including VAT for this VAT rate. Example: `"12000.00"` | ## Responses ### 200 The report was accepted for processing | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | Yes | Value: `true` | | `id` | string | Yes | The identifier of the document this report was recorded as. Pass it to the get document endpoint to follow the report's `reporting` block until it is filed | | `duplicate` | boolean | Yes | True when this reference was already filed, in which case the identifier of the existing report is returned and nothing was filed again | ### 400 Invalid reporting data; the company is not registered for e-reporting, its registration is not yet registered, or it is suspended; the company is not registered in France or lacks the identifiers a report needs; a payment report was sent for a company whose VAT is due on invoicing; or the reporting service refused the report. | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | | `invalidInputDetails` | object[] | No | Present when the request body or query did not match the schema | **`invalidInputDetails`** properties: | Name | Type | Required | Description | |------|------|----------|-------------| | `path` | string | No | Dotted path of the field the message applies to | | `message` | string | No | | | `unionErrors` | object[][] | No | For a union of schemas, the failures of every variant, in the order the variants are declared | ### 409 The report conflicts with what was filed before | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 502 The reporting service could not accept the report; retry with the same reference | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Verify Authentication `GET /api/core/auth/verify` Verify if the user is authenticated ## Authorization - **BASIC** — Basic API key authentication. Create a new API key and secret in the Recommand dashboard. - **BEARER** — JWT authentication. Create a new JWT token in the Recommand dashboard. ## Responses ### 200 User is authenticated | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `true` | ### 401 User is not authenticated | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | ### 500 Internal server error | Name | Type | Required | Description | |------|------|----------|-------------| | `success` | boolean | No | Example: `false` | | `errors` | object | No | Map of field names to arrays of error message strings | # Email (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `when` | `always` \| `on_peppol_failure` | No | When to send the email. If the provided Peppol recipient is null, email becomes the primary delivery method and emails are always sent. Default: `on_peppol_failure`. Values: `always`, `on_peppol_failure` | | `to` | string[] | Yes | The email addresses to send the document to. Example: `["support@recommand.eu"]` | | `subject` | string | No | The subject of the email. If not provided, the subject will be autogenerated based on the document type. Example: `"Invoice SI-001"` | | `htmlBody` | string | No | The HTML body of the email. If not provided, the body will be autogenerated based on the document type. Example: `"Dear customer, you can find your invoice attached."` | ## Used by - [Send Document](/reference/sending/send-document) # PDFGeneration (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `enabled` | boolean | No | Whether to generate a PDF of the document and include it as an embedded attachment. Default: `false` | | `filename` | string | No | Optional filename to use for the generated PDF attachment. Defaults to a filename derived from the document number (e.g. invoice-001.pdf). Example: `"INV-2024-001.pdf"` | ## Used by - [Send Document](/reference/sending/send-document) - [Generate Document](/reference/sending/generate) # Invoice (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `invoiceNumber` | string | Yes | The number the seller assigned to the invoice. Example: `"INV-2024-001"` | | `issueDate` | string (date) | Yes | The date the invoice was issued, as YYYY-MM-DD. Example: `"2024-03-20"`. Format: date | | `dueDate` | string \| null | No | The date the payment is due, as YYYY-MM-DD. Example: `"2024-04-20"`. Format: date | | `note` | string \| null | No | A free text note about the invoice as a whole. Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | A reference the buyer asked you to put on the invoice so they can route it internally. If neither this nor `purchaseOrderReference` is provided, the invoice number is used. Example: `"PO-2024-001"` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | [`seller`](#seller-properties) | object | Yes | | | [`buyer`](#buyer-properties) | object | Yes | | | [`delivery`](#delivery-one-of) | Delivery | null | No | Optional delivery information | | [`paymentMeans`](#paymentmeans-properties) | object[] \| null | No | Optional payment information. For most invoices, this should be provided. For prepaid invoices, this could be omitted | | [`paymentTerms`](#paymentterms-properties) | object \| null | No | Optional payment terms | | [`lines`](#lines-properties) | object[] | Yes | The invoice lines. At least one line is required. Min items: 1 | | [`discounts`](#discounts-properties) | object[] \| null | No | Optional global discounts | | [`surcharges`](#surcharges-properties) | object[] \| null | No | Optional global surcharges | | [`totals`](#totals-one-of) | Totals | null | No | | | [`vat`](#vat-one-of) | Provided VAT totals | null | No | The VAT totals of the invoice, broken down per VAT category and rate | | [`attachments`](#attachments-properties) | object[] \| null | No | Optional attachments to the invoice | | `currency` | string (enum) | No | The currency of the invoice. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | [`countrySpecific`](#countryspecific-one-of) | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | ### `seller` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | ### `buyer` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | ### `delivery` (One of) **Delivery:** | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | [`locationIdentifier`](#deliverylocationidentifier-properties) | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | [`location`](#deliverylocation-properties) | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | #### `delivery.locationIdentifier` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | #### `delivery.location` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | ### `paymentMeans` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | ### `paymentTerms` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | The payment terms as free text. Example: `"Net 30"` | ### `lines` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | [`standardId`](#linesstandardid-properties) | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | [`commodityClassifications`](#linescommodityclassifications-properties) | object[] \| null | No | Optional commodity classifications | | [`additionalItemProperties`](#linesadditionalitemproperties-properties) | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | [`discounts`](#linesdiscounts-properties) | object[] \| null | No | Optional discounts for the line | | [`surcharges`](#linessurcharges-properties) | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | [`vat`](#linesvat-properties) | object | Yes | | #### `lines.standardId` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | #### `lines.commodityClassifications` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | #### `lines.additionalItemProperties` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | #### `lines.discounts` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | #### `lines.surcharges` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | #### `lines.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `discounts` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | [`vat`](#discountsvat-properties) | object | Yes | | #### `discounts.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `surcharges` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | [`vat`](#surchargesvat-properties) | object | Yes | | #### `surcharges.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `totals` (One of) **Totals:** If not provided, the totals will be calculated from the document lines. | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | ### `vat` (One of) **Provided VAT totals:** | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | [`subtotals`](#vatsubtotals-properties) | object[] | Yes | One entry for every combination of VAT category and rate used in the document | #### `vat.subtotals` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | ### `attachments` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | ### `countrySpecific` (One of) ## Used by - [List Documents](/reference/documents/get-documents) - [Get Document](/reference/documents/get-document) # Party (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | # Delivery (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | [`locationIdentifier`](#locationidentifier-properties) | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | [`location`](#location-properties) | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | ### `locationIdentifier` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | ### `location` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | # Payment Means (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | # Line (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | [`standardId`](#standardid-properties) | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | [`commodityClassifications`](#commodityclassifications-properties) | object[] \| null | No | Optional commodity classifications | | [`additionalItemProperties`](#additionalitemproperties-properties) | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | [`discounts`](#discounts-properties) | object[] \| null | No | Optional discounts for the line | | [`surcharges`](#surcharges-properties) | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | [`vat`](#vat-properties) | object | Yes | | ### `standardId` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | ### `commodityClassifications` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | ### `additionalItemProperties` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | ### `discounts` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | ### `surcharges` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | ### `vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | # Item Classification Code (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | # Additional Item Property (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | # Line Discount (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | # Line Surcharge (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | # VAT (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | # Discount (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | [`vat`](#vat-properties) | object | Yes | | ### `vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | # Surcharge (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | [`vat`](#vat-properties) | object | Yes | | ### `vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | # Totals (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | # Provided VAT totals (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | [`subtotals`](#subtotals-properties) | object[] | Yes | One entry for every combination of VAT category and rate used in the document | ### `subtotals` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | # VATSubtotal (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | # Attachment (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | # Country Specific Billing (Model) ## One of ### French Country Specific Billing Structured information required by French regulated UBL, CII, and Factur-X. The billing modes and notes follow AFNOR XP Z12-012. | Name | Type | Required | Description | |------|------|----------|-------------| | `country` | string | Yes | Identifies this as the French regulatory extension. This is independent from seller, buyer, delivery, and origin country codes. Value: `FR` | | `billingMode` | string (enum) | Yes | Required only for French regulated UBL, CII, and Factur-X. Select the invoicing framework that matches the invoice. \| Mode \| Description \| \| --- \| --- \| \| `B1` \| Goods invoice. \| \| `S1` \| Services invoice. \| \| `M1` \| Mixed invoice containing goods and services that are not ancillary to each other. \| \| `B2` \| Goods invoice that has already been paid. \| \| `S2` \| Services invoice that has already been paid. \| \| `M2` \| Mixed invoice that has already been paid. \| \| `S3` \| B2G subcontractor payment request with direct payment. \| \| `B4` \| Final goods invoice after an advance payment. \| \| `S4` \| Final services invoice after an advance payment. \| \| `M4` \| Final mixed invoice after an advance payment. \| \| `S5` \| Invoice submitted by a subcontractor for services rendered. \| \| `S6` \| Invoice submitted by a co-contractor for services rendered. \| \| `B7` \| Goods invoice that has already been e-reported and for which VAT has already been collected. \| \| `S7` \| Services invoice that has already been e-reported and for which VAT has already been collected. \| \| `B8` \| Multi-seller goods invoice. \| \| `S8` \| Multi-seller services invoice. \| \| `M8` \| Multi-seller mixed invoice whose individual invoices are not all goods invoices or all services invoices. \| . Example: `"S1"`. Values: `B1`, `S1`, `M1`, `B2`, `S2`, `M2`, `S3`, `B4`, `S4`, `M4`, `S5`, `S6`, `B7`, `S7`, `B8`, `S8`, `M8`, `B9`, `S9`, `M9` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` | No | Determines which French Peppol process the document is sent over. Defaults to `REGULATED`. \| Value \| Description \| \| --- \| --- \| \| `REGULATED` \| Transaction inside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:regulated`. \| \| `NON_REGULATED` \| Transaction outside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:non-regulated`. \| The recipient must have registered the matching process for the document type in its SMP. Default: `REGULATED`. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED` | | `recoveryCostsNote` | string | Yes | The mandatory French recovery-cost indemnity statement, written as an IncludedNote with subject code PMT. Example: `"Indemnite forfaitaire de 40 EUR pour frais de recouvrement."` | | `latePaymentPenaltiesNote` | string | Yes | The mandatory French late-payment penalties statement, written as an IncludedNote with subject code PMD. Example: `"Penalites de retard exigibles au taux prevu dans les conditions generales de vente."` | | `earlyPaymentDiscountNote` | string | Yes | The mandatory French early-payment discount statement, written as an IncludedNote with subject code AAB. State either the offered discount terms or explicitly that no early-payment discount applies. Example: `"Aucun escompte accorde pour paiement anticipe."` | # French Country Specific Billing (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `country` | string | Yes | Identifies this as the French regulatory extension. This is independent from seller, buyer, delivery, and origin country codes. Value: `FR` | | `billingMode` | string (enum) | Yes | Required only for French regulated UBL, CII, and Factur-X. Select the invoicing framework that matches the invoice. \| Mode \| Description \| \| --- \| --- \| \| `B1` \| Goods invoice. \| \| `S1` \| Services invoice. \| \| `M1` \| Mixed invoice containing goods and services that are not ancillary to each other. \| \| `B2` \| Goods invoice that has already been paid. \| \| `S2` \| Services invoice that has already been paid. \| \| `M2` \| Mixed invoice that has already been paid. \| \| `S3` \| B2G subcontractor payment request with direct payment. \| \| `B4` \| Final goods invoice after an advance payment. \| \| `S4` \| Final services invoice after an advance payment. \| \| `M4` \| Final mixed invoice after an advance payment. \| \| `S5` \| Invoice submitted by a subcontractor for services rendered. \| \| `S6` \| Invoice submitted by a co-contractor for services rendered. \| \| `B7` \| Goods invoice that has already been e-reported and for which VAT has already been collected. \| \| `S7` \| Services invoice that has already been e-reported and for which VAT has already been collected. \| \| `B8` \| Multi-seller goods invoice. \| \| `S8` \| Multi-seller services invoice. \| \| `M8` \| Multi-seller mixed invoice whose individual invoices are not all goods invoices or all services invoices. \| . Example: `"S1"`. Values: `B1`, `S1`, `M1`, `B2`, `S2`, `M2`, `S3`, `B4`, `S4`, `M4`, `S5`, `S6`, `B7`, `S7`, `B8`, `S8`, `M8`, `B9`, `S9`, `M9` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` | No | Determines which French Peppol process the document is sent over. Defaults to `REGULATED`. \| Value \| Description \| \| --- \| --- \| \| `REGULATED` \| Transaction inside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:regulated`. \| \| `NON_REGULATED` \| Transaction outside the French e-invoicing perimeter. Sent over `urn:peppol:france:billing:non-regulated`. \| The recipient must have registered the matching process for the document type in its SMP. Default: `REGULATED`. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED` | | `recoveryCostsNote` | string | Yes | The mandatory French recovery-cost indemnity statement, written as an IncludedNote with subject code PMT. Example: `"Indemnite forfaitaire de 40 EUR pour frais de recouvrement."` | | `latePaymentPenaltiesNote` | string | Yes | The mandatory French late-payment penalties statement, written as an IncludedNote with subject code PMD. Example: `"Penalites de retard exigibles au taux prevu dans les conditions generales de vente."` | | `earlyPaymentDiscountNote` | string | Yes | The mandatory French early-payment discount statement, written as an IncludedNote with subject code AAB. State either the offered discount terms or explicitly that no early-payment discount applies. Example: `"Aucun escompte accorde pour paiement anticipe."` | # Invoice to send (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `invoiceNumber` | string | Yes | The number the seller assigned to the invoice. Example: `"INV-2024-001"` | | `issueDate` | string \| null | No | If not provided, the issue date will be the current date. Example: `"2024-03-20"`. Format: date | | `dueDate` | string \| null | No | If not provided, the due date will be 1 month from the issue date. Example: `"2024-04-20"`. Format: date | | `note` | string \| null | No | A free text note about the invoice as a whole. Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | A reference the buyer asked you to put on the invoice so they can route it internally. If neither this nor `purchaseOrderReference` is provided, the invoice number is used. Example: `"PO-2024-001"` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | [`seller`](#seller-one-of) | Party | null | No | If not provided, the seller will be the company that is sending the invoice | | [`buyer`](#buyer-properties) | object | Yes | | | [`delivery`](#delivery-one-of) | Delivery | null | No | Optional delivery information | | [`paymentMeans`](#paymentmeans-properties) | object[] \| null | No | Optional payment information. For most invoices, this should be provided. For prepaid invoices, this could be omitted | | [`paymentTerms`](#paymentterms-properties) | object \| null | No | Optional payment terms | | [`lines`](#lines-properties) | object[] | Yes | The invoice lines. At least one line is required. Min items: 1 | | [`discounts`](#discounts-properties) | object[] \| null | No | Optional global discounts | | [`surcharges`](#surcharges-properties) | object[] \| null | No | Optional global surcharges | | [`totals`](#totals-one-of) | Totals | null | No | | | [`vat`](#vat-any-of) | Provided VAT totals | VAT totals auto calculation | null | No | If not provided, the VAT totals will be calculated from the document lines | | [`attachments`](#attachments-properties) | object[] \| null | No | Optional attachments to the invoice | | `currency` | string (enum) | No | The currency of the invoice. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | [`countrySpecific`](#countryspecific-one-of) | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | ### `seller` (One of) **Party:** | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | ### `buyer` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | ### `delivery` (One of) **Delivery:** | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | [`locationIdentifier`](#deliverylocationidentifier-properties) | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | [`location`](#deliverylocation-properties) | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | #### `delivery.locationIdentifier` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | #### `delivery.location` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | ### `paymentMeans` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | ### `paymentTerms` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | The payment terms as free text. Example: `"Net 30"` | ### `lines` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | [`standardId`](#linesstandardid-properties) | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | [`commodityClassifications`](#linescommodityclassifications-properties) | object[] \| null | No | Optional commodity classifications | | [`additionalItemProperties`](#linesadditionalitemproperties-properties) | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | [`discounts`](#linesdiscounts-properties) | object[] \| null | No | Optional discounts for the line | | [`surcharges`](#linessurcharges-properties) | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | [`vat`](#linesvat-properties) | object | Yes | | #### `lines.standardId` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | #### `lines.commodityClassifications` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | #### `lines.additionalItemProperties` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | #### `lines.discounts` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | #### `lines.surcharges` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | #### `lines.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `discounts` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | [`vat`](#discountsvat-properties) | object | Yes | | #### `discounts.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `surcharges` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | [`vat`](#surchargesvat-properties) | object | Yes | | #### `surcharges.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `totals` (One of) **Totals:** If not provided, the totals will be calculated from the document lines. | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | ### `vat` (Any of) **Provided VAT totals:** | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | [`subtotals`](#vatsubtotals-properties) | object[] | Yes | One entry for every combination of VAT category and rate used in the document | #### `vat.subtotals` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | **VAT totals auto calculation:** Recommand will automatically calculate the VAT totals based on the document lines. For invoices that are exempt from VAT, you can provide the exemption reason or reason code here to inform the recipient of the reason why the amount is exempt from VAT. | Name | Type | Required | Description | |------|------|----------|-------------| | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | ### `attachments` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | ### `countrySpecific` (One of) ## Used by - [Send Document](/reference/sending/send-document) - [Generate Document](/reference/sending/generate) # VAT totals auto calculation (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | # Credit Note (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `creditNoteNumber` | string | Yes | Example: `"CN-2024-001"` | | `issueDate` | string (date) | Yes | Example: `"2024-03-20"`. Format: date | | `note` | string \| null | No | Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | Example: `"PO-2024-001"` | | [`invoiceReferences`](#invoicereferences-properties) | object[] | No | References to one or more invoices that are being credited. Default: `` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | [`seller`](#seller-properties) | object | Yes | | | [`buyer`](#buyer-properties) | object | Yes | | | [`delivery`](#delivery-one-of) | Delivery | null | No | Optional delivery information | | [`paymentMeans`](#paymentmeans-properties) | object[] \| null | No | | | [`paymentTerms`](#paymentterms-properties) | object \| null | No | | | [`lines`](#lines-properties) | object[] | Yes | Min items: 1 | | [`discounts`](#discounts-properties) | object[] \| null | No | Optional global discounts | | [`surcharges`](#surcharges-properties) | object[] \| null | No | Optional global surcharges | | [`totals`](#totals-one-of) | Totals | null | No | | | [`vat`](#vat-one-of) | Provided VAT totals | null | No | | | [`attachments`](#attachments-properties) | object[] \| null | No | Optional attachments to the credit note | | `currency` | string (enum) | No | The currency of the credit note. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | [`countrySpecific`](#countryspecific-one-of) | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | ### `invoiceReferences` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The reference to the invoice that is being credited. Example: `"INV-2024-001"` | | `issueDate` | string \| null | No | The issue date of the invoice that is being credited. Example: `"2024-03-20"`. Format: date | ### `seller` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | ### `buyer` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | ### `delivery` (One of) **Delivery:** | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | [`locationIdentifier`](#deliverylocationidentifier-properties) | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | [`location`](#deliverylocation-properties) | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | #### `delivery.locationIdentifier` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | #### `delivery.location` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | ### `paymentMeans` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | ### `paymentTerms` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | Example: `"Net 30"` | ### `lines` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | [`standardId`](#linesstandardid-properties) | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | [`commodityClassifications`](#linescommodityclassifications-properties) | object[] \| null | No | Optional commodity classifications | | [`additionalItemProperties`](#linesadditionalitemproperties-properties) | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | [`discounts`](#linesdiscounts-properties) | object[] \| null | No | Optional discounts for the line | | [`surcharges`](#linessurcharges-properties) | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | [`vat`](#linesvat-properties) | object | Yes | | #### `lines.standardId` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | #### `lines.commodityClassifications` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | #### `lines.additionalItemProperties` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | #### `lines.discounts` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | #### `lines.surcharges` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | #### `lines.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `discounts` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | [`vat`](#discountsvat-properties) | object | Yes | | #### `discounts.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `surcharges` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | [`vat`](#surchargesvat-properties) | object | Yes | | #### `surcharges.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `totals` (One of) **Totals:** If not provided, the totals will be calculated from the document lines. | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | ### `vat` (One of) **Provided VAT totals:** | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | [`subtotals`](#vatsubtotals-properties) | object[] | Yes | One entry for every combination of VAT category and rate used in the document | #### `vat.subtotals` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | ### `attachments` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | ### `countrySpecific` (One of) ## Used by - [List Documents](/reference/documents/get-documents) - [Get Document](/reference/documents/get-document) # Credit Note to send (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `creditNoteNumber` | string | Yes | Example: `"CN-2024-001"` | | `issueDate` | string \| null | No | If not provided, the issue date will be the current date. Example: `"2024-03-20"`. Format: date | | `note` | string \| null | No | Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | Example: `"PO-2024-001"` | | [`invoiceReferences`](#invoicereferences-properties) | object[] | No | References to one or more invoices that are being credited. Default: `` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | [`seller`](#seller-one-of) | Party | null | No | If not provided, the seller will be the company that is sending the credit note | | [`buyer`](#buyer-properties) | object | Yes | | | [`delivery`](#delivery-one-of) | Delivery | null | No | Optional delivery information | | [`paymentMeans`](#paymentmeans-properties) | object[] \| null | No | | | [`paymentTerms`](#paymentterms-properties) | object \| null | No | | | [`lines`](#lines-properties) | object[] | Yes | Min items: 1 | | [`discounts`](#discounts-properties) | object[] \| null | No | Optional global discounts | | [`surcharges`](#surcharges-properties) | object[] \| null | No | Optional global surcharges | | [`totals`](#totals-one-of) | Totals | null | No | | | [`vat`](#vat-any-of) | Provided VAT totals | VAT totals auto calculation | null | No | If not provided, the VAT totals will be calculated from the document lines | | [`attachments`](#attachments-properties) | object[] \| null | No | Optional attachments to the credit note | | `currency` | string (enum) | No | The currency of the credit note. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | [`countrySpecific`](#countryspecific-one-of) | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | | `dueDate` | string \| null | No | If not provided, the due date will be 1 month from the issue date. Example: `"2024-04-20"`. Format: date | ### `invoiceReferences` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The reference to the invoice that is being credited. Example: `"INV-2024-001"` | | `issueDate` | string \| null | No | The issue date of the invoice that is being credited. Example: `"2024-03-20"`. Format: date | ### `seller` (One of) **Party:** | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | ### `buyer` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | ### `delivery` (One of) **Delivery:** | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | [`locationIdentifier`](#deliverylocationidentifier-properties) | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | [`location`](#deliverylocation-properties) | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | #### `delivery.locationIdentifier` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | #### `delivery.location` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | ### `paymentMeans` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | ### `paymentTerms` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | Example: `"Net 30"` | ### `lines` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | [`standardId`](#linesstandardid-properties) | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | [`commodityClassifications`](#linescommodityclassifications-properties) | object[] \| null | No | Optional commodity classifications | | [`additionalItemProperties`](#linesadditionalitemproperties-properties) | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | [`discounts`](#linesdiscounts-properties) | object[] \| null | No | Optional discounts for the line | | [`surcharges`](#linessurcharges-properties) | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | [`vat`](#linesvat-properties) | object | Yes | | #### `lines.standardId` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | #### `lines.commodityClassifications` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | #### `lines.additionalItemProperties` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | #### `lines.discounts` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | #### `lines.surcharges` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | #### `lines.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `discounts` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | [`vat`](#discountsvat-properties) | object | Yes | | #### `discounts.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `surcharges` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | [`vat`](#surchargesvat-properties) | object | Yes | | #### `surcharges.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `totals` (One of) **Totals:** If not provided, the totals will be calculated from the document lines. | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | ### `vat` (Any of) **Provided VAT totals:** | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | [`subtotals`](#vatsubtotals-properties) | object[] | Yes | One entry for every combination of VAT category and rate used in the document | #### `vat.subtotals` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | **VAT totals auto calculation:** Recommand will automatically calculate the VAT totals based on the document lines. For invoices that are exempt from VAT, you can provide the exemption reason or reason code here to inform the recipient of the reason why the amount is exempt from VAT. | Name | Type | Required | Description | |------|------|----------|-------------| | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | ### `attachments` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | ### `countrySpecific` (One of) ## Used by - [Send Document](/reference/sending/send-document) - [Generate Document](/reference/sending/generate) # Self Billing Invoice to send (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `invoiceNumber` | string | Yes | The number the seller assigned to the invoice. Example: `"INV-2024-001"` | | `issueDate` | string \| null | No | If not provided, the issue date will be the current date. Example: `"2024-03-20"`. Format: date | | `dueDate` | string \| null | No | If not provided, the due date will be 1 month from the issue date. Example: `"2024-04-20"`. Format: date | | `note` | string \| null | No | A free text note about the invoice as a whole. Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | A reference the buyer asked you to put on the invoice so they can route it internally. If neither this nor `purchaseOrderReference` is provided, the invoice number is used. Example: `"PO-2024-001"` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | [`seller`](#seller-properties) | object | Yes | | | [`buyer`](#buyer-one-of) | Party | null | No | If not provided, the buyer will be the company that is sending the self billing invoice | | [`delivery`](#delivery-one-of) | Delivery | null | No | Optional delivery information | | [`paymentMeans`](#paymentmeans-properties) | object[] \| null | No | Optional payment information. For most invoices, this should be provided. For prepaid invoices, this could be omitted | | [`paymentTerms`](#paymentterms-properties) | object \| null | No | Optional payment terms | | [`lines`](#lines-properties) | object[] | Yes | The invoice lines. At least one line is required. Min items: 1 | | [`discounts`](#discounts-properties) | object[] \| null | No | Optional global discounts | | [`surcharges`](#surcharges-properties) | object[] \| null | No | Optional global surcharges | | [`totals`](#totals-one-of) | Totals | null | No | | | [`vat`](#vat-any-of) | Provided VAT totals | VAT totals auto calculation | null | No | If not provided, the VAT totals will be calculated from the document lines | | [`attachments`](#attachments-properties) | object[] \| null | No | Optional attachments to the invoice | | `currency` | string (enum) | No | The currency of the invoice. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | [`countrySpecific`](#countryspecific-one-of) | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | ### `seller` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | ### `buyer` (One of) **Party:** | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | ### `delivery` (One of) **Delivery:** | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | [`locationIdentifier`](#deliverylocationidentifier-properties) | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | [`location`](#deliverylocation-properties) | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | #### `delivery.locationIdentifier` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | #### `delivery.location` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | ### `paymentMeans` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | ### `paymentTerms` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | The payment terms as free text. Example: `"Net 30"` | ### `lines` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | [`standardId`](#linesstandardid-properties) | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | [`commodityClassifications`](#linescommodityclassifications-properties) | object[] \| null | No | Optional commodity classifications | | [`additionalItemProperties`](#linesadditionalitemproperties-properties) | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | [`discounts`](#linesdiscounts-properties) | object[] \| null | No | Optional discounts for the line | | [`surcharges`](#linessurcharges-properties) | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | [`vat`](#linesvat-properties) | object | Yes | | #### `lines.standardId` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | #### `lines.commodityClassifications` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | #### `lines.additionalItemProperties` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | #### `lines.discounts` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | #### `lines.surcharges` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | #### `lines.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `discounts` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | [`vat`](#discountsvat-properties) | object | Yes | | #### `discounts.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `surcharges` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | [`vat`](#surchargesvat-properties) | object | Yes | | #### `surcharges.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `totals` (One of) **Totals:** If not provided, the totals will be calculated from the document lines. | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | ### `vat` (Any of) **Provided VAT totals:** | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | [`subtotals`](#vatsubtotals-properties) | object[] | Yes | One entry for every combination of VAT category and rate used in the document | #### `vat.subtotals` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | **VAT totals auto calculation:** Recommand will automatically calculate the VAT totals based on the document lines. For invoices that are exempt from VAT, you can provide the exemption reason or reason code here to inform the recipient of the reason why the amount is exempt from VAT. | Name | Type | Required | Description | |------|------|----------|-------------| | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | ### `attachments` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | ### `countrySpecific` (One of) ## Used by - [Send Document](/reference/sending/send-document) - [Generate Document](/reference/sending/generate) # Self Billing Credit Note to send (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `creditNoteNumber` | string | Yes | Example: `"CN-2024-001"` | | `issueDate` | string \| null | No | If not provided, the issue date will be the current date. Example: `"2024-03-20"`. Format: date | | `note` | string \| null | No | Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | Example: `"PO-2024-001"` | | [`invoiceReferences`](#invoicereferences-properties) | object[] | No | References to one or more invoices that are being credited. Default: `` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | [`seller`](#seller-properties) | object | Yes | | | [`buyer`](#buyer-one-of) | Party | null | No | If not provided, the buyer will be the company that is sending the self billing credit note | | [`delivery`](#delivery-one-of) | Delivery | null | No | Optional delivery information | | [`paymentMeans`](#paymentmeans-properties) | object[] \| null | No | | | [`paymentTerms`](#paymentterms-properties) | object \| null | No | | | [`lines`](#lines-properties) | object[] | Yes | Min items: 1 | | [`discounts`](#discounts-properties) | object[] \| null | No | Optional global discounts | | [`surcharges`](#surcharges-properties) | object[] \| null | No | Optional global surcharges | | [`totals`](#totals-one-of) | Totals | null | No | | | [`vat`](#vat-any-of) | Provided VAT totals | VAT totals auto calculation | null | No | If not provided, the VAT totals will be calculated from the document lines | | [`attachments`](#attachments-properties) | object[] \| null | No | Optional attachments to the credit note | | `currency` | string (enum) | No | The currency of the credit note. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | [`countrySpecific`](#countryspecific-one-of) | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | | `dueDate` | string \| null | No | If not provided, the due date will be 1 month from the issue date. Example: `"2024-04-20"`. Format: date | ### `invoiceReferences` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The reference to the invoice that is being credited. Example: `"INV-2024-001"` | | `issueDate` | string \| null | No | The issue date of the invoice that is being credited. Example: `"2024-03-20"`. Format: date | ### `seller` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | ### `buyer` (One of) **Party:** | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | ### `delivery` (One of) **Delivery:** | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | [`locationIdentifier`](#deliverylocationidentifier-properties) | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | [`location`](#deliverylocation-properties) | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | #### `delivery.locationIdentifier` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | #### `delivery.location` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | ### `paymentMeans` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | ### `paymentTerms` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | Example: `"Net 30"` | ### `lines` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | [`standardId`](#linesstandardid-properties) | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | [`commodityClassifications`](#linescommodityclassifications-properties) | object[] \| null | No | Optional commodity classifications | | [`additionalItemProperties`](#linesadditionalitemproperties-properties) | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | [`discounts`](#linesdiscounts-properties) | object[] \| null | No | Optional discounts for the line | | [`surcharges`](#linessurcharges-properties) | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | [`vat`](#linesvat-properties) | object | Yes | | #### `lines.standardId` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | #### `lines.commodityClassifications` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | #### `lines.additionalItemProperties` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | #### `lines.discounts` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | #### `lines.surcharges` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | #### `lines.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `discounts` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | [`vat`](#discountsvat-properties) | object | Yes | | #### `discounts.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `surcharges` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | [`vat`](#surchargesvat-properties) | object | Yes | | #### `surcharges.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `totals` (One of) **Totals:** If not provided, the totals will be calculated from the document lines. | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | ### `vat` (Any of) **Provided VAT totals:** | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | [`subtotals`](#vatsubtotals-properties) | object[] | Yes | One entry for every combination of VAT category and rate used in the document | #### `vat.subtotals` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | **VAT totals auto calculation:** Recommand will automatically calculate the VAT totals based on the document lines. For invoices that are exempt from VAT, you can provide the exemption reason or reason code here to inform the recipient of the reason why the amount is exempt from VAT. | Name | Type | Required | Description | |------|------|----------|-------------| | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | ### `attachments` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | ### `countrySpecific` (One of) ## Used by - [Send Document](/reference/sending/send-document) - [Generate Document](/reference/sending/generate) # Message Level Response (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | | | `issueDate` | string (date) | Yes | Example: `"2024-03-20"`. Format: date | | `responseCode` | `AB` \| `AP` \| `RE` | Yes | The response code of the message level response (AB: Message acknowledgement, AP: Accepted, RE: Rejected). Example: `"AB"`. Values: `AB`, `AP`, `RE` | | `envelopeId` | string | Yes | Identifies the document on which the message level response is based | ## Used by - [List Documents](/reference/documents/get-documents) - [Get Document](/reference/documents/get-document) # Message Level Response to send (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | No | The ID of the message level response. If not provided, the ID will be autogenerated | | `issueDate` | string (date) | No | If not provided, the issue date will be the current date. Example: `"2024-03-20"`. Format: date | | `responseCode` | `AB` \| `AP` \| `RE` | Yes | The response code of the message level response (AB: Message acknowledgement, AP: Accepted, RE: Rejected). Example: `"AB"`. Values: `AB`, `AP`, `RE` | | `envelopeId` | string | Yes | Identifies the document on which the message level response is based | ## Used by - [Send Document](/reference/sending/send-document) - [Generate Document](/reference/sending/generate) # French Invoicing CDAR to send (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | No | The ID of the CDAR. If not provided, the ID will be autogenerated | | `issueDate` | string (date-time) | No | If not provided, the issue date and time will be the current local date and time. Example: `"2024-03-20T14:05:09"`. Format: date-time | | `businessProcess` | `REGULATED` \| `NON_REGULATED` \| `B2C` \| `B2CINT` \| `B2BINT` \| `OUTOFSCOPE` | Yes | Flow classification. \| Value \| Meaning \| \| --- \| --- \| \| `REGULATED` \| Regulated French domestic e-invoicing \| \| `NON_REGULATED` \| Outside the regulated French e-invoicing perimeter \| \| `B2C` \| B2C sales e-reporting \| \| `B2CINT` \| International B2C sales e-reporting \| \| `B2BINT` \| International B2B sales e-reporting \| \| `OUTOFSCOPE` \| Outside the French e-invoicing and e-reporting reform \|. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED`, `B2C`, `B2CINT`, `B2BINT`, `OUTOFSCOPE` | | `phase` | `23` \| `305` | No | CDAR phase. \| Value \| Meaning \| \| --- \| --- \| \| `23` \| Processing phase \| \| `305` \| Transmission phase \| Defaults to `305` for statuses `200`, `201`, `202`, `203`, `213`, and `501`; otherwise defaults to `23`. Example: `"23"`. Values: `23`, `305` | | `senderRole` | string (enum) | Yes | Role of the CDAR sender. CDAR party role code (UNCL 3035). \| Value \| Meaning \| \| --- \| --- \| \| `BY` \| Buyer \| \| `AB` \| Buyer's agent or representative \| \| `DL` \| Factor \| \| `SE` \| Seller \| \| `SR` \| Seller's agent \| \| `WK` \| Platform or dematerialisation operator \| \| `DFH` \| French public invoicing portal (PPF) \| \| `PE` \| Payee \| \| `PR` \| Payer \| \| `II` \| Invoicer (invoice issuer) \| \| `IV` \| Invoicee (party invoiced) \|. Example: `"WK"`. Values: `BY`, `AB`, `DL`, `SE`, `SR`, `WK`, `DFH`, `PE`, `PR`, `II`, `IV` | | `issuerRole` | string (enum) | Yes | Role of the party that creates and issues the invoice lifecycle status. This is independent from the CDAR sender role. CDAR party role code (UNCL 3035). \| Value \| Meaning \| \| --- \| --- \| \| `BY` \| Buyer \| \| `AB` \| Buyer's agent or representative \| \| `DL` \| Factor \| \| `SE` \| Seller \| \| `SR` \| Seller's agent \| \| `WK` \| Platform or dematerialisation operator \| \| `DFH` \| French public invoicing portal (PPF) \| \| `PE` \| Payee \| \| `PR` \| Payer \| \| `II` \| Invoicer (invoice issuer) \| \| `IV` \| Invoicee (party invoiced) \|. Example: `"BY"`. Values: `BY`, `AB`, `DL`, `SE`, `SR`, `WK`, `DFH`, `PE`, `PR`, `II`, `IV` | | `issuerLegalId` | string | No | Legal identifier of the party setting the status. Required when phase is 23; must be omitted when phase is 305 unless recipientRole is DFH. Example: `"200000008"` | | `issuerLegalIdScheme` | string | No | ISO 6523 ICD scheme of the party-setting-status legal identifier. Required together with issuerLegalId. Example: `"0002"` | | `recipientRole` | string (enum) | Yes | Role of the CDAR recipient. CDAR party role code (UNCL 3035). \| Value \| Meaning \| \| --- \| --- \| \| `BY` \| Buyer \| \| `AB` \| Buyer's agent or representative \| \| `DL` \| Factor \| \| `SE` \| Seller \| \| `SR` \| Seller's agent \| \| `WK` \| Platform or dematerialisation operator \| \| `DFH` \| French public invoicing portal (PPF) \| \| `PE` \| Payee \| \| `PR` \| Payer \| \| `II` \| Invoicer (invoice issuer) \| \| `IV` \| Invoicee (party invoiced) \|. Example: `"SE"`. Values: `BY`, `AB`, `DL`, `SE`, `SR`, `WK`, `DFH`, `PE`, `PR`, `II`, `IV` | | `recipientLegalId` | string | No | Legal identifier of the CDAR recipient. Example: `"200000008"` | | `recipientLegalIdScheme` | string | No | ISO 6523 ICD scheme of the CDAR recipient legal identifier. Required together with recipientLegalId. Example: `"0002"` | | `statusCode` | string (enum) | Yes | French invoice lifecycle status. \| Value \| Meaning \| \| --- \| --- \| \| `200` \| Submitted \| \| `201` \| Issued \| \| `202` \| Received \| \| `203` \| Made available \| \| `204` \| Taken in charge (processing started) \| \| `205` \| Approved \| \| `206` \| Partially approved \| \| `207` \| In dispute \| \| `208` \| Suspended \| \| `209` \| Completed \| \| `210` \| Refused \| \| `211` \| Payment sent \| \| `212` \| Collected (cashed) \| \| `213` \| Rejected \| \| `214` \| Validated or pre-validated ("Visée") \| \| `501` \| Inadmissible file \|. Example: `"200"`. Values: `200`, `201`, `202`, `203`, `204`, `205`, `206`, `207`, `208`, `209`, `210`, `211`, `212`, `213`, `214`, `501` | | `statusDate` | string (date-time) | No | Date and time at which the status was set. If not provided, the issue date and time of the CDAR is used. Example: `"2024-03-20T14:05:09"`. Format: date-time | | `invoiceId` | string | Yes | Number of the invoice this status relates to. For status 501, this is the filename of the inadmissible file | | `invoiceTypeCode` | string (enum) | No | Type of the referenced invoice. Type of the referenced invoice (UNTDID 1001, restricted to the values allowed by BR-FR-04). \| Value \| Meaning \| \| --- \| --- \| \| `380` \| Commercial invoice \| \| `389` \| Self-billed invoice \| \| `393` \| Factored invoice \| \| `501` \| Self-billed factored invoice \| \| `386` \| Advance payment invoice \| \| `500` \| Self-billed advance payment invoice \| \| `384` \| Corrective invoice \| \| `471` \| Self-billed corrective invoice \| \| `472` \| Factored corrective invoice \| \| `473` \| Self-billed factored corrective invoice \| \| `261` \| Self-billed credit note \| \| `262` \| Global rebate credit note \| \| `381` \| Credit note \| \| `396` \| Factored credit note \| \| `502` \| Self-billed factored credit note \| \| `503` \| Credit note for an advance payment invoice \|. Example: `"380"`. Values: `380`, `389`, `393`, `501`, `386`, `500`, `384`, `471`, `472`, `473`, `261`, `262`, `381`, `396`, `502`, `503` | | `invoiceIssueDate` | string (date) | No | Issue date of the referenced invoice. Required unless statusCode is 501. Example: `"2024-03-15"`. Format: date | | `sellerLegalId` | string | No | Legal identifier (e.g. SIREN) of the invoice seller. Required unless statusCode is 501. Example: `"123456789"` | | `sellerLegalIdScheme` | string | No | ISO 6523 ICD scheme of the referenced invoice seller legal identifier. Required together with sellerLegalId. Example: `"0002"` | | `reasonCode` | string (enum) | No | Coded reason for the invoice lifecycle status. \| Value \| Meaning \| \| --- \| --- \| \| `JUSTIF_ABS` \| Supporting document missing or insufficient \| \| `ROUTAGE_ERR` \| Routing error \| \| `AUTRE` \| Other reason; provide an explanation in `reasonNote` \| \| `COORD_BANC_ERR` \| Incorrect bank details \| \| `TX_TVA_ERR` \| Incorrect VAT rate \| \| `MONTANTTOTAL_ERR` \| Incorrect invoice total \| \| `CALCUL_ERR` \| Invoice calculation error \| \| `NON_CONFORME` \| Missing legal information \| \| `DOUBLON` \| Duplicate invoice \| \| `DEST_INC` \| Unknown recipient \| \| `DEST_ERR` \| Incorrect recipient \| \| `TRANSAC_INC` \| Unknown transaction \| \| `EMMET_INC` \| Unknown issuer \| \| `CONTRAT_TERM` \| Contract ended \| \| `DOUBLE_FACT` \| Supply or service already invoiced on another invoice \| \| `CMD_ERR` \| Incorrect or missing order number \| \| `ADR_ERR` \| Incorrect electronic invoicing address \| \| `SIRET_ERR` \| Incorrect or missing SIRET \| \| `CODE_ROUTAGE_ERR` \| Incorrect or missing routing code \| \| `REF_CT_ABSENT` \| Required contractual reference missing \| \| `REF_ERR` \| Incorrect reference \| \| `PU_ERR` \| Incorrect unit price \| \| `REM_ERR` \| Incorrect discount \| \| `QTE_ERR` \| Incorrect invoiced quantity \| \| `ART_ERR` \| Incorrect invoiced item \| \| `MODPAI_ERR` \| Incorrect payment terms \| \| `QUALITE_ERR` \| Incorrect quality of delivered item \| \| `LIVR_INCOMP` \| Incomplete or non-compliant delivery \| \| `REJ_SEMAN` \| Rejected because of a semantic error \| \| `REJ_UNI` \| Rejected by uniqueness control \| \| `REJ_COH` \| Rejected by data-consistency control \| \| `REJ_ADR` \| Rejected by addressing control \| \| `REJ_CONT_B2G` \| Rejected by B2G business controls \| \| `REJ_REF_PJ` \| Rejected because of an attachment-reference error \| \| `REJ_ASS_PJ` \| Rejected because of an attachment-association error \| \| `NON_TRANSMISE` \| Submitted but not transmitted because the recipient has no receiving platform \|. Values: `JUSTIF_ABS`, `ROUTAGE_ERR`, `AUTRE`, `COORD_BANC_ERR`, `TX_TVA_ERR`, `MONTANTTOTAL_ERR`, `CALCUL_ERR`, `NON_CONFORME`, `DOUBLON`, `DEST_INC`, `DEST_ERR`, `TRANSAC_INC`, `EMMET_INC`, `CONTRAT_TERM`, `DOUBLE_FACT`, `CMD_ERR`, `ADR_ERR`, `SIRET_ERR`, `CODE_ROUTAGE_ERR`, `REF_CT_ABSENT`, `REF_ERR`, `PU_ERR`, `REM_ERR`, `QTE_ERR`, `ART_ERR`, `MODPAI_ERR`, `QUALITE_ERR`, `LIVR_INCOMP`, `REJ_SEMAN`, `REJ_UNI`, `REJ_COH`, `REJ_ADR`, `REJ_CONT_B2G`, `REJ_REF_PJ`, `REJ_ASS_PJ`, `NON_TRANSMISE` | | `reason` | string | No | Optional free-text status reason. This is distinct from the IncludedNote explanation required for reasonCode AUTRE | | `reasonNote` | string | No | Free-text comment in the status detail IncludedNote. Required when reasonCode is AUTRE. Example: `"The invoice needs manual review."` | | [`collectedAmounts`](#collectedamounts-properties) | object[] | No | Collected amounts with VAT rates (TypeCode MEN). Required for status 212; at least one entry | ### `collectedAmounts` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `amount` | string | Yes | Net collected amount (positive) or disbursed amount (negative), for status 212. Example: `"12000.00"` | | `currency` | string (enum) | Yes | ISO 4217 currency code of the collected amount. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `vatPercent` | string | Yes | VAT rate applicable to the collected amount. Example: `"20.00"` | ## Used by - [Send Document](/reference/sending/send-document) - [Generate Document](/reference/sending/generate) # XML (Model) **Type:** `string` ## Used by - [Send Document](/reference/sending/send-document) # Self Billing Invoice (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `invoiceNumber` | string | Yes | The number the seller assigned to the invoice. Example: `"INV-2024-001"` | | `issueDate` | string (date) | Yes | The date the invoice was issued, as YYYY-MM-DD. Example: `"2024-03-20"`. Format: date | | `dueDate` | string \| null | No | The date the payment is due, as YYYY-MM-DD. Example: `"2024-04-20"`. Format: date | | `note` | string \| null | No | A free text note about the invoice as a whole. Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | A reference the buyer asked you to put on the invoice so they can route it internally. If neither this nor `purchaseOrderReference` is provided, the invoice number is used. Example: `"PO-2024-001"` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | [`seller`](#seller-properties) | object | Yes | | | [`buyer`](#buyer-properties) | object | Yes | | | [`delivery`](#delivery-one-of) | Delivery | null | No | Optional delivery information | | [`paymentMeans`](#paymentmeans-properties) | object[] \| null | No | Optional payment information. For most invoices, this should be provided. For prepaid invoices, this could be omitted | | [`paymentTerms`](#paymentterms-properties) | object \| null | No | Optional payment terms | | [`lines`](#lines-properties) | object[] | Yes | The invoice lines. At least one line is required. Min items: 1 | | [`discounts`](#discounts-properties) | object[] \| null | No | Optional global discounts | | [`surcharges`](#surcharges-properties) | object[] \| null | No | Optional global surcharges | | [`totals`](#totals-one-of) | Totals | null | No | | | [`vat`](#vat-one-of) | Provided VAT totals | null | No | The VAT totals of the invoice, broken down per VAT category and rate | | [`attachments`](#attachments-properties) | object[] \| null | No | Optional attachments to the invoice | | `currency` | string (enum) | Yes | The currency of the invoice. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | [`countrySpecific`](#countryspecific-one-of) | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | ### `seller` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | ### `buyer` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | ### `delivery` (One of) **Delivery:** | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | [`locationIdentifier`](#deliverylocationidentifier-properties) | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | [`location`](#deliverylocation-properties) | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | #### `delivery.locationIdentifier` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | #### `delivery.location` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | ### `paymentMeans` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | ### `paymentTerms` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | The payment terms as free text. Example: `"Net 30"` | ### `lines` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | [`standardId`](#linesstandardid-properties) | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | [`commodityClassifications`](#linescommodityclassifications-properties) | object[] \| null | No | Optional commodity classifications | | [`additionalItemProperties`](#linesadditionalitemproperties-properties) | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | [`discounts`](#linesdiscounts-properties) | object[] \| null | No | Optional discounts for the line | | [`surcharges`](#linessurcharges-properties) | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | [`vat`](#linesvat-properties) | object | Yes | | #### `lines.standardId` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | #### `lines.commodityClassifications` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | #### `lines.additionalItemProperties` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | #### `lines.discounts` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | #### `lines.surcharges` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | #### `lines.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `discounts` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | [`vat`](#discountsvat-properties) | object | Yes | | #### `discounts.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `surcharges` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | [`vat`](#surchargesvat-properties) | object | Yes | | #### `surcharges.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `totals` (One of) **Totals:** If not provided, the totals will be calculated from the document lines. | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | ### `vat` (One of) **Provided VAT totals:** | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | [`subtotals`](#vatsubtotals-properties) | object[] | Yes | One entry for every combination of VAT category and rate used in the document | #### `vat.subtotals` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | ### `attachments` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | ### `countrySpecific` (One of) ## Used by - [List Documents](/reference/documents/get-documents) - [Get Document](/reference/documents/get-document) # Self Billing Credit Note (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `creditNoteNumber` | string | Yes | Example: `"CN-2024-001"` | | `issueDate` | string (date) | Yes | Example: `"2024-03-20"`. Format: date | | `note` | string \| null | No | Example: `"Thank you for your business"` | | `buyerReference` | string \| null | No | Example: `"PO-2024-001"` | | [`invoiceReferences`](#invoicereferences-properties) | object[] | Yes | References to one or more invoices that are being credited. Default: `` | | `purchaseOrderReference` | string \| null | No | A reference to a related purchase order. Example: `"PO-2024-001"` | | `salesOrderReference` | string \| null | No | A reference to a related sales order. Example: `"SO-2024-001"` | | `despatchReference` | string \| null | No | A reference to a related despatch advice document (e.g. packing slip). Example: `"DE-2024-001"` | | [`seller`](#seller-properties) | object | Yes | | | [`buyer`](#buyer-properties) | object | Yes | | | [`delivery`](#delivery-one-of) | Delivery | null | No | Optional delivery information | | [`paymentMeans`](#paymentmeans-properties) | object[] \| null | No | | | [`paymentTerms`](#paymentterms-properties) | object \| null | No | | | [`lines`](#lines-properties) | object[] | Yes | Min items: 1 | | [`discounts`](#discounts-properties) | object[] \| null | No | Optional global discounts | | [`surcharges`](#surcharges-properties) | object[] \| null | No | Optional global surcharges | | [`totals`](#totals-one-of) | Totals | null | No | | | [`vat`](#vat-one-of) | Provided VAT totals | null | No | | | [`attachments`](#attachments-properties) | object[] \| null | No | Optional attachments to the credit note | | `currency` | string (enum) | Yes | The currency of the credit note. Defaults to EUR. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | [`countrySpecific`](#countryspecific-one-of) | Country Specific Billing | null | No | Structured country-specific requirements. The FR variant is required for French regulated UBL, CII, and Factur-X document types | ### `invoiceReferences` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | The reference to the invoice that is being credited. Example: `"INV-2024-001"` | | `issueDate` | string \| null | No | The issue date of the invoice that is being credited. Example: `"2024-03-20"`. Format: date | ### `seller` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | ### `buyer` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `vatNumber` | string \| null | No | The VAT number including its country prefix, for example BE0123456789. Example: `"BE1234567894"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme that corresponds to the enterprise number. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0208"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | | `enterpriseNumber` | string \| null | No | The national registration number without a country prefix, paired with `enterpriseNumberScheme`. Example: `"1234567894"` | | `name` | string | Yes | The registered name of the party. Example: `"Example Company"` | | `street` | string | Yes | The street name and number of the party's address. Example: `"Example Street 1"` | | `street2` | string \| null | No | An extra address line, for example a suite or a building name. Example: `"Suite 100"` | | `city` | string | Yes | The city of the party's address. Example: `"Brussels"` | | `postalZone` | string | Yes | The postal code of the party's address. Example: `"1000"` | | `country` | string | Yes | The country of the party's address, as an ISO 3166-1 alpha-2 code. Example: `"BE"` | | `email` | string \| null | No | The email address of the party. If not provided, the email address will not be included in the document. Example: `"email@example.com"` | | `phone` | string \| null | No | The phone number of the party. Must contain at least 3 digits. If not provided, the phone number will not be included in the document. Example: `"887 654 321"` | ### `delivery` (One of) **Delivery:** | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | string \| null | No | The date of the delivery. Example: `"2025-03-20"`. Format: date | | [`locationIdentifier`](#deliverylocationidentifier-properties) | object \| null | No | The identifier of the delivery location. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `{"scheme":"0088","identifier":"123456789"}` | | [`location`](#deliverylocation-properties) | object | No | | | `recipientName` | string | No | The name of the party to which the goods and services are delivered. Example: `"Company Ltd."` | #### `delivery.locationIdentifier` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0088"` | | `identifier` | string | Yes | Example: `"123456789"` | #### `delivery.location` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `street` | string \| null | No | Example: `"Example Street 1"` | | `street2` | string \| null | No | Example: `"Suite 100"` | | `city` | string \| null | No | Example: `"Brussels"` | | `postalZone` | string \| null | No | Example: `"1000"` | | `country` | string | Yes | Example: `"BE"` | ### `paymentMeans` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string \| null | No | The name of the payment means. Example: `"Credit Transfer"` | | `paymentMethod` | `cash` \| `credit_transfer` \| `debit_transfer` \| `bank_card` \| `credit_card` \| `debit_card` \| `sepa_credit_transfer` \| `sepa_direct_debit` \| `other` | No | How the invoice is to be paid. Defaults to `credit_transfer`. Accepted values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other`. Default: `credit_transfer`. Example: `"credit_transfer"`. Values: `cash`, `credit_transfer`, `debit_transfer`, `bank_card`, `credit_card`, `debit_card`, `sepa_credit_transfer`, `sepa_direct_debit`, `other` | | `reference` | string | No | The payment reference the buyer should quote when paying, such as a structured communication. Default: ``. Example: `"INV-2026-001"` | | `iban` | string | Yes | The account the payment is to be made to, usually an IBAN. Example: `"BE1234567890"` | | `financialInstitutionBranch` | string \| null | No | An identifier for the payment service provider where a payment account is located. Such as a BIC or a national clearing code where required | ### `paymentTerms` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `note` | string | Yes | Example: `"Net 30"` | ### `lines` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string \| null | No | A line number. If not provided, it will be calculated automatically. Example: `"1"` | | `name` | string | No | The name of the item or service being billed. Default: ``. Example: `"Consulting Services"` | | `description` | string \| null | No | A longer description of the item or service. Example: `"Professional consulting services"` | | `note` | string \| null | No | A textual note that gives unstructured information that is relevant to this line | | `buyersId` | string \| null | No | The item identifier of the item as defined by the buyer. Example: `"CS-001"` | | `sellersId` | string \| null | No | The item identifier of the item as defined by the seller. This is typically a product code or SKU. Example: `"CS-001"` | | [`standardId`](#linesstandardid-properties) | object \| null | No | The standard identifier of the item based on a registered scheme. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/) | | `documentReference` | string \| null | No | A reference to a related document, mostly used to refer to a related invoice. Example: `"INV-2024-001"` | | `orderLineReference` | string \| null | No | A reference to a related order line | | [`commodityClassifications`](#linescommodityclassifications-properties) | object[] \| null | No | Optional commodity classifications | | [`additionalItemProperties`](#linesadditionalitemproperties-properties) | object[] \| null | No | Optional additional item properties | | `originCountry` | string \| null | No | The country of origin of the item. Example: `"BE"` | | `quantity` | string | No | The number of units billed on this line, expressed in `unitCode`. Default: `1.00`. Example: `"21.00"` | | `unitCode` | string | No | Recommended unit codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/). Default: `C62`. Example: `"HUR"` | | `netPriceAmount` | string | Yes | The price of one unit excluding VAT, after any discount that is already reflected in the price. Example: `"12.40"` | | `baseQuantity` | string \| null | No | The number of units to which the price refers. When greater than 1, the price is for a batch/pack of this size. The actual unit price is netPriceAmount / baseQuantity. Example: `"1"` | | [`discounts`](#linesdiscounts-properties) | object[] \| null | No | Optional discounts for the line | | [`surcharges`](#linessurcharges-properties) | object[] \| null | No | Optional surcharges for the line | | `netAmount` | string \| null | No | The total net amount of the line: quantity * netPriceAmount. Rounded to 2 decimal places. If not provided, it will be calculated automatically. Example: `"21.00"` | | [`vat`](#linesvat-properties) | object | Yes | | #### `lines.standardId` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string | Yes | Example: `"0160"` | | `identifier` | string | Yes | Example: `"10986700"` | #### `lines.commodityClassifications` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `scheme` | string (enum) | Yes | The scheme of the item classification code. Can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7143/). Example: `"SN"`. Values: `AA`, `AB`, `AC`, `AD`, `AE`, `AF`, `AG`, `AH`, `AI`, `AJ`, `AK`, `AL`, `AM`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AV`, `AW`, `AX`, `AY`, `AZ`, `BA`, `BB`, `BC`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BK`, `BL`, `BM`, `BN`, `BO`, `BP`, `BQ`, `BR`, `BS`, `BT`, `BU`, `BV`, `BW`, `BX`, `BY`, `BZ`, `CC`, `CG`, `CL`, `CR`, `CV`, `DR`, `DW`, `EC`, `EF`, `EMD`, `EN`, `FS`, `GB`, `GMN`, `GN`, `GS`, `HS`, `IB`, `IN`, `IS`, `IT`, `IZ`, `MA`, `MF`, `MN`, `MP`, `NB`, `ON`, `PD`, `PL`, `PO`, `PV`, `QS`, `RC`, `RN`, `RU`, `RY`, `SA`, `SG`, `SK`, `SN`, `SRS`, `SRT`, `SRU`, `SRV`, `SRW`, `SRX`, `SRY`, `SRZ`, `SS`, `SSA`, `SSB`, `SSC`, `SSD`, `SSE`, `SSF`, `SSG`, `SSH`, `SSI`, `SSJ`, `SSK`, `SSL`, `SSM`, `SSN`, `SSO`, `SSP`, `SSQ`, `SSR`, `SSS`, `SST`, `SSU`, `SSV`, `SSW`, `SSX`, `SSY`, `SSZ`, `ST`, `STA`, `STB`, `STC`, `STD`, `STE`, `STF`, `STG`, `STH`, `STI`, `STJ`, `STK`, `STL`, `STM`, `STN`, `STO`, `STP`, `STQ`, `STR`, `STS`, `STT`, `STU`, `STV`, `STW`, `STX`, `STY`, `STZ`, `SUA`, `SUB`, `SUC`, `SUD`, `SUE`, `SUF`, `SUG`, `SUH`, `SUI`, `SUJ`, `SUK`, `SUL`, `SUM`, `TG`, `TSN`, `TSO`, `TSP`, `TSQ`, `TSR`, `TSS`, `TST`, `TSU`, `UA`, `UP`, `VN`, `VP`, `VS`, `VX`, `ZZZ`, `PPI` | | `schemeVersion` | string \| null | No | | | `value` | string | Yes | The value of the item classification code. Example: `"123456"` | #### `lines.additionalItemProperties` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | Example: `"Color"` | | `value` | string | Yes | Example: `"Red"` | #### `lines.discounts` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | #### `lines.surcharges` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | #### `lines.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `discounts` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the discount. This must be one of the codes in the [UNCL5189 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/) code list. For example, `95` for regular discounts. Either reason or reasonCode must be provided. Example: `"95"` | | `reason` | string \| null | No | The reason for the discount. This is a free text field. Either reason or reasonCode must be provided. Example: `"Discount"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | [`vat`](#discountsvat-properties) | object | Yes | | #### `discounts.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `surcharges` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reasonCode` | string \| null | No | The reason code for the surcharge. This must be one of the codes in the [UNCL7161 subset](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL7161/) code list. For example, `FC` for freight services. Either reason or reasonCode must be provided. Example: `"FC"` | | `reason` | string \| null | No | The reason for the surcharge. This is a free text field. Either reason or reasonCode must be provided. Example: `"Freight services"` | | `amount` | string | Yes | Decimal number as a string with 2 decimal places. Example: `"21.00"` | | [`vat`](#surchargesvat-properties) | object | Yes | | #### `surcharges.vat` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | No | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Default: `S`. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | ### `totals` (One of) **Totals:** If not provided, the totals will be calculated from the document lines. | Name | Type | Required | Description | |------|------|----------|-------------| | `linesAmount` | string \| null | No | The tax exclusive total amount of all lines. Rounded to 2 decimal places. Example: `"21.00"` | | `discountAmount` | string \| null | No | The tax exclusive total amount of all discounts. If not provided, this will be calculated automatically. Example: `"21.00"` | | `surchargeAmount` | string \| null | No | The tax exclusive total amount of all surcharges. If not provided, this will be calculated automatically. Example: `"21.00"` | | `taxExclusiveAmount` | string | Yes | The tax exclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `taxInclusiveAmount` | string | Yes | The tax inclusive total amount of all lines, discounts and surcharges. Rounded to 2 decimal places. Example: `"21.00"` | | `payableAmount` | string \| null | No | The amount to be paid. If not provided, this will be taxInclusiveAmount. Can be used in combination with paidAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | | `paidAmount` | string \| null | No | The amount paid. If not provided, this will be taxInclusiveAmount - payableAmount. Can be used in combination with payableAmount to indicate partial payment or payment rounding. Rounded to 2 decimal places. Example: `"21.00"` | ### `vat` (One of) **Provided VAT totals:** | Name | Type | Required | Description | |------|------|----------|-------------| | `totalVatAmount` | string | Yes | The total VAT amount of the document, the sum of the VAT amounts of all subtotals. Example: `"21.00"` | | [`subtotals`](#vatsubtotals-properties) | object[] | Yes | One entry for every combination of VAT category and rate used in the document | #### `vat.subtotals` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `taxableAmount` | string | Yes | The total amount in this VAT category and rate that the VAT is calculated on. Example: `"21.00"` | | `vatAmount` | string | Yes | The VAT amount for this VAT category and rate. Example: `"21.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code. All codes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/). When sending regular invoices, you should most often use the `S` category. When sending an invoice to another EU country, use the `AE` category for VAT Reverse Charge. In those cases, it is still recommended to include a note in the invoice explaining that the VAT Reverse Charge applies. Example: `"S"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `percentage` | string | Yes | The VAT rate as a percentage, for example 21.00. Example: `"21.00"` | | `exemptionReasonCode` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReason) is required. The exemption reason code identifier must belong to the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/) | | `exemptionReason` | string \| null | No | If the invoice is exempt from VAT, this (or exemptionReasonCode) is required. The exemption reason must be a textual statement of the reason why the amount is exempt from VAT or why no VAT is charged | ### `attachments` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | An identifier for the attachment within the document. Example: `"ATT-001"` | | `mimeCode` | string | No | MIME type of the document (e.g. application/pdf, text/csv, image/png). Default: `application/pdf`. Example: `"application/pdf"` | | `filename` | string | Yes | Filename for an embedded attachment. This is included in the Peppol XML only when `embeddedDocument` is provided. For URL-only attachments, the document contains an external reference and the filename is not embedded. Example: `"contract.pdf"` | | `description` | string \| null | No | A short description of what the attachment contains. Example: `"Signed contract"` | | `embeddedDocument` | string \| null | No | The contents of the attachment, base64 encoded. Provide this or `url` | | `url` | string \| null | No | A link to the attachment, for when the contents are not embedded. Provide this or `embeddedDocument`. Example: `"https://example.com/contract.pdf"` | ### `countrySpecific` (One of) ## Used by - [List Documents](/reference/documents/get-documents) - [Get Document](/reference/documents/get-document) # French Invoicing CDAR (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | string | Yes | | | [`issueDate`](#issuedate-any-of) | string (date-time) | string (date) | Yes | Creation date and time of the CDAR, without a timezone and with second precision. Date-only values are accepted for incoming format-102 documents. Example: `"2024-03-20T14:05:09"` | | `businessProcess` | `REGULATED` \| `NON_REGULATED` \| `B2C` \| `B2CINT` \| `B2BINT` \| `OUTOFSCOPE` | Yes | Flow classification. \| Value \| Meaning \| \| --- \| --- \| \| `REGULATED` \| Regulated French domestic e-invoicing \| \| `NON_REGULATED` \| Outside the regulated French e-invoicing perimeter \| \| `B2C` \| B2C sales e-reporting \| \| `B2CINT` \| International B2C sales e-reporting \| \| `B2BINT` \| International B2B sales e-reporting \| \| `OUTOFSCOPE` \| Outside the French e-invoicing and e-reporting reform \|. Example: `"REGULATED"`. Values: `REGULATED`, `NON_REGULATED`, `B2C`, `B2CINT`, `B2BINT`, `OUTOFSCOPE` | | `phase` | `23` \| `305` | Yes | CDAR phase. \| Value \| Meaning \| \| --- \| --- \| \| `23` \| Processing phase \| \| `305` \| Transmission phase \|. Example: `"23"`. Values: `23`, `305` | | `senderRole` | string (enum) | Yes | Role of the CDAR sender. CDAR party role code (UNCL 3035). \| Value \| Meaning \| \| --- \| --- \| \| `BY` \| Buyer \| \| `AB` \| Buyer's agent or representative \| \| `DL` \| Factor \| \| `SE` \| Seller \| \| `SR` \| Seller's agent \| \| `WK` \| Platform or dematerialisation operator \| \| `DFH` \| French public invoicing portal (PPF) \| \| `PE` \| Payee \| \| `PR` \| Payer \| \| `II` \| Invoicer (invoice issuer) \| \| `IV` \| Invoicee (party invoiced) \|. Example: `"WK"`. Values: `BY`, `AB`, `DL`, `SE`, `SR`, `WK`, `DFH`, `PE`, `PR`, `II`, `IV` | | `issuerRole` | string (enum) | Yes | Role of the party that creates and issues the invoice lifecycle status. This is independent from the CDAR sender role. CDAR party role code (UNCL 3035). \| Value \| Meaning \| \| --- \| --- \| \| `BY` \| Buyer \| \| `AB` \| Buyer's agent or representative \| \| `DL` \| Factor \| \| `SE` \| Seller \| \| `SR` \| Seller's agent \| \| `WK` \| Platform or dematerialisation operator \| \| `DFH` \| French public invoicing portal (PPF) \| \| `PE` \| Payee \| \| `PR` \| Payer \| \| `II` \| Invoicer (invoice issuer) \| \| `IV` \| Invoicee (party invoiced) \|. Example: `"BY"`. Values: `BY`, `AB`, `DL`, `SE`, `SR`, `WK`, `DFH`, `PE`, `PR`, `II`, `IV` | | `issuerLegalId` | string | No | Legal identifier of the party setting the status. Required when phase is 23; must be omitted when phase is 305 unless recipientRole is DFH. Example: `"200000008"` | | `issuerLegalIdScheme` | string | No | ISO 6523 ICD scheme of the party-setting-status legal identifier. Required together with issuerLegalId. Example: `"0002"` | | `recipientRole` | string (enum) | Yes | Role of the CDAR recipient. CDAR party role code (UNCL 3035). \| Value \| Meaning \| \| --- \| --- \| \| `BY` \| Buyer \| \| `AB` \| Buyer's agent or representative \| \| `DL` \| Factor \| \| `SE` \| Seller \| \| `SR` \| Seller's agent \| \| `WK` \| Platform or dematerialisation operator \| \| `DFH` \| French public invoicing portal (PPF) \| \| `PE` \| Payee \| \| `PR` \| Payer \| \| `II` \| Invoicer (invoice issuer) \| \| `IV` \| Invoicee (party invoiced) \|. Example: `"SE"`. Values: `BY`, `AB`, `DL`, `SE`, `SR`, `WK`, `DFH`, `PE`, `PR`, `II`, `IV` | | `recipientLegalId` | string | No | Legal identifier of the CDAR recipient. Example: `"200000008"` | | `recipientLegalIdScheme` | string | No | ISO 6523 ICD scheme of the CDAR recipient legal identifier. Required together with recipientLegalId. Example: `"0002"` | | `recipientElectronicAddress` | string | No | Electronic address of the CDAR recipient. Required when recipientRole is not WK or DFH. Example: `"100000009"` | | `recipientElectronicAddressScheme` | string | No | Electronic Address Scheme (EAS) code of the CDAR recipient electronic address. Required together with recipientElectronicAddress. Example: `"0225"` | | `statusCode` | string (enum) | Yes | French invoice lifecycle status. \| Value \| Meaning \| \| --- \| --- \| \| `200` \| Submitted \| \| `201` \| Issued \| \| `202` \| Received \| \| `203` \| Made available \| \| `204` \| Taken in charge (processing started) \| \| `205` \| Approved \| \| `206` \| Partially approved \| \| `207` \| In dispute \| \| `208` \| Suspended \| \| `209` \| Completed \| \| `210` \| Refused \| \| `211` \| Payment sent \| \| `212` \| Collected (cashed) \| \| `213` \| Rejected \| \| `214` \| Validated or pre-validated ("Visée") \| \| `501` \| Inadmissible file \|. Example: `"200"`. Values: `200`, `201`, `202`, `203`, `204`, `205`, `206`, `207`, `208`, `209`, `210`, `211`, `212`, `213`, `214`, `501` | | [`statusDate`](#statusdate-any-of) | string (date-time) | string (date) | Yes | Date and time at which the status itself was set, without a timezone and with second precision. This is distinct from issueDate, which is the creation date and time of the CDAR message. Date-only values are accepted for incoming format-102 documents. Example: `"2024-03-20T14:05:09"` | | `invoiceId` | string | Yes | Number of the invoice this status relates to. For status 501, this is the filename of the inadmissible file | | `invoiceTypeCode` | string (enum) | No | Type of the referenced invoice. Type of the referenced invoice (UNTDID 1001, restricted to the values allowed by BR-FR-04). \| Value \| Meaning \| \| --- \| --- \| \| `380` \| Commercial invoice \| \| `389` \| Self-billed invoice \| \| `393` \| Factored invoice \| \| `501` \| Self-billed factored invoice \| \| `386` \| Advance payment invoice \| \| `500` \| Self-billed advance payment invoice \| \| `384` \| Corrective invoice \| \| `471` \| Self-billed corrective invoice \| \| `472` \| Factored corrective invoice \| \| `473` \| Self-billed factored corrective invoice \| \| `261` \| Self-billed credit note \| \| `262` \| Global rebate credit note \| \| `381` \| Credit note \| \| `396` \| Factored credit note \| \| `502` \| Self-billed factored credit note \| \| `503` \| Credit note for an advance payment invoice \|. Example: `"380"`. Values: `380`, `389`, `393`, `501`, `386`, `500`, `384`, `471`, `472`, `473`, `261`, `262`, `381`, `396`, `502`, `503` | | `invoiceIssueDate` | string (date) | No | Issue date of the referenced invoice. Required unless statusCode is 501. Example: `"2024-03-15"`. Format: date | | `sellerLegalId` | string | No | Legal identifier (e.g. SIREN) of the invoice seller. Required unless statusCode is 501. Example: `"123456789"` | | `sellerLegalIdScheme` | string | No | ISO 6523 ICD scheme of the referenced invoice seller legal identifier. Required together with sellerLegalId. Example: `"0002"` | | `reasonCode` | string (enum) | No | Coded reason for the invoice lifecycle status. \| Value \| Meaning \| \| --- \| --- \| \| `JUSTIF_ABS` \| Supporting document missing or insufficient \| \| `ROUTAGE_ERR` \| Routing error \| \| `AUTRE` \| Other reason; provide an explanation in `reasonNote` \| \| `COORD_BANC_ERR` \| Incorrect bank details \| \| `TX_TVA_ERR` \| Incorrect VAT rate \| \| `MONTANTTOTAL_ERR` \| Incorrect invoice total \| \| `CALCUL_ERR` \| Invoice calculation error \| \| `NON_CONFORME` \| Missing legal information \| \| `DOUBLON` \| Duplicate invoice \| \| `DEST_INC` \| Unknown recipient \| \| `DEST_ERR` \| Incorrect recipient \| \| `TRANSAC_INC` \| Unknown transaction \| \| `EMMET_INC` \| Unknown issuer \| \| `CONTRAT_TERM` \| Contract ended \| \| `DOUBLE_FACT` \| Supply or service already invoiced on another invoice \| \| `CMD_ERR` \| Incorrect or missing order number \| \| `ADR_ERR` \| Incorrect electronic invoicing address \| \| `SIRET_ERR` \| Incorrect or missing SIRET \| \| `CODE_ROUTAGE_ERR` \| Incorrect or missing routing code \| \| `REF_CT_ABSENT` \| Required contractual reference missing \| \| `REF_ERR` \| Incorrect reference \| \| `PU_ERR` \| Incorrect unit price \| \| `REM_ERR` \| Incorrect discount \| \| `QTE_ERR` \| Incorrect invoiced quantity \| \| `ART_ERR` \| Incorrect invoiced item \| \| `MODPAI_ERR` \| Incorrect payment terms \| \| `QUALITE_ERR` \| Incorrect quality of delivered item \| \| `LIVR_INCOMP` \| Incomplete or non-compliant delivery \| \| `REJ_SEMAN` \| Rejected because of a semantic error \| \| `REJ_UNI` \| Rejected by uniqueness control \| \| `REJ_COH` \| Rejected by data-consistency control \| \| `REJ_ADR` \| Rejected by addressing control \| \| `REJ_CONT_B2G` \| Rejected by B2G business controls \| \| `REJ_REF_PJ` \| Rejected because of an attachment-reference error \| \| `REJ_ASS_PJ` \| Rejected because of an attachment-association error \| \| `NON_TRANSMISE` \| Submitted but not transmitted because the recipient has no receiving platform \|. Values: `JUSTIF_ABS`, `ROUTAGE_ERR`, `AUTRE`, `COORD_BANC_ERR`, `TX_TVA_ERR`, `MONTANTTOTAL_ERR`, `CALCUL_ERR`, `NON_CONFORME`, `DOUBLON`, `DEST_INC`, `DEST_ERR`, `TRANSAC_INC`, `EMMET_INC`, `CONTRAT_TERM`, `DOUBLE_FACT`, `CMD_ERR`, `ADR_ERR`, `SIRET_ERR`, `CODE_ROUTAGE_ERR`, `REF_CT_ABSENT`, `REF_ERR`, `PU_ERR`, `REM_ERR`, `QTE_ERR`, `ART_ERR`, `MODPAI_ERR`, `QUALITE_ERR`, `LIVR_INCOMP`, `REJ_SEMAN`, `REJ_UNI`, `REJ_COH`, `REJ_ADR`, `REJ_CONT_B2G`, `REJ_REF_PJ`, `REJ_ASS_PJ`, `NON_TRANSMISE` | | `reason` | string | No | Optional free-text status reason. This is distinct from the IncludedNote explanation required for reasonCode AUTRE | | `reasonNote` | string | No | Free-text comment in the status detail IncludedNote. Required when reasonCode is AUTRE. Example: `"The invoice needs manual review."` | | [`collectedAmounts`](#collectedamounts-properties) | object[] | No | Collected amounts with VAT rates (TypeCode MEN). Required for status 212; at least one entry | ### `issueDate` (Any of) ### `statusDate` (Any of) ### `collectedAmounts` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `amount` | string | Yes | Net collected amount (positive) or disbursed amount (negative), for status 212. Example: `"12000.00"` | | `currency` | string (enum) | Yes | ISO 4217 currency code of the collected amount. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `vatPercent` | string | Yes | VAT rate applicable to the collected amount. Example: `"20.00"` | ## Used by - [List Documents](/reference/documents/get-documents) - [Get Document](/reference/documents/get-document) # French B2C reporting request (Model) ## One of ### French B2C sales report The normal daily report for sales to private individuals. It records the sale date, category, transaction count, amounts excluding VAT, and VAT totals. Submit it regardless of whether customers paid immediately or will pay later. This does not send invoices to consumers. The current integration supports taxable goods and taxable services only. A day, category and currency are reported once; use `action: correct` with a new reference to replace that report. | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"SALES-2026-07-01-GOODS"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `sales` to report transactions with private individuals. Send one sales report per day, category and currency, regardless of when customers pay. Value: `sales` | | `date` | string (date) | Yes | Day on which the reported sales took place. Example: `"2026-07-01"`. Format: date | | `category` | `goods` \| `services` | Yes | Whether this daily total covers taxable goods or taxable services. Use a separate report when both were sold on the same day. These are the two categories currently supported by this API. Example: `"goods"`. Values: `goods`, `services` | | `currency` | string (enum) | No | Three-letter currency code for the sales amounts excluding VAT. EUR is used when this field is omitted. French VAT amounts are always reported in EUR, including when this field uses another currency. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `taxExclusiveAmount` | string | Yes | Total sales amount excluding VAT for this day and category. Example: `"10000.00"` | | `taxAmount` | string | Yes | Total VAT amount for this day and category, expressed in EUR even when the sales currency is different. Example: `"2000.00"` | | `transactionCount` | integer | Yes | Number of individual sales included in this daily total. At least 1; a day without sales is not reported. Example: `42` | | `vatBreakdown` | object[] | Yes | Breakdown of the daily sales total by VAT rate. Include one entry for every VAT rate used. Min items: 1 | ### French B2C payment report An additional daily report for payments received for services using cash-basis VAT (`TVA sur les encaissements`), where VAT becomes due when the customer pays. Submit the sales report as usual, then submit this payment report for the day payment is received. Do not use this report for goods or for services where VAT becomes due when invoiced (`TVA sur les débits`); it is only accepted for companies registered with VAT due on payment. | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"SALES-2026-07-01-GOODS"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `payments` only to additionally report payments received for services using cash-basis VAT (`TVA sur les encaissements`). Value: `payments` | | `date` | string (date) | Yes | Day on which the reported payments were received. Example: `"2026-07-01"`. Format: date | | `currency` | string (enum) | No | Three-letter currency code of the received amounts. EUR is used when this field is omitted. One report covers one day in one currency. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `vatBreakdown` | object[] | Yes | Payments received, grouped by VAT rate. Amounts include VAT. Min items: 1 | ## Used by - [List Documents](/reference/documents/get-documents) - [Get Document](/reference/documents/get-document) - [Submit a French B2C report](/reference/reporting/submit-french-b2creport) # French B2C sales report (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"SALES-2026-07-01-GOODS"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `sales` to report transactions with private individuals. Send one sales report per day, category and currency, regardless of when customers pay. Value: `sales` | | `date` | string (date) | Yes | Day on which the reported sales took place. Example: `"2026-07-01"`. Format: date | | `category` | `goods` \| `services` | Yes | Whether this daily total covers taxable goods or taxable services. Use a separate report when both were sold on the same day. These are the two categories currently supported by this API. Example: `"goods"`. Values: `goods`, `services` | | `currency` | string (enum) | No | Three-letter currency code for the sales amounts excluding VAT. EUR is used when this field is omitted. French VAT amounts are always reported in EUR, including when this field uses another currency. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `taxExclusiveAmount` | string | Yes | Total sales amount excluding VAT for this day and category. Example: `"10000.00"` | | `taxAmount` | string | Yes | Total VAT amount for this day and category, expressed in EUR even when the sales currency is different. Example: `"2000.00"` | | `transactionCount` | integer | Yes | Number of individual sales included in this daily total. At least 1; a day without sales is not reported. Example: `42` | | [`vatBreakdown`](#vatbreakdown-properties) | object[] | Yes | Breakdown of the daily sales total by VAT rate. Include one entry for every VAT rate used. Min items: 1 | ### `vatBreakdown` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate applied to these sales. Example: `"20.00"` | | `taxableAmount` | string | Yes | Sales amount excluding VAT for this VAT rate, expressed in the report's sales currency. Example: `"10000.00"` | | `taxAmount` | string | Yes | VAT amount for this VAT rate, expressed in EUR even when the sales currency is different. Example: `"2000.00"` | # French B2CSales Vat Breakdown (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate applied to these sales. Example: `"20.00"` | | `taxableAmount` | string | Yes | Sales amount excluding VAT for this VAT rate, expressed in the report's sales currency. Example: `"10000.00"` | | `taxAmount` | string | Yes | VAT amount for this VAT rate, expressed in EUR even when the sales currency is different. Example: `"2000.00"` | # French B2C payment report (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"SALES-2026-07-01-GOODS"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `payments` only to additionally report payments received for services using cash-basis VAT (`TVA sur les encaissements`). Value: `payments` | | `date` | string (date) | Yes | Day on which the reported payments were received. Example: `"2026-07-01"`. Format: date | | `currency` | string (enum) | No | Three-letter currency code of the received amounts. EUR is used when this field is omitted. One report covers one day in one currency. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | [`vatBreakdown`](#vatbreakdown-properties) | object[] | Yes | Payments received, grouped by VAT rate. Amounts include VAT. Min items: 1 | ### `vatBreakdown` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate that applies to the received amount. Example: `"20.00"` | | `amount` | string | Yes | Amount received including VAT for this VAT rate, expressed in the report's currency. Example: `"12000.00"` | # French B2CPayment Vat Breakdown (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate that applies to the received amount. Example: `"20.00"` | | `amount` | string | Yes | Amount received including VAT for this VAT rate, expressed in the report's currency. Example: `"12000.00"` | # French cross-border reporting request (Model) ## One of ### French cross-border invoice report Reports one invoice or credit note issued to a business established outside France. These operations are not exchanged over the French e-invoicing network, so they are reported to the French tax administration instead. The reporting company must carry its own French VAT number as well as its SIREN; cross-border reports identify the seller by both. | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"EREPORT-INV-2026-000431"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `invoice` to report a single cross-border invoice or credit note issued to a business. Value: `invoice` | | `documentNumber` | string | Yes | The number of the invoice or credit note being reported. A payment report refers back to it, and a correction or cancellation is matched on it. Example: `"INV-2026-000431"` | | `documentType` | `invoice` \| `creditNote` | No | Whether the reported document is an invoice or a credit note. Defaults to `invoice`. Default: `invoice`. Example: `"invoice"`. Values: `invoice`, `creditNote` | | `issueDate` | string (date) | Yes | Date on which the document was issued. Example: `"2026-01-15"`. Format: date | | `dueDate` | string \| null | No | Date on which the amount is due, when the document names one. Example: `"2026-02-14"`. Format: date | | `currency` | string (enum) | No | Three-letter currency code of the reported amounts. EUR is used when this field is omitted. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `buyer` | object | Yes | The foreign business the reported operation was invoiced to | | `taxExclusiveAmount` | string | Yes | Total amount of the document excluding VAT. Example: `"10000.00"` | | `taxAmount` | string | Yes | Total VAT amount of the document. Example: `"0.00"` | | `vatBreakdown` | object[] | Yes | Breakdown of the document total by VAT rate. Include one entry for every VAT rate used. Min items: 1 | ### French cross-border payment report Reports a payment received on a cross-border invoice. Report the invoice first, then report the payment for the day it was received. Only accepted for companies registered with VAT due on payment. | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"EREPORT-INV-2026-000431"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `payment` to report a payment received on a cross-border invoice you reported earlier. Value: `payment` | | `invoiceNumber` | string | Yes | The `documentNumber` of the invoice report this payment belongs to. The invoice must have been reported before its payment can be. Example: `"INV-2026-000431"` | | `issueDate` | string (date) | Yes | Date on which the invoice was issued. Example: `"2026-01-15"`. Format: date | | `date` | string (date) | Yes | Date on which the payment was received. Example: `"2026-02-10"`. Format: date | | `currency` | string (enum) | No | Three-letter currency code of the received amounts. EUR is used when this field is omitted. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | `vatBreakdown` | object[] | Yes | Amounts received, grouped by VAT rate. Amounts include VAT. Min items: 1 | ## Used by - [List Documents](/reference/documents/get-documents) - [Get Document](/reference/documents/get-document) - [Submit a French cross-border report](/reference/reporting/submit-french-b2bi-report) # French cross-border invoice report (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"EREPORT-INV-2026-000431"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `invoice` to report a single cross-border invoice or credit note issued to a business. Value: `invoice` | | `documentNumber` | string | Yes | The number of the invoice or credit note being reported. A payment report refers back to it, and a correction or cancellation is matched on it. Example: `"INV-2026-000431"` | | `documentType` | `invoice` \| `creditNote` | No | Whether the reported document is an invoice or a credit note. Defaults to `invoice`. Default: `invoice`. Example: `"invoice"`. Values: `invoice`, `creditNote` | | `issueDate` | string (date) | Yes | Date on which the document was issued. Example: `"2026-01-15"`. Format: date | | `dueDate` | string \| null | No | Date on which the amount is due, when the document names one. Example: `"2026-02-14"`. Format: date | | `currency` | string (enum) | No | Three-letter currency code of the reported amounts. EUR is used when this field is omitted. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | [`buyer`](#buyer-properties) | object | Yes | The foreign business the reported operation was invoiced to | | `taxExclusiveAmount` | string | Yes | Total amount of the document excluding VAT. Example: `"10000.00"` | | `taxAmount` | string | Yes | Total VAT amount of the document. Example: `"0.00"` | | [`vatBreakdown`](#vatbreakdown-properties) | object[] | Yes | Breakdown of the document total by VAT rate. Include one entry for every VAT rate used. Min items: 1 | ### `buyer` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | The buyer's legal name. Example: `"Rossi Forniture S.r.l."` | | `country` | string | Yes | The country the buyer is established in, in ISO 3166-1:Alpha2 format. Must not be `FR`: invoices to French buyers are exchanged over the e-invoicing network instead of being reported. Example: `"IT"` | | `vatNumber` | string \| null | No | The buyer's intra-community VAT number. Required for buyers established in the European Union; it is how the tax administration identifies them. Leave it off for buyers outside the European Union, who are identified by their country and name instead. Example: `"IT00987654321"` | | `enterpriseNumber` | string \| null | No | The buyer's company registration number. Used for buyers in Nouvelle-Calédonie (RIDET) and Polynésie française (TAHITI); optional elsewhere. Example: `"0123456"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme the buyer's company registration number belongs to. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0223"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | ### `vatBreakdown` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate applied to this part of the invoice. Example: `"0.00"` | | `taxableAmount` | string | Yes | Amount excluding VAT taxed at this rate. Example: `"10000.00"` | | `taxAmount` | string | Yes | VAT amount for this rate. Example: `"0.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code for this rate. Cross-border operations are typically exempt or reverse charged rather than taxed. Example: `"K"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `exemptionReason` | string \| null | No | Why no VAT is charged. Required, together with or instead of `exemptionReasonCode`, whenever the VAT category is an exempt one. Example: `"Intra-Community supply"` | | `exemptionReasonCode` | string \| null | No | The exemption reason code, from the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/). Example: `"VATEX-EU-IC"` | # French B2Bi Buyer (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `name` | string | Yes | The buyer's legal name. Example: `"Rossi Forniture S.r.l."` | | `country` | string | Yes | The country the buyer is established in, in ISO 3166-1:Alpha2 format. Must not be `FR`: invoices to French buyers are exchanged over the e-invoicing network instead of being reported. Example: `"IT"` | | `vatNumber` | string \| null | No | The buyer's intra-community VAT number. Required for buyers established in the European Union; it is how the tax administration identifies them. Leave it off for buyers outside the European Union, who are identified by their country and name instead. Example: `"IT00987654321"` | | `enterpriseNumber` | string \| null | No | The buyer's company registration number. Used for buyers in Nouvelle-Calédonie (RIDET) and Polynésie française (TAHITI); optional elsewhere. Example: `"0123456"` | | `enterpriseNumberScheme` | string (enum) | No | The scheme the buyer's company registration number belongs to. Schemes can be found [here](https://docs.peppol.eu/poacc/billing/3.0/codelist/ICD/). Example: `"0223"`. Values: `0002`, `0003`, `0004`, `0005`, `0006`, `0007`, `0008`, `0009`, `0010`, `0011`, `0012`, `0013`, `0014`, `0015`, `0016`, `0017`, `0018`, `0019`, `0020`, `0021`, `0022`, `0023`, `0024`, `0025`, `0026`, `0027`, `0028`, `0029`, `0030`, `0031`, `0032`, `0033`, `0034`, `0035`, `0036`, `0037`, `0038`, `0039`, `0040`, `0041`, `0042`, `0043`, `0044`, `0045`, `0046`, `0047`, `0048`, `0049`, `0050`, `0051`, `0052`, `0053`, `0054`, `0055`, `0056`, `0057`, `0058`, `0059`, `0060`, `0061`, `0062`, `0063`, `0064`, `0065`, `0066`, `0067`, `0068`, `0069`, `0070`, `0071`, `0072`, `0073`, `0074`, `0075`, `0076`, `0077`, `0078`, `0079`, `0080`, `0081`, `0082`, `0083`, `0084`, `0085`, `0086`, `0087`, `0088`, `0089`, `0090`, `0091`, `0093`, `0094`, `0095`, `0096`, `0097`, `0098`, `0099`, `0100`, `0101`, `0102`, `0104`, `0105`, `0106`, `0107`, `0108`, `0109`, `0110`, `0111`, `0112`, `0113`, `0114`, `0115`, `0116`, `0117`, `0118`, `0119`, `0120`, `0121`, `0122`, `0123`, `0124`, `0125`, `0126`, `0127`, `0128`, `0129`, `0130`, `0131`, `0132`, `0133`, `0134`, `0135`, `0136`, `0137`, `0138`, `0139`, `0140`, `0141`, `0142`, `0143`, `0144`, `0145`, `0146`, `0147`, `0148`, `0149`, `0150`, `0151`, `0152`, `0153`, `0154`, `0155`, `0156`, `0157`, `0158`, `0159`, `0160`, `0161`, `0162`, `0163`, `0164`, `0165`, `0166`, `0167`, `0168`, `0169`, `0170`, `0171`, `0172`, `0173`, `0174`, `0175`, `0176`, `0177`, `0178`, `0179`, `0180`, `0183`, `0184`, `0185`, `0186`, `0187`, `0188`, `0189`, `0190`, `0191`, `0192`, `0193`, `0194`, `0195`, `0196`, `0197`, `0198`, `0199`, `0200`, `0201`, `0202`, `0203`, `0204`, `0205`, `0206`, `0207`, `0208`, `0209`, `0210`, `0211`, `0212`, `0213`, `0214`, `0215`, `0216`, `0217`, `0218`, `0219`, `0220`, `0221`, `0222`, `0223`, `0224`, `0225`, `0226`, `0227`, `0228`, `0229`, `0230`, `0231`, `0232`, `0233`, `0234`, `0235`, `0236`, `0237`, `0238`, `0239`, `0240`, `null` | # French B2Bi Invoice Vat Breakdown (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate applied to this part of the invoice. Example: `"0.00"` | | `taxableAmount` | string | Yes | Amount excluding VAT taxed at this rate. Example: `"10000.00"` | | `taxAmount` | string | Yes | VAT amount for this rate. Example: `"0.00"` | | `category` | `AE` \| `E` \| `S` \| `Z` \| `G` \| `O` \| `K` \| `L` \| `M` \| `B` | Yes | VAT category code for this rate. Cross-border operations are typically exempt or reverse charged rather than taxed. Example: `"K"`. Values: `AE`, `E`, `S`, `Z`, `G`, `O`, `K`, `L`, `M`, `B` | | `exemptionReason` | string \| null | No | Why no VAT is charged. Required, together with or instead of `exemptionReasonCode`, whenever the VAT category is an exempt one. Example: `"Intra-Community supply"` | | `exemptionReasonCode` | string \| null | No | The exemption reason code, from the CEF VATEX code list found [here](https://docs.peppol.eu/poacc/billing/3.0/2024-Q4/codelist/vatex/). Example: `"VATEX-EU-IC"` | # French cross-border payment report (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reference` | string | Yes | Your unique reference for this submission, at most 128 characters. It is the idempotency key: retrying the exact same request with the same reference files nothing again and returns the report filed the first time, with `duplicate: true`. Every new submission, corrections and cancellations included, needs its own reference. Example: `"EREPORT-INV-2026-000431"` | | `action` | `submit` \| `correct` \| `cancel` | No | Use `submit` for a new report, `correct` to replace a report you filed earlier for the same period or document, or `cancel` to cancel it. Corrections and cancellations are matched on the data that identifies the report (for example the day and category of a daily total, or the document number of an invoice), and always need a new `reference`. Defaults to `submit`. Default: `submit`. Example: `"submit"`. Values: `submit`, `correct`, `cancel` | | `type` | string | Yes | Choose `payment` to report a payment received on a cross-border invoice you reported earlier. Value: `payment` | | `invoiceNumber` | string | Yes | The `documentNumber` of the invoice report this payment belongs to. The invoice must have been reported before its payment can be. Example: `"INV-2026-000431"` | | `issueDate` | string (date) | Yes | Date on which the invoice was issued. Example: `"2026-01-15"`. Format: date | | `date` | string (date) | Yes | Date on which the payment was received. Example: `"2026-02-10"`. Format: date | | `currency` | string (enum) | No | Three-letter currency code of the received amounts. EUR is used when this field is omitted. Default: `EUR`. Example: `"EUR"`. Values: `XUA`, `AFN`, `DZD`, `ARS`, `AMD`, `AWG`, `AUD`, `AZN`, `BSD`, `BHD`, `THB`, `PAB`, `BBD`, `BYN`, `BZD`, `BMD`, `VES`, `VED`, `BOB`, `XBA`, `XBB`, `XBD`, `XBC`, `BRL`, `BND`, `BGN`, `BIF`, `CVE`, `CAD`, `KYD`, `XOF`, `XAF`, `XPF`, `CLP`, `XTS`, `COP`, `KMF`, `CDF`, `BAM`, `NIO`, `CRC`, `CUP`, `CZK`, `GMD`, `DKK`, `MKD`, `DJF`, `STN`, `DOP`, `VND`, `XCD`, `EGP`, `SVC`, `ETB`, `EUR`, `FKP`, `FJD`, `HUF`, `GHS`, `GIP`, `XAU`, `HTG`, `PYG`, `GNF`, `GYD`, `HKD`, `UAH`, `ISK`, `INR`, `IRR`, `IQD`, `JMD`, `JOD`, `KES`, `PGK`, `KWD`, `AOA`, `MMK`, `LAK`, `GEL`, `LBP`, `ALL`, `HNL`, `LRD`, `LYD`, `SZL`, `LSL`, `MGA`, `MWK`, `MYR`, `MUR`, `MXN`, `MXV`, `MDL`, `MAD`, `MZN`, `BOV`, `NGN`, `ERN`, `NAD`, `NPR`, `ANG`, `ILS`, `TWD`, `NZD`, `BTN`, `KPW`, `NOK`, `MRU`, `TOP`, `PKR`, `XPD`, `MOP`, `UYU`, `PHP`, `XPT`, `GBP`, `BWP`, `QAR`, `GTQ`, `ZAR`, `OMR`, `KHR`, `RON`, `MVR`, `IDR`, `RUB`, `RWF`, `SHP`, `SAR`, `XDR`, `RSD`, `SCR`, `SLE`, `XAG`, `SGD`, `PEN`, `SBD`, `KGS`, `SOS`, `TJS`, `SSP`, `LKR`, `XSU`, `SDG`, `SRD`, `SEK`, `CHF`, `SYP`, `BDT`, `WST`, `TZS`, `KZT`, `XXX`, `TTD`, `MNT`, `TND`, `TRY`, `TMT`, `AED`, `UGX`, `CLF`, `COU`, `UYW`, `UYI`, `USD`, `USN`, `UZS`, `VUV`, `CHE`, `CHW`, `KRW`, `YER`, `JPY`, `CNY`, `ZMW`, `ZWG`, `PLN` | | [`vatBreakdown`](#vatbreakdown-properties) | object[] | Yes | Amounts received, grouped by VAT rate. Amounts include VAT. Min items: 1 | ### `vatBreakdown` properties | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate that applies to the received amount. Example: `"20.00"` | | `amount` | string | Yes | Amount received including VAT for this VAT rate. Example: `"12000.00"` | # French B2Bi Payment Vat Breakdown (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `percentage` | string | Yes | VAT rate that applies to the received amount. Example: `"20.00"` | | `amount` | string | Yes | Amount received including VAT for this VAT rate. Example: `"12000.00"` | # French Reporting Status (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `reportingStatus` | `accepted` \| `pending_rectificative` \| `filed` \| `filed_rectificative` \| `superseded` \| `rejected` | Yes | `accepted`: on file, inside its reporting period. `pending_rectificative`: arrived after the period was filed and will be carried by a corrective filing. `filed` / `filed_rectificative`: reported to the tax administration. `superseded`: replaced by a correction or cancelled. `rejected`: refused by the tax administration; see `outcomeCode`. Values: `accepted`, `pending_rectificative`, `filed`, `filed_rectificative`, `superseded`, `rejected` | | `receivedAt` | string \| null | Yes | When the report reached the reporting service | | `periodStart` | string \| null | Yes | First day of the reporting period the report belongs to | | `periodEnd` | string \| null | Yes | Last day of the reporting period; the cutoff for on-time filing | | `submissionId` | string \| null | Yes | The period filing the report was carried on, once assembled | | `outcomeCode` | string \| null | Yes | The tax administration's outcome code, once known | | `outcomeAt` | string \| null | Yes | When the tax administration returned its outcome | | `checkedAt` | string \| null | Yes | When the status was last refreshed from the reporting service | | `simulated` | boolean | Yes | True for playground and test-network reports, which are recorded but never filed | ## Used by - [List Documents](/reference/documents/get-documents) - [Get Document](/reference/documents/get-document) # French e-reporting registration (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `environment` | `PROD` \| `TEST` | Yes | The reporting environment this registration belongs to. Teams on the test network are registered in `TEST`, all other teams in `PROD`. Values: `PROD`, `TEST` | | `siren` | string | Yes | The SIREN the company reports under, derived from its enterprise number. Example: `"123456789"` | | `issuerName` | string | Yes | The legal name carried as the issuer on every report filed for the company | | `vatRegime` | `REEL_NORMAL_MENSUEL` \| `REEL_SIMPLIFIE` \| `FRANCHISE_EN_BASE` | Yes | The company's French VAT regime. It determines how often its reports are filed with the tax administration. Values: `REEL_NORMAL_MENSUEL`, `REEL_SIMPLIFIE`, `FRANCHISE_EN_BASE` | | `vatExigibility` | `ENCAISSEMENTS` \| `DEBITS` | Yes | When VAT becomes due for the company. Payment reports are only accepted under `ENCAISSEMENTS`; under `DEBITS` they are out of scope. Values: `ENCAISSEMENTS`, `DEBITS` | | `enabled` | boolean | Yes | Whether reports are currently accepted. A suspended registration keeps its registered state but refuses reports with a 400 until support re-enables it | | `state` | `pending` \| `registered` \| `blocked` | Yes | `pending` while the registration is being completed, `registered` once reports can be submitted, `blocked` when the registration needs support. Values: `pending`, `registered`, `blocked` | | `simulated` | boolean | Yes | True for playground and test-network teams, whose registration and reports are simulated instead of filed | | `lastError` | string \| null | Yes | The reason the last registration attempt failed, if any | | `registeredAt` | string \| null | Yes | When the registration was accepted. The company's reporting periods run from this moment. Null while the state is still `pending` | | `createdAt` | string | Yes | When the registration was first requested | | `updatedAt` | string | Yes | When the registration last changed, including a background retry of a `pending` registration | ## Used by - [Get the French e-reporting registration](/reference/reporting/get-french-reporting-declarant) - [Register a company for French e-reporting](/reference/reporting/register-french-reporting-declarant) # Register French Reporting Declarant (Model) ## Properties | Name | Type | Required | Description | |------|------|----------|-------------| | `vatRegime` | `REEL_NORMAL_MENSUEL` \| `REEL_SIMPLIFIE` \| `FRANCHISE_EN_BASE` | Yes | The company's French VAT regime: `REEL_NORMAL_MENSUEL` (régime réel normal), `REEL_SIMPLIFIE` (régime réel simplifié) or `FRANCHISE_EN_BASE` (franchise en base de TVA). Changing it after registration can leave the current reporting period unfiled; contact support before changing it. Example: `"REEL_NORMAL_MENSUEL"`. Values: `REEL_NORMAL_MENSUEL`, `REEL_SIMPLIFIE`, `FRANCHISE_EN_BASE` | | `vatExigibility` | `ENCAISSEMENTS` \| `DEBITS` | Yes | When VAT becomes due: `ENCAISSEMENTS` (on payment, typical for services) or `DEBITS` (on invoicing, typical for goods). Payment reports can only be submitted under `ENCAISSEMENTS`. Example: `"DEBITS"`. Values: `ENCAISSEMENTS`, `DEBITS` | ## Used by - [Register a company for French e-reporting](/reference/reporting/register-french-reporting-declarant)