Fattura elettronica in Python
Questo tutorial crea tre semplici applicazioni Python da zero:
- Receive: si connette e autentica con l'API Invoicetronic e scarica le nuove fatture passive in arrivo.
- Send: si connette e autentica con l'API Invoicetronic e invia una fattura al SDI.
- Update: si connette e autentica con l'API Invoicetronic e consulta la cronologia delle notifiche restituite dallo SDI.
Prima di continuare, assicurati che tutti i prerequisiti siano soddisfatti.
Prerequisiti
Assumiamo che questi prerequisiti siano soddisfatti:
- Python 3.9+ è stato scaricato e installato
- pip è installato (viene fornito con Python)
- Hai ottenuto una API Key attiva
- Ti sei registrato con l'Agenzia delle Entrate (necessario per l'ambiente live)
Usiamo pip per la gestione delle dipendenze, che è lo standard de facto per Python moderno.
Tip
Per un'esperienza Python ottimale, considera l'uso di VS Code con l'estensione Python o PyCharm per un IDE completo.
Lo sapevi?
L'SDK Python supporta type hints e validazione Pydantic, fornendo controlli runtime e migliore autocomplete nell'IDE.
Receive
Creare l'applicazione
Il primo passo è creare la directory dell'applicazione:
Installare l'SDK
Installa l'SDK Python di Invoicetronic:
Una volta fatto, apri VS Code nella directory corrente:
Configurare l'SDK
Crea un nuovo file chiamato index.py e aggiungi il seguente codice:
import invoicetronic_sdk
from invoicetronic_sdk.rest import ApiException
# Configura l'SDK
configuration = invoicetronic_sdk.Configuration(
username='LA TUA CHIAVE API DI TEST (inizia con ik_test_)',
host='https://api.invoicetronic.com/v1'
)
Come puoi vedere, configuriamo l'SDK passando la tua chiave API di test (non quella live) e l'host dell'API. Nota come usiamo il parametro username per impostare la chiave API.
Le chiavi API vengono fornite in coppia
Quando crei il tuo account, ottieni una coppia di chiavi API. Una è la chiave di test per l'API Sandbox, e l'altra è quella live. Puoi distinguerle perché la prima inizia con ik_test_, mentre la seconda inizia con ik_live_. In questo tutorial, usa sempre la chiave di test.
Scaricare le fatture
Siamo pronti per effettuare una richiesta. Vogliamo scaricare le nuove fatture passive che potrebbero essere disponibili dall'SDI. Aggiungi queste righe:
import base64
# Scarica le fatture non lette
with invoicetronic_sdk.ApiClient(configuration) as api_client:
receive_api = invoicetronic_sdk.ReceiveApi(api_client)
try:
inbound_invoices = receive_api.receive_get(
unread=True,
include_payload=True
)
print(f"Ricevute {len(inbound_invoices)} fatture")
for invoice in inbound_invoices:
if invoice.encoding == 'Xml':
with open(invoice.file_name, 'w', encoding='utf-8') as f:
f.write(invoice.payload)
elif invoice.encoding == 'Base64':
with open(invoice.file_name, 'wb') as f:
f.write(base64.b64decode(invoice.payload))
print(f"Scaricato {invoice.file_name} da un fornitore con Partita IVA {invoice.prestatore}")
except ApiException as e:
print(f"Errore: {e}")
Inclusione del Payload
Impostiamo include_payload=True per recuperare il contenuto effettivo della fattura nella proprietà payload. Senza questo parametro, il campo payload sarebbe None di default, il che migliora le prestazioni e riduce la dimensione della risposta quando hai bisogno solo dei metadati.
Nel terminale, esegui l'applicazione:
Dovresti ottenere un output simile a questo:
Ricevute 3 fatture
Scaricato file1.xml da un fornitore con Partita IVA IT06157670966
Scaricato file2.xml.p7m da un fornitore con Partita IVA IT01280270057
Scaricato file3.xml.p7m da un fornitore con Partita IVA IT01280270057
I file sono nella directory corrente, pronti per essere ispezionati.
Non ricevi fatture nell'ambiente live?
Assicurati di esserti registrato con l'Agenzia delle Entrate, che è un requisito per l'ambiente live.
Cosa abbiamo imparato
In questo esempio, abbiamo imparato diverse cose.
-
Dobbiamo configurare l'SDK creando un'istanza di
Configuratione passando username (chiave API) e host (URL dell'API). -
Usiamo il context manager
withper gestire automaticamente la chiusura del client API. IstanziamoApiClientpassando la configurazione. -
Dobbiamo istanziare una classe che rappresenta l'endpoint con cui vogliamo lavorare. In questo caso, utilizziamo
ReceiveApiper scaricare le fatture in arrivo, passando il client API. -
Le classi endpoint come
ReceiveApioffrono metodi per interagire con la loro entità target. Chiamiamoreceive_get()per recuperare le fatture. Poiché vogliamo solo fatture nuove e non lette, passiamounread=True. Passiamo ancheinclude_payload=Trueper recuperare il contenuto effettivo della fattura. -
Gli oggetti fattura espongono attributi come
encoding,file_nameepayload. L'ultimo contiene il contenuto della fattura, come testo semplice o codificato in Base64, come descritto daencoding.
Codice sorgente su GitHub
Il codice sorgente per questo Quickstart è disponibile anche su GitHub.
Send
Creare l'applicazione
Il primo passo è creare la directory dell'applicazione:
Installare l'SDK
Installa l'SDK Python di Invoicetronic:
Una volta fatto, apri VS Code nella directory corrente:
Configurare l'SDK
Crea un nuovo file chiamato index.py e aggiungi il seguente codice:
import invoicetronic_sdk
from invoicetronic_sdk.rest import ApiException
from invoicetronic_sdk.models.send import Send
# Configura l'SDK
configuration = invoicetronic_sdk.Configuration(
username='LA TUA CHIAVE API DI TEST (inizia con ik_test_)',
host='https://api.invoicetronic.com/v1'
)
Come puoi vedere, configuriamo l'SDK passando la tua chiave API di test (non quella live) e l'host dell'API. Nota come usiamo il parametro username per impostare la chiave API.
Le chiavi API vengono fornite in coppia
Quando crei il tuo account, ottieni una coppia di chiavi API. Una è la chiave di test per l'API Sandbox, e l'altra è quella live. Puoi distinguerle perché la prima inizia con ik_test_, mentre la seconda inizia con ik_live_. In questo tutorial, usa sempre la chiave di test.
Inviare una fattura
Siamo pronti per effettuare una richiesta. Vogliamo inviare una fattura all'SDI. Aggiungi il seguente codice:
import os
# Invia una fattura
file_path = '/qualche/percorso/file/nomefile.xml'
meta_data = {
'internal_id': '123',
'created_with': 'myapp',
'some_other_custom_data': 'value'
}
with invoicetronic_sdk.ApiClient(configuration) as api_client:
send_api = invoicetronic_sdk.SendApi(api_client)
try:
with open(file_path, 'r', encoding='utf-8') as f:
payload = f.read()
send_data = Send(
file_name=os.path.basename(file_path),
payload=payload,
meta_data=meta_data
)
sent_invoice = send_api.send_post(send_data)
print(f"La fattura è stata inviata con successo, ora ha l'Id univoco {sent_invoice.id}.")
except ApiException as e:
print(f"Errore: {e}")
Nel terminale, esegui l'applicazione:
Dovresti ottenere un output simile a questo:
Verificare lo stato della fattura
Quando inoltri una fattura allo SDI, la consegna non è istantanea: l'SDI esegue dei controlli e restituisce una sequenza di notifiche che descrivono lo stato del processo (Inviato, Consegnato, Scartato, ecc.). L'oggetto Send espone il campo latest_state con lo stato corrente, evitando una chiamata separata a /update quando ti serve sapere solo come è andata.
# Recupera lo stato più recente di una fattura già inviata
with invoicetronic_sdk.ApiClient(configuration) as api_client:
send_api = invoicetronic_sdk.SendApi(api_client)
fresh = send_api.send_id_get(sent_invoice.id)
print(f"Stato corrente: {fresh.latest_state or 'In elaborazione'}")
Subito dopo l'invio, latest_state può essere None: l'SDI non ha ancora processato il documento. Ricontrolla dopo qualche secondo o, meglio, configura un webhook per ricevere una notifica push ad ogni cambio di stato.
Risparmia richieste API
Usa latest_state su Send ogni volta che ti serve solo lo stato corrente: una sola chiamata invece di una a /send più una a /update. Ricorri a UpdateApi solo quando ti serve la cronologia completa delle transizioni.
Cosa abbiamo imparato
In questo esempio, abbiamo imparato diverse cose.
-
Dobbiamo configurare l'SDK creando un'istanza di
Configuratione passando username (chiave API) e host (URL dell'API). -
Usiamo il context manager
withper gestire automaticamente la chiusura del client API. IstanziamoApiClientpassando la configurazione. -
Dobbiamo istanziare una classe che rappresenta l'endpoint con cui vogliamo lavorare. In questo caso, utilizziamo
SendApiper inviare fatture. Le classi endpoint comeSendApioffrono metodi per interagire con la loro entità target. Chiamiamosend_post()per inviare una fattura. -
Il modello
Sendespone attributi comefile_name,meta_dataepayload. L'ultimo contiene il contenuto della fattura, mentremeta_dataè opzionale e lega dati personalizzati al documento. -
Il modello
Sendespone anchelatest_statecon lo stato SDI corrente, leggibile viasend_id_get(id). Evita una chiamata a/updatequando serve solo conoscere lo stato.
Codice sorgente su GitHub
Il codice sorgente per questo Quickstart è disponibile anche su GitHub.
Update
Per lo stato corrente di una fattura inviata, è sufficiente leggere latest_state dall'oggetto Send (vedi Verificare lo stato della fattura). Se invece vuoi la cronologia completa delle transizioni — per esempio per capire perché una fattura è stata scartata, mostrare in UI tutti i passaggi di stato con timestamp, o tracciare le notifiche restituite da un ente della Pubblica Amministrazione — usa UpdateApi.
Le query su /update sono gratuite
Le richieste a /update non vengono conteggiate sul tuo piano: puoi consultare la cronologia delle notifiche con la frequenza che preferisci.
Creare l'applicazione
Installare l'SDK
Recuperare la cronologia delle notifiche
Crea un file index.py con il seguente codice:
import invoicetronic_sdk
from invoicetronic_sdk.rest import ApiException
# Configura l'SDK
configuration = invoicetronic_sdk.Configuration(
username='LA TUA CHIAVE API DI TEST (inizia con ik_test_)',
host='https://api.invoicetronic.com/v1'
)
# Id della fattura inviata di cui vogliamo ricostruire la cronologia
send_id = 225
with invoicetronic_sdk.ApiClient(configuration) as api_client:
update_api = invoicetronic_sdk.UpdateApi(api_client)
try:
updates = update_api.update_get(send_id=send_id, sort='last_update')
print(f"Trovate {len(updates)} notifiche per la fattura {send_id}")
for update in updates:
print(f" [{update.last_update}] state={update.state} - {update.description or 'OK'}")
except ApiException as e:
print(f"Errore: {e}")
Esegui l'applicazione:
Dovresti ottenere un output simile a questo:
Trovate 2 notifiche per la fattura 225
[2025-01-23 16:56:14+00:00] state=State.INVIATO - OK
[2025-01-23 17:12:03+00:00] state=State.CONSEGNATO - OK
Il campo state è la proprietà più importante. I valori più comuni sono:
| Valore | Nome | Descrizione |
|---|---|---|
| 2 | Inviato |
Inviata allo SDI. |
| 5 | Consegnato |
Consegnata al destinatario. |
| 7 | Scartato |
Rifiutata dallo SDI. In description trovi il motivo. |
L'elenco completo dei valori è disponibile nella API Reference. Puoi anche filtrare per stato, per esempio per ottenere solo le fatture scartate:
Monitora sempre lo stato delle fatture inviate
Lo stato Inviato significa solo che il documento è stato preso in carico dallo SDI, non che sia stato consegnato. Uno stato Scartato indica che la fattura non è stata accettata e potrebbe richiedere una correzione e un nuovo invio.
Cosa abbiamo imparato
-
Per consultare la cronologia delle notifiche utilizziamo la classe
UpdateApiinvece diSendApioReceiveApi. -
Il metodo
update_get()accetta filtri comesend_id(per le notifiche di una specifica fattura inviata),state(per filtrare per stato),last_update_from/last_update_to(intervallo temporale) e altri. -
Le query su
/updatesono gratuite e non vengono conteggiate sul tuo piano, quindi puoi richiamarle con la frequenza che ti serve.
Codice sorgente su GitHub
Il codice sorgente per questo Quickstart è disponibile anche su GitHub.