Vai al contenuto

API fattura elettronica in Node.js

Invia fatture elettroniche allo SdI e ricevi fatture e notifiche dei fornitori dal tuo codice Node.js, con esempi completi da copiare. Ambiente: Node.js 18+ con fetch ed Express.

Prima di iniziare

  1. Crea un account e conferma l'e-mail: hai 30 giorni e 20 fatture di prova.
  2. Usa le stesse credenziali del portale per il login alle API (POST https://api.fattura-elettronica.cloud/api/login) e conserva il token.
  3. Per ricevere fatture e notifiche sul tuo server, imposta gli indirizzi dei tuoi endpoint nel profilo del portale e attiva l'inoltro.

Inviare una fattura elettronica in Node.js

Da Node.js 18 fetch, FormData e Blob sono già inclusi: nessuna dipendenza per inviare. Con versioni precedenti usa undici o axios con form-data. La risposta contiene inoltro.id_sdi, l'identificativo con cui arriveranno le notifiche della fattura.

// Node.js 18+ (fetch, FormData e Blob sono già inclusi) - file invio.mjs
import { readFile } from "node:fs/promises";

const API = "https://api.fattura-elettronica.cloud/api";

// 1. Login: il token vale a lungo, salvalo e rifai il login solo se ricevi 401
const login = await fetch(`${API}/login`, {
  method: "POST",
  headers: { Accept: "application/json", "Content-Type": "application/json" },
  body: JSON.stringify({ email: "tua@email.it", password: "LaTuaPassword" }),
}).then((r) => r.json());
if (!login.access_token) throw new Error(`Login non riuscito: ${login.message}`);
const auth = { Accept: "application/json", Authorization: `Bearer ${login.access_token}` };

// 2. Invio della fattura XML allo SdI
const nome = "IT01234567890_00001.xml";
const form = new FormData();
form.append("fileFattura", new Blob([await readFile(nome)], { type: "application/xml" }), nome);

const risposta = await fetch(`${API}/inoltro`, { method: "POST", headers: auth, body: form });
const esito = await risposta.json();

if (risposta.ok && esito.esito === "ok") {
  console.log("Inviata, identificativo SdI:", esito.inoltro.id_sdi);
} else {
  console.error(`Errore ${risposta.status}: ${esito.messaggio}`);
}

// 3. Elenco delle fatture inviate (esito: 0 in attesa, 1 consegnata, 2 mancata consegna, 3 scartata, ...)
const { inoltri } = await fetch(`${API}/inoltro`, { headers: auth }).then((r) => r.json());
for (const inoltro of inoltri) console.log(inoltro.id_sdi, inoltro.esito);

Codici di risposta: 200 inviata, 400 file non valido, 401 token scaduto, 403 pacchetto esaurito o e-mail non confermata, 422 rifiutata dallo SdI. Tutti i dettagli nella documentazione completa.

Ricevere le fatture elettroniche in Node.js

Quando arriva una fattura per il tuo codice destinatario la mandiamo al tuo endpoint con una POST form-urlencoded: strxml (XML della fattura), xmlF (file originale), xmlM (metadati SdI), tutti in base64, e formato. Con Express usa express.raw() sulle route degli endpoint, così req.body è il Buffer originale su cui verificare la firma; poi decodifica i campi con URLSearchParams.

// Node.js 18+ con Express (npm install express) - URL da indicare in "Endpoint ricezione fatture"
import express from "express";
import crypto from "node:crypto";
import { mkdir, writeFile } from "node:fs/promises";

const SEGRETO = process.env.FE_SEGRETO ?? ""; // pagina Integrazione del portale; vuoto se non usi la firma
const app = express();

// X-FE-Firma = HMAC-SHA256 di "timestamp\ncorpo" con il tuo segreto
function firmaValida(req, corpo) {
  if (!SEGRETO) return true;
  const ts = req.get("X-FE-Timestamp") ?? "";
  const firma = Buffer.from(req.get("X-FE-Firma") ?? "");
  const attesa = Buffer.from(crypto.createHmac("sha256", SEGRETO).update(`${ts}\n`).update(corpo).digest("hex"));
  return /^\d+$/.test(ts) && Math.abs(Date.now() / 1000 - Number(ts)) <= 300
    && firma.length === attesa.length && crypto.timingSafeEqual(firma, attesa);
}

// express.raw: serve il corpo così com'è arrivato per verificare la firma
app.post("/ricevi-fatture", express.raw({ type: "*/*", limit: "50mb" }), async (req, res) => {
  if (!firmaValida(req, req.body)) return res.status(403).send("firma non valida");

  const dati = new URLSearchParams(req.body.toString());
  const xmlFattura = Buffer.from(dati.get("strxml") ?? "", "base64");   // XML, già estratto dal .p7m
  const metadati = Buffer.from(dati.get("xmlM") ?? "", "base64").toString();
  const idSdi = metadati.match(/<IdentificativoSdI>(\d+)</)?.[1];
  if (!idSdi || !xmlFattura.length) return res.status(400).send("dati mancanti");

  // Stesso IdentificativoSdI = stessa fattura: se arriva di nuovo sovrascrivi, non duplicare
  await mkdir("fatture_ricevute", { recursive: true });
  await writeFile(`fatture_ricevute/${idSdi}.xml`, xmlFattura);

  res.type("text/plain").send("OK"); // esattamente OK: con qualsiasi altra risposta viene rimandata
});

app.listen(3000);

Rispondi OK con HTTP 200 solo dopo aver salvato la fattura. Se il tuo server non risponde riproviamo per circa 4 giorni: la stessa fattura può arrivare più volte, riconoscila da IdentificativoSdI.

Ricevere le notifiche SdI in Node.js

Ogni notifica dello SdI (consegna, scarto, mancata consegna, esiti della PA) arriva al tuo endpoint notifiche con i campi tipoNotifica e esitojson. Il significato di ogni notifica è spiegato nella guida alle notifiche SdI.

// Express - URL da indicare in "Endpoint ricezione notifiche" (firmaValida è la stessa dell'endpoint fatture)
const TIPI = { 1: "RC", 2: "MC", 3: "NS", 4: "NE", 5: "DT", 6: "AT" };
const STATI = {
  RC: "consegnata",
  MC: "mancata consegna: disponibile nel cassetto fiscale del cliente",
  NS: "scartata",              // i motivi sono in notifica.ListaErrori
  NE: "esito del committente", // solo PA: EsitoCommittente.Esito = EC01 accettata, EC02 rifiutata
  DT: "decorrenza termini",    // solo PA: nessuna risposta entro 15 giorni
  AT: "attestazione di avvenuta trasmissione",
};

app.post("/ricevi-notifiche", express.raw({ type: "*/*", limit: "5mb" }), async (req, res) => {
  if (!firmaValida(req, req.body)) return res.status(403).send("firma non valida");

  const dati = new URLSearchParams(req.body.toString());
  const tipo = TIPI[dati.get("tipoNotifica")];
  const notifica = JSON.parse(dati.get("esitojson") ?? "null"); // la notifica SdI convertita in JSON
  if (!tipo || !notifica) return res.status(400).send("dati mancanti");

  // IdentificativoSdI è lo stesso restituito dall'API all'invio (inoltro.id_sdi).
  // La stessa notifica può arrivare due volte: l'aggiornamento deve poter essere ripetuto.
  await aggiornaFattura(notifica.IdentificativoSdI, STATI[tipo], notifica);

  res.type("text/plain").send("OK"); // esattamente OK: con qualsiasi altra risposta viene rimandata
});

Prossimi passi

Inizia con Node.js

Prova gratis 30 giorni con 20 fatture, poi da 5 € al mese.