Skip to content

Electronic invoicing with Java

This tutorial builds two simple Java 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:

We use Maven for dependency management, which is the de facto standard for modern Java projects.

Tip

For an optimal Java experience, consider using IntelliJ IDEA or Eclipse as your IDE.

Did you know?

The Java SDK is compatible with Spring Boot, Jakarta EE, and all modern enterprise Java applications.

Receive

Create the app

The first step is to create the application directory:

mkdir receive && cd receive

Configure Maven

Create a pom.xml file with the following configuration:

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.invoicetronic.example</groupId>
    <artifactId>receive-example</artifactId>
    <version>1.0.0</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.invoicetronic</groupId>
            <artifactId>java-sdk</artifactId>
            <version>1.1.7</version>
        </dependency>
    </dependencies>
</project>

Configure the SDK

Create the directory structure and main file:

mkdir -p src/main/java/com/invoicetronic/example

Create the file src/main/java/com/invoicetronic/example/Main.java:

Configure the SDK
package com.invoicetronic.example;

import com.invoicetronic.sdk.ApiClient;
import com.invoicetronic.sdk.ApiException;
import com.invoicetronic.sdk.Configuration;
import com.invoicetronic.sdk.auth.HttpBasicAuth;
import com.invoicetronic.sdk.api.ReceiveApi;
import com.invoicetronic.sdk.model.Receive;

import java.util.List;

public class Main {
    public static void main(String[] args) {
        // Configure the SDK
        ApiClient defaultClient = Configuration.getDefaultApiClient();
        defaultClient.setBasePath("https://api.invoicetronic.com/v1");

        HttpBasicAuth basicAuth = (HttpBasicAuth) defaultClient.getAuthentication("Basic");
        basicAuth.setUsername("YOUR TEST API KEY (starts with ik_test_)");
        basicAuth.setPassword("");
    }
}

As you can see, we configure the SDK by setting the base path and HTTP Basic authentication with your test API Key (not the live one). Notice how we use setUsername() for the API Key and setPassword("") empty.

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 in the main method:

Download unread invoices
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

// Download unread invoices
ReceiveApi receiveApi = new ReceiveApi(defaultClient);

try {
    List<Receive> inboundInvoices = receiveApi.receiveGet(
        null,  // companyId
        null,  // identifier
        true,  // unread
        null,  // committente
        null,  // prestatore
        null,  // fileName
        null,  // lastUpdateFrom
        null,  // lastUpdateTo
        null,  // dateSentFrom
        null,  // dateSentTo
        null,  // documentDateFrom
        null,  // documentDateTo
        null,  // documentNumber
        true,  // includePayload
        null,  // page
        null,  // pageSize
        null   // sort
    );

    System.out.println("Received " + inboundInvoices.size() + " invoices");

    for (Receive invoice : inboundInvoices) {
        if (invoice.getEncoding() == Receive.EncodingEnum.XML) {
            try (FileOutputStream fos = new FileOutputStream(invoice.getFileName())) {
                fos.write(invoice.getPayload().getBytes(StandardCharsets.UTF_8));
            }
        } else if (invoice.getEncoding() == Receive.EncodingEnum.BASE64) {
            try (FileOutputStream fos = new FileOutputStream(invoice.getFileName())) {
                fos.write(Base64.getDecoder().decode(invoice.getPayload()));
            }
        }

        System.out.println("Downloaded " + invoice.getFileName() +
            " from a vendor with VAT ID " + invoice.getPrestatore());
    }
} catch (ApiException | IOException e) {
    System.err.println("Error: " + e.getMessage());
    e.printStackTrace();
}

Payload Inclusion

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

Compile and run the application:

mvn clean compile exec:java -Dexec.mainClass="com.invoicetronic.example.Main"

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 getting the default client with Configuration.getDefaultApiClient(), setting the base path, and configuring HTTP Basic authentication with username (API key) and empty password.

  2. We must instantiate a class representing the endpoint we want to work with. In this case, we leverage ReceiveApi to download incoming invoices, passing the configured client.

  3. Endpoint classes like ReceiveApi offer methods for interacting with their target entity. We call receiveGet() to retrieve invoices. Because we only want new, unread invoices, we pass true for the unread parameter. We also pass true for includePayload to retrieve the actual invoice content.

  4. Invoice objects expose methods like getEncoding(), getFileName(), and getPayload(). The last one contains the invoice content, as plain text or Base64-encoded, as described by getEncoding() which returns a Receive.EncodingEnum.

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:

mkdir send && cd send

Configure Maven

Create a pom.xml file with the following configuration:

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.invoicetronic.example</groupId>
    <artifactId>send-example</artifactId>
    <version>1.0.0</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.invoicetronic</groupId>
            <artifactId>java-sdk</artifactId>
            <version>1.1.7</version>
        </dependency>
    </dependencies>
</project>

Configure the SDK

Create the directory structure and main file:

mkdir -p src/main/java/com/invoicetronic/example

Create the file src/main/java/com/invoicetronic/example/Main.java:

Configure the SDK
package com.invoicetronic.example;

import com.invoicetronic.sdk.ApiClient;
import com.invoicetronic.sdk.ApiException;
import com.invoicetronic.sdk.Configuration;
import com.invoicetronic.sdk.auth.HttpBasicAuth;
import com.invoicetronic.sdk.api.SendApi;
import com.invoicetronic.sdk.model.Send;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        // Configure the SDK
        ApiClient defaultClient = Configuration.getDefaultApiClient();
        defaultClient.setBasePath("https://api.invoicetronic.com/v1");

        HttpBasicAuth basicAuth = (HttpBasicAuth) defaultClient.getAuthentication("Basic");
        basicAuth.setUsername("YOUR TEST API KEY (starts with ik_test_)");
        basicAuth.setPassword("");
    }
}

As you can see, we configure the SDK by setting the base path 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 in the main method:

Send an invoice
// Send an invoice
String filePath = "/some/file/path/filename.xml";

Map<String, String> metaData = new HashMap<>();
metaData.put("internal_id", "123");
metaData.put("created_with", "myapp");
metaData.put("some_other_custom_data", "value");

SendApi sendApi = new SendApi(defaultClient);

try {
    String payload = new String(Files.readAllBytes(Paths.get(filePath)));

    Send sendData = new Send();
    sendData.setFileName(Paths.get(filePath).getFileName().toString());
    sendData.setPayload(payload);
    sendData.setMetaData(metaData);

    Send sentInvoice = sendApi.sendPost(sendData, null, null);

    System.out.println("The invoice was sent successfully, it now has the unique Id of " +
        sentInvoice.getId() + ".");

} catch (ApiException | IOException e) {
    System.err.println("Error: " + e.getMessage());
    e.printStackTrace();
}

Compile and run the application:

mvn clean compile exec:java -Dexec.mainClass="com.invoicetronic.example.Main"

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 getting the default client with Configuration.getDefaultApiClient(), setting the base path, and configuring HTTP Basic authentication.

  2. We must instantiate a class representing the endpoint we want to work with. In this case, we leverage SendApi to send invoices. Endpoint classes like SendApi offer methods for interacting with their target entity. We call sendPost() to send an invoice.

  3. The Send model exposes methods like setFileName(), setMetaData(), and setPayload(). The last one contains the invoice content, while setMetaData() is optional and binds custom data to the document.

Source Code on GitHub

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