# REST API

> Tutte le operazioni REST con parametri, corpo della richiesta, risposte ed errori, generate dalla specifica OpenAPI.

Pagina HTML: https://app.billyssw.it/documentazione/api  
Indice della documentazione: https://app.billyssw.it/documentazione/index.md  
Tutta la documentazione in un file: https://app.billyssw.it/documentazione/full.md

Tutte le operazioni pubblicate dell'API fiscale, generate dalla specifica OpenAPI (https://app.billyssw.it/documentazione/openapi.json).

I percorsi sono relativi al base URL dell'ambiente: in staging `https://pem-staging.billyssw.it` (vedi Base URL, https://app.billyssw.it/documentazione/ambienti). Ogni richiesta porta `Accept: application/json`.

## Autenticazione

Il bearer è un <b>access token</b> del realm Keycloak <code>billy</code>, ottenuto con Authorization Code + PKCE e il consenso dell'esercente. Per i client partner vale 10 minuti: alla scadenza (401 con <code>error: token_expired</code>) se ne chiede uno nuovo al token endpoint del realm con il <code>refresh_token</code>. Ogni endpoint dichiara lo scope richiesto ai client partner; quelli riservati all'app e al pannello Billy rispondono 403 a un client partner.

- Autorizzazione: `https://auth.billyssw.it/realms/billy/protocol/openid-connect/auth`
- Token e rinnovo: `https://auth.billyssw.it/realms/billy/protocol/openid-connect/token`

| Scope | Descrizione |
| --- | --- |
| `fiscale:read` | Leggere lo stato dei PEM, consultare documenti commerciali e report |
| `fiscale:manage` | Emettere documenti commerciali, annulli, resi e documenti gestionali, eseguire la chiusura giornaliera e di emergenza, gestire il PEM (cambio stato, dismissione, cambio sede, periodi di inattività) |
| `catalogo:read` | Leggere reparti e codici ATECO |
| `catalogo:write` | Creare, modificare ed eliminare reparti, categorie e codici ATECO |
| `offline_access` | Refresh token di lunga durata (sessione offline) |

## Indice delle operazioni
- **Account - Registrazione**
  - [POST /api/auth/register](https://app.billyssw.it/documentazione/api#post-api-auth-register): Richiesta di registrazione esercente
- **Anagrafica - PEM**
  - [GET /api/pem](https://app.billyssw.it/documentazione/api#get-api-pem): Lista PEM
  - [GET /api/pem/{serial_number}](https://app.billyssw.it/documentazione/api#get-api-pem-serial_number): Mostra PEM
  - [POST /api/pem/{serial_number}/cambio-sede](https://app.billyssw.it/documentazione/api#post-api-pem-serial_number-cambio-sede): Richiedi il cambio sede
  - [DELETE /api/pem/{serial_number}/cambio-sede/{cambio_sede}](https://app.billyssw.it/documentazione/api#delete-api-pem-serial_number-cambio-sede-cambio_sede): Annulla il cambio sede
- **Catalogo - ATECO**
  - [GET /api/pem/{serial_number}/dati/ateco](https://app.billyssw.it/documentazione/api#get-api-pem-serial_number-dati-ateco): Lista ATECO
  - [POST /api/pem/{serial_number}/dati/ateco](https://app.billyssw.it/documentazione/api#post-api-pem-serial_number-dati-ateco): Crea ATECO
  - [PUT /api/pem/{serial_number}/dati/ateco/{id}](https://app.billyssw.it/documentazione/api#put-api-pem-serial_number-dati-ateco-id): Aggiorna ATECO
  - [DELETE /api/pem/{serial_number}/dati/ateco/{id}](https://app.billyssw.it/documentazione/api#delete-api-pem-serial_number-dati-ateco-id): Elimina ATECO
- **Catalogo - Reparti**
  - [GET /api/pem/{serial_number}/dati/reparti](https://app.billyssw.it/documentazione/api#get-api-pem-serial_number-dati-reparti): Lista Reparti
  - [POST /api/pem/{serial_number}/dati/reparti](https://app.billyssw.it/documentazione/api#post-api-pem-serial_number-dati-reparti): Crea Reparto
  - [PUT /api/pem/{serial_number}/dati/reparti/{reparto_id}](https://app.billyssw.it/documentazione/api#put-api-pem-serial_number-dati-reparti-reparto_id): Aggiorna Reparto
  - [DELETE /api/pem/{serial_number}/dati/reparti/{reparto_id}](https://app.billyssw.it/documentazione/api#delete-api-pem-serial_number-dati-reparti-reparto_id): Elimina Reparto
- **Funzioni fiscali - Consultazione**
  - [GET /api/pem/{serial_number}/fiscale/chiusure/storico](https://app.billyssw.it/documentazione/api#get-api-pem-serial_number-fiscale-chiusure-storico): Storico chiusure
  - [GET /api/pem/{serial_number}/fiscale/chiusure/{journalId}/documento](https://app.billyssw.it/documentazione/api#get-api-pem-serial_number-fiscale-chiusure-journalid-documento): Dati di una chiusura
  - [POST /api/pem/{serial_number}/fiscale/consultazione/report](https://app.billyssw.it/documentazione/api#post-api-pem-serial_number-fiscale-consultazione-report): Report
  - [GET /api/pem/{serial_number}/fiscale/consultazione/dc](https://app.billyssw.it/documentazione/api#get-api-pem-serial_number-fiscale-consultazione-dc): Dettaglio di un DC
  - [GET /pem/{serial_number}/fiscale/consultazione/dc/{hash}/pdf](https://app.billyssw.it/documentazione/api#get-pem-serial_number-fiscale-consultazione-dc-hash-pdf): PDF pubblico di un DC
- **Funzioni fiscali - Controllo PEM**
  - [GET /api/pem/{serial_number}/controllo](https://app.billyssw.it/documentazione/api#get-api-pem-serial_number-controllo): Dati di controllo AdE del PEM
  - [POST /api/pem/{serial_number}/fiscale/gestionali/controllo](https://app.billyssw.it/documentazione/api#post-api-pem-serial_number-fiscale-gestionali-controllo): Emetti Documento Gestionale di Controllo
- **Funzioni fiscali - Documenti gestionali**
  - [GET /api/pem/{serial_number}/fiscale/gestionali](https://app.billyssw.it/documentazione/api#get-api-pem-serial_number-fiscale-gestionali): Archivio documenti gestionali
  - [GET /api/pem/{serial_number}/fiscale/gestionali/{id}/pdf](https://app.billyssw.it/documentazione/api#get-api-pem-serial_number-fiscale-gestionali-id-pdf): Download di un documento gestionale archiviato
  - [POST /api/pem/{serial_number}/fiscale/gestionali/operazioni](https://app.billyssw.it/documentazione/api#post-api-pem-serial_number-fiscale-gestionali-operazioni): Documento gestionale operazioni memorizzate
  - [POST /api/pem/{serial_number}/fiscale/gestionali/esiti-trasmissione](https://app.billyssw.it/documentazione/api#post-api-pem-serial_number-fiscale-gestionali-esiti-trasmissione): Documento gestionale esiti trasmissioni corrispettivi
  - [POST /api/pem/{serial_number}/fiscale/gestionali/storico-buoni-pasto](https://app.billyssw.it/documentazione/api#post-api-pem-serial_number-fiscale-gestionali-storico-buoni-pasto): Documento gestionale storico opzione buoni pasto
  - [POST /api/pem/{serial_number}/fiscale/gestionali/chiusura/{journalId}](https://app.billyssw.it/documentazione/api#post-api-pem-serial_number-fiscale-gestionali-chiusura-journalid): Documento gestionale di chiusura
- **Funzioni fiscali - Emergenza**
  - [POST /api/pem/{serial_number}/fiscale/emergenza/chiusura](https://app.billyssw.it/documentazione/api#post-api-pem-serial_number-fiscale-emergenza-chiusura): Chiusura di emergenza
- **Funzioni fiscali - Opzione buoni pasto**
  - [GET /api/pem/{serial_number}/fiscale/opzione-buoni-pasto](https://app.billyssw.it/documentazione/api#get-api-pem-serial_number-fiscale-opzione-buoni-pasto): Stato opzione buoni pasto
  - [POST /api/pem/{serial_number}/fiscale/opzione-buoni-pasto](https://app.billyssw.it/documentazione/api#post-api-pem-serial_number-fiscale-opzione-buoni-pasto): Attiva/disattiva opzione buoni pasto
  - [GET /api/pem/{serial_number}/fiscale/opzione-buoni-pasto/storico](https://app.billyssw.it/documentazione/api#get-api-pem-serial_number-fiscale-opzione-buoni-pasto-storico): Storico opzione buoni pasto
- **Funzioni fiscali - Richieste PEM**
  - [GET /api/pem/{serial_number}/fiscale/richieste](https://app.billyssw.it/documentazione/api#get-api-pem-serial_number-fiscale-richieste): Lista richieste
  - [GET /api/pem/{serial_number}/fiscale/richieste/stato/{idRichiesta}](https://app.billyssw.it/documentazione/api#get-api-pem-serial_number-fiscale-richieste-stato-idrichiesta): Verifica stato richiesta
  - [GET /api/pem/{serial_number}/fiscale/richieste/esito/{idRichiesta}](https://app.billyssw.it/documentazione/api#get-api-pem-serial_number-fiscale-richieste-esito-idrichiesta): Recupera esito richiesta
- **Funzioni fiscali - Segnalazioni**
  - [GET /api/pem/{serial_number}/fiscale/segnalazioni/inattivita](https://app.billyssw.it/documentazione/api#get-api-pem-serial_number-fiscale-segnalazioni-inattivita): Periodi di inattività
  - [POST /api/pem/{serial_number}/fiscale/segnalazioni/inattivita](https://app.billyssw.it/documentazione/api#post-api-pem-serial_number-fiscale-segnalazioni-inattivita): Segnala un periodo di inattività
- **Funzioni fiscali - Stato PEM**
  - [GET /api/pem/{serial_number}/fiscale/stati](https://app.billyssw.it/documentazione/api#get-api-pem-serial_number-fiscale-stati): Lista Stati PEM
  - [PUT /api/pem/{serial_number}/fiscale/stato](https://app.billyssw.it/documentazione/api#put-api-pem-serial_number-fiscale-stato): Modifica lo stato del PEM
  - [POST /api/pem/{serial_number}/fiscale/stato/dismissione](https://app.billyssw.it/documentazione/api#post-api-pem-serial_number-fiscale-stato-dismissione): Dismissione del PEM
- **Funzioni fiscali - Trasmissioni**
  - [POST /api/pem/{serial_number}/fiscale/invio/dc](https://app.billyssw.it/documentazione/api#post-api-pem-serial_number-fiscale-invio-dc): Invio DC
  - [POST /api/pem/{serial_number}/fiscale/invio/annullo](https://app.billyssw.it/documentazione/api#post-api-pem-serial_number-fiscale-invio-annullo): Annulla DC
  - [GET /api/pem/{serial_number}/fiscale/invio/reso](https://app.billyssw.it/documentazione/api#get-api-pem-serial_number-fiscale-invio-reso): Recupera dati reso DC
  - [POST /api/pem/{serial_number}/fiscale/invio/reso](https://app.billyssw.it/documentazione/api#post-api-pem-serial_number-fiscale-invio-reso): Reso DC
  - [POST /api/pem/{serial_number}/fiscale/invio/chiusura](https://app.billyssw.it/documentazione/api#post-api-pem-serial_number-fiscale-invio-chiusura): Chiusura giornaliera

## Account - Registrazione

<a id="post-api-auth-register"></a>

### Richiesta di registrazione esercente

`POST /api/auth/register`

Pubblica: nessun token.

Registra la richiesta di adesione di un esercente, senza credenziali: la
esamina l'erogatore e, all'approvazione, l'esercente riceve l'email per
scegliere la password. `affiliate_code` è il codice del partner che
l'ha portato (`AFF-…`), facoltativo.

**Corpo della richiesta** (`application/json`, obbligatorio)

| Campo | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `nome` | `string` | sì | Nome del titolare. Al massimo 60 caratteri. Esempio: `Mario`. |
| `cognome` | `string` | sì | Cognome del titolare. Al massimo 60 caratteri. Esempio: `Rossi`. |
| `email` | `string` | sì | Email del titolare, unica: è l'indirizzo dell'account Billy ed è anche il nome utente dell'account. Non si può cambiare dopo l'approvazione. Deve essere un indirizzo email valido. Al massimo 80 caratteri. Esempio: `mario.rossi@example.it`. |
| `telefono` | `string` | sì | Telefono, da 6 a 11 cifre; il prefisso +39 o 0039, gli spazi e i separatori vengono tolti. Formato: <code>/^\d{6,11}$/</code>. Esempio: `3331234567`. |
| `partita_iva` | `string` | sì | Partita IVA dell'attività, verificata e unica. Va inviata come stringa: un numero JSON perderebbe gli zeri iniziali ed è rifiutato. Esempio: `01234567897`. |
| `codice_fiscale` | `string` | sì | Codice fiscale dell'attività o del titolare: 16 caratteri con carattere di controllo valido (omocodie ammesse, convertito in maiuscolo), oppure 11 cifre per le società, di solito uguali alla partita IVA. Esempio: `RSSMRA80A01F205X`. |
| `denominazione` | `string` | sì | Denominazione dell'attività. Al massimo 80 caratteri. Esempio: `Bar Centrale di Mario Rossi`. |
| `indirizzo` | `string` | sì | Indirizzo della sede legale. Al massimo 60 caratteri. Esempio: `Via Roma`. |
| `civico` | `string` | sì | Numero civico della sede legale. Al massimo 8 caratteri. Esempio: `1`. |
| `cap` | `string` | sì | CAP della sede legale, 5 cifre. Deve essere composto da 5 cifre. Esempio: `20121`. |
| `comune` | `string` | sì | Comune della sede legale. Al massimo 60 caratteri. Esempio: `Milano`. |
| `provincia` | `string` | sì | Sigla della provincia (elenco ISTAT; `EE` per l'estero). Deve essere lungo 2 caratteri. Valori: `AG`, `AL`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AT`, `AV`, `BA`, `BG`, `BI`, `BL`, `BN`, `BO`, `BR`, `BS`, `BT`, `BZ`, `CA`, `CB`, `CE`, `CH`, `CL`, `CN`, `CO`, `CR`, `CS`, `CT`, `CZ`, `EN`, `FC`, `FE`, `FG`, `FI`, `FM`, `FR`, `GE`, `GO`, `GR`, `IM`, `IS`, `KR`, `LC`, `LE`, `LI`, `LO`, `LT`, `LU`, `MB`, `MC`, `ME`, `MI`, `MN`, `MO`, `MS`, `MT`, `NA`, `NO`, `NU`, `OR`, `PA`, `PC`, `PD`, `PE`, `PG`, `PI`, `PN`, `PO`, `PR`, `PT`, `PU`, `PV`, `PZ`, `RA`, `RC`, `RE`, `RG`, `RI`, `RM`, `RN`, `RO`, `SA`, `SI`, `SO`, `SP`, `SR`, `SS`, `SU`, `SV`, `TA`, `TE`, `TN`, `TO`, `TP`, `TR`, `TS`, `TV`, `UD`, `VA`, `VB`, `VC`, `VE`, `VI`, `VR`, `VT`, `VV`, `EE`. Esempio: `MI`. |
| `nazione` | `string` | sì | Codice della nazione, 2 caratteri. Deve essere lungo 2 caratteri. Esempio: `IT`. |
| `pec` | `string` | no | PEC dell'attività, facoltativa. Deve essere un indirizzo email valido. Al massimo 80 caratteri. Può essere `null`. Esempio: `barcentrale@pec.it`. |
| `sdi` | `string` | no | Codice destinatario SDI, 7 lettere o cifre (convertito in maiuscolo), facoltativo. Formato: <code>/^[A-Z0-9]{7}$/</code>. Deve essere lungo 7 caratteri. Può essere `null`. Esempio: `M5UXCR1`. |
| `regime_fiscale` | `string` | sì | Regime fiscale dell'attività. Valori: `ordinario`, `semplificato`, `forfettario_minimo`. Esempio: `ordinario`. |
| `sede_operativa` | `object` | no | Facoltativa: sede e referente del punto vendita, sede del primo PEM. Se manca, è `null` o è vuota vale la sede legale con i dati del titolare. Può essere `null`. |
| `sede_operativa.nome_referente` | `string` | sì | Al massimo 60 caratteri. Esempio: `Mario`. |
| `sede_operativa.cognome_referente` | `string` | sì | Al massimo 60 caratteri. Esempio: `Rossi`. |
| `sede_operativa.email_referente` | `string` | sì | Deve essere un indirizzo email valido. Al massimo 80 caratteri. Esempio: `mario.rossi@example.it`. |
| `sede_operativa.telefono_referente` | `string` | sì | Formato: <code>/^\d{6,11}$/</code>. Esempio: `3331234567`. |
| `sede_operativa.indirizzo` | `string` | sì | Al massimo 60 caratteri. Esempio: `Corso Buenos Aires`. |
| `sede_operativa.civico` | `string` | sì | Al massimo 8 caratteri. Esempio: `10`. |
| `sede_operativa.cap` | `string` | sì | Deve essere composto da 5 cifre. Esempio: `20124`. |
| `sede_operativa.comune` | `string` | sì | Al massimo 60 caratteri. Esempio: `Milano`. |
| `sede_operativa.provincia` | `string` | sì | Deve essere lungo 2 caratteri. Valori: `AG`, `AL`, `AN`, `AO`, `AP`, `AQ`, `AR`, `AT`, `AV`, `BA`, `BG`, `BI`, `BL`, `BN`, `BO`, `BR`, `BS`, `BT`, `BZ`, `CA`, `CB`, `CE`, `CH`, `CL`, `CN`, `CO`, `CR`, `CS`, `CT`, `CZ`, `EN`, `FC`, `FE`, `FG`, `FI`, `FM`, `FR`, `GE`, `GO`, `GR`, `IM`, `IS`, `KR`, `LC`, `LE`, `LI`, `LO`, `LT`, `LU`, `MB`, `MC`, `ME`, `MI`, `MN`, `MO`, `MS`, `MT`, `NA`, `NO`, `NU`, `OR`, `PA`, `PC`, `PD`, `PE`, `PG`, `PI`, `PN`, `PO`, `PR`, `PT`, `PU`, `PV`, `PZ`, `RA`, `RC`, `RE`, `RG`, `RI`, `RM`, `RN`, `RO`, `SA`, `SI`, `SO`, `SP`, `SR`, `SS`, `SU`, `SV`, `TA`, `TE`, `TN`, `TO`, `TP`, `TR`, `TS`, `TV`, `UD`, `VA`, `VB`, `VC`, `VE`, `VI`, `VR`, `VT`, `VV`, `EE`. Esempio: `MI`. |
| `sede_operativa.nazione` | `string` | sì | Deve essere lungo 2 caratteri. Esempio: `IT`. |
| `affiliate_code` | `string` | no | Codice del partner affiliato che ha portato l'esercente, facoltativo. Al massimo 32 caratteri. Può essere `null`. Esempio: `AFF-7K2M9QXA`. |
| `privacy` | `boolean` | sì | Accettazione dell'informativa privacy. Deve valere true. Esempio: `true`. |

Esempio:

```json
{
    "nome": "Mario",
    "cognome": "Rossi",
    "email": "mario.rossi@example.it",
    "telefono": "3331234567",
    "partita_iva": "01234567897",
    "codice_fiscale": "RSSMRA80A01F205X",
    "denominazione": "Bar Centrale di Mario Rossi",
    "indirizzo": "Via Roma",
    "civico": "1",
    "cap": "20121",
    "comune": "Milano",
    "provincia": "MI",
    "nazione": "IT",
    "regime_fiscale": "ordinario",
    "privacy": true
}
```

**Risposte**

- `200` — Richiesta registrata

```json
{
    "success": true,
    "message": "Registrazione avvenuta con successo"
}
```

- `422` — Dati non validi: errors riporta i messaggi per campo. Richiede Accept: application/json.

```json
{
    "success": false,
    "message": "La somma degli importi dei pagamenti è inferiore al totale da pagare",
    "errors": {
        "pagamenti": [
            "La somma degli importi dei pagamenti è inferiore al totale da pagare"
        ]
    }
}
```

- `429` — Troppe richieste

```json
{
    "success": false,
    "message": "Troppe richieste di registrazione: riprova tra qualche minuto",
    "error": "too_many_requests"
}
```

## Anagrafica - PEM

<a id="get-api-pem"></a>

### Lista PEM

`GET /api/pem`

Scope richiesto ai client partner: `fiscale:read`.

Mostra la lista dei PEM associati all'utente autenticato.

**Risposte**

- `200` — success

```json
{
    "success": true,
    "pem": [
        {
            "id": 1,
            "serial_number": "ASVS-241232",
            "stato": "In servizio",
            "created_at": "01-01-2025 13:00:00",
            "indirizzo": "Via Roma 1"
        }
    ]
}
```

- `401` — Non autenticato

```json
{
    "message": "Non hai i permessi per accedere a questa risorsa.",
    "error": "unauthenticated"
}
```

- `403` — Non autorizzato

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

<a id="get-api-pem-serial_number"></a>

### Mostra PEM

`GET /api/pem/{serial_number}`

Scope richiesto ai client partner: `fiscale:read`.

Mostra i dettagli del PEM indicato.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Risposte**

- `200` — success

```json
{
    "success": true,
    "pem": {
        "id": 1,
        "serial_number": "ASVS-241232",
        "stato": "In servizio",
        "created_at": "01-01-2025 13:00:00",
        "indirizzo": "Via Roma 1"
    }
}
```

- `401` — Non autenticato

```json
{
    "message": "Non hai i permessi per accedere a questa risorsa.",
    "error": "unauthenticated"
}
```

- `403` — Non autorizzato

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

<a id="post-api-pem-serial_number-cambio-sede"></a>

### Richiedi il cambio sede

`POST /api/pem/{serial_number}/cambio-sede`

Scope richiesto ai client partner: `fiscale:manage`.

Chiede di spostare il PEM a un nuovo indirizzo. Se serve l'approvazione
dell'erogatore la richiesta resta in attesa; una volta approvata l'emissione
è sospesa fino alla chiusura di giornata e la nuova sede vale dalla prima
emissione successiva.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Corpo della richiesta** (`application/json`, obbligatorio)

| Campo | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `indirizzo` | `string` | sì | Al massimo 60 caratteri. Esempio: `Via Garibaldi`. |
| `civico` | `string` | sì | Al massimo 8 caratteri. Esempio: `12`. |
| `cap` | `string` | sì | Deve essere composto da 5 cifre. Esempio: `20121`. |
| `comune` | `string` | sì | Al massimo 60 caratteri. Esempio: `Milano`. |
| `provincia` | `string` | sì | Deve essere lungo 2 caratteri. Esempio: `MI`. |
| `nazione` | `string` | sì | Al massimo 2 caratteri. Esempio: `IT`. |
| `sede_legale` | `boolean` | sì | Esempio: `false`. |

Esempio:

```json
{
    "indirizzo": "Via Garibaldi",
    "civico": "12",
    "cap": "20121",
    "comune": "Milano",
    "provincia": "MI",
    "nazione": "IT",
    "sede_legale": false
}
```

**Risposte**

- `200` — Richiesta registrata

```json
{
    "success": true,
    "cambio_sede": {
        "id": 3,
        "stato": "richiesta",
        "indirizzo": "Via Garibaldi",
        "civico": "12",
        "cap": "20121",
        "comune": "Milano",
        "provincia": "MI",
        "nazione": "IT",
        "sede_legale": false,
        "motivazione_rifiuto": null,
        "created_at": "08-10-2026 10:15:42",
        "approvato_il": null
    },
    "message": "Richiesta inviata: dopo l'approvazione dell'erogatore l'emissione sarà sospesa fino alla chiusura di giornata, poi la nuova sede sarà applicata automaticamente alla prima emissione"
}
```

- `401` — Token assente (error: unauthenticated), scaduto (error: token_expired) o non valido (error: token_invalid).

```json
{
    "success": false,
    "message": "Il token di accesso è scaduto.",
    "error": "token_expired"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

- `422` — Dati non validi: errors riporta i messaggi per campo. Richiede Accept: application/json.

```json
{
    "success": false,
    "message": "La somma degli importi dei pagamenti è inferiore al totale da pagare",
    "errors": {
        "pagamenti": [
            "La somma degli importi dei pagamenti è inferiore al totale da pagare"
        ]
    }
}
```

<a id="delete-api-pem-serial_number-cambio-sede-cambio_sede"></a>

### Annulla il cambio sede

`DELETE /api/pem/{serial_number}/cambio-sede/{cambio_sede}`

Scope richiesto ai client partner: `fiscale:manage`.

Ritira una richiesta di cambio sede non ancora applicata (409 se non è più annullabile).

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |
| `cambio_sede` | `integer` | sì | L'id della richiesta di cambio sede. Esempio: `4`. |

**Risposte**

- `200` — success

```json
{
    "success": true,
    "message": "Richiesta di cambio sede annullata"
}
```

- `401` — Token assente (error: unauthenticated), scaduto (error: token_expired) o non valido (error: token_invalid).

```json
{
    "success": false,
    "message": "Il token di accesso è scaduto.",
    "error": "token_expired"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

## Catalogo - ATECO

<a id="get-api-pem-serial_number-dati-ateco"></a>

### Lista ATECO

`GET /api/pem/{serial_number}/dati/ateco`

Scope richiesto ai client partner: `catalogo:read`.

Restituisce i codici ATECO associati al PEM indicato.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Risposte**

- `200` — success

```json
{
    "success": true,
    "ateco": [
        {
            "id": 1,
            "codice": "112233",
            "descrizione": "TEST ATECO"
        }
    ]
}
```

- `401` — Non autenticato

```json
{
    "message": "Non hai i permessi per accedere a questa risorsa.",
    "error": "unauthenticated"
}
```

- `403` — Non autorizzato

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

<a id="post-api-pem-serial_number-dati-ateco"></a>

### Crea ATECO

`POST /api/pem/{serial_number}/dati/ateco`

Scope richiesto ai client partner: `catalogo:write`.

Crea un nuovo codice ATECO associato al PEM indicato.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Corpo della richiesta** (`application/json`)

| Campo | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `ateco` | `object` | no |  |
| `ateco.descrizione` | `string` | sì | La descrizione dell'ATECO. Al massimo 100 caratteri. Esempio: `Commercio al dettaglio`. |
| `ateco.codice` | `string` | sì | Il codice ATECO nel formato XX.XX.XX. Unico sul PEM. Formato: <code>/^\d{2}\.\d{2}\.\d{2}$/</code>. Esempio: `47.11.00`. |

Esempio:

```json
{
    "ateco": {
        "descrizione": "Commercio al dettaglio",
        "codice": "47.11.00"
    }
}
```

**Risposte**

- `200` — success

```json
{
    "success": true,
    "message": "ATECO creato con successo",
    "ateco": {
        "id": 1,
        "codice": "112233",
        "descrizione": "TEST ATECO"
    }
}
```

- `401` — Non autenticato

```json
{
    "message": "Non hai i permessi per accedere a questa risorsa.",
    "error": "unauthenticated"
}
```

- `403` — Non autorizzato

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

- `422` — Validazione fallita

```json
{
    "success": false,
    "message": "Il campo codice è obbligatorio",
    "errors": {
        "ateco.codice": [
            "Il campo codice è obbligatorio"
        ]
    }
}
```

<a id="put-api-pem-serial_number-dati-ateco-id"></a>

### Aggiorna ATECO

`PUT /api/pem/{serial_number}/dati/ateco/{id}`

Scope richiesto ai client partner: `catalogo:write`.

Aggiorna un codice ATECO esistente associato al PEM indicato.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |
| `id` | `integer` | sì | L'ID dell'ATECO. Esempio: `23`. |

**Corpo della richiesta** (`application/json`)

| Campo | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `ateco` | `object` | no |  |
| `ateco.descrizione` | `string` | no | La descrizione dell'ATECO. Al massimo 100 caratteri. Esempio: `Commercio al dettaglio`. |
| `ateco.codice` | `string` | no | Il codice ATECO nel formato XX.XX.XX. Unico sul PEM. Formato: <code>/^\d{2}\.\d{2}\.\d{2}$/</code>. Esempio: `47.11.00`. |

Esempio:

```json
{
    "ateco": {
        "descrizione": "Commercio al dettaglio",
        "codice": "47.11.00"
    }
}
```

**Risposte**

- `200` — success

```json
{
    "success": true,
    "message": "ATECO aggiornato con successo",
    "ateco": {
        "id": 1,
        "codice": "112233",
        "descrizione": "TEST ATECO"
    }
}
```

- `401` — Non autenticato

```json
{
    "message": "Non hai i permessi per accedere a questa risorsa.",
    "error": "unauthenticated"
}
```

- `403` — Non autorizzato

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — ATECO non trovato

```json
{
    "success": false,
    "message": "La risorsa richiesta non è stata trovata."
}
```

- `422` — Validazione fallita

```json
{
    "success": false,
    "message": "Il campo codice è obbligatorio",
    "errors": {
        "ateco.codice": [
            "Il campo codice è obbligatorio"
        ]
    }
}
```

<a id="delete-api-pem-serial_number-dati-ateco-id"></a>

### Elimina ATECO

`DELETE /api/pem/{serial_number}/dati/ateco/{id}`

Scope richiesto ai client partner: `catalogo:write`.

Elimina un codice ATECO associato al PEM indicato.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |
| `id` | `integer` | sì | L'ID dell'ATECO. Esempio: `23`. |

**Risposte**

- `200` — success

```json
{
    "success": true,
    "message": "ATECO eliminato con successo"
}
```

- `401` — Non autenticato

```json
{
    "message": "Non hai i permessi per accedere a questa risorsa.",
    "error": "unauthenticated"
}
```

- `403` — Non autorizzato

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — ATECO non trovato

```json
{
    "success": false,
    "message": "La risorsa richiesta non è stata trovata."
}
```

## Catalogo - Reparti

<a id="get-api-pem-serial_number-dati-reparti"></a>

### Lista Reparti

`GET /api/pem/{serial_number}/dati/reparti`

Scope richiesto ai client partner: `catalogo:read`.

Mostra la lista dei reparti associati al PEM corrente.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Risposte**

- `200` — success

```json
{
    "success": true,
    "reparti": [
        {
            "id": 1,
            "sigla": "R1",
            "descrizione": "Reparto 1",
            "importo": 100,
            "iva": "22",
            "colore": "#FFFFFF",
            "bene_servizio": "B",
            "id_categoria": 1,
            "id_ateco": 1
        }
    ]
}
```

- `401` — Non autenticato

```json
{
    "message": "Non hai i permessi per accedere a questa risorsa.",
    "error": "unauthenticated"
}
```

- `403` — Non autorizzato

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

<a id="post-api-pem-serial_number-dati-reparti"></a>

### Crea Reparto

`POST /api/pem/{serial_number}/dati/reparti`

Scope richiesto ai client partner: `catalogo:write`.

Memorizza un nuovo reparto associato al PEM corrente.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Corpo della richiesta** (`application/json`)

| Campo | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `reparto` | `object` | no |  |
| `reparto.sigla` | `string` | sì | La sigla del reparto. Al massimo 20 caratteri. Esempio: `A`. |
| `reparto.codice` | `string` | no | Il codice del reparto. Al massimo 50 caratteri. Può essere `null`. Esempio: `REP-001`. |
| `reparto.descrizione` | `string` | sì | La descrizione del reparto. Al massimo 100 caratteri. Esempio: `Caffetteria`. |
| `reparto.importo` | `number` | sì | L'importo del reparto. Esempio: `1.2`. |
| `reparto.iva` | `string` | sì | L'aliquota IVA del reparto. Valori: `4`, `5`, `10`, `22`, `N1`, `N2`, `N3`, `N4`, `N5`, `N6`, `VI`. Esempio: `10`. |
| `reparto.colore` | `string` | no | Il colore del reparto. Formato: <code>/^#([A-Fa-f0-9]{6}\|[A-Fa-f0-9]{3})$/</code>. Esempio: `#FFFFFF`. |
| `reparto.bene_servizio` | `string` | sì | Il tipo di bene/servizio del reparto. Valori: `B`, `S`. Esempio: `B`. |
| `reparto.id_categoria` | `number` | no | L'ID della categoria del reparto. Può essere `null`. Esempio: `1`. |
| `reparto.id_ateco` | `number` | no | L'ID dell'ATECO del reparto. Può essere `null`. Esempio: `1`. |

Esempio:

```json
{
    "reparto": {
        "sigla": "A",
        "descrizione": "Caffetteria",
        "importo": 1.2,
        "iva": "10",
        "bene_servizio": "B"
    }
}
```

**Risposte**

- `200` — success

```json
{
    "success": true,
    "message": "Reparto creato con successo",
    "reparto": {
        "id": 1,
        "sigla": "R1",
        "descrizione": "Reparto 1",
        "importo": 100,
        "iva": "22",
        "colore": "#FFFFFF",
        "bene_servizio": "B",
        "id_categoria": 1,
        "id_ateco": 1
    }
}
```

- `401` — Non autenticato

```json
{
    "message": "Non hai i permessi per accedere a questa risorsa.",
    "error": "unauthenticated"
}
```

- `403` — Non autorizzato

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

- `422` — Validazione fallita

```json
{
    "success": false,
    "message": "Il campo iva è obbligatorio",
    "errors": {
        "reparto.iva": [
            "Il campo iva è obbligatorio"
        ]
    }
}
```

<a id="put-api-pem-serial_number-dati-reparti-reparto_id"></a>

### Aggiorna Reparto

`PUT /api/pem/{serial_number}/dati/reparti/{reparto_id}`

Scope richiesto ai client partner: `catalogo:write`.

Aggiorna un reparto esistente associato al PEM indicato.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |
| `reparto_id` | `integer` | sì | L'ID del reparto. Esempio: `23`. |

**Corpo della richiesta** (`application/json`)

| Campo | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `reparto` | `object` | no |  |
| `reparto.sigla` | `string` | no | La sigla del Reparto. Al massimo 20 caratteri. Esempio: `A`. |
| `reparto.codice` | `string` | no | Il codice del Reparto. Al massimo 50 caratteri. Può essere `null`. Esempio: `REP-001`. |
| `reparto.descrizione` | `string` | no | La descrizione del Reparto. Al massimo 100 caratteri. Esempio: `Caffetteria`. |
| `reparto.importo` | `number` | no | L'importo del Reparto. Esempio: `1.2`. |
| `reparto.iva` | `string` | no | L'IVA del Reparto. Valori: `4`, `5`, `10`, `22`, `N1`, `N2`, `N3`, `N4`, `N5`, `N6`, `VI`. Esempio: `10`. |
| `reparto.colore` | `string` | no | Il colore del Reparto in esadecimale. Formato: <code>/^#([A-Fa-f0-9]{6}\|[A-Fa-f0-9]{3})$/</code>. Esempio: `#FFFFFF`. |
| `reparto.ordine` | `number` | no | L'ordine del Reparto. Esempio: `1`. |
| `reparto.bene_servizio` | `string` | no | Il tipo di Bene/Servizio del Reparto. Valori: `B`, `S`. Esempio: `B`. |
| `reparto.preferito` | `boolean` | no | Indica se il Reparto è preferito. Esempio: `true`. |
| `reparto.id_categoria` | `number` | no | L'ID della Categoria del Reparto. Può essere `null`. Esempio: `1`. |
| `reparto.id_ateco` | `number` | no | L'ID dell'ATECO del Reparto. Può essere `null`. Esempio: `1`. |

Esempio:

```json
{
    "reparto": {
        "sigla": "A",
        "descrizione": "Caffetteria",
        "importo": 1.2,
        "iva": "10",
        "bene_servizio": "B"
    }
}
```

**Risposte**

- `200` — success

```json
{
    "success": true,
    "message": "Reparto aggiornato con successo",
    "reparto": {
        "id": 1,
        "sigla": "R1",
        "descrizione": "Reparto 1",
        "importo": 100,
        "iva": "22",
        "colore": "#FFFFFF",
        "bene_servizio": "B",
        "id_categoria": 1,
        "id_ateco": 1
    }
}
```

- `401` — Non autenticato

```json
{
    "message": "Non hai i permessi per accedere a questa risorsa.",
    "error": "unauthenticated"
}
```

- `403` — Non autorizzato

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Reparto non trovato

```json
{
    "success": false,
    "message": "La risorsa richiesta non è stata trovata."
}
```

- `422` — Validazione fallita

```json
{
    "success": false,
    "message": "Aliquota non valida",
    "errors": {
        "reparto.iva": [
            "Aliquota non valida"
        ]
    }
}
```

<a id="delete-api-pem-serial_number-dati-reparti-reparto_id"></a>

### Elimina Reparto

`DELETE /api/pem/{serial_number}/dati/reparti/{reparto_id}`

Scope richiesto ai client partner: `catalogo:write`.

Elimina un reparto associato al PEM indicato.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |
| `reparto_id` | `integer` | sì | L'ID del reparto. Esempio: `23`. |

**Risposte**

- `200` — success

```json
{
    "success": true,
    "message": "Reparto eliminato con successo"
}
```

- `401` — Non autenticato

```json
{
    "message": "Non hai i permessi per accedere a questa risorsa.",
    "error": "unauthenticated"
}
```

- `403` — Non autorizzato

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Reparto non trovato

```json
{
    "success": false,
    "message": "La risorsa richiesta non è stata trovata."
}
```

## Funzioni fiscali - Consultazione

<a id="get-api-pem-serial_number-fiscale-chiusure-storico"></a>

### Storico chiusure

`GET /api/pem/{serial_number}/fiscale/chiusure/storico`

Scope richiesto ai client partner: `fiscale:read`.

Elenca le giornate chiuse del PEM, dalla più recente, con il numero di DC
e la data di trasmissione al PEL (`inviato_il` nullo = chiusura non ancora
trasmessa). `journal_aperto` è la giornata in corso, nullo se la cassa è chiusa.
`data_chiusura` è in ora locale; `inviato_il` e `aperto_il` in UTC.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Risposte**

- `200` — success

```json
{
    "success": true,
    "chiusure": [
        {
            "id": 12,
            "progressivo": 12,
            "data_chiusura": "2026-10-07T21:30:00",
            "numero_dc": 48,
            "numero_dc_journal": 48,
            "inviato_il": "2026-10-07T19:30:04.000000Z"
        }
    ],
    "journal_aperto": {
        "id": 13,
        "progressivo": 13,
        "aperto_il": "2026-10-08T06:02:11.000000Z"
    }
}
```

- `401` — Token assente (error: unauthenticated), scaduto (error: token_expired) o non valido (error: token_invalid).

```json
{
    "success": false,
    "message": "Il token di accesso è scaduto.",
    "error": "token_expired"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

<a id="get-api-pem-serial_number-fiscale-chiusure-journalid-documento"></a>

### Dati di una chiusura

`GET /api/pem/{serial_number}/fiscale/chiusure/{journalId}/documento`

Scope richiesto ai client partner: `fiscale:read`.

Restituisce i dati della giornata fiscale chiusa (`journalId` da *Storico
chiusure*): dati locali della chiusura uniti ai totali del PEL, unica fonte
fiscale. Finché la chiusura non è stata trasmessa all'AdE il PEL non ha i
totali e la risposta è 409.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |
| `journalId` | `integer` | sì | L'id della chiusura (campo `id` dello storico). Esempio: `12`. |

**Risposte**

- `200` — success

```json
{
    "success": true,
    "documento": {
        "pem": {
            "serial_number": "ASVS-241232",
            "indirizzo": "Via Roma 1",
            "comune": "Milano",
            "cap": "20100",
            "provincia": "MI"
        },
        "esercente": {
            "denominazione": "Bar Centrale srl",
            "partita_iva": "01234567890"
        },
        "journal": {
            "progressivo": 12,
            "data_chiusura": "2026-10-07T21:30:00",
            "numero_dc": 48,
            "numero_dc_journal": 48
        },
        "riepilogo": [],
        "pagamenti": [],
        "riepiloghi": [],
        "chiusure": [],
        "buoni_pasto": {
            "attiva": false,
            "aggiornato_il": null
        }
    }
}
```

- `401` — Token assente (error: unauthenticated), scaduto (error: token_expired) o non valido (error: token_invalid).

```json
{
    "success": false,
    "message": "Il token di accesso è scaduto.",
    "error": "token_expired"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

- `409` — Corrispettivi non trasmessi

```json
{
    "success": false,
    "message": "Chiusura non ancora trasmessa all'AdE"
}
```

<a id="post-api-pem-serial_number-fiscale-consultazione-report"></a>

### Report

`POST /api/pem/{serial_number}/fiscale/consultazione/report`

Scope richiesto ai client partner: `fiscale:read`.

Elabora il report delle vendite del PEM indicato

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Corpo della richiesta** (`application/json`)

| Campo | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `data_inizio` | `string` | no | Data di inizio del periodo di report. Deve essere una data valida. Esempio: `2026-10-01`. |
| `data_fine` | `string` | no | Data di fine del periodo di report. Deve essere una data valida. Esempio: `2026-10-31`. |
| `metodi_pagamento` | `array<string>` | no | Metodo di pagamento da filtrare, con i codici di emissione (PC, PP, TK, NRF, NRB, NRS, NRD). Esempio: `["PP"]`. |
| `utenti` | `array<integer>` | no | ID utente specifico da filtrare. Esempio: `[121]`. |
| `tipo_documenti` | `array<string>` | no | Tipo di documento da filtrare: DC (vendita), ANNULLO o RESO. Esempio: `["DC"]`. |
| `ricerca` | `string` | no | Testo libero per filtrare per progressivo DC (es. '0089-0001') o per descrizione di un elemento contabile. Al massimo 255 caratteri. Può essere `null`. Esempio: `0089`. |

Esempio:

```json
{
    "data_inizio": "2026-10-01",
    "data_fine": "2026-10-31"
}
```

**Risposte**

- `200` — success

```json
{
    "success": true,
    "scontrini": [
        {
            "id": 102,
            "user": "EsercenteTEST",
            "tipo": "DC",
            "progressivo": "0089-0001",
            "data": "2025-07-22 14:58:57",
            "inviato_il": "2025-07-22 14:59:02",
            "importo": 377.5,
            "pagamenti_metodo": "PC",
            "progressivo_riferimento": null,
            "annullato": false,
            "reso_fatto": false,
            "hash": "NmNhMzI5MDc3NjY2YzI5OTk2NDBiODg5YmFhMjEyMDI3MzZlZmNiNTMzMjEzNDQxNDE1YzQ1MmZlYWMyMjYyZTlmMTljMWVkYzFmN2UzMGU2ODYxMGIxMzVjZmJiMDBjNDAwMDI5NmQ5YTk1ODk4ZDI4NWQ3NmU1MjI5ZTkwMzg="
        }
    ],
    "totali": {
        "totaleLordo": 377.5,
        "totaleAnnulli": 0,
        "totaleResi": 0,
        "pagamenti": {
            "contanti": 377,
            "elettronico": 0,
            "ticket": 0,
            "nonRiscossoBeni": 0,
            "nonRiscossoServizi": 0,
            "nonRiscossoFattura": 0,
            "scontoAPagare": 0
        },
        "iva": {
            "10": {
                "imponibile": 70.45454545,
                "importo": 7.04545455
            },
            "N2": {
                "imponibile": 100,
                "importo": 0
            },
            "N4": {
                "imponibile": 200,
                "importo": 0
            }
        },
        "reparto": {
            "Nessuno": 377.5
        },
        "totaleOmaggi": 0
    }
}
```

- `401` — Non autenticato

```json
{
    "message": "Non hai i permessi per accedere a questa risorsa.",
    "error": "unauthenticated"
}
```

- `403` — Non autorizzato

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

- `422` — Dati non validi: errors riporta i messaggi per campo. Richiede Accept: application/json.

```json
{
    "success": false,
    "message": "La somma degli importi dei pagamenti è inferiore al totale da pagare",
    "errors": {
        "pagamenti": [
            "La somma degli importi dei pagamenti è inferiore al totale da pagare"
        ]
    }
}
```

<a id="get-api-pem-serial_number-fiscale-consultazione-dc"></a>

### Dettaglio di un DC

`GET /api/pem/{serial_number}/fiscale/consultazione/dc`

Scope richiesto ai client partner: `fiscale:read`.

Restituisce un documento commerciale del PEM nello stesso formato della
risposta di emissione: con `id` quello indicato, senza l'ultimo emesso
dall'utente del token.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Parametri della query**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `id` | `integer` | no | L'id del documento commerciale (dal report). Esempio: `1532`. |

**Risposte**

- `200` — Il documento commerciale (abbreviato)

```json
{
    "success": true,
    "dati": {
        "tipo": "DC",
        "progressivo": "0012-0007",
        "data": "2026-10-08 10:15:42",
        "hash": "YjQ0ZDJmMGE5YzFl...MmEzYjQ=",
        "codice_lotteria": null,
        "cessionario_committente": null,
        "elementi_contabili": [
            {
                "id": 5531,
                "descrizione": "Caffè espresso",
                "bene_servizio": "B",
                "quantita": "2.00",
                "prezzo_unitario": "1.20",
                "sconto": "0.00",
                "iva": "10",
                "acconto_versato_beni_non_consegnati": false,
                "omaggio": false
            }
        ],
        "pagamenti_dc": [
            {
                "importo": "2.40",
                "metodo": "PC"
            }
        ],
        "condivisione": {
            "testo_stampa": "G0AbYQFCQVIgQ0VOVFJBTEUg...",
            "pdf_url": "https://pem-staging.billyssw.it/pem/ASVS-241232/fiscale/consultazione/dc/YjQ0ZDJmMGE5YzFl...MmEzYjQ%3D/pdf"
        }
    }
}
```

- `401` — 

```json
{
    "success": false,
    "message": "Il token di accesso non è valido.",
    "error": "token_invalid"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Documento inesistente

```json
{
    "success": false,
    "errore": "Documento commerciale non trovato"
}
```

<a id="get-pem-serial_number-fiscale-consultazione-dc-hash-pdf"></a>

### PDF pubblico di un DC

`GET /pem/{serial_number}/fiscale/consultazione/dc/{hash}/pdf`

Pubblica: nessun token.

Il PDF firmato del documento, senza token: è l'URL di Content-Location della risposta di emissione. Sta fuori da /api. Limite di 60 richieste al minuto per indirizzo IP. width e font_size cambiano solo il PDF: il testo ESC/POS nei metadati segue le impostazioni di stampa dell'esercente.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |
| `hash` | `string` | sì | L'hash del documento, URL-encoded. Esempio: `YjQ0ZDJmMGE5YzFl...MmEzYjQ=`. |

**Parametri della query**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `width` | `integer` | no | Larghezza in mm, da 58 a 120 (default 120); i valori fuori intervallo vengono riportati al limite. Esempio: `58`. |
| `font_size` | `integer` | no | Corpo del testo, da 6 a 14 (default 10), con lo stesso limite. Esempio: `8`. |
| `regalo` | `integer` | no | Con 1, la copia di cortesia senza importi (solo per i DC di vendita). Esempio: `1`. |

**Risposte**

- `200` — Il PDF firmato del documento.

Corpo: `application/pdf`, binario.

- `429` — Più di 60 richieste al minuto dallo stesso indirizzo IP.

```json
{
    "message": "Too Many Attempts."
}
```

## Funzioni fiscali - Controllo PEM

<a id="get-api-pem-serial_number-controllo"></a>

### Dati di controllo AdE del PEM

`GET /api/pem/{serial_number}/controllo`

Scope richiesto ai client partner: `fiscale:read`.

Restituisce i dati identificativi, di stato e di versione richiesti per il controllo del PEM.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Risposte**

- `200` — success

```json
{
    "success": true,
    "data": {
        "matricola": "ASVS-000001",
        "stato": "In servizio",
        "data_cambio_stato": "01-01-2025 10:00:00",
        "esercente": {
            "partita_iva": "12345678901",
            "codice_fiscale": "RSSMRA80A01H501Z",
            "denominazione": "Esercente Srl"
        },
        "erogatore": {
            "partita_iva": "12345678901",
            "codice_fiscale": "RSSMRA80A01H501Z",
            "denominazione": "Erogatore Srl"
        },
        "soluzione_software": {
            "sigla": "123e4567-e89b-12d3-a456-426614174000",
            "id_approvazione": "0000",
            "data_approvazione": null
        },
        "versione_installata": {
            "versione": 1,
            "sotto_versione": 0,
            "patch": "0",
            "data_ora": "01-01-2025 10:00:00",
            "swid": null
        },
        "versione_disponibile": {
            "versione": 1,
            "sotto_versione": 0,
            "patch": "0",
            "data_creazione": "01-01-2025 10:00:00",
            "data_approvazione": null,
            "swid": null
        },
        "dc_non_trasmessi": {
            "count": 3,
            "importo_totale": 125.5
        }
    }
}
```

- `401` — Non autenticato

```json
{
    "message": "Non hai i permessi per accedere a questa risorsa."
}
```

- `403` — Non autorizzato

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — PEM non trovato

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

<a id="post-api-pem-serial_number-fiscale-gestionali-controllo"></a>

### Emetti Documento Gestionale di Controllo

`POST /api/pem/{serial_number}/fiscale/gestionali/controllo`

Scope richiesto ai client partner: `fiscale:manage`.

Genera il PDF dei dati di controllo del PEM lato backend e lo archivia
come Documento Gestionale (tipo `controllo`), restituendolo in download.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Risposte**

- `200` — Il PDF firmato del documento gestionale.

| Header | Descrizione | Esempio |
| --- | --- | --- |
| `Content-Disposition` | Il nome del file contiene il progressivo del documento gestionale. | `attachment; filename="documento_gestionale_0012-0001.pdf"` |

Corpo: `application/pdf`, binario.

- `401` — Non autenticato

```json
{
    "message": "Non hai i permessi per accedere a questa risorsa."
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — PEM non trovato

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

- `409` — Nessun Journal aperto

```json
{
    "success": false,
    "message": "Nessun Journal aperto disponibile"
}
```

## Funzioni fiscali - Documenti gestionali

<a id="get-api-pem-serial_number-fiscale-gestionali"></a>

### Archivio documenti gestionali

`GET /api/pem/{serial_number}/fiscale/gestionali`

Scope richiesto ai client partner: `fiscale:read`.

Elenca i documenti gestionali del PEM, di qualunque tipo, filtrabili per
data di elaborazione e per tipo. Senza `Accept: application/json` rende la
pagina Inertia dell'archivio.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Parametri della query**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `data` | `string` | no | Filtra per data di elaborazione. Esempio: `2026-08-20`. |
| `tipo` | `string` | no | Filtra per tipo di documento gestionale. Valori: `chiusura`, `controllo`, `operazioni`, `esiti_trasmissione`, `storico_buoni_pasto`. Esempio: `operazioni`. |

**Risposte**

- `200` — I documenti gestionali del PEM, dal più recente

```json
{
    "success": true,
    "gestionali": [
        {
            "id": 5,
            "progressivo": "0012-0001",
            "tipo": "operazioni",
            "data_elaborazione": "2026-10-08T10:15:42+02:00",
            "parametri": {
                "selezione": "date",
                "data_inizio": "2026-10-01",
                "data_fine": "2026-10-08"
            }
        }
    ]
}
```

- `401` — 

```json
{
    "success": false,
    "message": "Il token di accesso non è valido.",
    "error": "token_invalid"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

<a id="get-api-pem-serial_number-fiscale-gestionali-id-pdf"></a>

### Download di un documento gestionale archiviato

`GET /api/pem/{serial_number}/fiscale/gestionali/{id}/pdf`

Scope richiesto ai client partner: `fiscale:read`.

Restituisce il PDF firmato già emesso, qualunque ne sia il tipo.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |
| `id` | `integer` | sì | L'id del documento gestionale (dall'archivio). Esempio: `5`. |

**Risposte**

- `200` — Il PDF firmato del documento gestionale.

| Header | Descrizione | Esempio |
| --- | --- | --- |
| `Content-Disposition` | Il nome del file contiene il progressivo del documento gestionale. | `attachment; filename="documento_gestionale_0012-0001.pdf"` |

Corpo: `application/pdf`, binario.

- `401` — 

```json
{
    "success": false,
    "message": "Il token di accesso non è valido.",
    "error": "token_invalid"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Non trovato

```json
{
    "success": false,
    "message": "Documento gestionale non trovato"
}
```

<a id="post-api-pem-serial_number-fiscale-gestionali-operazioni"></a>

### Documento gestionale operazioni memorizzate

`POST /api/pem/{serial_number}/fiscale/gestionali/operazioni`

Scope richiesto ai client partner: `fiscale:manage`.

Emette e restituisce il documento gestionale con le operazioni memorizzate
dal PEM secondo la chiave di selezione indicata (ST v1.4 §3.4.2, punti 1-4).
La selezione `integrale` produce il solo riepilogo; le selezioni delimitate
includono anche il dettaglio per documento e gli aggregati giornalieri.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Corpo della richiesta** (`application/json`, obbligatorio)

| Campo | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `selezione` | `string` | sì | Chiave di selezione: `integrale` (tutto l'archivio, solo riepilogo), `date` (tra due date), `documento` (per numero di documento), `intervallo` (tra due numeri di documento dello stesso journal). Valori: `integrale`, `date`, `documento`, `intervallo`. Esempio: `date`. |
| `data_inizio` | `string` | no | Data di inizio del periodo. Obbligatoria con `selezione=date`. Deve essere una data valida. Esempio: `2026-10-01`. |
| `data_fine` | `string` | no | Data di fine del periodo. Obbligatoria con `selezione=date`. Deve essere una data valida. Deve essere una data uguale o successiva a <code>data_inizio</code>. Esempio: `2026-10-08`. |
| `progressivo` | `string` | no | Numero del documento in forma `NNNN-PPPP`. Obbligatorio con `selezione=documento`. Al massimo 32 caratteri. Esempio: `0089-0001`. |
| `journal` | `integer` | no | Progressivo del journal (`NNNN`). Obbligatorio con `selezione=intervallo`. Almeno 1. Esempio: `89`. |
| `progressivo_da` | `integer` | no | Progressivo iniziale del documento (`PPPP`). Obbligatorio con `selezione=intervallo`. Almeno 1. Al massimo 9999. Esempio: `1`. |
| `progressivo_a` | `integer` | no | Progressivo finale del documento (`PPPP`). Obbligatorio con `selezione=intervallo`. Al massimo 9999. Esempio: `50`. |
| `metodi_pagamento` | `array<string>` | no | Metodo di pagamento specifico da filtrare (es. "PC" per contanti, "PP" per pagamento elettronico). Esempio: `["PP"]`. |
| `utenti` | `array<integer>` | no | ID utente specifico da filtrare. Esempio: `[121]`. |
| `tipo_documenti` | `array<string>` | no | Tipo di documento specifico da filtrare (es. "DC", "A" per annullo, "R" per reso). Esempio: `["DC"]`. |
| `ateco` | `array<string>` | no | Codice ATECO specifico da filtrare. Esempio: `["011101"]`. |
| `ricerca` | `string` | no | Testo libero su progressivo DC (es. '0089-0001') o descrizione di un elemento contabile. Al massimo 255 caratteri. Può essere `null`. Esempio: `0089`. |

Esempio:

```json
{
    "selezione": "date",
    "data_inizio": "2026-10-01",
    "data_fine": "2026-10-08"
}
```

**Risposte**

- `200` — Il PDF firmato del documento gestionale.

| Header | Descrizione | Esempio |
| --- | --- | --- |
| `Content-Disposition` | Il nome del file contiene il progressivo del documento gestionale. | `attachment; filename="documento_gestionale_0012-0001.pdf"` |

Corpo: `application/pdf`, binario.

- `401` — Token assente (error: unauthenticated), scaduto (error: token_expired) o non valido (error: token_invalid).

```json
{
    "success": false,
    "message": "Il token di accesso è scaduto.",
    "error": "token_expired"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

- `409` — Cassa chiusa

```json
{
    "success": false,
    "message": "Nessun Journal aperto disponibile"
}
```

- `422` — Dati non validi: errors riporta i messaggi per campo. Richiede Accept: application/json.

```json
{
    "success": false,
    "message": "La somma degli importi dei pagamenti è inferiore al totale da pagare",
    "errors": {
        "pagamenti": [
            "La somma degli importi dei pagamenti è inferiore al totale da pagare"
        ]
    }
}
```

<a id="post-api-pem-serial_number-fiscale-gestionali-esiti-trasmissione"></a>

### Documento gestionale esiti trasmissioni corrispettivi

`POST /api/pem/{serial_number}/fiscale/gestionali/esiti-trasmissione`

Scope richiesto ai client partner: `fiscale:manage`.

Emette e restituisce il documento gestionale con gli esiti delle
trasmissioni dei corrispettivi comprese tra due date (ST v1.4 §3.4.2,
punto 5). I dati provengono da `richieste_pem`: nessuna chiamata al PEL.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Corpo della richiesta** (`application/json`, obbligatorio)

| Campo | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `data_inizio` | `string` | sì | Data di inizio dell'intervallo di trasmissioni. Deve essere una data valida. Esempio: `2026-01-01`. |
| `data_fine` | `string` | sì | Data di fine dell'intervallo di trasmissioni. Deve essere una data valida. Deve essere una data uguale o successiva a <code>data_inizio</code>. Esempio: `2026-08-20`. |

Esempio:

```json
{
    "data_inizio": "2026-01-01",
    "data_fine": "2026-08-20"
}
```

**Risposte**

- `200` — Il PDF firmato del documento gestionale.

| Header | Descrizione | Esempio |
| --- | --- | --- |
| `Content-Disposition` | Il nome del file contiene il progressivo del documento gestionale. | `attachment; filename="documento_gestionale_0012-0001.pdf"` |

Corpo: `application/pdf`, binario.

- `401` — Token assente (error: unauthenticated), scaduto (error: token_expired) o non valido (error: token_invalid).

```json
{
    "success": false,
    "message": "Il token di accesso è scaduto.",
    "error": "token_expired"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

- `409` — Cassa chiusa

```json
{
    "success": false,
    "message": "Nessun Journal aperto disponibile"
}
```

- `422` — Dati non validi: errors riporta i messaggi per campo. Richiede Accept: application/json.

```json
{
    "success": false,
    "message": "La somma degli importi dei pagamenti è inferiore al totale da pagare",
    "errors": {
        "pagamenti": [
            "La somma degli importi dei pagamenti è inferiore al totale da pagare"
        ]
    }
}
```

<a id="post-api-pem-serial_number-fiscale-gestionali-storico-buoni-pasto"></a>

### Documento gestionale storico opzione buoni pasto

`POST /api/pem/{serial_number}/fiscale/gestionali/storico-buoni-pasto`

Scope richiesto ai client partner: `fiscale:manage`.

Emette e restituisce il documento gestionale con lo storico delle
attivazioni e disattivazioni dell'opzione buoni pasto (ST v1.4 §3.4.2,
punto 8). Nessun parametro di selezione.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Risposte**

- `200` — Il PDF firmato del documento gestionale.

| Header | Descrizione | Esempio |
| --- | --- | --- |
| `Content-Disposition` | Il nome del file contiene il progressivo del documento gestionale. | `attachment; filename="documento_gestionale_0012-0001.pdf"` |

Corpo: `application/pdf`, binario.

- `401` — Token assente (error: unauthenticated), scaduto (error: token_expired) o non valido (error: token_invalid).

```json
{
    "success": false,
    "message": "Il token di accesso è scaduto.",
    "error": "token_expired"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

- `409` — Cassa chiusa

```json
{
    "success": false,
    "message": "Nessun Journal aperto disponibile"
}
```

<a id="post-api-pem-serial_number-fiscale-gestionali-chiusura-journalid"></a>

### Documento gestionale di chiusura

`POST /api/pem/{serial_number}/fiscale/gestionali/chiusura/{journalId}`

Scope richiesto ai client partner: `fiscale:manage`.

Emette il Documento Gestionale PDF firmato della giornata fiscale chiusa.
I totali provengono dal PEL, unica fonte fiscale. Come per il report vendite
ogni richiesta emette un nuovo documento, numerato sul journal corrente; le
copie già emesse restano scaricabili dall'archivio gestionali.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |
| `journalId` | `integer` | sì | L'id della chiusura (campo `id` dello storico chiusure). Esempio: `12`. |

**Risposte**

- `200` — Il PDF firmato del documento gestionale.

| Header | Descrizione | Esempio |
| --- | --- | --- |
| `Content-Disposition` | Il nome del file contiene il progressivo del documento gestionale. | `attachment; filename="documento_gestionale_0012-0001.pdf"` |

Corpo: `application/pdf`, binario.

- `401` — Token assente (error: unauthenticated), scaduto (error: token_expired) o non valido (error: token_invalid).

```json
{
    "success": false,
    "message": "Il token di accesso è scaduto.",
    "error": "token_expired"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

- `409` — Corrispettivi non trasmessi

```json
{
    "success": false,
    "message": "Chiusura non ancora trasmessa all'AdE"
}
```

## Funzioni fiscali - Emergenza

<a id="post-api-pem-serial_number-fiscale-emergenza-chiusura"></a>

### Chiusura di emergenza

`POST /api/pem/{serial_number}/fiscale/emergenza/chiusura`

Scope richiesto ai client partner: `fiscale:manage`.

Trasmette al PEL gli aggregati della giornata annotati sul registro di
emergenza dei corrispettivi: riepiloghi IVA e totali dei pagamenti,
dichiarati dall'esercente. Ammessa solo a PEM `Fuori servizio`; la
chiusura riguarda la giornata in cui è inviata.

Una giornata ammette più chiusure, anche con dati diversi: ogni
`idempotency_key` (UUID scelto dal client) è una chiusura e un invio
distinto al PEL. Ripetere la chiamata con la stessa chiave è sicuro: se
la chiusura è già trasmessa si riceve il suo esito senza un nuovo invio,
se l'invio era fallito lo si ritenta. La stessa chiave con dati diversi,
o già usata su un altro PEM, è rifiutata (422).

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Corpo della richiesta** (`application/json`, obbligatorio)

| Campo | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `idempotency_key` | `string` | sì | UUID scelto dal client, uno per chiusura e propagato al PEL. Ripetendo la chiamata con la stessa chiave non si crea una seconda chiusura: si riceve l'esito di quella già trasmessa, o si ritenta l'invio fallito. La stessa chiave con dati diversi, o già usata su un altro PEM, è rifiutata (422). Deve essere un UUID valido. Esempio: `3f1c2a9e-8b7d-4c1e-9a2f-5d6e7f8a9b0c`. |
| `n_doc_commerciali` | `integer` | sì | Numero di documenti commerciali annotati sul registro di emergenza nella giornata. Almeno 1. Al massimo 999999999. Esempio: `12`. |
| `riepiloghi` | `array<object>` | sì |  |
| `riepiloghi[].iva` | `string` | no | Aliquota IVA (4, 5, 10, 22). Richiede `imposta`. Può essere `null`. Esempio: `22`. |
| `riepiloghi[].natura` | `string` | no | Codice natura (N1–N6), in alternativa a `iva`. Valori: `N1`, `N2`, `N3`, `N4`, `N5`, `N6`. Può essere `null`. |
| `riepiloghi[].ventilazione_iva` | `string` | no | Ventilazione IVA (`SI`), in alternativa a `iva` e `natura`. Valori: `SI`. Può essere `null`. |
| `riepiloghi[].importo_parziale` | `string` | sì | Imponibile della riga, stringa decimale con al massimo 2 decimali (può essere negativo). Al netto dell'IVA (al lordo con `ventilazione_iva`), al netto di resi, annulli, beni in sospeso e non riscossi, ma comprensivo degli omaggi. Formato: <code>/^-?\d{1,11}(\.\d{1,2})?$/</code>. Esempio: `100.00`. |
| `riepiloghi[].imposta` | `string` | no | Imposta della riga: obbligatoria se e solo se è indicata `iva`, coerente con `importo_parziale × aliquota` entro ±0,01. Formato: <code>/^-?\d{1,11}(\.\d{1,2})?$/</code>. Può essere `null`. Esempio: `22.00`. |
| `riepiloghi[].codice_attivita` | `string` | no | Codice Ateco della riga (facoltativo), tra quelli configurati sul PEM. Valori: `null`. Può essere `null`. |
| `riepiloghi[].totale_ammontare_resi` | `string` | no | Ammontare dei resi (facoltativo, ≥ 0, al netto dell'IVA; al lordo con ventilazione IVA). Formato: <code>/^\d{1,11}(\.\d{1,2})?$/</code>. Può essere `null`. |
| `riepiloghi[].totale_ammontare_annulli` | `string` | no | Ammontare degli annulli (facoltativo, ≥ 0). Formato: <code>/^\d{1,11}(\.\d{1,2})?$/</code>. Può essere `null`. |
| `riepiloghi[].beni_in_sospeso` | `string` | no | Beni in sospeso (facoltativo, ≥ 0). Formato: <code>/^\d{1,11}(\.\d{1,2})?$/</code>. Può essere `null`. |
| `riepiloghi[].non_riscosso_servizi` | `string` | no | Non riscosso servizi (facoltativo, ≥ 0). Formato: <code>/^\d{1,11}(\.\d{1,2})?$/</code>. Può essere `null`. |
| `riepiloghi[].non_riscosso_fatture` | `string` | no | Non riscosso fatture (facoltativo, ≥ 0). Formato: <code>/^\d{1,11}(\.\d{1,2})?$/</code>. Può essere `null`. |
| `riepiloghi[].non_riscosso_dcra_ssn` | `string` | no | Non riscosso DCR a SSN (facoltativo, ≥ 0). Formato: <code>/^\d{1,11}(\.\d{1,2})?$/</code>. Può essere `null`. |
| `riepiloghi[].non_riscosso_omaggio` | `string` | no | Non riscosso omaggio (facoltativo, ≥ 0). Formato: <code>/^\d{1,11}(\.\d{1,2})?$/</code>. Può essere `null`. |
| `totali` | `object` | sì |  |
| `totali.pagato_contanti` | `string` | sì | Totale pagato in contanti. Formato: <code>/^\d{1,11}(\.\d{1,2})?$/</code>. Esempio: `100.00`. |
| `totali.pagato_elettronico` | `string` | sì | Totale pagato con strumenti elettronici. Formato: <code>/^\d{1,11}(\.\d{1,2})?$/</code>. Esempio: `77.55`. |
| `totali.sconto_a_pagare` | `string` | sì | Totale degli sconti a pagare. Formato: <code>/^\d{1,11}(\.\d{1,2})?$/</code>. Esempio: `0.00`. |
| `totali.ticket` | `object` | no | Buoni pasto incassati (facoltativo). Senza opzione buoni pasto sono un normale pagamento. Con l'opzione attiva nella giornata richiedono un riepilogo al 10% il cui lordo (`(importo_parziale + non_riscosso_servizi) × 1,10`) li copra, e il sistema attribuisce il riferimento normativo `TICKET` ai riepiloghi al 10%: il client non invia `rif_normativo`. Può essere `null`. |
| `totali.ticket.pagato_ticket` | `string` | no | Importo pagato con buoni pasto. Obbligatorio se è presente <code>totali.ticket</code>. Formato: <code>/^\d{1,11}(\.\d{1,2})?$/</code>. |
| `totali.ticket.numero_ticket` | `integer` | no | Numero di buoni pasto (≥ 1). Obbligatorio se è presente <code>totali.ticket</code>. Almeno 1. Al massimo 999999999. |

Esempio:

```json
{
    "idempotency_key": "3f1c2a9e-8b7d-4c1e-9a2f-5d6e7f8a9b0c",
    "n_doc_commerciali": 12,
    "riepiloghi": [
        {
            "iva": "22",
            "importo_parziale": "100.00",
            "imposta": "22.00"
        },
        {
            "iva": "10",
            "importo_parziale": "50.50",
            "imposta": "5.05"
        }
    ],
    "totali": {
        "pagato_contanti": "100.00",
        "pagato_elettronico": "77.55",
        "sconto_a_pagare": "0.00"
    }
}
```

**Risposte**

- `200` — success

```json
{
    "success": true,
    "dati": {
        "id_presa_in_carico": "12345",
        "n_doc_commerciali": 12
    }
}
```

- `401` — Token assente (error: unauthenticated), scaduto (error: token_expired) o non valido (error: token_invalid).

```json
{
    "success": false,
    "message": "Il token di accesso è scaduto.",
    "error": "token_expired"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

- `422` — 

## Funzioni fiscali - Opzione buoni pasto

<a id="get-api-pem-serial_number-fiscale-opzione-buoni-pasto"></a>

### Stato opzione buoni pasto

`GET /api/pem/{serial_number}/fiscale/opzione-buoni-pasto`

Scope richiesto ai client partner: `fiscale:read`.

Restituisce lo stato *efficace* dell'opzione (quello che governa
l'emissione) e, se una scelta è stata registrata ma decorre dal primo
giorno del mese successivo (§5.3), anche la scelta in sospeso.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Risposte**

- `200` — success

```json
{
    "success": true,
    "attiva": true,
    "opzione": {
        "attiva": true,
        "aggiornato_il": "12-08-2026 10:00:00",
        "decorre_dal": "12-08-2026 10:00:00"
    },
    "scelta_pendente": null,
    "modificabile": true
}
```

- `401` — Token assente (error: unauthenticated), scaduto (error: token_expired) o non valido (error: token_invalid).

```json
{
    "success": false,
    "message": "Il token di accesso è scaduto.",
    "error": "token_expired"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

<a id="post-api-pem-serial_number-fiscale-opzione-buoni-pasto"></a>

### Attiva/disattiva opzione buoni pasto

`POST /api/pem/{serial_number}/fiscale/opzione-buoni-pasto`

Scope richiesto ai client partner: `fiscale:manage`.

Registra l'attivazione o disattivazione dell'opzione per il trattamento dei
buoni pasto (ST v1.4 §5.3). Ammessa solo a cassa chiusa. Ha effetto dal
momento della scelta, salvo che nel mese corrente sia già stato emesso
almeno un DC con buoni pasto accettati: in tal caso decorre dal primo
giorno del mese successivo (campo `decorre_dal` della risposta).

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Corpo della richiesta** (`application/json`, obbligatorio)

| Campo | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `attiva` | `boolean` | sì | true per attivare l'opzione di trattamento dei buoni pasto, false per disattivarla. Il cambio è ammesso solo a cassa chiusa. Esempio: `true`. |

Esempio:

```json
{
    "attiva": true
}
```

**Risposte**

- `200` — success

```json
{
    "success": true,
    "message": "Opzione buoni pasto aggiornata",
    "opzione": {
        "attiva": true,
        "aggiornato_il": "12-08-2026 10:00:00",
        "decorre_dal": "01-09-2026 00:00:00"
    }
}
```

- `401` — Token assente (error: unauthenticated), scaduto (error: token_expired) o non valido (error: token_invalid).

```json
{
    "success": false,
    "message": "Il token di accesso è scaduto.",
    "error": "token_expired"
}
```

- `403` — Ruolo non ammesso

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

- `422` — Cassa aperta

```json
{
    "error_code": "BP001",
    "message": "Impossibile modificare opzione buoni pasto. Effettua chiusura di cassa e riprova."
}
```

<a id="get-api-pem-serial_number-fiscale-opzione-buoni-pasto-storico"></a>

### Storico opzione buoni pasto

`GET /api/pem/{serial_number}/fiscale/opzione-buoni-pasto/storico`

Scope richiesto ai client partner: `fiscale:read`.

Restituisce lo storico delle attivazioni/disattivazioni dell'opzione,
come richiesto dalle ST v1.4 (§3.4.2, lettura e stampa).

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Risposte**

- `200` — success

```json
{
    "success": true,
    "storico": [
        {
            "attiva": true,
            "aggiornato_il": "12-08-2026 10:00:00",
            "utente": "Mario Rossi"
        }
    ]
}
```

- `401` — Token assente (error: unauthenticated), scaduto (error: token_expired) o non valido (error: token_invalid).

```json
{
    "success": false,
    "message": "Il token di accesso è scaduto.",
    "error": "token_expired"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

## Funzioni fiscali - Richieste PEM

<a id="get-api-pem-serial_number-fiscale-richieste"></a>

### Lista richieste

`GET /api/pem/{serial_number}/fiscale/richieste`

Scope richiesto ai client partner: `fiscale:read`.

Recupera la lista delle richieste effettuate dal PEM specificato.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Parametri della query**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `tipo` | `string` | no | Filtra per tipo di richiesta (CENSIMENTO, CORRISPETTIVI). Valori: `CENSIMENTO`, `CORRISPETTIVI`. Esempio: `CENSIMENTO`. |

**Risposte**

- `200` — success

```json
{
    "success": true,
    "message": "Richieste PEM recuperate",
    "richieste": [
        {
            "id": 1,
            "id_presa_in_carico": "ABC123",
            "stato": "PRONTA",
            "data": "2025-07-01 10:30:00",
            "tipo": "CENSIMENTO"
        }
    ]
}
```

- `401` — Non autenticato

```json
{
    "message": "Non hai i permessi per accedere a questa risorsa.",
    "error": "unauthenticated"
}
```

- `403` — Non autorizzato

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

- `422` — Dati non validi: errors riporta i messaggi per campo. Richiede Accept: application/json.

```json
{
    "success": false,
    "message": "La somma degli importi dei pagamenti è inferiore al totale da pagare",
    "errors": {
        "pagamenti": [
            "La somma degli importi dei pagamenti è inferiore al totale da pagare"
        ]
    }
}
```

<a id="get-api-pem-serial_number-fiscale-richieste-stato-idrichiesta"></a>

### Verifica stato richiesta

`GET /api/pem/{serial_number}/fiscale/richieste/stato/{idRichiesta}`

Scope richiesto ai client partner: `fiscale:read`.

Controlla lo stato attuale di una richiesta PEM specifica.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |
| `idRichiesta` | `integer` | sì | L'id della richiesta (campo `id` della lista). Esempio: `1`. |

**Risposte**

- `200` — success

```json
{
    "success": true,
    "message": "Stato richiesta: COMPLETED",
    "stato": "COMPLETED"
}
```

- `401` — Non autenticato

```json
{
    "message": "Non hai i permessi per accedere a questa risorsa.",
    "error": "unauthenticated"
}
```

- `403` — Non autorizzato

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

<a id="get-api-pem-serial_number-fiscale-richieste-esito-idrichiesta"></a>

### Recupera esito richiesta

`GET /api/pem/{serial_number}/fiscale/richieste/esito/{idRichiesta}`

Scope richiesto ai client partner: `fiscale:read`.

Recupera l'esito finale di una richiesta pronta.
Se l'esito è già presente nel database, lo restituisce direttamente
senza effettuare una nuova chiamata al PEL.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |
| `idRichiesta` | `integer` | sì | L'id della richiesta (campo `id` della lista). Esempio: `1`. |

**Risposte**

- `200` — success

```json
{
    "success": true,
    "message": "Esito richiesta recuperato",
    "esito": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4..."
}
```

- `401` — Non autenticato

```json
{
    "message": "Non hai i permessi per accedere a questa risorsa.",
    "error": "unauthenticated"
}
```

- `403` — Non autorizzato

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

## Funzioni fiscali - Segnalazioni

<a id="get-api-pem-serial_number-fiscale-segnalazioni-inattivita"></a>

### Periodi di inattività

`GET /api/pem/{serial_number}/fiscale/segnalazioni/inattivita`

Scope richiesto ai client partner: `fiscale:read`.

Elenca i periodi di inattività segnalati per il PEM, dal più recente, con
lo stato dell'inoltro al PEL.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Risposte**

- `200` — success

```json
{
    "status": "success",
    "data": [
        {
            "id": 3,
            "serial_number": "ASVS-241232",
            "dal": "2026-12-24 00:00:00",
            "al": "2027-01-06 23:59:59",
            "stato": "PENDING"
        }
    ]
}
```

- `401` — Token assente (error: unauthenticated), scaduto (error: token_expired) o non valido (error: token_invalid).

```json
{
    "success": false,
    "message": "Il token di accesso è scaduto.",
    "error": "token_expired"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

<a id="post-api-pem-serial_number-fiscale-segnalazioni-inattivita"></a>

### Segnala un periodo di inattività

`POST /api/pem/{serial_number}/fiscale/segnalazioni/inattivita`

Scope richiesto ai client partner: `fiscale:manage`.

Comunica all'AdE, tramite il PEL, un periodo futuro in cui il PEM non
emetterà documenti (ferie, chiusura stagionale). La segnalazione è
accodata e inoltrata in modo asincrono: la risposta è 202. Le date sono
nel formato `Y-m-d H:i:s`, `al` successiva a `dal` e nel futuro.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Corpo della richiesta** (`application/json`, obbligatorio)

| Campo | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `dal` | `string` | sì | Data nel formato <code>Y-m-d H:i:s</code>. Esempio: `2026-11-01 00:00:00`. |
| `al` | `string` | sì | Data nel formato <code>Y-m-d H:i:s</code>. Deve essere una data successiva a <code>dal</code>. Esempio: `2026-11-30 23:59:59`. |

Esempio:

```json
{
    "dal": "2026-11-01 00:00:00",
    "al": "2026-11-30 23:59:59"
}
```

**Risposte**

- `202` — success

```json
{
    "status": "success",
    "message": "Periodo inattivo registrato"
}
```

- `401` — Token assente (error: unauthenticated), scaduto (error: token_expired) o non valido (error: token_invalid).

```json
{
    "success": false,
    "message": "Il token di accesso è scaduto.",
    "error": "token_expired"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

- `422` — Dati non validi: errors riporta i messaggi per campo. Richiede Accept: application/json.

```json
{
    "success": false,
    "message": "La somma degli importi dei pagamenti è inferiore al totale da pagare",
    "errors": {
        "pagamenti": [
            "La somma degli importi dei pagamenti è inferiore al totale da pagare"
        ]
    }
}
```

## Funzioni fiscali - Stato PEM

<a id="get-api-pem-serial_number-fiscale-stati"></a>

### Lista Stati PEM

`GET /api/pem/{serial_number}/fiscale/stati`

Scope richiesto ai client partner: `fiscale:read`.

Restituisce la lista degli stati del PEM corrente.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Risposte**

- `200` — success

```json
{
    "success": true,
    "data": [
        {
            "id": 1,
            "stato": "In servizio"
        },
        {
            "id": 2,
            "stato": "Dismesso"
        }
    ]
}
```

- `401` — Non autenticato

```json
{
    "message": "Non hai i permessi per accedere a questa risorsa.",
    "error": "unauthenticated"
}
```

- `403` — Non autorizzato

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

<a id="put-api-pem-serial_number-fiscale-stato"></a>

### Modifica lo stato del PEM

`PUT /api/pem/{serial_number}/fiscale/stato`

Scope richiesto ai client partner: `fiscale:manage`.

Comunica al PEL il cambio di stato del PEM.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Corpo della richiesta** (`application/json`, obbligatorio)

| Campo | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `stato` | `string` | sì | Stato del PEM (01: Fuori servizio, 03: In servizio). La dismissione (02) deve usare endpoint dedicato. Formato: <code>/^\d{2}$/D</code>. Valori: `01`, `03`. Esempio: `01`. |
| `motivazione` | `string` | no | Motivazione del Fuori servizio (01), obbligatoria con quello stato (01: Problemi hardware PEM, 02: Problemi software PEM, 03: Problemi di comunicazione PEM-PEL, 08: Mancata integrità, 09: Messa in magazzino - periodo di inattività, 10: Altro). Da non inviare con stato In servizio (03): il sistema trasmette 06 (Inizio ciclo di vita PEM) al primo passaggio in servizio e 07 (Ripristino da un fuori servizio) altrimenti. Formato: <code>/^\d{2}$/D</code>. Valori: `01`, `02`, `03`, `08`, `09`, `10`. Può essere `null`. Esempio: `01`. |
| `note` | `string` | no | Note sul cambiamento di stato, obbligatorie con stato Fuori servizio (01) qualunque sia la motivazione (AdE rifiuta altrimenti con CS009); facoltative con stato In servizio (03). Massimo 255 caratteri. Al massimo 255 caratteri. Può essere `null`. Esempio: `Guasto alla rete del punto vendita`. |

Esempio:

```json
{
    "stato": "01",
    "motivazione": "01",
    "note": "Guasto alla rete del punto vendita"
}
```

**Risposte**

- `200` — success

```json
{
    "success": true,
    "message": "Stato PEM aggiornato con successo",
    "data": {
        "id": 1,
        "stato": "In servizio"
    }
}
```

- `401` — Non autenticato

```json
{
    "message": "Non hai i permessi per accedere a questa risorsa.",
    "error": "unauthenticated"
}
```

- `403` — Non autorizzato

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

- `422` — Validazione fallita

```json
{
    "success": false,
    "message": "La motivazione è obbligatoria",
    "errors": {
        "motivazione": [
            "Il campo motivazione è obbligatorio"
        ]
    }
}
```

<a id="post-api-pem-serial_number-fiscale-stato-dismissione"></a>

### Dismissione del PEM

`POST /api/pem/{serial_number}/fiscale/stato/dismissione`

Scope richiesto ai client partner: `fiscale:manage`.

Porta il PEM nello stato definitivo *Dismesso* e lo comunica al PEL. Riservata
all'esercente titolare; lo stato e la motivazione non si scelgono (campi rifiutati).

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Corpo della richiesta** (`application/json`, obbligatorio)

| Campo | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `note` | `string` | sì | Note sulla dismissione del PEM, obbligatorie (AdE rifiuta altrimenti con CS009). Massimo 255 caratteri. Al massimo 255 caratteri. Esempio: `Chiusura definitiva del ciclo di vita PEM`. |

Esempio:

```json
{
    "note": "Chiusura definitiva del ciclo di vita PEM"
}
```

**Risposte**

- `200` — success

```json
{
    "success": true,
    "message": "Dismissione PEM completata con successo",
    "data": {
        "id": 7,
        "stato": "Dismesso"
    }
}
```

- `401` — Token assente (error: unauthenticated), scaduto (error: token_expired) o non valido (error: token_invalid).

```json
{
    "success": false,
    "message": "Il token di accesso è scaduto.",
    "error": "token_expired"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

- `422` — Dati non validi: errors riporta i messaggi per campo. Richiede Accept: application/json.

```json
{
    "success": false,
    "message": "La somma degli importi dei pagamenti è inferiore al totale da pagare",
    "errors": {
        "pagamenti": [
            "La somma degli importi dei pagamenti è inferiore al totale da pagare"
        ]
    }
}
```

## Funzioni fiscali - Trasmissioni

<a id="post-api-pem-serial_number-fiscale-invio-dc"></a>

### Invio DC

`POST /api/pem/{serial_number}/fiscale/invio/dc`

Scope richiesto ai client partner: `fiscale:manage`.

Emette un documento commerciale di vendita: genera e firma l'XML, lo aggiunge
al Journal e ne accoda la trasmissione al PEL (la risposta non attende il PEL).
Ammesso solo su un PEM In servizio.

`idempotency_key` (UUID) rende sicuro ripetere la chiamata: con una chiave già
usata sul PEM la risposta è il documento già emesso, senza emetterne un altro.
Come richiesto dalle specifiche AdE, l'unico output è lo stream di byte del PDF
firmato (PAdES, `application/pdf`): il testo ESC/POS per la stampante termica è
nei metadati XMP del PDF (`billy:escPosBase64`) e `Content-Location` è l'URL
pubblico dello stesso PDF (con `?regalo=1` la copia di cortesia). Gli errori
restano JSON. Il primo DC dopo una chiusura apre la nuova giornata.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Corpo della richiesta** (`application/json`, obbligatorio)

| Campo | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `idempotency_key` | `string` | sì | UUID scelto dal client, uno per documento: ripetendo la chiamata con la stessa chiave si riceve il documento già emesso. Deve essere un UUID valido. Al massimo 36 caratteri. Esempio: `3f1c2a9e-8b7d-4c1e-9a2f-5d6e7f8a9b0c`. |
| `sconto_a_pagare` | `number` | no | Lo sconto a pagare sul documento commerciale. Può essere `null`. Esempio: `2`. |
| `arrotondamento_dl50_difetto` | `boolean` | no | Indica che lo sconto a pagare rappresenta l'arrotondamento DL 50/2017 per difetto. Ammesso solo con pagamento integralmente in contanti e importo massimo 0,02 euro. Può essere `null`. Esempio: `false`. |
| `arrotondamento_dl50_eccesso` | `number` | no | Importo dell'arrotondamento DL 50/2017 per eccesso. Ammesso solo con pagamento integralmente in contanti, mutuamente esclusivo con arrotondamento_dl50_difetto e importo massimo 0,02 euro. Almeno 0. Può essere `null`. Esempio: `0.01`. |
| `sconto_subtotale` | `number` | no | Sconto applicato all'intero subtotale (importo assoluto in euro, dopo gli sconti di linea). Viene ripartito sulle singole linee ai soli fini fiscali e non può superare il subtotale al netto degli sconti di linea. Almeno 0. Può essere `null`. Esempio: `1.8`. |
| `codice_lotteria` | `string` | no | Codice lotteria del cliente (massimo 8 caratteri). Richiede un totale di almeno 1 euro pagato con un unico pagamento PP; alternativo a cessionario_committente. Al massimo 8 caratteri. Può essere `null`. Esempio: `ABC12345`. |
| `cessionario_committente` | `string` | no | Codice fiscale del cliente (massimo 16 caratteri), per il documento commerciale con codice fiscale. Alternativo a codice_lotteria. Al massimo 16 caratteri. Può essere `null`. Esempio: `RSSMRA85M01H501Z`. |
| `ateco` | `string` | no | Codice ATECO dell'operazione (massimo 6 caratteri). Oggi è accettato ma non riportato nel documento. Al massimo 6 caratteri. Può essere `null`. Esempio: `561011`. |
| `appendice` | `array<string>` | no | Una riga di appendice (massimo 255 caratteri). Al massimo 255 caratteri. Esempio: `["Grazie e arrivederci"]`. |
| `elementi` | `array<object>` | sì | Le righe (elementi contabili) del documento commerciale, al massimo 200 e con al massimo 40 aliquote distinte. Al massimo 200 elementi. |
| `elementi[].descrizione` | `string` | sì | La descrizione dell'elemento. Al massimo 255 caratteri. Esempio: `Caffè espresso`. |
| `elementi[].bene_servizio` | `string` | sì | Indica se l'elemento è un bene (B) o un servizio (S). Valori: `B`, `S`. Esempio: `B`. |
| `elementi[].quantita` | `number` | sì | La quantità dell'elemento (due decimali). Almeno 0. Esempio: `2`. |
| `elementi[].prezzo_unitario` | `number` | sì | Il prezzo unitario dell'elemento, IVA inclusa, in euro (due decimali). Almeno 0. Esempio: `1.20`. |
| `elementi[].iva` | `string` | sì | Aliquota IVA (4, 5, 10, 22), natura dell'operazione (N1-N6) o VI per la ventilazione. Valori: `4`, `5`, `10`, `22`, `N1`, `N2`, `N3`, `N4`, `N5`, `N6`, `VI`. Esempio: `10`. |
| `elementi[].sconto` | `number` | no | Sconto sulla riga, importo assoluto in euro. Almeno 0. Può essere `null`. Esempio: `0.2`. |
| `elementi[].maggiorazione` | `number` | no | La maggiorazione applicata all'elemento come importo assoluto. Almeno 0. Può essere `null`. Esempio: `1.5`. |
| `elementi[].acconto_versato_beni_non_consegnati` | `boolean` | no | Indica se l'elemento è un acconto versato per beni non consegnati. Può essere `null`. Esempio: `false`. |
| `elementi[].omaggio` | `boolean` | no | Indica se l'elemento è un omaggio. Può essere `null`. Esempio: `false`. |
| `elementi[].id_reparto` | `integer` | no | L'ID del reparto associato all'elemento. Può essere `null`. Esempio: `1`. |
| `pagamenti` | `array<object>` | no | I pagamenti. Obbligatori se il totale da pagare è maggiore di zero; devono coprirlo (i contanti possono eccederlo: la differenza è il resto). |
| `pagamenti[].importo` | `number` | sì | L'importo del pagamento in euro. Almeno 0. Esempio: `2.40`. |
| `pagamenti[].metodo` | `string` | sì | PC contanti, PP elettronico, TK buoni pasto (con l'opzione buoni pasto attiva solo su operazioni al 10%), NRF/NRB/NRS/NRD non riscosso (fattura, beni, servizi, DCR a SSN). NRF e NRD escludono altri pagamenti. Valori: `PC`, `PP`, `TK`, `NRF`, `NRB`, `NRS`, `NRD`. Esempio: `PC`. |
| `pagamenti[].numero_ticket` | `integer` | no | Il numero del ticket per i pagamenti con metodo TK. Obbligatorio se <code>pagamenti.*.metodo</code> vale <code>TK</code>. Almeno 0. Esempio: `123456`. |
| `pagamenti[].pos` | `object` | no | Facoltativo, per i pagamenti PP: dati della transazione sul terminale. |
| `pagamenti[].pos.pos` | `string` | no | Circuito o fornitore del terminale (massimo 32 caratteri). Obbligatorio se è presente <code>pagamenti.*.pos</code>. Esempio: `Nexi`. |
| `pagamenti[].pos.uuid` | `string` | no | Identificativo univoco della transazione. Obbligatorio se è presente <code>pagamenti.*.pos</code>. Al massimo 50 caratteri. Esempio: `9f8e7d6c-5b4a-4c3d-8e2f-1a0b9c8d7e6f`. |
| `pagamenti[].pos.data_ora` | `string` | no | Data e ora della transazione. Obbligatorio se è presente <code>pagamenti.*.pos</code>. Deve essere una data valida. Esempio: `2026-10-08T10:15:00+02:00`. |
| `pagamenti[].pos.tid` | `string` | no | Terminal ID. Al massimo 36 caratteri. Può essere `null`. Esempio: `12345678`. |
| `pagamenti[].pos.auth_code` | `string` | no | Codice di autorizzazione (massimo 20 caratteri). Al massimo 255 caratteri. Può essere `null`. Esempio: `A1B2C3`. |

Esempio:

```json
{
    "idempotency_key": "3f1c2a9e-8b7d-4c1e-9a2f-5d6e7f8a9b0c",
    "elementi": [
        {
            "descrizione": "Caffè espresso",
            "bene_servizio": "B",
            "quantita": "2",
            "prezzo_unitario": "1.20",
            "iva": "10"
        }
    ],
    "pagamenti": [
        {
            "metodo": "PC",
            "importo": "2.40"
        }
    ]
}
```

**Risposte**

- `200` — Il PDF firmato (PAdES) del documento emesso.

| Header | Descrizione | Esempio |
| --- | --- | --- |
| `Content-Disposition` | Il nome del file contiene il progressivo del documento (NNNN-PPPP). | `inline; filename="DC_0012-0007.pdf"` |
| `Content-Location` | L'URL pubblico dello stesso PDF, senza token: con `?regalo=1` la copia di cortesia (solo DC di vendita). Il segmento prima di /pdf è l'hash del documento, URL-encoded. | `https://pem-staging.billyssw.it/pem/ASVS-241232/fiscale/consultazione/dc/YjQ0ZDJmMGE5YzFl...MmEzYjQ%3D/pdf` |

Corpo: `application/pdf`, binario.

- `401` — Token assente (error: unauthenticated), scaduto (error: token_expired) o non valido (error: token_invalid).

```json
{
    "success": false,
    "message": "Il token di accesso è scaduto.",
    "error": "token_expired"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

- `409` — Giornata aperta da più di 24 ore

```json
{
    "error_code": "JN002",
    "message": "Apertura effettuata da più di 24 ore (ID: 42, Data: 2026-10-07 08:00:00)"
}
```

- `422` — Validazione fallita

```json
{
    "success": false,
    "message": "La somma degli importi dei pagamenti è inferiore al totale da pagare",
    "errors": {
        "pagamenti": [
            "La somma degli importi dei pagamenti è inferiore al totale da pagare"
        ]
    }
}
```

- `502` — Il PEL non ha aperto la nuova giornata (JN004): il documento non è emesso, ripetere con la stessa idempotency_key.

```json
{
    "error_code": "JN004",
    "message": "Errore apertura journal PEL: …"
}
```

<a id="post-api-pem-serial_number-fiscale-invio-annullo"></a>

### Annulla DC

`POST /api/pem/{serial_number}/fiscale/invio/annullo`

Scope richiesto ai client partner: `fiscale:manage`.

Emette il documento commerciale di annullo di una vendita e ne accoda la
trasmissione al PEL. Per una vendita dello stesso PEM basta il suo
`progressivo` (`NNNN-PPPP`): righe e codice lotteria si prendono dall'originale.
Per un documento di un altro dispositivo si indicano `matricola_annullo`,
`progressivo`, `dataOra` ed `elementi`; con matricola `POS`, `VR` o `ND` il
progressivo non serve. La risposta, come per *Invio DC*, è il PDF firmato del documento.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Corpo della richiesta** (`application/json`, obbligatorio)

| Campo | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `idempotency_key` | `string` | sì | Chiave UUID usata per rendere idempotente la richiesta di annullo. Deve essere un UUID valido. Al massimo 36 caratteri. Esempio: `9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d`. |
| `progressivo` | `string` | no | Il progressivo (NNNN-PPPP) del documento da annullare. Obbligatorio salvo matricola_annullo POS, VR o ND. Al massimo 11 caratteri. Esempio: `0012-0007`. |
| `matricola_annullo` | `string` | no | Solo per un documento emesso da un altro dispositivo: la sua matricola, oppure POS, VR o ND. Vuoto per un documento di questo PEM. Al massimo 11 caratteri. Esempio: `99MEX012345`. |
| `dataOra` | `string` | no | Data e ora del documento da annullare. Obbligatoria con matricola_annullo. Deve essere una data valida. Esempio: `2026-01-15 18:30:00`. |
| `codice_lotteria` | `string` | no | Codice lotteria associato al documento. Questo campo è opzionale e va fornito se il documento da annullare è stato emesso da un altro dispositivo. Al massimo 8 caratteri. Può essere `null`. Esempio: `ABC12345`. |
| `elementi` | `array<object>` | no | L'array di elementi del documento di annullo. Questo campo è obbligatorio se il documento da annullare è stato emesso da un altro dispositivo. |
| `elementi[].descrizione` | `string` | sì | La descrizione dell'elemento. Al massimo 255 caratteri. Esempio: `Prodotto A`. |
| `elementi[].bene_servizio` | `string` | sì | Indica se l'elemento è un bene (B) o un servizio (S). Valori: `B`, `S`. Esempio: `B`. |
| `elementi[].quantita` | `number` | sì | La quantità dell'elemento. Esempio: `2`. |
| `elementi[].prezzo_unitario` | `number` | sì | Il prezzo unitario dell'elemento. Esempio: `100`. |
| `elementi[].iva` | `string` | no | Il codice IVA applicato all'elemento. Obbligatorio se manca <code>elementi.*.id</code>. Valori: `4`, `5`, `10`, `22`, `N1`, `N2`, `N3`, `N4`, `N5`, `N6`, `VI`. |
| `elementi[].sconto` | `number` | no | Lo sconto applicato all'elemento. Può essere `null`. Esempio: `10`. |
| `elementi[].acconto_versato_beni_non_consegnati` | `boolean` | no | Indica se l'elemento è un acconto versato per beni non consegnati. Può essere `null`. Esempio: `false`. |
| `elementi[].omaggio` | `boolean` | no | Indica se l'elemento è un omaggio. Può essere `null`. Esempio: `false`. |
| `elementi[].ateco` | `string` | no | Al massimo 6 caratteri. Può essere `null`. Esempio: `bngz`. |

Esempio:

```json
{
    "idempotency_key": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
    "progressivo": "0012-0007"
}
```

**Risposte**

- `200` — Il PDF firmato (PAdES) del documento emesso.

| Header | Descrizione | Esempio |
| --- | --- | --- |
| `Content-Disposition` | Il nome del file contiene il progressivo del documento (NNNN-PPPP). | `inline; filename="DC_0012-0007.pdf"` |
| `Content-Location` | L'URL pubblico dello stesso PDF, senza token: con `?regalo=1` la copia di cortesia (solo DC di vendita). Il segmento prima di /pdf è l'hash del documento, URL-encoded. | `https://pem-staging.billyssw.it/pem/ASVS-241232/fiscale/consultazione/dc/YjQ0ZDJmMGE5YzFl...MmEzYjQ%3D/pdf` |

Corpo: `application/pdf`, binario.

- `401` — Token assente (error: unauthenticated), scaduto (error: token_expired) o non valido (error: token_invalid).

```json
{
    "success": false,
    "message": "Il token di accesso è scaduto.",
    "error": "token_expired"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Documento inesistente

```json
{
    "error_code": "DC001",
    "message": "Documento commerciale non trovato"
}
```

- `409` — Già annullato

```json
{
    "error_code": "DC003",
    "message": "Il documento commerciale è già stato annullato"
}
```

- `422` — Dati non validi: errors riporta i messaggi per campo. Richiede Accept: application/json.

```json
{
    "success": false,
    "message": "La somma degli importi dei pagamenti è inferiore al totale da pagare",
    "errors": {
        "pagamenti": [
            "La somma degli importi dei pagamenti è inferiore al totale da pagare"
        ]
    }
}
```

- `502` — Il PEL non ha aperto la nuova giornata (JN004): il documento non è emesso, ripetere con la stessa idempotency_key.

```json
{
    "error_code": "JN004",
    "message": "Errore apertura journal PEL: …"
}
```

<a id="get-api-pem-serial_number-fiscale-invio-reso"></a>

### Recupera dati reso DC

`GET /api/pem/{serial_number}/fiscale/invio/reso`

Scope richiesto ai client partner: `fiscale:manage`.

Restituisce le righe di un documento commerciale, con il loro `id` e la
quantità già resa (`reso`), per comporre la richiesta di reso.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Parametri della query**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `hash` | `string` | sì | L'hash del documento commerciale (campo `hash` della risposta di emissione). Esempio: `YjQ0ZDJmMGE5YzFlNGI3ZDhmMDAxMmFiMzRjZDU2ZWY3ODkwYTFiMmMzZDRlNWY2YTdiOGM5ZDBlMWYyYTNiNA==`. |

**Risposte**

- `200` — success

```json
{
    "success": true,
    "dati": {
        "progressivo": "0012-0007",
        "data": "2026-10-08 10:15:42",
        "serial_number": "ASVS-241232",
        "elementi_contabili": [
            {
                "id": 5531,
                "descrizione": "Caffè espresso",
                "bene_servizio": "B",
                "quantita": "2.00",
                "prezzo_unitario": "1.20",
                "sconto": "0.00",
                "iva": "10",
                "acconto_versato_beni_non_consegnati": false,
                "omaggio": false,
                "reso": 0
            }
        ]
    }
}
```

- `401` — Token assente (error: unauthenticated), scaduto (error: token_expired) o non valido (error: token_invalid).

```json
{
    "success": false,
    "message": "Il token di accesso è scaduto.",
    "error": "token_expired"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Documento inesistente

```json
{
    "success": false,
    "message": "Documento commerciale non trovato"
}
```

<a id="post-api-pem-serial_number-fiscale-invio-reso"></a>

### Reso DC

`POST /api/pem/{serial_number}/fiscale/invio/reso`

Scope richiesto ai client partner: `fiscale:manage`.

Emette il documento commerciale di reso, totale o parziale, e ne accoda la
trasmissione al PEL. Per una vendita dello stesso PEM si indicano il suo
`progressivo` e, per ogni riga resa, l'`id` della riga originale (da *Recupera
dati reso DC*) con la `quantita`: il resto si prende dall'originale. Le righe di
servizio non sono rendibili. Per un documento di un altro dispositivo si
indicano `matricola_reso`, `progressivo`, `dataOra` e le righe complete.
La risposta, come per *Invio DC*, è il PDF firmato del documento.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Corpo della richiesta** (`application/json`, obbligatorio)

| Campo | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `idempotency_key` | `string` | sì | Chiave UUID usata per rendere idempotente la richiesta di reso. Deve essere un UUID valido. Al massimo 36 caratteri. Esempio: `c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f`. |
| `progressivo` | `string` | no | Il progressivo (NNNN-PPPP) del documento di vendita da rendere. Obbligatorio salvo matricola_reso POS, VR o ND. Al massimo 11 caratteri. Esempio: `0012-0007`. |
| `matricola_reso` | `string` | no | Solo per un documento emesso da un altro dispositivo: la sua matricola, oppure POS, VR o ND. Vuoto per un documento di questo PEM. Al massimo 11 caratteri. Esempio: `99MEX012345`. |
| `dataOra` | `string` | no | Data e ora del documento da rendere. Obbligatoria con matricola_reso. Deve essere una data valida. Esempio: `2026-01-15 18:30:00`. |
| `codice_lotteria` | `string` | no | Il codice lotteria associato al reso. Questo campo è opzionale e va fornito se il documento di cui si vuole fare il reso è stato emesso da un altro dispositivo. Al massimo 8 caratteri. Può essere `null`. Esempio: `ABC12345`. |
| `elementi` | `array<object>` | sì | L'array di elementi contabili del documento commerciale. |
| `elementi[].quantita` | `number` | sì | La quantità dell'elemento da rendere. Esempio: `1`. |
| `elementi[].id` | `integer` | no | L'id della riga originale da rendere (da Recupera dati reso DC). Obbligatorio se il documento è stato emesso dallo stesso PEM. Esempio: `5531`. |
| `elementi[].descrizione` | `string` | no | La descrizione dell'elemento. Questo campo è obbligatorio se il documento di cui si vuole fare il reso è stato emesso da un altro dispositivo. Al massimo 255 caratteri. Esempio: `Prodotto A`. |
| `elementi[].bene_servizio` | `string` | no | Indica se l'elemento è un bene (B). I servizi (S) non sono ammessi al reso. Questo campo è obbligatorio se il documento di cui si vuole fare il reso è stato emesso da un altro dispositivo. Valori: `B`. Esempio: `B`. |
| `elementi[].prezzo_unitario` | `number` | no | Il prezzo unitario dell'elemento da rendere. Questo campo è obbligatorio se il documento di cui si vuole fare il reso è stato emesso da un altro dispositivo. Esempio: `10.5`. |
| `elementi[].iva` | `string` | no | Il codice IVA applicato all'elemento da rendere. Questo campo è obbligatorio se il documento di cui si vuole fare il reso è stato emesso da un altro dispositivo. Valori: `4`, `5`, `10`, `22`, `N1`, `N2`, `N3`, `N4`, `N5`, `N6`, `VI`. |
| `elementi[].sconto` | `number` | no | Lo sconto applicato all'elemento da rendere. Può essere `null`. Esempio: `1`. |
| `elementi[].acconto_versato_beni_non_consegnati` | `boolean` | no | Indica se l'elemento è un acconto versato per beni non consegnati. Può essere `null`. Esempio: `false`. |
| `elementi[].omaggio` | `boolean` | no | Indica se l'elemento è un omaggio. Può essere `null`. Esempio: `false`. |
| `elementi[].ateco` | `string` | no | Il codice ATECO associato all'elemento. Al massimo 6 caratteri. Può essere `null`. Esempio: `123456`. |

Esempio:

```json
{
    "idempotency_key": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
    "progressivo": "0012-0007",
    "elementi": [
        {
            "id": 5531,
            "quantita": "1"
        }
    ]
}
```

**Risposte**

- `200` — Il PDF firmato (PAdES) del documento emesso.

| Header | Descrizione | Esempio |
| --- | --- | --- |
| `Content-Disposition` | Il nome del file contiene il progressivo del documento (NNNN-PPPP). | `inline; filename="DC_0012-0007.pdf"` |
| `Content-Location` | L'URL pubblico dello stesso PDF, senza token: con `?regalo=1` la copia di cortesia (solo DC di vendita). Il segmento prima di /pdf è l'hash del documento, URL-encoded. | `https://pem-staging.billyssw.it/pem/ASVS-241232/fiscale/consultazione/dc/YjQ0ZDJmMGE5YzFl...MmEzYjQ%3D/pdf` |

Corpo: `application/pdf`, binario.

- `401` — Token assente (error: unauthenticated), scaduto (error: token_expired) o non valido (error: token_invalid).

```json
{
    "success": false,
    "message": "Il token di accesso è scaduto.",
    "error": "token_expired"
}
```

- `403` — Scope non concesso al client partner o ruolo non ammesso per l'operazione.

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

- `409` — 

- `422` — Dati non validi: errors riporta i messaggi per campo. Richiede Accept: application/json.

```json
{
    "success": false,
    "message": "La somma degli importi dei pagamenti è inferiore al totale da pagare",
    "errors": {
        "pagamenti": [
            "La somma degli importi dei pagamenti è inferiore al totale da pagare"
        ]
    }
}
```

- `502` — Il PEL non ha aperto la nuova giornata (JN004): il documento non è emesso, ripetere con la stessa idempotency_key.

```json
{
    "error_code": "JN004",
    "message": "Errore apertura journal PEL: …"
}
```

<a id="post-api-pem-serial_number-fiscale-invio-chiusura"></a>

### Chiusura giornaliera

`POST /api/pem/{serial_number}/fiscale/invio/chiusura`

Scope richiesto ai client partner: `fiscale:manage`.

Chiude la giornata fiscale: scrive il blocco di chiusura del Journal e accoda
l'invio firmato al PEL, che trasmette i corrispettivi all'AdE. La risposta
arriva subito: l'esito si segue con *Storico chiusure* (`inviato_il`) e con le
richieste di tipo CORRISPETTIVI. Se ci sono DC appena emessi ancora in invio al
PEL la risposta è 409 `JN005`: riprovare dopo qualche istante. Una giornata
aperta da 23 ore viene chiusa in automatico.

**Parametri di percorso**

| Nome | Tipo | Obbligatorio | Descrizione |
| --- | --- | --- | --- |
| `serial_number` | `string` | sì | Il seriale del PEM. Esempio: `ASVS-241232`. |

**Risposte**

- `200` — success

```json
{
    "success": true,
    "message": "Chiusura in elaborazione"
}
```

- `401` — Non autenticato

```json
{
    "message": "Non hai i permessi per accedere a questa risorsa.",
    "error": "unauthenticated"
}
```

- `403` — Non autorizzato

```json
{
    "success": false,
    "message": "Richiesta non autorizzata"
}
```

- `404` — Seriale inesistente o PEM non accessibile all'utente.

```json
{
    "success": false,
    "message": "Il PEM specificato non è stato trovato."
}
```

- `409` — 

