Italian e-invoicing: the SdI notifications that decide whether an invoice exists
The moment you press send is not the moment the invoice exists. It exists when the Italian exchange system answers — and it answers in five different ways, four of which require you to do something.
The lifecycle does not end at send
Anyone integrating Italian e-invoicing for the first time models two states: to send, and sent. That is the wrong model, because the exchange system answers every transmission with a notification, and those notifications are the invoice's real state.
There are five, and it is worth learning them by their abbreviations, because that is how the arriving XML names them:
- RC — delivery receipt. Delivered to the recipient. The outcome you wanted.
- NS — rejection. For the tax authority, this invoice never existed.
- MC — failed delivery. Valid but undelivered; made available in the recipient's reserved area.
- NE — outcome notification. Public-sector invoices only: the customer accepted (EC01) or rejected (EC02).
- DT — deadline elapsed. The customer did not respond in time, and the invoice stands.
One implementation detail that costs people days: the outcome of an NE is not in the file name or the root element. It is inside the notification body. Read only the root and you see "outcome notification" without knowing whether the invoice was accepted or refused — two lines of code apart, and opposite meanings.

Rejection and failed delivery look alike and need opposite handling
Both arrive as "the invoice is not with the recipient", which is where the most common mistake begins.
A rejection requires a correction and a new transmission. A failed delivery requires nothing: the invoice is valid and the recipient will find it in their reserved area. Software that treats failed delivery as an error pushes operators to resend perfectly valid invoices, and the result is duplicated numbering — a considerably worse problem than the one it thought it was fixing.
For the same reason, "refused" (EC02, from a public-sector customer) and "rejected" (NS, from the exchange system) should stay distinct in the data even though the operator's next action is the same. The causes differ, and in six months that difference matters to someone.
The recipient field is where invoices break
The addressing part looks trivial and is not. The recipient code has three cases, and an accommodation business meets all three:
- The recipient's own seven-character code, when they supplied one.
0000000, when delivery falls back to certified email or the reserved area.XXXXXXX, the foreign-customer case — which for a hotel or a B&B is not an edge case but half the guest list.
Getting this field wrong does not produce an accounting error. It produces a rejection — an invoice that does not exist — discovered days later by whoever reads the notifications. If nobody reads them, discovered never.
Exemption nature belongs to the line, not the total
An invoice mixing standard-rate items with exempt or out-of-scope items cannot be judged from its total. The software has to look at the lines: every line without a rate needs its own exemption nature, and a mixed invoice is perfectly legitimate.
Checking only the total is a bug that never shows on simple invoices and lands precisely on the complicated ones: accommodation with VAT, tourist tax outside scope, a couple of extras. Exactly the invoice you did not want to get wrong.
You need a transmission log, not a status column
A single "invoice status" column is not enough, because an invoice's journey has a history: when it left, under which file name, how many attempts, what the exchange system answered, which external reference it assigned.
In Boris each invoice gets a dedicated delivery row — one per invoice, with status, attempt count, a hash of the request, the external reference and the response body. It buys two concrete things. An accidental resend is recognisable instead of becoming a second transmission. And when an accountant asks why a March invoice does not appear, the answer is a record rather than a reconstruction.
Questions to ask a vendor
- Where do I see, today, the invoices that were rejected and never retransmitted?
- Is failed delivery shown as an error or as a valid outcome?
- Does it read the EC01/EC02 outcome inside the notification, or only the notification type?
- How does it handle foreign customers in the recipient code?
- Does a mixed invoice carry the exemption nature on individual lines?
None of these questions is about how the invoice looks, and that is the point: the PDF is the part the customer sees, and the notifications are the part that decides whether the invoice exists.
Frequently asked questions
What is the difference between transmitted, delivered and accepted?
Transmitted means the file left. Delivered (RC) means the exchange system handed it to the recipient. Accepted is a third thing and applies only to invoices to public bodies, where the customer may reject: it arrives as a NotificaEsito carrying EC01 (accepted) or EC02 (rejected). Software that shows "sent" and stops there is telling you the least useful of the three.
What do you do with a rejection (NS)?
A rejected file means the invoice never existed for tax purposes. It must be corrected and retransmitted — and here is the trap: it is not a resend of the same file, because the rejected file has content errors. The invoice has to be regenerated, and the earlier state must stay visible. A rejected invoice nobody retransmitted is exactly the hole discovered at quarter end.
And failed delivery (MC)?
That one is not your fault and needs no action. The exchange system accepted the invoice but could not deliver it, so it makes it available in the recipient's reserved area and the invoice is valid. Treating it as a failure makes operators resend valid invoices, which is the fastest way to duplicate invoice numbers.
What does decorrenza termini (DT) mean?
It applies to invoices to public bodies: the customer did not respond within the deadline, so the invoice is considered to have gone through. It is a final outcome, not a waiting state. Confusing it with "pending" leaves rows open forever that are in fact closed.
