Skip to content

Electronic invoicing with TypeScript

This tutorial builds two simple TypeScript 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 npm for dependency management, but you can also use yarn if you prefer.

Tip

For an optimal TypeScript experience, consider using VS Code with TypeScript extensions or WebStorm for a complete IDE.

Did you know?

The TypeScript SDK offers full type safety, IDE autocomplete, and compile-time error detection, making integration safer and faster.

Receive

Create the app

The first step is to create the application directory:

mkdir receive && cd receive

Initialize the project with npm:

npm init -y

The command created a new Node.js project with a package.json file in the current directory.

Install the SDK

Install the Invoicetronic TypeScript SDK and TypeScript:

npm install @invoicetronic/ts-sdk typescript @types/node --save-dev

Once that's done, open VS Code in the current directory:

code .

Configure TypeScript

Create a tsconfig.json file with the following configuration:

tsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020"],
    "outDir": "./dist",
    "rootDir": "./",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true
  },
  "include": ["*.ts"],
  "exclude": ["node_modules"]
}

Configure the SDK

Create a new file called index.ts and add the following code:

Configure the SDK
import { Configuration, ReceiveApi } from '@invoicetronic/ts-sdk';

// Configure the SDK
const config = new Configuration({
  username: 'YOUR TEST API KEY (starts with ik_test_)',
  basePath: 'https://api.invoicetronic.com/v1'
});

As you can see, we configure the SDK by passing your test API Key (not the live one) and the API host. Notice how we use the username field to set the API Key.

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 these lines:

Download unread invoices
import * as fs from 'fs';

// Download unread invoices
const receiveApi = new ReceiveApi(config);

async function downloadInvoices() {
  try {
    const inboundInvoices = await receiveApi.receiveGet(
      undefined,  // companyId
      undefined,  // identifier
      true,       // unread
      undefined,  // committente
      undefined,  // prestatore
      undefined,  // fileName
      undefined,  // lastUpdateFrom
      undefined,  // lastUpdateTo
      undefined,  // dateSentFrom
      undefined,  // dateSentTo
      undefined,  // documentDateFrom
      undefined,  // documentDateTo
      undefined,  // documentNumber
      true        // includePayload
    );

    console.log(`Received ${inboundInvoices.data.length} invoices`);

    for (const invoice of inboundInvoices.data) {
      if (invoice.encoding === 'Xml') {
        fs.writeFileSync(invoice.file_name!, invoice.payload!, 'utf8');
      } else if (invoice.encoding === 'Base64') {
        const buffer = Buffer.from(invoice.payload!, 'base64');
        fs.writeFileSync(invoice.file_name!, buffer);
      }

      console.log(`Downloaded ${invoice.file_name} from a vendor with VAT ID ${invoice.prestatore}`);
    }
  } catch (error: any) {
    console.error('Error:', error.message);
    if (error.response) {
      console.error('Details:', error.response.data);
    }
  }
}

downloadInvoices();

Payload Inclusion

We set includePayload: 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.

Add a build script in package.json:

{
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js"
  }
}

In the terminal, build and run the application:

npm run build && npm start

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 instance and passing username (API key) and basePath (API URL).

  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 configuration.

  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 properties like encoding, file_name, and payload. The last one contains the invoice content, as plain text or Base64-encoded, as described by encoding.

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

Initialize the project with npm:

npm init -y

Install the SDK

Install the Invoicetronic TypeScript SDK and TypeScript:

npm install @invoicetronic/ts-sdk typescript @types/node --save-dev

Once that's done, open VS Code in the current directory:

code .

Configure TypeScript

Create a tsconfig.json file with the following configuration:

tsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020"],
    "outDir": "./dist",
    "rootDir": "./",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true
  },
  "include": ["*.ts"],
  "exclude": ["node_modules"]
}

Configure the SDK

Create a new file called index.ts and add the following code:

Configure the SDK
import { Configuration, SendApi, Send } from '@invoicetronic/ts-sdk';

// Configure the SDK
const config = new Configuration({
  username: 'YOUR TEST API KEY (starts with ik_test_)',
  basePath: 'https://api.invoicetronic.com/v1'
});

As you can see, we configure the SDK by passing your test API Key (not the live one) and the API host. Notice how we use the username field to set the API Key.

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 the following code:

Send an invoice
import * as fs from 'fs';
import * as path from 'path';

// Send an invoice
const filePath = '/some/file/path/filename.xml';

const metaData: { [key: string]: string } = {
  'internal_id': '123',
  'created_with': 'myapp',
  'some_other_custom_data': 'value'
};

const sendApi = new SendApi(config);

async function sendInvoice() {
  try {
    const sendData: Send = {
      file_name: path.basename(filePath),
      payload: fs.readFileSync(filePath, 'utf8'),
      meta_data: metaData
    };

    const sentInvoice = await sendApi.sendPost(sendData);

    console.log(`The invoice was sent successfully, it now has the unique Id of ${sentInvoice.data.id}.`);
  } catch (error: any) {
    console.error('Error:', error.message);
    if (error.response) {
      console.error('Details:', error.response.data);
    }
  }
}

sendInvoice();

Add a build script in package.json:

{
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js"
  }
}

In the terminal, build and run the application:

npm run build && npm start

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 instance and passing username (API key) and basePath (API URL).

  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 interface exposes properties like file_name, meta_data, and payload. The last one contains the invoice content, while meta_data is optional and binds custom data to the document.

Source Code on GitHub

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