Fattura elettronica in Go
Questo tutorial crea tre semplici applicazioni Go 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:
- Go 1.18+ è stato installato
- Hai ottenuto una API Key attiva
- Ti sei registrato con l'Agenzia delle Entrate (necessario per l'ambiente live)
Tip
Per un'esperienza Go ottimale, considera l'uso di Go modules per la gestione delle dipendenze.
Lo sapevi?
L'SDK Go è perfetto per microservizi, applicazioni cloud e sistemi ad alte prestazioni grazie alla sua natura compilata e alla concorrenza nativa.
Receive
Creare l'applicazione
Il primo passo è creare la directory dell'applicazione e inizializzare un modulo Go:
Installare l'SDK
Installa l'SDK Go:
Configurare l'SDK
Crea il file main.go:
package main
import (
"context"
"encoding/base64"
"fmt"
"os"
invoicetronicsdk "github.com/invoicetronic/go-sdk"
)
func main() {
// Configura l'SDK
config := invoicetronicsdk.NewConfiguration()
config.Servers = invoicetronicsdk.ServerConfigurations{
{
URL: "https://api.invoicetronic.com/v1",
},
}
apiKey := "LA TUA CHIAVE API DI TEST (inizia con ik_test_)"
auth := apiKey + ":"
authHeader := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
config.AddDefaultHeader("Authorization", authHeader)
client := invoicetronicsdk.NewAPIClient(config)
}
Come puoi vedere, configuriamo l'SDK impostando l'URL del server e l'autenticazione HTTP Basic con la tua chiave API di test (non quella live). Nota come codifichiamo in Base64 la chiave API seguita da ":" per l'header Authorization.
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 questo codice nella funzione main:
// Scarica le fatture non lette
ctx := context.Background()
unread := true
includePayload := true
inboundInvoices, _, err := client.ReceiveAPI.ReceiveGet(ctx).
Unread(unread).
IncludePayload(includePayload).
Execute()
if err != nil {
fmt.Fprintf(os.Stderr, "Errore: %v\\n", err)
return
}
fmt.Printf("Ricevute %d fatture\\n", len(inboundInvoices))
for _, invoice := range inboundInvoices {
if invoice.Encoding != nil {
if *invoice.Encoding == "Xml" {
err = os.WriteFile(*invoice.FileName, []byte(*invoice.Payload), 0644)
} else if *invoice.Encoding == "Base64" {
decoded, _ := base64.StdEncoding.DecodeString(*invoice.Payload)
err = os.WriteFile(*invoice.FileName, decoded, 0644)
}
if err != nil {
fmt.Fprintf(os.Stderr, "Errore nel salvataggio del file: %v\\n", err)
continue
}
fmt.Printf("Scaricato %s da un fornitore con Partita IVA %s\\n",
*invoice.FileName, invoice.Prestatore.Get())
}
}
Inclusione del Payload
Impostiamo IncludePayload(true) per recuperare il contenuto effettivo della fattura nella proprietà Payload. Senza questo parametro, il campo Payload sarebbe nil di default, il che migliora le prestazioni e riduce la dimensione della risposta quando hai bisogno solo dei metadati.
Compila ed 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 una
Configuration, impostando l'URL del server e aggiungendo l'header Authorization con HTTP Basic (API key codificata in Base64 seguita da ":"). -
Dobbiamo creare un client API con
NewAPIClient(config)e utilizzare le API specifiche comeReceiveAPIper scaricare le fatture in arrivo. -
Le chiamate API usano un pattern fluent con metodi come
ReceiveGet(ctx).Unread(true).IncludePayload(true).Execute(). Poiché vogliamo solo fatture nuove e non lette, passiamoUnread(true). Passiamo ancheIncludePayload(true)per recuperare il contenuto effettivo della fattura. -
Gli oggetti fattura usano puntatori per i campi opzionali. Il campo
Encodingpuò avere i valori"Xml"o"Base64", ePayloadcontiene il contenuto della fattura.
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 e inizializzare un modulo Go:
Installare l'SDK
Installa l'SDK Go:
Configurare l'SDK
Crea il file main.go:
package main
import (
"context"
"encoding/base64"
"fmt"
"os"
"path/filepath"
invoicetronicsdk "github.com/invoicetronic/go-sdk"
)
func main() {
// Configura l'SDK
config := invoicetronicsdk.NewConfiguration()
config.Servers = invoicetronicsdk.ServerConfigurations{
{
URL: "https://api.invoicetronic.com/v1",
},
}
apiKey := "LA TUA CHIAVE API DI TEST (inizia con ik_test_)"
auth := apiKey + ":"
authHeader := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
config.AddDefaultHeader("Authorization", authHeader)
client := invoicetronicsdk.NewAPIClient(config)
}
Come puoi vedere, configuriamo l'SDK impostando l'URL del server e l'autenticazione HTTP Basic con la tua chiave API di test (non quella live).
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 questo codice nella funzione main:
// Invia una fattura
filePath := "/qualche/percorso/file/nomefile.xml"
metaData := map[string]string{
"internal_id": "123",
"created_with": "myapp",
"some_other_custom_data": "value",
}
ctx := context.Background()
payload, err := os.ReadFile(filePath)
if err != nil {
fmt.Fprintf(os.Stderr, "Errore nella lettura del file: %v\\n", err)
return
}
fileName := filepath.Base(filePath)
payloadStr := string(payload)
sendData := *invoicetronicsdk.NewSend(payloadStr)
sendData.SetFileName(fileName)
sendData.SetMetaData(metaData)
sentInvoice, _, err := client.SendAPI.SendPost(ctx).Send(sendData).Execute()
if err != nil {
fmt.Fprintf(os.Stderr, "Errore: %v\\n", err)
return
}
fmt.Printf("La fattura è stata inviata con successo, ora ha l'Id univoco %s.\\n",
*sentInvoice.Id)
Compila ed 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: lo SDI esegue dei controlli e restituisce una sequenza di notifiche che descrivono lo stato del processo (Inviato, Consegnato, Scartato, ecc.). Il modello Send espone il campo LatestState 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
fresh, _, err := client.SendAPI.SendIdGet(ctx, *sentInvoice.Id).Execute()
if err != nil {
fmt.Fprintf(os.Stderr, "Errore: %v\\n", err)
return
}
state := fresh.GetLatestState()
if state == "" {
state = "In elaborazione"
}
fmt.Printf("Stato corrente: %s\\n", state)
Subito dopo l'invio, GetLatestState() può restituire stringa vuota (HasLatestState() ritorna false): lo 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 LatestState 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 una
Configuration, impostando l'URL del server e aggiungendo l'header Authorization con HTTP Basic. -
Dobbiamo creare un client API e utilizzare
SendAPIper inviare fatture. Le chiamate API usano il patternSendPost(ctx).Send(sendData).Execute(). -
Il modello
Sendviene creato conNewSend()e configurato con setter:SetFileName(),SetPayload()eSetMetaData(). Il payload contiene il contenuto della fattura, mentreMetaDataè opzionale e lega dati personalizzati al documento. -
Il modello
Sendespone ancheLatestStatecon lo stato SDI corrente, leggibile viaclient.SendAPI.SendIdGet(ctx, id).Execute()con il getterGetLatestState(). 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 LatestState dal modello 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 il file main.go:
package main
import (
"context"
"encoding/base64"
"fmt"
"os"
invoicetronicsdk "github.com/invoicetronic/go-sdk"
)
func main() {
// Configura l'SDK
config := invoicetronicsdk.NewConfiguration()
config.Servers = invoicetronicsdk.ServerConfigurations{
{
URL: "https://api.invoicetronic.com/v1",
},
}
apiKey := "LA TUA CHIAVE API DI TEST (inizia con ik_test_)"
auth := apiKey + ":"
authHeader := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
config.AddDefaultHeader("Authorization", authHeader)
client := invoicetronicsdk.NewAPIClient(config)
// Id della fattura inviata di cui vogliamo ricostruire la cronologia
sendId := int32(225)
ctx := context.Background()
updates, _, err := client.UpdateAPI.UpdateGet(ctx).
SendId(sendId).
Sort("last_update").
Execute()
if err != nil {
fmt.Fprintf(os.Stderr, "Errore: %v\n", err)
return
}
fmt.Printf("Trovate %d notifiche per la fattura %d\n", len(updates), sendId)
for _, update := range updates {
description := "OK"
if update.Description.IsSet() && update.Description.Get() != nil {
description = *update.Description.Get()
}
fmt.Printf(" [%s] state=%v - %s\n", update.LastUpdate.Format("2006-01-02T15:04:05Z"), *update.State, description)
}
}
Compila ed esegui l'applicazione:
Dovresti ottenere un output simile a questo:
Trovate 2 notifiche per la fattura 225
[2025-01-23T16:56:14Z] state=Inviato - OK
[2025-01-23T17:12:03Z] 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.
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
UpdateAPIinvece diSendAPIoReceiveAPI. -
Le chiamate API usano il pattern fluent
UpdateGet(ctx).SendId(...).Sort(...).Execute(). Sono disponibili filtri comeSendId,State,LastUpdateFrom/LastUpdateToe 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.