Vai al contenuto

Fattura elettronica con curl

curl è usato nelle righe di comando o negli script per trasferire dati. È onnipresente e usato quotidianamente da virtualmente ogni essere umano che usa Internet, anche se probabilmente a loro insaputa.

Un ovvio vantaggio di curl è che non hai bisogno di un linguaggio di programmazione (e tutta la toolchain che ne deriva) per lavorare con Invoicetronic API. Inoltre, curl è scriptabile, il che significa che puoi automatizzare attività tramite cronjobs o altri mezzi.

In questa guida rapida useremo curl per:

  1. Inviare una fattura allo SDI.
  2. Ricevere fatture dallo SDI

Prima di continuare, assicurati che tutti i prerequisiti sotto siano soddisfatti.

Prerequisiti

Assumiamo che questi prerequisiti siano soddisfatti:

Send

Con curl possiamo sfruttare l'endpoint API send/file per caricare un file:

curl -u "LA TUA TEST API KEY (inizia con ik_test_)": \
  -F "file=@path/to/file/filename.xml" \
  https://api.invoicetronic.com/v1/send/file | jq
Assicurati di inserire la tua test API Key, non quella live.

Le API Key vengono in coppia

Quando crei il tuo account, ottieni una coppia di API Key. Una è la chiave di test per la Sandbox API, e l'altra è quella live. Puoi notare la differenza perché la prima inizia con ik_test_, mentre la seconda inizia con ik_live_. In questo tutorial, usa sempre la chiave di test.

Alcune cose da notare:

  1. Aggiungiamo i due punti dopo la API key. Impedisce a curl di chiedere la password. Se dimentichi i due punti, curl diventerà interattivo e chiederà una password: lasciala vuota.
  2. Non dimenticare di iniziare il percorso del tuo file con il carattere @ iniziale.
  3. Il pipe | jq non è strettamente richiesto, ma produrrà un JSON piacevolmente leggibile. In uno script, potresti volerlo omettere.

Grazie al pipe jq, otteniamo una risposta JSON nell'output della console:

{
  "meta_data": null,
  ...
  "user_id": 1,
  "company_id": 13,
  "committente": "IT01234567891",
  "prestatore": "IT06157670966",
  "identifier": null,
  "file_name": "filename.xml",
  "format": "FPR12",
  "payload": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\...",
  "last_update": null,
  "date_sent": null,
  "documents": [
    {
      "number": "IT2368735",
      "date": "2024-05-31T22:00:00Z"
    }
  ],
  "encoding": "Xml",
  "id": 225,
  "created": "2025-01-23T16:55:51.491271Z",
}

Se inviamo la stessa richiesta di nuovo, otteniamo un risultato diverso:

{
  "problem_details": {
    "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
    "title": "Bad Request",
    "status": 400,
    "detail": "A file with the same name already exists."
  },
  "content_type": "application/problem+json",
  "status_code": 400
}
Otteniamo una risposta Bad Request perché, come riportato, una fattura con quel nome di file esiste già. Ovviamente, l'abbiamo appena caricata poco fa.

Se vogliamo gli header di risposta, proviamo qualcosa del genere:

curl -u "LA TUA TEST API KEY (inizia con ik_test_)": \
  -i -F "file=@path/to/file/filename.xml" \
  https://api.invoicetronic.com/v1/send/file

Abbiamo aggiunto l'opzione -i per ottenere gli header di risposta, ma abbiamo dovuto rinunciare al pipe jq poiché non stiamo più ottenendo un JSON valido, e jq fallirebbe:

HTTP/2 400
content-type: application/json; charset=utf-8
date: Thu, 23 Jan 2025 16:13:55 GMT
...

{"problem_details":{"type":"https://tools.ietf.org/html/rfc9110#section-15.5.1","title":"Bad Request","status":400,"detail":"A file with the same name already exists."},"content_type":"application/problem+json","status_code":400}

Infine, come salvare la risposta in un file? Con l'opzione -o di curl:

curl -u "LA TUA TEST API KEY (inizia con ik_test_)": \
  -o response.json -F "file=@path/to/file/filename.xml" \
  https://api.invoicetronic.com/v1/send/file

Nell'esempio sopra, il risultato va in response.json invece che nella console.

Validazione preventiva

La validazione preventiva viene richiesta con il parametro di query validate:

curl -u "LA TUA TEST API KEY (inizia con ik_test_)": \
  -o response.json -F "file=@path/to/file/filename.xml" \
  https://api.invoicetronic.com/v1/send/file?validate=true

Se la validazione fallisce, una risposta 400 Bad Request verrà restituita al client, con i problemi di validazione elencati nel suo body. Se la validazione ha successo, la fattura verrà archiviata e messa in coda per l'invio allo SDI, e una risposta 200 OK verrà inviata al client. Come ti aspetteresti, il parametro validate è disponibile su tutti gli endpoint POST: xml, json, file ed entity.

Firme digitali

Vogliamo caricare una fattura e applicare una firma digitale ad essa.

curl -u "LA TUA TEST API KEY (inizia con ik_test_)": \
  -o response.json -F "file=@path/to/file/filename.xml" \
  https://api.invoicetronic.com/v1/send/file?signature=Apply

Le firme digitali sono controllate dal parametro di query signature. Aggiungendo signature=Apply all'URL sopra, abbiamo richiesto che una firma digitale venga applicata alla fattura. Una volta applicata la firma, il nome del file viene aggiornato di conseguenza (filename.xml diventa filename.xml.p7m). Tieni presente che, se il documento inviato è già firmato, non verrà eseguita alcuna operazione per preservare la firma originale.

Allo stesso modo, signature=None impedisce che qualsiasi firma venga applicata a un documento. signature=None prevale anche sui documenti di tipo FPA12 non firmati (uffici della pubblica amministrazione) che altrimenti verrebbero firmati per impostazione predefinita, poiché le firme sono obbligatorie su di essi.

Il corpo della risposta verrà aggiornato per riflettere le modifiche apportate al documento. Considera la richiesta di esempio sopra. Abbiamo inviato un file XML semplice, richiedendo che venga firmato digitalmente prima di essere inviato allo SDI. Una tipica risposta API a una richiesta del genere sarebbe così:

{
  ...
  "file_name": "filename.xml.p7m",
  "format": "FPR12",
  "payload": "MII...",
  ...
  "encoding": "Base64",
  "id": 225,
  "created": "2025-01-23T16:55:51.491271Z",
}

L'estensione p7m è stata aggiunta a file_name. Poiché il suo contenuto è ora firmato digitalmente, payload è codificato in Base64, e la proprietà encoding lo riflette.

Receive

Vogliamo scaricare fatture non lette dallo SDI. Ecco come lo realizziamo con curl:

curl -u "LA TUA TEST API KEY (inizia con ik_test_)": \
  "https://api.invoicetronic.com/v1/receive?unread=true&include_payload=true" | jq

Assicurati di inserire la tua test API Key, non quella live.

Le API Key vengono in coppia

Quando crei il tuo account, ottieni una coppia di API Key. Una è la chiave di test per la Sandbox API, e l'altra è quella live. Puoi notare la differenza perché la prima inizia con ik_test_, mentre la seconda inizia con ik_live_. In questo tutorial, usa sempre la chiave di test.

Alcune cose da notare:

  1. Aggiungiamo i due punti dopo la API key. Impedisce a curl di chiedere la password. Se dimentichi i due punti, curl diventerà interattivo e chiederà una password: lasciala vuota.
  2. Stiamo aggiungendo ?unread=true alla nostra query perché vogliamo solo fatture che non abbiamo scaricato prima.
  3. Stiamo aggiungendo &include_payload=true per recuperare il contenuto effettivo della fattura. Senza questo parametro, il campo payload sarà null per impostazione predefinita.
  4. Poiché stiamo aggiungendo argomenti di query (e non vogliamo avere a che fare con caratteri di escape), dobbiamo racchiudere l'intera query tra virgolette doppie.
  5. Il pipe | jq non è strettamente richiesto, ma produrrà un JSON piacevolmente leggibile. Potresti volerlo omettere in uno script.

Grazie al pipe jq otteniamo una risposta JSON come questa:

[
  {
    "is_read": false,
    "message_id": "234234234",
    "user_id": 1,
    "company_id": 1,
    "committente": "IT01180680397",
    "prestatore": "IT06157670966",
    "identifier": "234234",
    "file_name": "filename.xml",
    "format": "FPR12",
    "payload": "PD94bWwgdmVyc2lvbj0i...",
    "last_update": "2025-01-21T15:39:55.734848Z",
    "date_sent": null,
    "documents": [
      {
        "number": "123",
        "date": "2024-05-31T22:00:00Z"
      }
    ],
    "encoding": "Base64",
    "id": 48,
    "created": "2025-01-21T15:39:28.57467Z",
    "version": 1781881
  }
]

Inclusione del Payload

La risposta sopra include il campo payload con il contenuto effettivo della fattura perché abbiamo aggiunto include_payload=true alla richiesta. Senza questo parametro, il campo payload sarebbe null, il che migliora le prestazioni e riduce la dimensione della risposta quando hai bisogno solo dei metadati.

Nell'esempio sopra, abbiamo ricevuto una lista di un solo documento. Se rinviamo la stessa richiesta, però, otteniamo un risultato diverso:

[]

Otteniamo una lista vuota perché abbiamo richiesto documenti non letti, e ora non ce ne sono (abbiamo letto l'ultimo nuovo poco fa).

Se vogliamo anche gli header di risposta, proviamo qualcosa del genere:

curl -i -u "LA TUA TEST API KEY (inizia con ik_test_)": \
  "https://api.invoicetronic.com/v1/receive?unread=true&include_payload=true"

Abbiamo aggiunto l'opzione -i per ottenere gli header di risposta, ma abbiamo dovuto rinunciare al pipe jq poiché non stiamo più ottenendo un JSON valido:

HTTP/2 200
content-type: application/json; charset=utf-8
date: Thu, 23 Jan 2025 16:47:44 GMT
...

[]

Infine, come salvare la risposta in un file? Con l'opzione -o di curl:

curl -i -o response.json -u "LA TUA TEST API KEY (inizia con ik_test_)": \
  "https://api.invoicetronic.com/v1/receive?unread=true&include_payload=true"

Nell'esempio sopra, il risultato va in response.json invece che nella console.

Non ricevi fatture nell'ambiente live?

Assicurati che i tuoi corrispondenti usino 7HD37X0 come valore del campo Codice Destinatario delle loro fatture. È così che lo SDI sa che dovrebbero essere inoltrate a Invoicetronic API.

Cosa abbiamo imparato

Abbiamo imparato come usare curl per inviare e ricevere fatture. curl è ovunque, non ci richiede di usare un linguaggio di programmazione o SDK ed è scriptabile. È molto potente e ti permette di eseguire varie attività, ma può essere piuttosto complesso da padroneggiare con tutte le sue numerose opzioni, fischietti e campane.

Se tutto ciò che cerchi è inviare e ricevere fatture dalla riga di comando, potresti voler dare un'occhiata al nostro strumento invoice.