# DPass API V2 — verifica congiunta di soste e abbonamenti

## Scopo

La V2 consente agli applicativi di controllo di verificare, con una sola chiamata, se una targa dispone nel Comune e nell’eventuale area indicata di:

- una sosta oraria valida;
- un abbonamento valido;
- almeno uno dei due titoli.

La V1 resta invariata e continua a restituire esclusivamente le soste.

## Endpoint

Endpoint canonico:

```text
POST /api/v2/parking-entitlements/search
```

Alias compatibile:

```text
POST /api/v2/parking/check-plate
```

Specifica OpenAPI:

```text
GET /api/v2/openapi.json
```

## Autenticazione

```http
Authorization: Bearer <TOKEN>
Accept: application/json
Content-Type: application/json
```

Restano validi lo scope per tenant e Comuni, le eventuali restrizioni IP, la scadenza della credenziale, il limite di chiamate e i giorni storici configurati per la terza parte. Per compatibilità con integrazioni precedenti sono ancora accettati anche gli header `X-DPass-Token` e `X-Api-Key`.

## Richiesta corrente

```json
{
  "plate": "AB123CD",
  "municipality_code": "ottaviano",
  "area_code": "centro"
}
```

- `plate` è obbligatorio e viene normalizzato da DPass.
- `municipality_code` è obbligatorio quando la credenziale è abilitata su più Comuni.
- `area_code` è facoltativo ma raccomandato.
- `checked_at` è facoltativo; se assente viene usato l’istante corrente nel timezone del Comune.

Per un controllo storico autorizzato:

```json
{
  "plate": "AB123CD",
  "municipality_code": "ottaviano",
  "area_code": "centro",
  "checked_at": "2026-08-05T12:30:00+02:00"
}
```

`checked_at` deve essere un istante ISO 8601 completo, non può essere futuro e deve rientrare in `historical_days_allowed`.

## Controllo dell’area

Quando `area_code` è presente, DPass filtra le soste sulla stessa area e verifica che l’abbonamento sia valido in quella zona.

Quando `area_code` è assente:

- una sosta può comunque essere verificata a livello comunale;
- un abbonamento valido in tutto il Comune può essere confermato;
- un abbonamento limitato ad aree selezionate non viene dichiarato valido;
- la risposta contiene `verification_complete: false`, `requires_area_code: true` e l’avvertenza `AREA_CODE_REQUIRED`.

Questa scelta è prudenziale: l’assenza dell’area non deve produrre un falso positivo.

## Esito operativo

Il campo da utilizzare come esito complessivo è:

```text
has_valid_entitlement
```

Le origini restano separate:

```text
has_valid_parking
has_valid_subscription
```

I conteggi principali sono:

```text
sessions_count
valid_sessions_count
subscriptions_count
valid_subscriptions_count
results_count
entitlements_count
```

`entitlements_count` rappresenta il numero complessivo di soste e abbonamenti validi nell’istante di verifica.

## Esempio di risposta

```json
{
  "success": true,
  "request_id": "deaf2285-04ee-4a13-8914-44dd949e0bfd",
  "ok": true,
  "api_version": "2.0",
  "plate": "AB123CD",
  "timezone": "Europe/Rome",
  "checked_at": "2026-08-05T12:30:00+02:00",
  "municipality": {
    "code": "ottaviano",
    "name": "Ottaviano"
  },
  "area": {
    "code": "centro",
    "name": "Centro"
  },
  "verification_scope": "area",
  "subscriptions_supported": true,
  "verification_complete": true,
  "requires_area_code": false,
  "has_valid_entitlement": true,
  "has_valid_parking": false,
  "has_valid_subscription": true,
  "sessions_count": 0,
  "valid_sessions_count": 0,
  "subscriptions_count": 1,
  "valid_subscriptions_count": 1,
  "results_count": 1,
  "entitlements_count": 1,
  "sessions": [],
  "subscriptions": [
    {
      "subscription_number": "OTTAVIANO-TIT-2026-000001",
      "plate": "AB123CD",
      "status": "active",
      "reason_code": "VALID_SUBSCRIPTION",
      "is_valid_at_check_time": true
    }
  ],
  "warnings": []
}
```

La risposta non contiene nome, codice fiscale, indirizzo, email, documenti o altri dati personali dell’intestatario.

## Esiti degli abbonamenti

Tra gli esiti diagnostici possibili:

```text
VALID_SUBSCRIPTION
FIRST_ACTIVATION_REQUIRED
PERIOD_NOT_YET_ACTIVE
PERIOD_EXPIRED
SUBSCRIPTION_SUSPENDED
SUBSCRIPTION_REVOKED
AUTHORIZATION_EXPIRED
AUTHORIZATION_NOT_YET_ACTIVE
AREA_CODE_REQUIRED
AREA_NOT_ALLOWED
```

Solo `is_valid_at_check_time: true` contribuisce a `has_valid_subscription` e a `has_valid_entitlement`.

## Gestione degli errori

Un errore HTTP o una risposta con:

```json
{
  "success": false,
  "ok": false
}
```

non deve mai essere interpretato come veicolo irregolare. L’applicativo chiamante deve distinguere chiaramente:

- esito negativo valido della verifica;
- errore di autenticazione, configurazione, rete o servizio.

Ogni risposta contiene un `request_id`, riportato anche nell’header `X-Request-Id`, da utilizzare per l’assistenza e la consultazione del registro chiamate.

---

## Estensione 61B — controllo accessi delle strutture prepagate

Lo stesso endpoint può essere utilizzato dai sistemi di lettura targa delle
strutture classificate come `facility`.

### Richiesta

Per una verifica di ingresso o uscita è necessario indicare la struttura e
l'evento:

```json
{
  "plate": "AB123CD",
  "municipality_code": "tolfa",
  "area_code": "parcheggio-centro",
  "event": "exit"
}
```

Valori ammessi per `event`:

- `verify`: verifica generica; è il valore predefinito;
- `entry`: controllo all'ingresso;
- `exit`: controllo all'uscita.

Per `entry` e `exit`, `area_code` è obbligatorio e deve identificare una
struttura attiva dello stesso Comune.

### Decisione

La risposta mantiene tutti i campi già previsti e aggiunge:

```json
{
  "access_event": "exit",
  "access_granted": true,
  "access_reason_code": "VALID_PREPAID_FACILITY_SESSION",
  "access_reason": "Accesso consentito: sosta prepagata valida per la struttura.",
  "access_control": {
    "event": "exit",
    "area_code": "parcheggio-centro",
    "entry_grace_minutes": 5,
    "exit_grace_minutes": 15,
    "access_granted": true,
    "reason_code": "VALID_PREPAID_FACILITY_SESSION",
    "matched_source": "parking_session"
  }
}
```

La decisione è strettamente riferita alla struttura richiesta. Una sosta o un
abbonamento valido in un'altra area non autorizza l'apertura della sbarra.

### Tolleranze

Per ciascuna struttura sono configurabili:

- tolleranza di ingresso: minuti consentiti prima dell'inizio della sosta;
- tolleranza di uscita: minuti consentiti dopo la scadenza;
- accesso tramite abbonamento: ammesso soltanto quando esplicitamente abilitato.

La verifica `entry` usa la tolleranza di ingresso; la verifica `exit` usa la
tolleranza di uscita; `verify` considera entrambe.

### Codici principali

- `VALID_PREPAID_FACILITY_SESSION`
- `VALID_FACILITY_SUBSCRIPTION`
- `VALID_SESSION_AND_SUBSCRIPTION`
- `SESSION_NOT_STARTED`
- `SESSION_EXPIRED`
- `SUBSCRIPTION_NOT_ALLOWED`
- `NO_VALID_FACILITY_ENTITLEMENT`
- `PLATE_CONTROL_DISABLED`
- `FACILITY_SERVICE_DISABLED`

La decisione `access_granted` è distinta da `has_valid_entitlement`: durante
una tolleranza di ingresso o uscita la sbarra può essere autorizzata anche se
l'istante non rientra nella validità ordinaria del titolo.
