SDI (FatturaPA)
The SDI (Sistema di Interscambio) is Italy’s mandatory e-invoicing platform, run by the Agenzia delle Entrate. All invoices between Italian operators —B2B, B2C and B2G— must be issued and received through the SDI in FatturaPA format (the Italian national structured XML format).
B2Brouter’s REST API generates the FatturaPA XML, transmits it to the SDI and retrieves the acknowledgements, so your integration can focus on business logic.
What is the SDI?
Section titled “What is the SDI?”The SDI is the central hub every Italian electronic invoice passes through. In practice:
- Invoices are issued in FatturaPA 1.2 format (
xml.fatturapa.1.2), an Italian XML format. - The SDI validates the document against the official schema (XSD) and delivers it to the recipient.
- Each accepted invoice receives a registration identifier (IdentificativoSdI).
- If the recipient cannot receive the document electronically, the SDI makes it available in their cassetto fiscale.
E-invoicing has been mandatory for all Italian companies since January 2019.
Recipient identification
Section titled “Recipient identification”To route an invoice, the SDI needs to know where to deliver it. There are several ways, and it is important not to confuse them:
| Concept | Field in B2Brouter | What it is |
|---|---|---|
| Codice Destinatario | recipient_code | Routing code assigned by the SDI to the recipient. 7 characters for private companies, 6 for public administrations (Codice Ufficio). |
| PEC (Posta Elettronica Certificata) | certified_email | Certified email, an alternative to the Codice Destinatario when the recipient does not have one. |
| Codice Fiscale / Partita IVA | cin_value / tin_value | The recipient’s tax identifier (not a routing code). |
| CUP / CIG | file_reference (CUP) / lot_reference (CIG) | Project and tender codes required in certain operations with the public sector; they do not route the invoice. |
To receive invoices in B2Brouter through the SDI, your supplier must use B2Brouter’s Codice Destinatario: EPKDZJB (after registering your company with the Agenzia delle Entrate).
B2B, B2C and B2G
Section titled “B2B, B2C and B2G”The technical flow is the same in all three cases; what changes is the recipient’s identification:
- B2B (company): identified by the Partita IVA (
tin_scheme: 9906). Therecipient_codeis 7 characters (or0000000if the customer does not have one). - B2C (private consumer): identified by the Codice Fiscale (
cin_scheme: 9907). They usually have no Codice Destinatario, so0000000is used and the SDI makes the invoice available in the citizen’s cassetto fiscale. On exempt invoices the bollo may apply. - B2G (public administration): identified by the Codice Ufficio, 6 characters. Mark the contact as
public_sector: trueand set the 6-character code inrecipient_code. With the public sector, split payment often applies (see Esigibilità IVA and split payment).
B2Brouter validates the code length (7 private / 6 public sector) at send time.
Before you start
Section titled “Before you start”- An Italian company with a valid Partita IVA and a complete address (validated at send time, not when the account is created).
- A B2Brouter test account: Register here.
- API permissions (request them by opening a support ticket).
Start with the sandbox for your first payload tests. Move to staging (
api-staging.b2brouter.net) when you want to test the full submission to the SDI test environment.
Enabling the SDI
Section titled “Enabling the SDI”For an account to issue to the SDI, it must be enabled with a tax report setting for the sdi authority. See the Tax Report Settings Guide for the general details.
curl --request POST \ --url https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/tax_report_settings \ --header 'X-B2B-API-Key: {YOUR_API_KEY}' \ --header 'X-B2B-API-Version: {YOUR_API_VERSION}' \ --header 'content-type: application/json' \ --data '{ "tax_report_setting": { "code": "sdi" } }'Response:
{ "tax_report_setting": { "code": "sdi", "start_date": null, "auto_generate": true, "auto_send": true, "enabled": true, "locked": false }}On creation, B2Brouter enables enabled, auto_generate and auto_send by default, so FatturaPA invoices are generated and sent to the SDI automatically.
Create the Italian company
Section titled “Create the Italian company”curl --request POST \ --url https://api-staging.b2brouter.net/accounts \ --header 'X-B2B-API-Key: {YOUR_API_KEY}' \ --header 'X-B2B-API-Version: {YOUR_API_VERSION}' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "account": { "country": "it", "rounding_method": "half_up", "tin_value": "20339260422", "tin_scheme": 211, "name": "Test Sender Italy", "address": "Milano street, 1", "city": "Milano", "postalcode": "20019", "province": "MI", "email": "john.doe@example.com", "tax_regime": "RF01" } }'The tax_regime field states the issuer’s tax regime (see Regime fiscale); if omitted, RF01 (ordinary) is applied.
Create the customer contact
Section titled “Create the customer contact”When you create an Italian customer:
- Use
tin_valuefor the Partita IVA withtin_scheme: 9906. - Use
cin_valuefor the Codice Fiscale withcin_scheme: 9907(scheme list). One of the two identifiers is enough. - The contact’s address and postal code are required to send to the SDI.
transport_type_codemust beit.sdi.document_type_codemust bexml.fatturapa.1.2.- If the contact has a Codice Destinatario, set it in
recipient_code(7 chars private / 6 public sector). If not,0000000is used. Optionally, set the buyer’s PEC incertified_email.
curl --request POST \ --url https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/contacts \ --header 'X-B2B-API-Key: {YOUR_API_KEY}' \ --header 'X-B2B-API-Version: {YOUR_API_VERSION}' \ --header 'accept: application/json' \ --header 'content-type: application/json' \ --data '{ "contact": { "tin_scheme": "9906", "tin_value": "IT12345678901", "name": "Esempio S.r.l.", "address": "Via Inventata 88", "postalcode": "00184", "city": "Roma", "province": "RM", "country": "it", "transport_type_code": "it.sdi", "document_type_code": "xml.fatturapa.1.2", "recipient_code": "{CODICE_DESTINATARIO}" } }'Create and send an invoice
Section titled “Create and send an invoice”curl --request POST \ --url https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/invoices \ --header 'X-B2B-API-Key: {YOUR_API_KEY}' \ --header 'X-B2B-API-Version: {YOUR_API_VERSION}' \ --header 'content-type: application/json' \ --data '{ "send_after_import": true, "invoice": { "type": "IssuedInvoice", "invoice_lines_attributes": [ { "quantity": 10, "price": 47, "description": "Test Item", "taxes_attributes": [ { "name": "IVA", "percent": 22 } ] } ], "number": "1", "date": "2025-01-22", "due_date": "2025-02-22", "contact_id": {YOUR_CONTACT_ID} } }'Notes:
- The invoice number can be at most 20 characters.
- Each line must have a description and at least one tax.
due_dateis optional for theit.sditransport.
Additional fields for Italian invoices
Section titled “Additional fields for Italian invoices”type_document(on the invoice): sets the FatturaPATipoDocumento. Optional; if omitted, B2Brouter assigns it automatically. See Document type.receipt_reference(on each line, not on the invoice): reference to a receipt/scontrino linked to the line, with the fieldsidentifier,numberanddate. Optional, FatturaPA only:
"invoice_lines_attributes": [ { "quantity": 1, "price": 47, "description": "Test Item", "taxes_attributes": [{ "name": "IVA", "percent": 22 }], "receipt_reference": { "identifier": "SCONTRINO-001", "number": "42", "date": "2025-01-20" } }]Document type (TipoDocumento)
Section titled “Document type (TipoDocumento)”The TipoDocumento (type_document) classifies the invoice (fattura, nota di credito, autofattura…). B2Brouter assigns it automatically based on the invoice type and content, but you can force it with a valid code (TD01–TD06, TD16–TD27).
Behavior:
- If you do not set
type_document, it is assigned automatically:TD01by default,TD04for credit notes/amendments,TD16when there are taxes with NaturaN6, andTD17/TD18/TD19for self-invoices (see Autofattura). - If you set it with a valid code, it is emitted as-is. If the value is not valid, it is ignored and the automatic assignment applies (no error is raised).
To see how each JSON field maps to the FatturaPA XML nodes, use the invoice field mapper.
VAT nature codes (Natura)
Section titled “VAT nature codes (Natura)”When an operation carries no VAT (exempt, non-taxable, reverse charge…), FatturaPA does not use a percentage but a Natura code (N1–N7). In B2Brouter it is set in category inside taxes_attributes, with percent: 0:
"taxes_attributes": [ { "name": "IVA", "percent": 0, "category": "N2.1" }]| Code | Meaning |
|---|---|
N1 | Excluded pursuant to art. 15 |
N2.1 / N2.2 | Not subject (art. 7-bis and others) |
N3.1–N3.6 | Non-taxable (exports, intra-EU supplies, San Marino…) |
N4 | Exempt |
N5 | Margin scheme / VAT not shown |
N6.1–N6.9 | Reverse charge (inversione contabile) — see Autofattura |
N7 | VAT chargeable in another EU state |
B2Brouter fills in the reason associated with each Natura code automatically; you only need to set the category.
Regime fiscale
Section titled “Regime fiscale”The issuer’s tax regime is set in the account’s tax_regime field. The default is RF01 (ordinary). Accepted values:
| Code | Regime | Code | Regime | |
|---|---|---|---|---|
RF01 | Ordinario | RF12 | Agriturismo | |
RF02 | Contribuenti minimi | RF13 | Vendite a domicilio | |
RF04 | Agricoltura e pesca | RF14 | Rivendita beni usati / oggetti d’arte | |
RF05 | Vendita sali e tabacchi | RF15 | Agenzie di vendite all’asta | |
RF06 | Commercio fiammiferi | RF16 | IVA per cassa P.A. | |
RF07 | Editoria | RF17 | IVA per cassa | |
RF08 | Servizi telefonia pubblica | RF18 | Altro | |
RF09 | Documenti di trasporto/sosta | RF19 | Regime forfettario | |
RF10 | Intrattenimenti e giochi | |||
RF11 | Agenzie viaggi e turismo |
Modalità di pagamento
Section titled “Modalità di pagamento”The payment method is set with the payment_method field (on the contact or the invoice) and B2Brouter maps it to the FatturaPA ModalitaPagamento code (MPxx). See the Payment Method Guide for the payment_method values.
Most common mappings:
MP FatturaPA | Payment method |
|---|---|
MP01 | Cash (contanti) |
MP02 | Cheque (assegno) |
MP05 | Bank transfer (bonifico) |
MP06 | Promissory note (vaglia cambiario) |
MP08 | Credit/debit card |
Esigibilità IVA and split payment
Section titled “Esigibilità IVA and split payment”Esigibilità indicates when the VAT becomes due. It is set in the vat_payability field of the contact (default I):
| Value | Meaning |
|---|---|
I | Immediate (default) |
D | Deferred (esigibilità differita) |
S | Split payment (scissione dei pagamenti) |
The value S (split payment) typically applies to invoices to the public sector: the buyer pays the VAT directly to the tax authority, so B2Brouter deducts it from the amount due (the subtotal and the VAT are shown, but the payable_amount does not include the VAT).
Ritenuta d’acconto
Section titled “Ritenuta d’acconto”For professionals subject to withholding (ritenuta d’acconto), set amounts_withheld_reason (the payment reason) and the withheld amount on the invoice. B2Brouter deducts the amount from the amount due and generates the DatiRitenuta block in the XML.
There are two ways to state the amount:
amounts_withheld: the exact amount to withhold. Recommended when the withholding base is not the total (for example, only the taxable base).withheld_percent: a percentage that B2Brouter applies to the invoice total (VAT included). Note: if you expect the withholding on the taxable base, useamounts_withheld.
{ "invoice": { "type": "IssuedInvoice", "withheld_percent": 20, "amounts_withheld_reason": "A", "...": "..." }}With the example above on a base with VAT, the response returns the computed amounts_withheld and the payable_amount reduced by that amount.
The bollo (imposta di bollo) is a €2.00 stamp duty required on VAT-free invoices exceeding €77.47.
B2Brouter applies it automatically when all of these conditions are met:
- The company has the bollo option enabled (
apply_stamp_duty), which is configured on the company (not through this API). - The issuer is Italian and the total exceeds €77.47.
- There is at least one tax with an applicable exemption Natura:
N2.1,N2.2,N3.5,N3.6orN4. - The document is not an integration/self-invoice (
TD16–TD19).
When it applies, the XML includes <DatiBollo> with BolloVirtuale: SI and ImportoBollo: 2.00. You can also add it manually as a line with the description “bollo”, price 2 and tax N1 at 0%.
Credit and debit notes
Section titled “Credit and debit notes”To correct an invoice that has already been issued:
- Nota di credito (credit note): create the invoice with
is_credit_note: true. B2Brouter assignsTD04automatically. - Nota di debito (debit note): set
type_document: "TD05".
To link the original invoice (so the SDI relates the documents), add a reference with invoice_references of type amend, or set amended_invoice_number and amended_invoice_date.
Receiving invoices
Section titled “Receiving invoices”Your suppliers’ invoices can reach B2Brouter through different reception channels:
- SDI: register B2Brouter’s Codice Destinatario (
EPKDZJB) with the Agenzia delle Entrate; Italian suppliers issue towards this code. - Peppol or email: enable the corresponding reception transport on the account to receive international suppliers that issue through those channels.
Whatever the channel, the invoice enters as a received invoice (ReceivedInvoice). To query them: GET /accounts/{id}/received_invoices (list) and GET /received_invoices/{id} (get).
When the supplier has not gone through the SDI (typically a foreign supplier), the purchase must be declared to the SDI as an autofattura. If you have a reception transport enabled, B2Brouter does it automatically when the invoice arrives; if you receive them in other software, you register them yourself (via the API) and they are integrated all the same. See the next section.
Autofattura and reverse charge
Section titled “Autofattura and reverse charge”When you buy from a foreign supplier (or in internal reverse charge operations), Italian law requires you to self-invoice: declare the operation to the SDI on your own behalf.
In B2Brouter, the autofattura is not created as a separate document: it is generated automatically from the received invoice. The flow is:
- Make sure the account has the SDI enabled (with
auto_generate, which is the default). - Get the supplier’s invoice into the account as a received invoice: if you have a reception transport (Peppol/email) enabled, it arrives on its own; if you receive it in other software, register it via the API with
POST /accounts/{id}/invoicesandtype: "ReceivedInvoice". Set thetype_operation(servicesorgoods) and the appropriate VAT Natura (e.g.N6.xfor reverse charge); the supplier goes inside thecontactobject. - On creation, B2Brouter automatically generates an integration tax report (the autofattura), exports it in FatturaPA format and, if the SDI has
auto_send, sends it. You can query it with the tax reports endpoint.
curl --request POST \ --url https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/invoices \ --header 'X-B2B-API-Key: {YOUR_API_KEY}' \ --header 'X-B2B-API-Version: {YOUR_API_VERSION}' \ --header 'content-type: application/json' \ --data '{ "invoice": { "type": "ReceivedInvoice", "number": "RIC-001", "date": "2026-07-22", "type_operation": "services", "contact": { "tin_scheme": "9930", "tin_value": "DE137869841", "name": "Fornitore Estero GmbH", "address": "Berlin str 1", "postalcode": "10115", "city": "Berlin", "country": "de" }, "invoice_lines_attributes": [ { "quantity": 1, "price": 500, "description": "Consulenza estera", "taxes_attributes": [{ "name": "IVA", "percent": 0, "category": "N6.9" }] } ] } }'The integration’s TipoDocumento is computed automatically:
| Situation | Code |
|---|---|
Internal reverse charge (taxes with Natura N6) | TD16 |
| Purchase of services from a non-resident supplier | TD17 |
| Intra-EU purchase of goods | TD18 |
| Purchase of goods from an extra-EU supplier | TD19 |
B2Brouter automatically fills in the DatiFattureCollegate block (reference to the received invoice) and marks the document as a self-invoice (SoggettoEmittente: CC).
Fattura Semplificata
Section titled “Fattura Semplificata”The Fattura Elettronica Semplificata (art. 21-bis of DPR 633/72) is a reduced XML format for low-value transactions: the total cannot exceed €400. It is legally equivalent to an ordinary invoice, but uses its own structure (FatturaElettronicaSemplificata, version FSM10) with fewer required fields —for example, it does not export payment data—. Like any Italian invoice, it must be submitted to the SDI.
In B2Brouter it is created as an IssuedInvoice with the document type xml.fattura.semplificata.1.0.2 (on the invoice or the contact).
Validation rules
Section titled “Validation rules”| Requirement | Value |
|---|---|
| Maximum invoice total | €400 |
| Buyer’s tax identifier | Codice Fiscale or Partita IVA (one of the two required) |
| Buyer’s address and postal code | Required |
| VAT per line | Exactly one tax per line |
| Global discounts or charges | Not allowed (use line-level discounts) |
Create a simplified invoice
Section titled “Create a simplified invoice”curl --request POST \ --url https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/invoices \ --header 'X-B2B-API-Key: {YOUR_API_KEY}' \ --header 'X-B2B-API-Version: {YOUR_API_VERSION}' \ --header 'content-type: application/json' \ --data '{ "send_after_import": true, "invoice": { "type": "IssuedInvoice", "document_type_code": "xml.fattura.semplificata.1.0.2", "number": "S-2025-001", "date": "2025-09-10", "contact_id": 123456789, "invoice_lines_attributes": [ { "quantity": 2, "price": 50.00, "description": "Servizi di consulenza", "taxes_attributes": [{ "name": "IVA", "percent": 22 }] } ] } }'Document type (TipoDocumento)
Section titled “Document type (TipoDocumento)”For the simplified format, B2Brouter assigns the TipoDocumento automatically; do not set type_document:
TD07— Fattura Semplificata (default).TD08— Nota di Credito Semplificata (whenis_credit_note: trueor an amendment).
If you set a valid code from the ordinary FatturaPA (TD01–TD06, TD16–TD27), it will be emitted as-is inside the simplified XML and the SDI will reject it (XSD error), because the simplified format only accepts TD07, TD08 and TD09. TD09 (Nota di Debito Semplificata) is not currently supported.
Checking the invoice status
Section titled “Checking the invoice status”With send_after_import: true, the invoice is sent to the SDI through the it.sdi transport and goes through sending → sent. If the SDI (or the recipient) rejects it, it moves to error with the reason. When the SDI returns the registration identifier (IdentificativoSdI), it becomes available in to_net_id.
Option 1: query a single invoice
Section titled “Option 1: query a single invoice”curl --request GET \ --url 'https://api-staging.b2brouter.net/invoices/{INVOICE_ID}?include=lines' \ --header 'X-B2B-API-Key: {YOUR_API_KEY}' \ --header 'X-B2B-API-Version: {YOUR_API_VERSION}' \ --header 'accept: application/json'Option 2: query several invoices
Section titled “Option 2: query several invoices”curl --request GET \ --url 'https://api-staging.b2brouter.net/accounts/{ACCOUNT_ID}/invoices?offset=0&limit=25' \ --header 'X-B2B-API-Key: {YOUR_API_KEY}' \ --header 'X-B2B-API-Version: {YOUR_API_VERSION}' \ --header 'accept: application/json'When the invoice reaches its final state, mark it as acknowledged to remove it from the active list:
curl --request POST \ --url https://api-staging.b2brouter.net/invoices/{INVOICE_ID}/ack \ --header 'X-B2B-API-Key: {YOUR_API_KEY}' \ --header 'X-B2B-API-Version: {YOUR_API_VERSION}' \ --header 'accept: application/json'Additional resources
Section titled “Additional resources”B2Brouter
Official documentation (Agenzia delle Entrate)