Skip to content

Electronic invoicing with Go

This tutorial builds two simple Go applications from scratch:

  1. Receive: connects and authenticates with the Invoicetronic API and downloads any new incoming invoices.
  2. Send: connects and authenticates with the Invoicetronic API and sends an invoice to the SDI.

Before continuing, make sure all the prerequisites below are met.

Prerequisites

We assume that these prerequisites are met:

Tip

For an optimal Go experience, consider using Go modules for dependency management.

Did you know?

The Go SDK is perfect for microservices, cloud applications, and high-performance systems thanks to its compiled nature and native concurrency.

Receive

Create the app

The first step is to create the application directory and initialize a Go module:

mkdir receive && cd receive
go mod init invoicetronic-receive-example

Install the SDK

Install the Go SDK:

go get github.com/invoicetronic/go-sdk@v1.1.7

Configure the SDK

Create the file main.go:

Configure the SDK
package main

import (
\t"context"
\t"encoding/base64"
\t"fmt"
\t"os"

\tinvoicetronicsdk "github.com/invoicetronic/go-sdk"
)

func main() {
\t// Configure the SDK
\tconfig := invoicetronicsdk.NewConfiguration()
\tconfig.Servers = invoicetronicsdk.ServerConfigurations{
\t\t{
\t\t\tURL: "https://api.invoicetronic.com/v1",
\t\t},
\t}

\tapiKey := "YOUR TEST API KEY (starts with ik_test_)"
\tauth := apiKey + ":"
\tauthHeader := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
\tconfig.AddDefaultHeader("Authorization", authHeader)

\tclient := invoicetronicsdk.NewAPIClient(config)
}

As you can see, we configure the SDK by setting the server URL and HTTP Basic authentication with your test API Key (not the live one). Notice how we encode the API key followed by ":" in Base64 for the Authorization header.

API Key comes in pairs

When you create your account, you obtain a pair of API Keys. One is the test key for the API Sandbox, and the other is the live API's. You can tell the difference because the former starts with ik_test_, while the latter begins with ik_live_. In this tutorial, always use the test key.

Download invoices

We are ready to make a request. We want to download new vendor invoices that may be available from the SDI. Add this code to the main function:

Download unread invoices
\t// Download unread invoices
\tctx := context.Background()

\tunread := true
\tincludePayload := true

\tinboundInvoices, _, err := client.ReceiveAPI.ReceiveGet(ctx).
\t\tUnread(unread).
\t\tIncludePayload(includePayload).
\t\tExecute()

\tif err != nil {
\t\tfmt.Fprintf(os.Stderr, "Error: %v\\n", err)
\t\treturn
\t}

\tfmt.Printf("Received %d invoices\\n", len(inboundInvoices))

\tfor _, invoice := range inboundInvoices {
\t\tif invoice.Encoding != nil {
\t\t\tif *invoice.Encoding == "Xml" {
\t\t\t\terr = os.WriteFile(*invoice.FileName, []byte(*invoice.Payload), 0644)
\t\t\t} else if *invoice.Encoding == "Base64" {
\t\t\t\tdecoded, _ := base64.StdEncoding.DecodeString(*invoice.Payload)
\t\t\t\terr = os.WriteFile(*invoice.FileName, decoded, 0644)
\t\t\t}

\t\t\tif err != nil {
\t\t\t\tfmt.Fprintf(os.Stderr, "Error saving file: %v\\n", err)
\t\t\t\tcontinue
\t\t\t}

\t\t\tfmt.Printf("Downloaded %s from a vendor with VAT ID %s\\n",
\t\t\t\t*invoice.FileName, invoice.Prestatore.Get())
\t\t}
\t}

Payload Inclusion

We set IncludePayload(true) to retrieve the actual invoice content in the Payload property. Without this parameter, the Payload field would be nil by default, which increases performance and reduces response size when you only need metadata.

Build and run the application:

go run main.go

You should obtain an output similar to this one:

Received 3 invoices
Downloaded file1.xml from a vendor with VAT ID IT06157670966
Downloaded file2.xml.p7m from a vendor with VAT ID IT01280270057
Downloaded file3.xml.p7m from a vendor with VAT ID IT01280270057

The files are in the current directory, ready for you to inspect them.

Not receiving invoices in the live environment?

Ensure you registered with the Italian Revenue Service, which is a requirement for the live environment.

What we learned

In this example, we learned several things.

  1. We must configure the SDK by creating a Configuration, setting the server URL, and adding the Authorization header with HTTP Basic (API key encoded in Base64 followed by ":").

  2. We must create an API client with NewAPIClient(config) and use specific APIs like ReceiveAPI to download incoming invoices.

  3. API calls use a fluent pattern with methods like ReceiveGet(ctx).Unread(true).IncludePayload(true).Execute(). Because we only want new, unread invoices, we pass Unread(true). We also pass IncludePayload(true) to retrieve the actual invoice content.

  4. Invoice objects use pointers for optional fields. The Encoding field can have the values "Xml" or "Base64", and Payload contains the invoice content.

Source Code on GitHub

The source code for this Quickstart is also available on GitHub.

Send

Create the app

The first step is to create the application directory and initialize a Go module:

mkdir send && cd send
go mod init invoicetronic-send-example

Install the SDK

Install the Go SDK:

go get github.com/invoicetronic/go-sdk@v1.1.7

Configure the SDK

Create the file main.go:

Configure the SDK
package main

import (
\t"context"
\t"encoding/base64"
\t"fmt"
\t"os"
\t"path/filepath"

\tinvoicetronicsdk "github.com/invoicetronic/go-sdk"
)

func main() {
\t// Configure the SDK
\tconfig := invoicetronicsdk.NewConfiguration()
\tconfig.Servers = invoicetronicsdk.ServerConfigurations{
\t\t{
\t\t\tURL: "https://api.invoicetronic.com/v1",
\t\t},
\t}

\tapiKey := "YOUR TEST API KEY (starts with ik_test_)"
\tauth := apiKey + ":"
\tauthHeader := "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
\tconfig.AddDefaultHeader("Authorization", authHeader)

\tclient := invoicetronicsdk.NewAPIClient(config)
}

As you can see, we configure the SDK by setting the server URL and HTTP Basic authentication with your test API Key (not the live one).

API Key comes in pairs

When you create your account, you obtain a pair of API Keys. One is the test key for the API Sandbox, and the other is the live API's. You can tell the difference because the former starts with ik_test_, while the latter begins with ik_live_. In this tutorial, always use the test key.

Send an invoice

We are ready to make a request. We want to send an invoice to the SDI. Add this code to the main function:

Send an invoice
\t// Send an invoice
\tfilePath := "/some/file/path/filename.xml"

\tmetaData := map[string]string{
\t\t"internal_id":             "123",
\t\t"created_with":            "myapp",
\t\t"some_other_custom_data": "value",
\t}

\tctx := context.Background()

\tpayload, err := os.ReadFile(filePath)
\tif err != nil {
\t\tfmt.Fprintf(os.Stderr, "Error reading file: %v\\n", err)
\t\treturn
\t}

\tfileName := filepath.Base(filePath)
\tpayloadStr := string(payload)

\tsendData := *invoicetronicsdk.NewSend()
\tsendData.SetFileName(fileName)
\tsendData.SetPayload(payloadStr)
\tsendData.SetMetaData(metaData)

\tsentInvoice, _, err := client.SendAPI.SendPost(ctx).Send(sendData).Execute()

\tif err != nil {
\t\tfmt.Fprintf(os.Stderr, "Error: %v\\n", err)
\t\treturn
\t}

\tfmt.Printf("The invoice was sent successfully, it now has the unique Id of %s.\\n",
\t\t*sentInvoice.Id)

Build and run the application:

go run main.go

You should obtain an output similar to this one:

The invoice was sent successfully, it now has the unique Id of 123.

What we learned

In this example, we learned several things.

  1. We must configure the SDK by creating a Configuration, setting the server URL, and adding the Authorization header with HTTP Basic.

  2. We must create an API client and use SendAPI to send invoices. API calls use the pattern SendPost(ctx).Send(sendData).Execute().

  3. The Send model is created with NewSend() and configured with setters: SetFileName(), SetPayload(), and SetMetaData(). The payload contains the invoice content, while MetaData is optional and binds custom data to the document.

Source Code on GitHub

The source code for this Quickstart is also available on GitHub.