Fattura elettronica in PHP
Questo tutorial crea tre semplici applicazioni PHP da zero:
- Receive: si connette e autentica con Invoicetronic API e scarica eventuali nuove fatture in arrivo.
- Send: si connette e autentica con Invoicetronic API e invia una fattura allo SDI.
- Update: si connette e autentica con Invoicetronic API e consulta la cronologia delle notifiche restituite dallo SDI.
Prima di continuare, assicurati che tutti i prerequisiti sotto siano soddisfatti.
Prerequisiti
Presupponiamo che questi prerequisiti siano soddisfatti:
- PHP 7.4+ o PHP 8.x è stato scaricato e installato
- Composer è stato installato
- Hai ottenuto una Chiave API attiva
- Ti sei registrato presso l'Agenzia delle Entrate (necessario per l'ambiente di produzione)
Utilizziamo Composer per la gestione delle dipendenze, che è lo standard de facto per PHP moderno.
Tip
Per un'esperienza PHP ottimale, considera l'uso di VS Code con l'estensione PHP o PHPStorm per un IDE completo.
Lo sapevi?
L'SDK PHP supporta sia Guzzle che altri client HTTP compatibili con PSR-18, offrendoti flessibilità nell'implementazione.
Receive
Crea l'app
Il primo passo è creare la directory dell'applicazione:
Inizializza il progetto con Composer:
Il comando ha creato un nuovo progetto PHP con un file composer.json nella directory corrente.
Installa l'SDK
Installa l'SDK PHP di Invoicetronic:
Una volta completato, apri VS Code nella directory corrente:
Configura l'SDK
Crea un nuovo file chiamato index.php e aggiungi il seguente codice:
<?php
require_once(__DIR__ . '/vendor/autoload.php');
// Configura l'SDK
$config = Invoicetronic\Configuration::getDefaultConfiguration()
->setUsername('LA TUA CHIAVE API DI TEST (inizia con ik_test_)');
$config->setHost('https://api.invoicetronic.com/v1');
Come puoi vedere, configuriamo l'SDK impostando l'host dell'API e la tua chiave API di test (non quella live). Nota come utilizziamo il metodo setUsername() per impostare la chiave API.
Le chiavi API vengono fornite in coppia
Quando crei il tuo account, ottieni una coppia di chiavi API. Una è la chiave di test per la Sandbox API, e l'altra è quella live dell'API. Puoi distinguerle perché la prima inizia con ik_test_, mentre la seconda inizia con ik_live_. In questo tutorial, usa sempre la chiave di test.
Scarica le fatture
Siamo pronti per effettuare una richiesta. Vogliamo scaricare nuove fatture dei fornitori che potrebbero essere disponibili dallo SDI. Aggiungi queste righe:
// Scarica le fatture non lette
$receiveApi = new Invoicetronic\Api\ReceiveApi(
new GuzzleHttp\Client(),
$config
);
try {
$inboundInvoices = $receiveApi->receiveGet(
null, // page
null, // pageSize
null, // sort
true, // unread
true // includePayload
);
echo "Ricevute " . count($inboundInvoices) . " fatture\n";
foreach ($inboundInvoices as $invoice) {
if ($invoice->getEncoding() === 'Xml') {
file_put_contents($invoice->getFileName(), $invoice->getPayload());
} elseif ($invoice->getEncoding() === 'Base64') {
file_put_contents($invoice->getFileName(), base64_decode($invoice->getPayload()));
}
echo "Scaricato {$invoice->getFileName()} da un fornitore con Partita IVA {$invoice->getPrestatore()}\n";
}
} catch (Exception $e) {
echo 'Errore: ' . $e->getMessage() . "\n";
}
Inclusione del Payload
Impostiamo includePayload: true per recuperare il contenuto effettivo della fattura nella proprietà payload. Senza questo parametro, il campo payload sarebbe null per impostazione predefinita, il che aumenta le prestazioni e riduce le dimensioni della risposta quando hai bisogno solo dei metadati.
Nel terminale, esegui l'applicazione:
Dovresti ottenere un output simile a questo:
Ricevute 3 fatture
Scaricato file1.xml da un fornitore con Partita IVA IT06157670966
Scaricato file2.xml.p7m da un fornitore con Partita IVA IT01280270057
Scaricato file3.xml.p7m da un fornitore con Partita IVA IT01280270057
I file sono nella directory corrente, pronti per essere ispezionati.
Non ricevi fatture nell'ambiente di produzione?
Assicurati di esserti registrato presso l'Agenzia delle Entrate, che è un requisito per l'ambiente di produzione.
Cosa abbiamo imparato
In questo esempio, abbiamo imparato diverse cose.
-
Dobbiamo configurare l'SDK chiamando
getDefaultConfiguration()e impostando l'username (chiave API) consetUsername()e l'host consetHost(). -
Dobbiamo istanziare una classe che rappresenta l'endpoint con cui vogliamo lavorare. In questo caso, sfruttiamo
ReceiveApiper scaricare le fatture in arrivo, passando un client HTTP (Guzzle) e la configurazione. -
Le classi endpoint come
ReceiveApioffrono metodi per interagire con la loro entità target. ChiamiamoreceiveGet()per recuperare le fatture. Poiché vogliamo solo fatture nuove e non lette, passiamotrueper il parametrounread. Passiamo anchetrueperincludePayloadper recuperare il contenuto effettivo della fattura. -
Gli oggetti fattura espongono metodi come
getEncoding(),getFileName()egetPayload(). Quest'ultimo contiene il contenuto della fattura, come testo normale o codificato in Base64, come descritto dagetEncoding().
Codice sorgente su GitHub
Il codice sorgente per questo Quickstart è disponibile anche su GitHub.
Send
Crea l'app
Il primo passo è creare la directory dell'applicazione:
Inizializza il progetto con Composer:
Installa l'SDK
Installa l'SDK PHP di Invoicetronic:
Una volta completato, apri VS Code nella directory corrente:
Configura l'SDK
Crea un nuovo file chiamato index.php e aggiungi il seguente codice:
<?php
require_once(__DIR__ . '/vendor/autoload.php');
// Configura l'SDK
$config = Invoicetronic\Configuration::getDefaultConfiguration()
->setUsername('LA TUA CHIAVE API DI TEST (inizia con ik_test_)');
$config->setHost('https://api.invoicetronic.com/v1');
Come puoi vedere, configuriamo l'SDK impostando l'host dell'API e la tua chiave API di test (non quella live). Nota come utilizziamo il metodo setUsername() per impostare la chiave API.
Le chiavi API vengono fornite in coppia
Quando crei il tuo account, ottieni una coppia di chiavi API. Una è la chiave di test per la Sandbox API, e l'altra è quella live dell'API. Puoi distinguerle perché la prima inizia con ik_test_, mentre la seconda inizia con ik_live_. In questo tutorial, usa sempre la chiave di test.
Invia una fattura
Siamo pronti per effettuare una richiesta. Vogliamo inviare una fattura allo SDI. Aggiungi il seguente codice:
// Invia una fattura
$filePath = '/qualche/percorso/file/nomefile.xml';
$metaData = [
'internal_id' => '123',
'created_with' => 'myapp',
'some_other_custom_data' => 'value'
];
$sendApi = new Invoicetronic\Api\SendApi(
new GuzzleHttp\Client(),
$config
);
try {
$sendData = new Invoicetronic\Model\Send();
$sendData->setFileName(basename($filePath));
$sendData->setPayload(file_get_contents($filePath));
$sendData->setMetaData($metaData);
$sentInvoice = $sendApi->sendPost($sendData);
echo "La fattura è stata inviata con successo, ora ha l'Id univoco {$sentInvoice->getId()}.\n";
} catch (Exception $e) {
echo 'Errore: ' . $e->getMessage() . "\n";
}
Nel terminale, esegui l'applicazione:
Dovresti ottenere un output simile a questo:
Verificare lo stato della fattura
Quando inoltri una fattura allo SDI, la consegna non è istantanea: l'SDI esegue dei controlli e restituisce una sequenza di notifiche che descrivono lo stato del processo (Inviato, Consegnato, Scartato, ecc.). La classe Send espone il metodo getLatestState() con lo stato corrente, evitando una chiamata separata a /update quando ti serve sapere solo come è andata.
// Recupera lo stato più recente di una fattura già inviata
$fresh = $sendApi->sendIdGet($sentInvoice->getId());
echo "Stato corrente: " . ($fresh->getLatestState() ?? 'In elaborazione') . "\n";
Subito dopo l'invio, getLatestState() può restituire null: l'SDI non ha ancora processato il documento. Ricontrolla dopo qualche secondo o, meglio, configura un webhook per ricevere una notifica push ad ogni cambio di stato.
Risparmia richieste API
Usa getLatestState() su Send ogni volta che ti serve solo lo stato corrente: una sola chiamata invece di una a /send più una a /update. Ricorri a UpdateApi solo quando ti serve la cronologia completa delle transizioni.
Cosa abbiamo imparato
In questo esempio, abbiamo imparato diverse cose.
-
Dobbiamo configurare l'SDK chiamando
getDefaultConfiguration()e impostando l'username (chiave API) consetUsername()e l'host consetHost(). -
Dobbiamo istanziare una classe che rappresenta l'endpoint con cui vogliamo lavorare. In questo caso, sfruttiamo
SendApiper inviare fatture. Le classi endpoint comeSendApioffrono metodi per interagire con la loro entità target. ChiamiamosendPost()per inviare una fattura. -
La classe
Sendespone metodi comesetFileName(),setMetaData()esetPayload(). Quest'ultimo contiene il contenuto della fattura, mentresetMetaData()è opzionale e associa dati personalizzati al documento. -
La classe
Sendespone anchegetLatestState()con lo stato SDI corrente, leggibile viasendIdGet($id). Evita una chiamata a/updatequando serve solo conoscere lo stato.
Codice sorgente su GitHub
Il codice sorgente per questo Quickstart è disponibile anche su GitHub.
Update
Per lo stato corrente di una fattura inviata, è sufficiente leggere getLatestState() dalla classe Send (vedi Verificare lo stato della fattura). Se invece vuoi la cronologia completa delle transizioni — per esempio per capire perché una fattura è stata scartata, mostrare in UI tutti i passaggi di stato con timestamp, o tracciare le notifiche restituite da un ente della Pubblica Amministrazione — usa UpdateApi.
Le query su /update sono gratuite
Le richieste a /update non vengono conteggiate sul tuo piano: puoi consultare la cronologia delle notifiche con la frequenza che preferisci.
Crea l'app
mkdir update && cd update
composer init --name="invoicetronic/update-example" --type=project --no-interaction
Installa l'SDK
Recuperare la cronologia delle notifiche
Crea un file index.php con il seguente codice:
<?php
require_once(__DIR__ . '/vendor/autoload.php');
// Configura l'SDK
$config = Invoicetronic\Configuration::getDefaultConfiguration()
->setUsername('LA TUA CHIAVE API DI TEST (inizia con ik_test_)');
$config->setHost('https://api.invoicetronic.com/v1');
// Id della fattura inviata di cui vogliamo ricostruire la cronologia
$sendId = 225;
$updateApi = new Invoicetronic\Api\UpdateApi(
new GuzzleHttp\Client(),
$config
);
try {
$updates = $updateApi->updateGet(
null, // companyId
null, // identifier
null, // prestatore
null, // unread
$sendId, // sendId
null, // state
null, // lastUpdateFrom
null, // lastUpdateTo
null, // dateSentFrom
null, // dateSentTo
null, // page
null, // pageSize
'last_update' // sort
);
echo "Trovate " . count($updates) . " notifiche per la fattura {$sendId}\n";
foreach ($updates as $update) {
$description = $update->getDescription() ?: 'OK';
echo " [{$update->getLastUpdate()->format('c')}] state={$update->getState()} - {$description}\n";
}
} catch (Exception $e) {
echo 'Errore: ' . $e->getMessage() . "\n";
}
Esegui l'applicazione:
Dovresti ottenere un output simile a questo:
Trovate 2 notifiche per la fattura 225
[2025-01-23T16:56:14+00:00] state=Inviato - OK
[2025-01-23T17:12:03+00:00] state=Consegnato - OK
Il campo state è la proprietà più importante. I valori più comuni sono:
| Valore | Nome | Descrizione |
|---|---|---|
| 2 | Inviato |
Inviata allo SDI. |
| 5 | Consegnato |
Consegnata al destinatario. |
| 7 | Scartato |
Rifiutata dallo SDI. In description trovi il motivo. |
L'elenco completo dei valori è disponibile nella API Reference.
Monitora sempre lo stato delle fatture inviate
Lo stato Inviato significa solo che il documento è stato preso in carico dallo SDI, non che sia stato consegnato. Uno stato Scartato indica che la fattura non è stata accettata e potrebbe richiedere una correzione e un nuovo invio.
Cosa abbiamo imparato
-
Per consultare la cronologia delle notifiche utilizziamo la classe
UpdateApiinvece diSendApioReceiveApi. -
Il metodo
updateGet()accetta filtri comesendId(per le notifiche di una specifica fattura inviata),state(per filtrare per stato),lastUpdateFrom/lastUpdateTo(intervallo temporale) e altri. -
Le query su
/updatesono gratuite e non vengono conteggiate sul tuo piano, quindi puoi richiamarle con la frequenza che ti serve.
Codice sorgente su GitHub
Il codice sorgente per questo Quickstart è disponibile anche su GitHub.