> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gestionesala.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Documentazione di Gestione Sala. Il testo completo, incluso il riferimento API, è in https://docs.gestionesala.com/llms-full.txt. Per endpoint, campi e codici di errore la fonte di verità è openapi.yaml: non usare endpoint o campi non documentati.

# Riferimento completo

> Tutti gli endpoint dell'API v1 in una pagina: parametri, body, risposte ed errori. Generata da openapi.yaml.

Base URL: `https://app.gestionesala.com/api/v1`. Autenticazione: header `Authorization: Bearer gsk_...` su ogni richiesta.
Specifica sorgente: [`openapi.yaml`](https://raw.githubusercontent.com/SQUADD26/docs/main/openapi.yaml).

## Recupera la chiave API corrente

`GET /me`

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden                                             |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                             | Tipo               | Sempre presente | Descrizione                                                    |
| --------------------------------- | ------------------ | --------------- | -------------------------------------------------------------- |
| `organization`                    | object             | sì              |                                                                |
| `organization.id`                 | string (uuid)      | sì              |                                                                |
| `organization.name`               | string             | sì              |                                                                |
| `apiKey`                          | object             | sì              |                                                                |
| `apiKey.id`                       | string (uuid)      | sì              |                                                                |
| `apiKey.name`                     | string             | sì              |                                                                |
| `apiKey.scopes`                   | array              | sì              |                                                                |
| `apiKey.voiceAgent`               | boolean            | sì              | La chiave dell'agente vocale                                   |
| `rateLimit`                       | object             | sì              |                                                                |
| `rateLimit.limit`                 | integer            | sì              | Richieste al minuto                                            |
| `rateLimit.remaining`             | integer            | sì              |                                                                |
| `rateLimit.resetAt`               | string (date-time) | sì              | Quando la finestra riparte                                     |
| `livemode`                        | boolean            | sì              | Falso per le chiavi dell'organizzazione di prova (gsk\_test\_) |
| `venues`                          | array              | sì              |                                                                |
| `venues[].id`                     | string (uuid)      | sì              |                                                                |
| `venues[].name`                   | string             | sì              |                                                                |
| `venues[].timezone`               | string             | sì              | Fuso orario IANA                                               |
| `venues[].noShowToleranceMinutes` | integer            | sì              |                                                                |
| `venues[].updatedAt`              | string (date-time) | sì              | Istante ISO 8601 con fuso                                      |

## Verifica lo stato del servizio

`GET /health`

Verifica che il servizio e il database rispondano. Non richiede autenticazione.

### Risposte

| Status | Descrizione |
| ------ | ----------- |
| `200`  | OK          |
| `503`  | unavailable |

### Campi della risposta

| Campo    | Tipo               | Sempre presente | Descrizione               |
| -------- | ------------------ | --------------- | ------------------------- |
| `status` | string: `ok`       | sì              |                           |
| `time`   | string (date-time) | sì              | Istante ISO 8601 con fuso |

## Recupera la specifica OpenAPI

`GET /openapi.json`

Restituisce la specifica OpenAPI 3.1 di questa API. Non richiede autenticazione.

### Risposte

| Status | Descrizione |
| ------ | ----------- |
| `200`  | OpenAPI 3.1 |

## Elenca i locali accessibili alla chiave

`GET /venues`

Scope: `venues:read`

### Parametri

| Nome           | Posizione | Tipo               | Obbligatorio | Descrizione                                 |
| -------------- | --------- | ------------------ | ------------ | ------------------------------------------- |
| `limit`        | query     | integer            | no           | Righe per pagina                            |
| `cursor`       | query     | string             | no           | Il nextCursor della risposta precedente     |
| `updatedSince` | query     | string (date-time) | no           | Solo ciò che è cambiato dopo questo istante |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                           | Tipo               | Sempre presente | Descrizione               |
| ------------------------------- | ------------------ | --------------- | ------------------------- |
| `data`                          | array              | sì              |                           |
| `data[].id`                     | string (uuid)      | sì              |                           |
| `data[].name`                   | string             | sì              |                           |
| `data[].timezone`               | string             | sì              | Fuso orario IANA          |
| `data[].noShowToleranceMinutes` | integer            | sì              |                           |
| `data[].updatedAt`              | string (date-time) | sì              | Istante ISO 8601 con fuso |
| `nextCursor`                    | object             | sì              |                           |

## Recupera un locale

`GET /venues/{id}`

Scope: `venues:read`

### Parametri

| Nome | Posizione | Tipo          | Obbligatorio | Descrizione |
| ---- | --------- | ------------- | ------------ | ----------- |
| `id` | path      | string (uuid) | sì           |             |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                          | Tipo               | Sempre presente | Descrizione               |
| ------------------------------ | ------------------ | --------------- | ------------------------- |
| `venue`                        | object             | sì              |                           |
| `venue.id`                     | string (uuid)      | sì              |                           |
| `venue.name`                   | string             | sì              |                           |
| `venue.timezone`               | string             | sì              | Fuso orario IANA          |
| `venue.noShowToleranceMinutes` | integer            | sì              |                           |
| `venue.updatedAt`              | string (date-time) | sì              | Istante ISO 8601 con fuso |

## Elenca i turni di un locale

`GET /venues/{id}/shifts`

Scope: `venues:read`

### Parametri

| Nome           | Posizione | Tipo               | Obbligatorio | Descrizione                                 |
| -------------- | --------- | ------------------ | ------------ | ------------------------------------------- |
| `id`           | path      | string (uuid)      | sì           |                                             |
| `limit`        | query     | integer            | no           | Righe per pagina                            |
| `cursor`       | query     | string             | no           | Il nextCursor della risposta precedente     |
| `updatedSince` | query     | string (date-time) | no           | Solo ciò che è cambiato dopo questo istante |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                    | Tipo               | Sempre presente | Descrizione                                      |
| ------------------------ | ------------------ | --------------- | ------------------------------------------------ |
| `data`                   | array              | sì              |                                                  |
| `data[].id`              | string (uuid)      | sì              |                                                  |
| `data[].name`            | string             | sì              |                                                  |
| `data[].openingTime`     | string             | sì              | Ora locale del locale, HH:mm                     |
| `data[].lastSeatingTime` | string             | sì              | Ora locale del locale, HH:mm                     |
| `data[].closingTime`     | string             | sì              | HH:mm; prima dell'apertura = sfora la mezzanotte |
| `data[].weekdays`        | array              | sì              |                                                  |
| `data[].updatedAt`       | string (date-time) | sì              | Istante ISO 8601 con fuso                        |
| `nextCursor`             | object             | sì              |                                                  |

## Elenca le chiusure di un locale

`GET /venues/{id}/closures`

Scope: `venues:read`

### Parametri

| Nome           | Posizione | Tipo               | Obbligatorio | Descrizione                                 |
| -------------- | --------- | ------------------ | ------------ | ------------------------------------------- |
| `id`           | path      | string (uuid)      | sì           |                                             |
| `limit`        | query     | integer            | no           | Righe per pagina                            |
| `cursor`       | query     | string             | no           | Il nextCursor della risposta precedente     |
| `updatedSince` | query     | string (date-time) | no           | Solo ciò che è cambiato dopo questo istante |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo              | Tipo               | Sempre presente | Descrizione               |
| ------------------ | ------------------ | --------------- | ------------------------- |
| `data`             | array              | sì              |                           |
| `data[].id`        | string (uuid)      | sì              |                           |
| `data[].weekday`   | object             | sì              |                           |
| `data[].date`      | object             | sì              |                           |
| `data[].reason`    | object             | sì              |                           |
| `data[].updatedAt` | string (date-time) | sì              | Istante ISO 8601 con fuso |
| `nextCursor`       | object             | sì              |                           |

## Elenca le sale di un locale

`GET /venues/{id}/areas`

Scope: `floor:read`

### Parametri

| Nome           | Posizione | Tipo               | Obbligatorio | Descrizione                                 |
| -------------- | --------- | ------------------ | ------------ | ------------------------------------------- |
| `id`           | path      | string (uuid)      | sì           |                                             |
| `limit`        | query     | integer            | no           | Righe per pagina                            |
| `cursor`       | query     | string             | no           | Il nextCursor della risposta precedente     |
| `updatedSince` | query     | string (date-time) | no           | Solo ciò che è cambiato dopo questo istante |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo              | Tipo               | Sempre presente | Descrizione               |
| ------------------ | ------------------ | --------------- | ------------------------- |
| `data`             | array              | sì              |                           |
| `data[].id`        | string (uuid)      | sì              |                           |
| `data[].name`      | string             | sì              |                           |
| `data[].icon`      | string             | sì              |                           |
| `data[].position`  | integer            | sì              |                           |
| `data[].widthCm`   | integer            | sì              |                           |
| `data[].heightCm`  | integer            | sì              |                           |
| `data[].updatedAt` | string (date-time) | sì              | Istante ISO 8601 con fuso |
| `nextCursor`       | object             | sì              |                           |

## Elenca i tavoli della pianta attiva

`GET /venues/{id}/tables`

Scope: `floor:read`

### Parametri

| Nome           | Posizione | Tipo               | Obbligatorio | Descrizione                                 |
| -------------- | --------- | ------------------ | ------------ | ------------------------------------------- |
| `id`           | path      | string (uuid)      | sì           |                                             |
| `limit`        | query     | integer            | no           | Righe per pagina                            |
| `cursor`       | query     | string             | no           | Il nextCursor della risposta precedente     |
| `updatedSince` | query     | string (date-time) | no           | Solo ciò che è cambiato dopo questo istante |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                   | Tipo                                           | Sempre presente | Descrizione               |
| ----------------------- | ---------------------------------------------- | --------------- | ------------------------- |
| `data`                  | array                                          | sì              |                           |
| `data[].id`             | string (uuid)                                  | sì              |                           |
| `data[].floorPlanId`    | string (uuid)                                  | sì              |                           |
| `data[].areaId`         | string (uuid)                                  | sì              |                           |
| `data[].name`           | string                                         | sì              |                           |
| `data[].shape`          | string: `square`, `rectangle`, `round`, `oval` | sì              |                           |
| `data[].minSeats`       | integer                                        | sì              |                           |
| `data[].maxSeats`       | integer                                        | sì              |                           |
| `data[].isBlocked`      | boolean                                        | sì              |                           |
| `data[].combinationIds` | array                                          | sì              | Le unioni di cui fa parte |
| `data[].updatedAt`      | string (date-time)                             | sì              | Istante ISO 8601 con fuso |
| `nextCursor`            | object                                         | sì              |                           |

## Elenca le piante di un locale

`GET /venues/{id}/floor-plans`

Scope: `floor:read`

### Parametri

| Nome           | Posizione | Tipo               | Obbligatorio | Descrizione                                 |
| -------------- | --------- | ------------------ | ------------ | ------------------------------------------- |
| `id`           | path      | string (uuid)      | sì           |                                             |
| `limit`        | query     | integer            | no           | Righe per pagina                            |
| `cursor`       | query     | string             | no           | Il nextCursor della risposta precedente     |
| `updatedSince` | query     | string (date-time) | no           | Solo ciò che è cambiato dopo questo istante |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo              | Tipo               | Sempre presente | Descrizione               |
| ------------------ | ------------------ | --------------- | ------------------------- |
| `data`             | array              | sì              |                           |
| `data[].id`        | string (uuid)      | sì              |                           |
| `data[].name`      | string             | sì              |                           |
| `data[].isActive`  | boolean            | sì              |                           |
| `data[].version`   | integer            | sì              |                           |
| `data[].updatedAt` | string (date-time) | sì              | Istante ISO 8601 con fuso |
| `nextCursor`       | object             | sì              |                           |

## Recupera una pianta

`GET /venues/{id}/floor-plans/{planId}`

Scope: `floor:read`

### Parametri

| Nome     | Posizione | Tipo          | Obbligatorio | Descrizione |
| -------- | --------- | ------------- | ------------ | ----------- |
| `id`     | path      | string (uuid) | sì           |             |
| `planId` | path      | string (uuid) | sì           |             |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                                | Tipo                                           | Sempre presente | Descrizione               |
| ------------------------------------ | ---------------------------------------------- | --------------- | ------------------------- |
| `floorPlan`                          | object                                         | sì              |                           |
| `floorPlan.id`                       | string (uuid)                                  | sì              |                           |
| `floorPlan.name`                     | string                                         | sì              |                           |
| `floorPlan.isActive`                 | boolean                                        | sì              |                           |
| `floorPlan.version`                  | integer                                        | sì              |                           |
| `floorPlan.updatedAt`                | string (date-time)                             | sì              | Istante ISO 8601 con fuso |
| `floorPlan.areas`                    | array                                          | sì              |                           |
| `floorPlan.areas[].id`               | string (uuid)                                  | sì              |                           |
| `floorPlan.areas[].name`             | string                                         | sì              |                           |
| `floorPlan.areas[].widthCm`          | integer                                        | sì              |                           |
| `floorPlan.areas[].heightCm`         | integer                                        | sì              |                           |
| `floorPlan.tables`                   | array                                          | sì              |                           |
| `floorPlan.tables[].id`              | string (uuid)                                  | sì              |                           |
| `floorPlan.tables[].areaId`          | string (uuid)                                  | sì              |                           |
| `floorPlan.tables[].name`            | string                                         | sì              |                           |
| `floorPlan.tables[].shape`           | string: `square`, `rectangle`, `round`, `oval` | sì              |                           |
| `floorPlan.tables[].minSeats`        | integer                                        | sì              |                           |
| `floorPlan.tables[].maxSeats`        | integer                                        | sì              |                           |
| `floorPlan.tables[].positionXCm`     | integer                                        | sì              |                           |
| `floorPlan.tables[].positionYCm`     | integer                                        | sì              |                           |
| `floorPlan.tables[].widthCm`         | integer                                        | sì              | Ingombro già ruotato      |
| `floorPlan.tables[].heightCm`        | integer                                        | sì              | Ingombro già ruotato      |
| `floorPlan.tables[].rotationDegrees` | integer                                        | sì              |                           |
| `floorPlan.tables[].isBlocked`       | boolean                                        | sì              |                           |
| `floorPlan.combinations`             | array                                          | sì              |                           |
| `floorPlan.combinations[].id`        | string (uuid)                                  | sì              |                           |
| `floorPlan.combinations[].tableIds`  | array                                          | sì              |                           |

## Recupera lo stato della sala

`GET /venues/{id}/floor`

Scope: `floor:read` e `reservations:read`

### Parametri

| Nome | Posizione | Tipo          | Obbligatorio | Descrizione |
| ---- | --------- | ------------- | ------------ | ----------- |
| `id` | path      | string (uuid) | sì           |             |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                           | Tipo                                                                                                 | Sempre presente | Descrizione                     |
| ------------------------------- | ---------------------------------------------------------------------------------------------------- | --------------- | ------------------------------- |
| `venueId`                       | string (uuid)                                                                                        | sì              |                                 |
| `timezone`                      | string                                                                                               | sì              | Fuso orario IANA                |
| `serviceDate`                   | string (date)                                                                                        | sì              | Giorno di servizio, YYYY-MM-DD  |
| `now`                           | string (date-time)                                                                                   | sì              | Istante ISO 8601 con fuso       |
| `currentShift`                  | object                                                                                               | sì              |                                 |
| `nextShift`                     | object                                                                                               | sì              |                                 |
| `floorPlanId`                   | object                                                                                               | sì              |                                 |
| `tables`                        | array                                                                                                | sì              |                                 |
| `tables[].id`                   | string (uuid)                                                                                        | sì              |                                 |
| `tables[].areaId`               | string (uuid)                                                                                        | sì              |                                 |
| `tables[].name`                 | string                                                                                               | sì              |                                 |
| `tables[].minSeats`             | integer                                                                                              | sì              |                                 |
| `tables[].maxSeats`             | integer                                                                                              | sì              |                                 |
| `tables[].state`                | string: `free`, `expected`, `late`, `arrived`, `seated`, `overstaying`, `blocked`                    | sì              |                                 |
| `tables[].reservationId`        | object                                                                                               | sì              |                                 |
| `reservations`                  | array                                                                                                | sì              |                                 |
| `reservations[].id`             | string (uuid)                                                                                        | sì              |                                 |
| `reservations[].venueId`        | string (uuid)                                                                                        | sì              |                                 |
| `reservations[].serviceDate`    | string (date)                                                                                        | sì              | Giorno di servizio, YYYY-MM-DD  |
| `reservations[].time`           | string                                                                                               | sì              | Ora locale del locale, HH:mm    |
| `reservations[].startsAt`       | string (date-time)                                                                                   | sì              | Istante ISO 8601 con fuso       |
| `reservations[].endsAt`         | string (date-time)                                                                                   | sì              | Istante ISO 8601 con fuso       |
| `reservations[].partySize`      | integer                                                                                              | sì              |                                 |
| `reservations[].status`         | string: `created`, `confirmed`, `arrived`, `seated`, `released`, `completed`, `no_show`, `cancelled` | sì              |                                 |
| `reservations[].tableAssigned`  | boolean                                                                                              | sì              |                                 |
| `reservations[].needsAttention` | boolean                                                                                              | sì              | Valida, ma da sistemare in sala |
| `reservations[].notes`          | object                                                                                               | sì              |                                 |
| `reservations[].source`         | string: `phone`, `voice_agent`, `floor`, `waitlist`, `walk_in`, `api`, `import`                      | sì              |                                 |
| `reservations[].sourceDetail`   | object                                                                                               | sì              |                                 |
| `reservations[].externalRef`    | object                                                                                               | sì              |                                 |
| `reservations[].guestId`        | object                                                                                               | sì              |                                 |
| `reservations[].updatedAt`      | string (date-time)                                                                                   | sì              | Anche la versione, per If-Match |
| `reservations[].guest`          | object                                                                                               | sì              |                                 |
| `reservations[].guestDetails`   | object                                                                                               | no              |                                 |
| `reservations[].table`          | object                                                                                               | no              |                                 |

## Elenca le regole di durata del tavolo

`GET /venues/{id}/turn-time-rules`

Scope: `venues:read`

### Parametri

| Nome           | Posizione | Tipo               | Obbligatorio | Descrizione                                 |
| -------------- | --------- | ------------------ | ------------ | ------------------------------------------- |
| `id`           | path      | string (uuid)      | sì           |                                             |
| `limit`        | query     | integer            | no           | Righe per pagina                            |
| `cursor`       | query     | string             | no           | Il nextCursor della risposta precedente     |
| `updatedSince` | query     | string (date-time) | no           | Solo ciò che è cambiato dopo questo istante |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                    | Tipo               | Sempre presente | Descrizione               |
| ------------------------ | ------------------ | --------------- | ------------------------- |
| `data`                   | array              | sì              |                           |
| `data[].id`              | string (uuid)      | sì              |                           |
| `data[].shiftId`         | object             | sì              |                           |
| `data[].minPartySize`    | integer            | sì              |                           |
| `data[].maxPartySize`    | object             | sì              |                           |
| `data[].turnTimeMinutes` | integer            | sì              |                           |
| `data[].bufferMinutes`   | integer            | sì              |                           |
| `data[].updatedAt`       | string (date-time) | sì              | Istante ISO 8601 con fuso |
| `nextCursor`             | object             | sì              |                           |

## Elenca le regole di ritmo degli arrivi

`GET /venues/{id}/pacing-rules`

Scope: `venues:read`

### Parametri

| Nome           | Posizione | Tipo               | Obbligatorio | Descrizione                                 |
| -------------- | --------- | ------------------ | ------------ | ------------------------------------------- |
| `id`           | path      | string (uuid)      | sì           |                                             |
| `limit`        | query     | integer            | no           | Righe per pagina                            |
| `cursor`       | query     | string             | no           | Il nextCursor della risposta precedente     |
| `updatedSince` | query     | string (date-time) | no           | Solo ciò che è cambiato dopo questo istante |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                  | Tipo               | Sempre presente | Descrizione               |
| ---------------------- | ------------------ | --------------- | ------------------------- |
| `data`                 | array              | sì              |                           |
| `data[].id`            | string (uuid)      | sì              |                           |
| `data[].shiftId`       | object             | sì              |                           |
| `data[].isEnabled`     | boolean            | sì              |                           |
| `data[].maxCovers`     | integer            | sì              |                           |
| `data[].windowMinutes` | integer            | sì              |                           |
| `data[].updatedAt`     | string (date-time) | sì              | Istante ISO 8601 con fuso |
| `nextCursor`           | object             | sì              |                           |

## Elenca i tag di servizio

`GET /service-tags`

Scope: `guests:read`

### Parametri

| Nome           | Posizione | Tipo               | Obbligatorio | Descrizione                                 |
| -------------- | --------- | ------------------ | ------------ | ------------------------------------------- |
| `limit`        | query     | integer            | no           | Righe per pagina                            |
| `cursor`       | query     | string             | no           | Il nextCursor della risposta precedente     |
| `updatedSince` | query     | string (date-time) | no           | Solo ciò che è cambiato dopo questo istante |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo              | Tipo               | Sempre presente | Descrizione               |
| ------------------ | ------------------ | --------------- | ------------------------- |
| `data`             | array              | sì              |                           |
| `data[].id`        | string (uuid)      | sì              |                           |
| `data[].name`      | string             | sì              |                           |
| `data[].updatedAt` | string (date-time) | sì              | Istante ISO 8601 con fuso |
| `nextCursor`       | object             | sì              |                           |

## Verifica la disponibilità

`GET /availability`

Scope: `reservations:read`

### Parametri

| Nome          | Posizione | Tipo          | Obbligatorio | Descrizione |
| ------------- | --------- | ------------- | ------------ | ----------- |
| `venueId`     | query     | string (uuid) | sì           |             |
| `serviceDate` | query     | string (date) | sì           |             |
| `time`        | query     | string        | sì           |             |
| `partySize`   | query     | integer       | sì           |             |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                            | Tipo               | Sempre presente | Descrizione                    |
| -------------------------------- | ------------------ | --------------- | ------------------------------ |
| `venueId`                        | string (uuid)      | sì              |                                |
| `serviceDate`                    | string (date)      | sì              | Giorno di servizio, YYYY-MM-DD |
| `partySize`                      | integer            | sì              |                                |
| `timezone`                       | string             | sì              | Fuso IANA del locale           |
| `available`                      | boolean            | sì              |                                |
| `reason`                         | string             | no              | Perché no, se non c'è posto    |
| `alternatives`                   | array              | sì              |                                |
| `alternatives[].time`            | string             | sì              | Ora locale del locale, HH:mm   |
| `alternatives[].startsAt`        | string (date-time) | sì              | Istante ISO 8601 con fuso      |
| `alternatives[].endsAt`          | string (date-time) | sì              | Istante ISO 8601 con fuso      |
| `alternatives[].turnTimeMinutes` | integer            | sì              |                                |
| `alternatives[].seats`           | integer            | sì              |                                |
| `alternatives[].overflowsShift`  | boolean            | sì              |                                |

## Elenca gli orari disponibili

`GET /availability/slots`

Scope: `reservations:read`. Ogni orario, a passi di 15 minuti dall'apertura del turno, è un orario in cui una prenotazione verrebbe accettata in questo momento.

### Parametri

| Nome          | Posizione | Tipo          | Obbligatorio | Descrizione |
| ------------- | --------- | ------------- | ------------ | ----------- |
| `venueId`     | query     | string (uuid) | sì           |             |
| `serviceDate` | query     | string (date) | sì           |             |
| `partySize`   | query     | integer       | sì           |             |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                    | Tipo               | Sempre presente | Descrizione                    |
| ------------------------ | ------------------ | --------------- | ------------------------------ |
| `venueId`                | string (uuid)      | sì              |                                |
| `serviceDate`            | string (date)      | sì              | Giorno di servizio, YYYY-MM-DD |
| `partySize`              | integer            | sì              |                                |
| `timezone`               | string             | sì              | Fuso IANA del locale           |
| `data`                   | array              | sì              |                                |
| `data[].time`            | string             | sì              | Ora locale del locale, HH:mm   |
| `data[].startsAt`        | string (date-time) | sì              | Istante ISO 8601 con fuso      |
| `data[].endsAt`          | string (date-time) | sì              | Istante ISO 8601 con fuso      |
| `data[].turnTimeMinutes` | integer            | sì              |                                |
| `data[].seats`           | integer            | sì              |                                |
| `data[].overflowsShift`  | boolean            | sì              |                                |
| `nextCursor`             | object             | sì              |                                |

## Elenca i giorni disponibili

`GET /availability/days`

Scope: `reservations:read`. Intervallo di al massimo 62 giorni, estremi inclusi.

### Parametri

| Nome        | Posizione | Tipo          | Obbligatorio | Descrizione |
| ----------- | --------- | ------------- | ------------ | ----------- |
| `venueId`   | query     | string (uuid) | sì           |             |
| `from`      | query     | string (date) | sì           |             |
| `to`        | query     | string (date) | sì           |             |
| `partySize` | query     | integer       | sì           |             |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                | Tipo          | Sempre presente | Descrizione                         |
| -------------------- | ------------- | --------------- | ----------------------------------- |
| `venueId`            | string (uuid) | sì              |                                     |
| `from`               | string (date) | sì              | Giorno di servizio, YYYY-MM-DD      |
| `to`                 | string (date) | sì              | Giorno di servizio, YYYY-MM-DD      |
| `partySize`          | integer       | sì              |                                     |
| `timezone`           | string        | sì              | Fuso IANA del locale                |
| `data`               | array         | sì              |                                     |
| `data[].serviceDate` | string (date) | sì              | Giorno di servizio, YYYY-MM-DD      |
| `data[].available`   | boolean       | sì              |                                     |
| `data[].slotCount`   | integer       | sì              | Quanti orari di /availability/slots |
| `nextCursor`         | object        | sì              |                                     |

## Elenca le prenotazioni

`GET /reservations`

Scope: `reservations:read`

### Parametri

| Nome           | Posizione | Tipo                                                                            | Obbligatorio | Descrizione                                                                 |
| -------------- | --------- | ------------------------------------------------------------------------------- | ------------ | --------------------------------------------------------------------------- |
| `limit`        | query     | integer                                                                         | no           | Righe per pagina                                                            |
| `cursor`       | query     | string                                                                          | no           | Il nextCursor della risposta precedente                                     |
| `venueId`      | query     | string (uuid)                                                                   | no           | Solo questo locale                                                          |
| `serviceDate`  | query     | string (date)                                                                   | no           | Un giorno di servizio, in alternativa a from/to                             |
| `from`         | query     | string (date)                                                                   | no           | Dal giorno di servizio (compreso)                                           |
| `to`           | query     | string (date)                                                                   | no           | Al giorno di servizio (compreso)                                            |
| `status`       | query     | array                                                                           | no           | Uno o più stati                                                             |
| `guestId`      | query     | string (uuid)                                                                   | no           | Solo questo ospite                                                          |
| `source`       | query     | string: `phone`, `voice_agent`, `floor`, `waitlist`, `walk_in`, `api`, `import` | no           | Solo questa origine                                                         |
| `updatedSince` | query     | string (date-time)                                                              | no           | Solo ciò che è cambiato dopo questo istante                                 |
| `externalRef`  | query     | string                                                                          | no           | Solo quella col tuo identificativo                                          |
| `expand`       | query     | array                                                                           | no           | guest aggiunge guestDetails (serve anche guests:read), table aggiunge table |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                   | Tipo                                                                                                 | Sempre presente | Descrizione                     |
| ----------------------- | ---------------------------------------------------------------------------------------------------- | --------------- | ------------------------------- |
| `data`                  | array                                                                                                | sì              |                                 |
| `data[].id`             | string (uuid)                                                                                        | sì              |                                 |
| `data[].venueId`        | string (uuid)                                                                                        | sì              |                                 |
| `data[].serviceDate`    | string (date)                                                                                        | sì              | Giorno di servizio, YYYY-MM-DD  |
| `data[].time`           | string                                                                                               | sì              | Ora locale del locale, HH:mm    |
| `data[].startsAt`       | string (date-time)                                                                                   | sì              | Istante ISO 8601 con fuso       |
| `data[].endsAt`         | string (date-time)                                                                                   | sì              | Istante ISO 8601 con fuso       |
| `data[].partySize`      | integer                                                                                              | sì              |                                 |
| `data[].status`         | string: `created`, `confirmed`, `arrived`, `seated`, `released`, `completed`, `no_show`, `cancelled` | sì              |                                 |
| `data[].tableAssigned`  | boolean                                                                                              | sì              |                                 |
| `data[].needsAttention` | boolean                                                                                              | sì              | Valida, ma da sistemare in sala |
| `data[].notes`          | object                                                                                               | sì              |                                 |
| `data[].source`         | string: `phone`, `voice_agent`, `floor`, `waitlist`, `walk_in`, `api`, `import`                      | sì              |                                 |
| `data[].sourceDetail`   | object                                                                                               | sì              |                                 |
| `data[].externalRef`    | object                                                                                               | sì              |                                 |
| `data[].guestId`        | object                                                                                               | sì              |                                 |
| `data[].updatedAt`      | string (date-time)                                                                                   | sì              | Anche la versione, per If-Match |
| `data[].guest`          | object                                                                                               | sì              |                                 |
| `data[].guestDetails`   | object                                                                                               | no              |                                 |
| `data[].table`          | object                                                                                               | no              |                                 |
| `nextCursor`            | object                                                                                               | sì              |                                 |

## Crea una prenotazione

`POST /reservations`

Scope: `reservations:write`

### Parametri

| Nome              | Posizione | Tipo   | Obbligatorio | Descrizione                                                             |
| ----------------- | --------- | ------ | ------------ | ----------------------------------------------------------------------- |
| `Idempotency-Key` | header    | string | no           | La stessa chiave ripetuta ritrova la risorsa invece di crearne un'altra |

### Body (JSON)

| Campo         | Tipo           | Obbligatorio | Descrizione                                                               |
| ------------- | -------------- | ------------ | ------------------------------------------------------------------------- |
| `venueId`     | string (uuid)  | sì           |                                                                           |
| `serviceDate` | string (date)  | sì           | Giorno di servizio, YYYY-MM-DD                                            |
| `time`        | string         | sì           | Ora locale del locale, HH:mm                                              |
| `partySize`   | integer        | sì           |                                                                           |
| `phone`       | string         | no           | Telefono dell'ospite: lo riconosce o lo crea                              |
| `guestName`   | string         | no           |                                                                           |
| `email`       | string (email) | no           | Solo con phone; riempie l'ospite se non l'ha già                          |
| `firstName`   | string         | no           | Solo con phone; riempie l'ospite se non l'ha già                          |
| `lastName`    | string         | no           | Solo con phone; riempie l'ospite se non l'ha già                          |
| `serviceTags` | array          | no           | Solo con phone: si aggiungono all'ospite; un nome fuori catalogo è un 400 |
| `notes`       | string         | no           |                                                                           |
| `channel`     | string         | no           | Da dove arriva, es. sito o Google: finisce in sourceDetail                |
| `externalRef` | string         | no           | Il tuo identificativo, unico nella tua organizzazione                     |

### Risposte

| Status | Descrizione                                                  |
| ------ | ------------------------------------------------------------ |
| `200`  | Già creata con la stessa Idempotency-Key                     |
| `201`  | Creata (dalla chiave pubblica del widget: WidgetReservation) |
| `400`  | invalid\_request                                             |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked        |
| `403`  | forbidden, insufficient\_scope                               |
| `404`  | not\_found                                                   |
| `409`  | no\_availability, conflict, idempotency\_in\_progress        |
| `422`  | idempotency\_key\_reused                                     |
| `429`  | rate\_limited                                                |

### Campi della risposta

| Campo         | Tipo   | Sempre presente | Descrizione |
| ------------- | ------ | --------------- | ----------- |
| `reservation` | object | sì              |             |

## Recupera una prenotazione

`GET /reservations/{id}`

Scope: `reservations:read`

### Parametri

| Nome     | Posizione | Tipo          | Obbligatorio | Descrizione                                                                 |
| -------- | --------- | ------------- | ------------ | --------------------------------------------------------------------------- |
| `id`     | path      | string (uuid) | sì           |                                                                             |
| `expand` | query     | array         | no           | guest aggiunge guestDetails (serve anche guests:read), table aggiunge table |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                        | Tipo                                                                                                 | Sempre presente | Descrizione                     |
| ---------------------------- | ---------------------------------------------------------------------------------------------------- | --------------- | ------------------------------- |
| `reservation`                | object                                                                                               | sì              |                                 |
| `reservation.id`             | string (uuid)                                                                                        | sì              |                                 |
| `reservation.venueId`        | string (uuid)                                                                                        | sì              |                                 |
| `reservation.serviceDate`    | string (date)                                                                                        | sì              | Giorno di servizio, YYYY-MM-DD  |
| `reservation.time`           | string                                                                                               | sì              | Ora locale del locale, HH:mm    |
| `reservation.startsAt`       | string (date-time)                                                                                   | sì              | Istante ISO 8601 con fuso       |
| `reservation.endsAt`         | string (date-time)                                                                                   | sì              | Istante ISO 8601 con fuso       |
| `reservation.partySize`      | integer                                                                                              | sì              |                                 |
| `reservation.status`         | string: `created`, `confirmed`, `arrived`, `seated`, `released`, `completed`, `no_show`, `cancelled` | sì              |                                 |
| `reservation.tableAssigned`  | boolean                                                                                              | sì              |                                 |
| `reservation.needsAttention` | boolean                                                                                              | sì              | Valida, ma da sistemare in sala |
| `reservation.notes`          | object                                                                                               | sì              |                                 |
| `reservation.source`         | string: `phone`, `voice_agent`, `floor`, `waitlist`, `walk_in`, `api`, `import`                      | sì              |                                 |
| `reservation.sourceDetail`   | object                                                                                               | sì              |                                 |
| `reservation.externalRef`    | object                                                                                               | sì              |                                 |
| `reservation.guestId`        | object                                                                                               | sì              |                                 |
| `reservation.updatedAt`      | string (date-time)                                                                                   | sì              | Anche la versione, per If-Match |
| `reservation.guest`          | object                                                                                               | sì              |                                 |
| `reservation.guestDetails`   | object                                                                                               | no              |                                 |
| `reservation.table`          | object                                                                                               | no              |                                 |

## Aggiorna una prenotazione

`PATCH /reservations/{id}`

Scope: `reservations:write`. Conferma, sposta o cambia stato, tavolo o ospite. Gli stati della sala (arrived, seated, released, completed, no\_show) e tableId/tableCombinationId chiedono anche `floor:write`. Per annullare si usa DELETE.

### Parametri

| Nome       | Posizione | Tipo          | Obbligatorio | Descrizione                                                          |
| ---------- | --------- | ------------- | ------------ | -------------------------------------------------------------------- |
| `id`       | path      | string (uuid) | sì           |                                                                      |
| `If-Match` | header    | string        | no           | L'updatedAt letto: la modifica passa solo se nessuno ha scritto dopo |

### Body (JSON)

| Campo                | Tipo                                                                         | Obbligatorio | Descrizione                                                    |
| -------------------- | ---------------------------------------------------------------------------- | ------------ | -------------------------------------------------------------- |
| `serviceDate`        | string (date)                                                                | no           | Giorno di servizio, YYYY-MM-DD                                 |
| `time`               | string                                                                       | no           | Ora locale del locale, HH:mm                                   |
| `partySize`          | integer                                                                      | no           |                                                                |
| `notes`              | object                                                                       | no           |                                                                |
| `status`             | string: `confirmed`, `arrived`, `seated`, `released`, `completed`, `no_show` | no           | Solo le transizioni ammesse; lo stesso stato non cambia niente |
| `tableId`            | object                                                                       | no           |                                                                |
| `tableCombinationId` | object                                                                       | no           |                                                                |
| `guestId`            | object                                                                       | no           |                                                                |
| `externalRef`        | object                                                                       | no           |                                                                |
| `version`            | string (date-time)                                                           | no           | In alternativa a If-Match: l'updatedAt letto                   |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `409`  | no\_availability, conflict                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                        | Tipo                                                                                                 | Sempre presente | Descrizione                     |
| ---------------------------- | ---------------------------------------------------------------------------------------------------- | --------------- | ------------------------------- |
| `reservation`                | object                                                                                               | sì              |                                 |
| `reservation.id`             | string (uuid)                                                                                        | sì              |                                 |
| `reservation.venueId`        | string (uuid)                                                                                        | sì              |                                 |
| `reservation.serviceDate`    | string (date)                                                                                        | sì              | Giorno di servizio, YYYY-MM-DD  |
| `reservation.time`           | string                                                                                               | sì              | Ora locale del locale, HH:mm    |
| `reservation.startsAt`       | string (date-time)                                                                                   | sì              | Istante ISO 8601 con fuso       |
| `reservation.endsAt`         | string (date-time)                                                                                   | sì              | Istante ISO 8601 con fuso       |
| `reservation.partySize`      | integer                                                                                              | sì              |                                 |
| `reservation.status`         | string: `created`, `confirmed`, `arrived`, `seated`, `released`, `completed`, `no_show`, `cancelled` | sì              |                                 |
| `reservation.tableAssigned`  | boolean                                                                                              | sì              |                                 |
| `reservation.needsAttention` | boolean                                                                                              | sì              | Valida, ma da sistemare in sala |
| `reservation.notes`          | object                                                                                               | sì              |                                 |
| `reservation.source`         | string: `phone`, `voice_agent`, `floor`, `waitlist`, `walk_in`, `api`, `import`                      | sì              |                                 |
| `reservation.sourceDetail`   | object                                                                                               | sì              |                                 |
| `reservation.externalRef`    | object                                                                                               | sì              |                                 |
| `reservation.guestId`        | object                                                                                               | sì              |                                 |
| `reservation.updatedAt`      | string (date-time)                                                                                   | sì              | Anche la versione, per If-Match |
| `reservation.guest`          | object                                                                                               | sì              |                                 |
| `reservation.guestDetails`   | object                                                                                               | no              |                                 |
| `reservation.table`          | object                                                                                               | no              |                                 |

## Annulla una prenotazione

`DELETE /reservations/{id}`

Scope: `reservations:write`. Porta la prenotazione allo stato `cancelled`. Se è già `cancelled`, risponde 200 senza effetti. Dagli stati seated, released, completed e no\_show risponde 409 conflict con details.allowedTransitions.

### Parametri

| Nome | Posizione | Tipo          | Obbligatorio | Descrizione |
| ---- | --------- | ------------- | ------------ | ----------- |
| `id` | path      | string (uuid) | sì           |             |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `409`  | conflict                                              |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                        | Tipo                                                                                                 | Sempre presente | Descrizione                     |
| ---------------------------- | ---------------------------------------------------------------------------------------------------- | --------------- | ------------------------------- |
| `reservation`                | object                                                                                               | sì              |                                 |
| `reservation.id`             | string (uuid)                                                                                        | sì              |                                 |
| `reservation.venueId`        | string (uuid)                                                                                        | sì              |                                 |
| `reservation.serviceDate`    | string (date)                                                                                        | sì              | Giorno di servizio, YYYY-MM-DD  |
| `reservation.time`           | string                                                                                               | sì              | Ora locale del locale, HH:mm    |
| `reservation.startsAt`       | string (date-time)                                                                                   | sì              | Istante ISO 8601 con fuso       |
| `reservation.endsAt`         | string (date-time)                                                                                   | sì              | Istante ISO 8601 con fuso       |
| `reservation.partySize`      | integer                                                                                              | sì              |                                 |
| `reservation.status`         | string: `created`, `confirmed`, `arrived`, `seated`, `released`, `completed`, `no_show`, `cancelled` | sì              |                                 |
| `reservation.tableAssigned`  | boolean                                                                                              | sì              |                                 |
| `reservation.needsAttention` | boolean                                                                                              | sì              | Valida, ma da sistemare in sala |
| `reservation.notes`          | object                                                                                               | sì              |                                 |
| `reservation.source`         | string: `phone`, `voice_agent`, `floor`, `waitlist`, `walk_in`, `api`, `import`                      | sì              |                                 |
| `reservation.sourceDetail`   | object                                                                                               | sì              |                                 |
| `reservation.externalRef`    | object                                                                                               | sì              |                                 |
| `reservation.guestId`        | object                                                                                               | sì              |                                 |
| `reservation.updatedAt`      | string (date-time)                                                                                   | sì              | Anche la versione, per If-Match |
| `reservation.guest`          | object                                                                                               | sì              |                                 |
| `reservation.guestDetails`   | object                                                                                               | no              |                                 |
| `reservation.table`          | object                                                                                               | no              |                                 |

## Elenca le voci della lista d'attesa

`GET /waitlist`

Scope: `waitlist:read`

### Parametri

| Nome           | Posizione | Tipo               | Obbligatorio | Descrizione                                     |
| -------------- | --------- | ------------------ | ------------ | ----------------------------------------------- |
| `limit`        | query     | integer            | no           | Righe per pagina                                |
| `cursor`       | query     | string             | no           | Il nextCursor della risposta precedente         |
| `venueId`      | query     | string (uuid)      | no           | Solo questo locale                              |
| `serviceDate`  | query     | string (date)      | no           | Un giorno di servizio, in alternativa a from/to |
| `from`         | query     | string (date)      | no           | Dal giorno di servizio (compreso)               |
| `to`           | query     | string (date)      | no           | Al giorno di servizio (compreso)                |
| `status`       | query     | array              | no           | Uno o più stati                                 |
| `guestId`      | query     | string (uuid)      | no           | Solo questo ospite                              |
| `updatedSince` | query     | string (date-time) | no           | Solo ciò che è cambiato dopo questo istante     |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                  | Tipo                                                  | Sempre presente | Descrizione                     |
| ---------------------- | ----------------------------------------------------- | --------------- | ------------------------------- |
| `data`                 | array                                                 | sì              |                                 |
| `data[].id`            | string (uuid)                                         | sì              |                                 |
| `data[].venueId`       | string (uuid)                                         | sì              |                                 |
| `data[].serviceDate`   | string (date)                                         | sì              | Giorno di servizio, YYYY-MM-DD  |
| `data[].partySize`     | integer                                               | sì              |                                 |
| `data[].earliestTime`  | string                                                | sì              | Ora locale del locale, HH:mm    |
| `data[].latestTime`    | string                                                | sì              | Ora locale del locale, HH:mm    |
| `data[].status`        | string: `waiting`, `called`, `converted`, `cancelled` | sì              |                                 |
| `data[].guestId`       | object                                                | sì              |                                 |
| `data[].reservationId` | object                                                | sì              |                                 |
| `data[].createdAt`     | string (date-time)                                    | sì              | Istante ISO 8601 con fuso       |
| `data[].updatedAt`     | string (date-time)                                    | sì              | Anche la versione, per If-Match |
| `data[].guest`         | object                                                | sì              |                                 |
| `nextCursor`           | object                                                | sì              |                                 |

## Crea una voce in lista d'attesa

`POST /waitlist`

Scope: `waitlist:write`

### Parametri

| Nome              | Posizione | Tipo   | Obbligatorio | Descrizione                                                             |
| ----------------- | --------- | ------ | ------------ | ----------------------------------------------------------------------- |
| `Idempotency-Key` | header    | string | no           | La stessa chiave ripetuta ritrova la risorsa invece di crearne un'altra |

### Body (JSON)

| Campo          | Tipo          | Obbligatorio | Descrizione                    |
| -------------- | ------------- | ------------ | ------------------------------ |
| `venueId`      | string (uuid) | sì           |                                |
| `serviceDate`  | string (date) | sì           | Giorno di servizio, YYYY-MM-DD |
| `partySize`    | integer       | sì           |                                |
| `earliestTime` | string        | sì           | Ora locale del locale, HH:mm   |
| `latestTime`   | string        | sì           | Ora locale del locale, HH:mm   |
| `phone`        | string        | sì           |                                |
| `guestName`    | string        | no           |                                |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | Già creata con la stessa Idempotency-Key              |
| `201`  | Creata                                                |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `409`  | idempotency\_in\_progress                             |
| `422`  | idempotency\_key\_reused                              |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                 | Tipo                                                  | Sempre presente | Descrizione                     |
| --------------------- | ----------------------------------------------------- | --------------- | ------------------------------- |
| `entry`               | object                                                | sì              |                                 |
| `entry.id`            | string (uuid)                                         | sì              |                                 |
| `entry.venueId`       | string (uuid)                                         | sì              |                                 |
| `entry.serviceDate`   | string (date)                                         | sì              | Giorno di servizio, YYYY-MM-DD  |
| `entry.partySize`     | integer                                               | sì              |                                 |
| `entry.earliestTime`  | string                                                | sì              | Ora locale del locale, HH:mm    |
| `entry.latestTime`    | string                                                | sì              | Ora locale del locale, HH:mm    |
| `entry.status`        | string: `waiting`, `called`, `converted`, `cancelled` | sì              |                                 |
| `entry.guestId`       | object                                                | sì              |                                 |
| `entry.reservationId` | object                                                | sì              |                                 |
| `entry.createdAt`     | string (date-time)                                    | sì              | Istante ISO 8601 con fuso       |
| `entry.updatedAt`     | string (date-time)                                    | sì              | Anche la versione, per If-Match |
| `entry.guest`         | object                                                | sì              |                                 |

## Recupera una voce della lista d'attesa

`GET /waitlist/{id}`

Scope: `waitlist:read`

### Parametri

| Nome | Posizione | Tipo          | Obbligatorio | Descrizione |
| ---- | --------- | ------------- | ------------ | ----------- |
| `id` | path      | string (uuid) | sì           |             |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                 | Tipo                                                  | Sempre presente | Descrizione                     |
| --------------------- | ----------------------------------------------------- | --------------- | ------------------------------- |
| `entry`               | object                                                | sì              |                                 |
| `entry.id`            | string (uuid)                                         | sì              |                                 |
| `entry.venueId`       | string (uuid)                                         | sì              |                                 |
| `entry.serviceDate`   | string (date)                                         | sì              | Giorno di servizio, YYYY-MM-DD  |
| `entry.partySize`     | integer                                               | sì              |                                 |
| `entry.earliestTime`  | string                                                | sì              | Ora locale del locale, HH:mm    |
| `entry.latestTime`    | string                                                | sì              | Ora locale del locale, HH:mm    |
| `entry.status`        | string: `waiting`, `called`, `converted`, `cancelled` | sì              |                                 |
| `entry.guestId`       | object                                                | sì              |                                 |
| `entry.reservationId` | object                                                | sì              |                                 |
| `entry.createdAt`     | string (date-time)                                    | sì              | Istante ISO 8601 con fuso       |
| `entry.updatedAt`     | string (date-time)                                    | sì              | Anche la versione, per If-Match |
| `entry.guest`         | object                                                | sì              |                                 |

## Aggiorna una voce della lista d'attesa

`PATCH /waitlist/{id}`

Scope: `waitlist:write`. Modifica coperti o fascia oraria. Una voce già richiamata torna in attesa. Una voce convertita o rimossa risponde 409.

### Parametri

| Nome       | Posizione | Tipo          | Obbligatorio | Descrizione                                                          |
| ---------- | --------- | ------------- | ------------ | -------------------------------------------------------------------- |
| `id`       | path      | string (uuid) | sì           |                                                                      |
| `If-Match` | header    | string        | no           | L'updatedAt letto: la modifica passa solo se nessuno ha scritto dopo |

### Body (JSON)

| Campo          | Tipo               | Obbligatorio | Descrizione                                  |
| -------------- | ------------------ | ------------ | -------------------------------------------- |
| `partySize`    | integer            | no           |                                              |
| `earliestTime` | string             | no           | Ora locale del locale, HH:mm                 |
| `latestTime`   | string             | no           | Ora locale del locale, HH:mm                 |
| `version`      | string (date-time) | no           | In alternativa a If-Match: l'updatedAt letto |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `409`  | conflict                                              |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                 | Tipo                                                  | Sempre presente | Descrizione                     |
| --------------------- | ----------------------------------------------------- | --------------- | ------------------------------- |
| `entry`               | object                                                | sì              |                                 |
| `entry.id`            | string (uuid)                                         | sì              |                                 |
| `entry.venueId`       | string (uuid)                                         | sì              |                                 |
| `entry.serviceDate`   | string (date)                                         | sì              | Giorno di servizio, YYYY-MM-DD  |
| `entry.partySize`     | integer                                               | sì              |                                 |
| `entry.earliestTime`  | string                                                | sì              | Ora locale del locale, HH:mm    |
| `entry.latestTime`    | string                                                | sì              | Ora locale del locale, HH:mm    |
| `entry.status`        | string: `waiting`, `called`, `converted`, `cancelled` | sì              |                                 |
| `entry.guestId`       | object                                                | sì              |                                 |
| `entry.reservationId` | object                                                | sì              |                                 |
| `entry.createdAt`     | string (date-time)                                    | sì              | Istante ISO 8601 con fuso       |
| `entry.updatedAt`     | string (date-time)                                    | sì              | Anche la versione, per If-Match |
| `entry.guest`         | object                                                | sì              |                                 |

## Rimuovi una voce dalla lista d'attesa

`DELETE /waitlist/{id}`

Scope: `waitlist:write`. Porta la voce allo stato `cancelled` ed emette l'evento waitlist\_entry\_cancelled. La richiesta ripetuta non ha effetti; una voce già convertita risponde 409.

### Parametri

| Nome | Posizione | Tipo          | Obbligatorio | Descrizione |
| ---- | --------- | ------------- | ------------ | ----------- |
| `id` | path      | string (uuid) | sì           |             |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `409`  | conflict                                              |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                 | Tipo                                                  | Sempre presente | Descrizione                     |
| --------------------- | ----------------------------------------------------- | --------------- | ------------------------------- |
| `entry`               | object                                                | sì              |                                 |
| `entry.id`            | string (uuid)                                         | sì              |                                 |
| `entry.venueId`       | string (uuid)                                         | sì              |                                 |
| `entry.serviceDate`   | string (date)                                         | sì              | Giorno di servizio, YYYY-MM-DD  |
| `entry.partySize`     | integer                                               | sì              |                                 |
| `entry.earliestTime`  | string                                                | sì              | Ora locale del locale, HH:mm    |
| `entry.latestTime`    | string                                                | sì              | Ora locale del locale, HH:mm    |
| `entry.status`        | string: `waiting`, `called`, `converted`, `cancelled` | sì              |                                 |
| `entry.guestId`       | object                                                | sì              |                                 |
| `entry.reservationId` | object                                                | sì              |                                 |
| `entry.createdAt`     | string (date-time)                                    | sì              | Istante ISO 8601 con fuso       |
| `entry.updatedAt`     | string (date-time)                                    | sì              | Anche la versione, per If-Match |
| `entry.guest`         | object                                                | sì              |                                 |

## Converti una voce in prenotazione

`POST /waitlist/{id}/convert`

Scope: `waitlist:write` e `reservations:write`. La prenotazione ha lo stesso ospite e gli stessi coperti; l'orario è quello del richiamo, se c'è stato, altrimenti l'inizio della fascia. Una voce già convertita risponde 200 con la sua prenotazione.

### Parametri

| Nome              | Posizione | Tipo          | Obbligatorio | Descrizione                                                             |
| ----------------- | --------- | ------------- | ------------ | ----------------------------------------------------------------------- |
| `id`              | path      | string (uuid) | sì           |                                                                         |
| `Idempotency-Key` | header    | string        | no           | La stessa chiave ripetuta ritrova la risorsa invece di crearne un'altra |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | Già convertita                                        |
| `201`  | Convertita                                            |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `409`  | no\_availability, conflict, idempotency\_in\_progress |
| `422`  | idempotency\_key\_reused                              |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                        | Tipo                                                                                                 | Sempre presente | Descrizione                     |
| ---------------------------- | ---------------------------------------------------------------------------------------------------- | --------------- | ------------------------------- |
| `reservation`                | object                                                                                               | sì              |                                 |
| `reservation.id`             | string (uuid)                                                                                        | sì              |                                 |
| `reservation.venueId`        | string (uuid)                                                                                        | sì              |                                 |
| `reservation.serviceDate`    | string (date)                                                                                        | sì              | Giorno di servizio, YYYY-MM-DD  |
| `reservation.time`           | string                                                                                               | sì              | Ora locale del locale, HH:mm    |
| `reservation.startsAt`       | string (date-time)                                                                                   | sì              | Istante ISO 8601 con fuso       |
| `reservation.endsAt`         | string (date-time)                                                                                   | sì              | Istante ISO 8601 con fuso       |
| `reservation.partySize`      | integer                                                                                              | sì              |                                 |
| `reservation.status`         | string: `created`, `confirmed`, `arrived`, `seated`, `released`, `completed`, `no_show`, `cancelled` | sì              |                                 |
| `reservation.tableAssigned`  | boolean                                                                                              | sì              |                                 |
| `reservation.needsAttention` | boolean                                                                                              | sì              | Valida, ma da sistemare in sala |
| `reservation.notes`          | object                                                                                               | sì              |                                 |
| `reservation.source`         | string: `phone`, `voice_agent`, `floor`, `waitlist`, `walk_in`, `api`, `import`                      | sì              |                                 |
| `reservation.sourceDetail`   | object                                                                                               | sì              |                                 |
| `reservation.externalRef`    | object                                                                                               | sì              |                                 |
| `reservation.guestId`        | object                                                                                               | sì              |                                 |
| `reservation.updatedAt`      | string (date-time)                                                                                   | sì              | Anche la versione, per If-Match |
| `reservation.guest`          | object                                                                                               | sì              |                                 |
| `reservation.guestDetails`   | object                                                                                               | no              |                                 |
| `reservation.table`          | object                                                                                               | no              |                                 |

## Elenca gli ospiti

`GET /guests`

Scope: `guests:read`

### Parametri

| Nome           | Posizione | Tipo               | Obbligatorio | Descrizione                                                                            |
| -------------- | --------- | ------------------ | ------------ | -------------------------------------------------------------------------------------- |
| `limit`        | query     | integer            | no           | Righe per pagina                                                                       |
| `cursor`       | query     | string             | no           | Il nextCursor della risposta precedente                                                |
| `q`            | query     | string             | no           | Nome, email o cifre del telefono (almeno 3, al massimo 200 caratteri; fino a 8 parole) |
| `phone`        | query     | string             | no           | Un telefono, qualunque forma                                                           |
| `email`        | query     | string             | no           | Un'email                                                                               |
| `externalRef`  | query     | string             | no           | Il tuo identificativo                                                                  |
| `updatedSince` | query     | string (date-time) | no           | Solo ciò che è cambiato dopo questo istante                                            |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                   | Tipo               | Sempre presente | Descrizione                     |
| ----------------------- | ------------------ | --------------- | ------------------------------- |
| `data`                  | array              | sì              |                                 |
| `data[].id`             | string (uuid)      | sì              |                                 |
| `data[].phone`          | string             | sì              | E.164                           |
| `data[].name`           | object             | sì              |                                 |
| `data[].firstName`      | object             | sì              |                                 |
| `data[].lastName`       | object             | sì              |                                 |
| `data[].email`          | object             | sì              |                                 |
| `data[].allergies`      | object             | sì              |                                 |
| `data[].allergens`      | array              | sì              |                                 |
| `data[].notes`          | object             | sì              |                                 |
| `data[].visitCount`     | integer            | sì              |                                 |
| `data[].noShowCount`    | integer            | sì              |                                 |
| `data[].cancelledCount` | integer            | sì              |                                 |
| `data[].lastVisitAt`    | object             | sì              |                                 |
| `data[].consents`       | object             | sì              |                                 |
| `data[].campaignTags`   | array              | sì              |                                 |
| `data[].serviceTags`    | array              | sì              |                                 |
| `data[].externalRef`    | object             | sì              |                                 |
| `data[].createdAt`      | string (date-time) | sì              | Istante ISO 8601 con fuso       |
| `data[].updatedAt`      | string (date-time) | sì              | Anche la versione, per If-Match |
| `nextCursor`            | object             | sì              |                                 |

## Crea o aggiorna un ospite

`POST /guests`

Scope: `guests:write`. Crea l'ospite o aggiorna quello con lo stesso telefono. Risponde 201 se l'ospite è nuovo, 200 se il telefono esiste già (i campi inviati vengono scritti) o se la stessa Idempotency-Key ritrova la richiesta precedente.

### Parametri

| Nome              | Posizione | Tipo   | Obbligatorio | Descrizione                                                             |
| ----------------- | --------- | ------ | ------------ | ----------------------------------------------------------------------- |
| `Idempotency-Key` | header    | string | no           | La stessa chiave ripetuta ritrova la risorsa invece di crearne un'altra |

### Body (JSON)

| Campo         | Tipo   | Obbligatorio | Descrizione                                 |
| ------------- | ------ | ------------ | ------------------------------------------- |
| `phone`       | string | sì           | Il telefono, qualunque forma: diventa E.164 |
| `name`        | object | no           |                                             |
| `firstName`   | object | no           |                                             |
| `lastName`    | object | no           |                                             |
| `email`       | object | no           |                                             |
| `allergies`   | object | no           |                                             |
| `notes`       | object | no           |                                             |
| `externalRef` | object | no           |                                             |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | Aggiornato o ritrovato                                |
| `201`  | Creato                                                |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `409`  | conflict, idempotency\_in\_progress                   |
| `422`  | idempotency\_key\_reused                              |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                  | Tipo               | Sempre presente | Descrizione                     |
| ---------------------- | ------------------ | --------------- | ------------------------------- |
| `guest`                | object             | sì              |                                 |
| `guest.id`             | string (uuid)      | sì              |                                 |
| `guest.phone`          | string             | sì              | E.164                           |
| `guest.name`           | object             | sì              |                                 |
| `guest.firstName`      | object             | sì              |                                 |
| `guest.lastName`       | object             | sì              |                                 |
| `guest.email`          | object             | sì              |                                 |
| `guest.allergies`      | object             | sì              |                                 |
| `guest.allergens`      | array              | sì              |                                 |
| `guest.notes`          | object             | sì              |                                 |
| `guest.visitCount`     | integer            | sì              |                                 |
| `guest.noShowCount`    | integer            | sì              |                                 |
| `guest.cancelledCount` | integer            | sì              |                                 |
| `guest.lastVisitAt`    | object             | sì              |                                 |
| `guest.consents`       | object             | sì              |                                 |
| `guest.campaignTags`   | array              | sì              |                                 |
| `guest.serviceTags`    | array              | sì              |                                 |
| `guest.externalRef`    | object             | sì              |                                 |
| `guest.createdAt`      | string (date-time) | sì              | Istante ISO 8601 con fuso       |
| `guest.updatedAt`      | string (date-time) | sì              | Anche la versione, per If-Match |

## Cerca un ospite per telefono

`GET /guests/lookup`

Scope: `guests:read`

### Parametri

| Nome    | Posizione | Tipo   | Obbligatorio | Descrizione |
| ------- | --------- | ------ | ------------ | ----------- |
| `phone` | query     | string | sì           |             |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo               | Tipo          | Sempre presente | Descrizione |
| ------------------- | ------------- | --------------- | ----------- |
| `found`             | object        | sì              |             |
| `guest`             | object        | sì              |             |
| `guest.id`          | string (uuid) | sì              |             |
| `guest.phone`       | string        | sì              | E.164       |
| `guest.name`        | object        | sì              |             |
| `guest.allergies`   | object        | sì              |             |
| `guest.notes`       | object        | sì              |             |
| `guest.visitCount`  | integer       | sì              |             |
| `guest.noShowCount` | integer       | sì              |             |

| Campo   | Tipo   | Sempre presente | Descrizione |
| ------- | ------ | --------------- | ----------- |
| `found` | object | sì              |             |
| `phone` | string | sì              | E.164       |

## Recupera un ospite

`GET /guests/{id}`

Scope: `guests:read`

### Parametri

| Nome | Posizione | Tipo          | Obbligatorio | Descrizione |
| ---- | --------- | ------------- | ------------ | ----------- |
| `id` | path      | string (uuid) | sì           |             |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                  | Tipo               | Sempre presente | Descrizione                     |
| ---------------------- | ------------------ | --------------- | ------------------------------- |
| `guest`                | object             | sì              |                                 |
| `guest.id`             | string (uuid)      | sì              |                                 |
| `guest.phone`          | string             | sì              | E.164                           |
| `guest.name`           | object             | sì              |                                 |
| `guest.firstName`      | object             | sì              |                                 |
| `guest.lastName`       | object             | sì              |                                 |
| `guest.email`          | object             | sì              |                                 |
| `guest.allergies`      | object             | sì              |                                 |
| `guest.allergens`      | array              | sì              |                                 |
| `guest.notes`          | object             | sì              |                                 |
| `guest.visitCount`     | integer            | sì              |                                 |
| `guest.noShowCount`    | integer            | sì              |                                 |
| `guest.cancelledCount` | integer            | sì              |                                 |
| `guest.lastVisitAt`    | object             | sì              |                                 |
| `guest.consents`       | object             | sì              |                                 |
| `guest.campaignTags`   | array              | sì              |                                 |
| `guest.serviceTags`    | array              | sì              |                                 |
| `guest.externalRef`    | object             | sì              |                                 |
| `guest.createdAt`      | string (date-time) | sì              | Istante ISO 8601 con fuso       |
| `guest.updatedAt`      | string (date-time) | sì              | Anche la versione, per If-Match |

## Aggiorna un ospite

`PATCH /guests/{id}`

Scope: `guests:write`. Aggiorna la scheda, i consensi e i tag di campagna. null o "" rimuove un campo. Se SQUADD è collegato all'organizzazione, consents e campaignTags appartengono a SQUADD e la modifica risponde 403.

### Parametri

| Nome       | Posizione | Tipo          | Obbligatorio | Descrizione                                                          |
| ---------- | --------- | ------------- | ------------ | -------------------------------------------------------------------- |
| `id`       | path      | string (uuid) | sì           |                                                                      |
| `If-Match` | header    | string        | no           | L'updatedAt letto: la modifica passa solo se nessuno ha scritto dopo |

### Body (JSON)

| Campo          | Tipo               | Obbligatorio | Descrizione                                  |
| -------------- | ------------------ | ------------ | -------------------------------------------- |
| `phone`        | string             | no           | Il telefono nuovo, unico nell'organizzazione |
| `name`         | object             | no           |                                              |
| `firstName`    | object             | no           |                                              |
| `lastName`     | object             | no           |                                              |
| `email`        | object             | no           |                                              |
| `allergies`    | object             | no           |                                              |
| `notes`        | object             | no           |                                              |
| `externalRef`  | object             | no           |                                              |
| `consents`     | object             | no           | I consensi, sostituiti per intero            |
| `campaignTags` | array              | no           | I tag di campagna, sostituiti per intero     |
| `version`      | string (date-time) | no           | In alternativa a If-Match: l'updatedAt letto |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `409`  | conflict                                              |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                  | Tipo               | Sempre presente | Descrizione                     |
| ---------------------- | ------------------ | --------------- | ------------------------------- |
| `guest`                | object             | sì              |                                 |
| `guest.id`             | string (uuid)      | sì              |                                 |
| `guest.phone`          | string             | sì              | E.164                           |
| `guest.name`           | object             | sì              |                                 |
| `guest.firstName`      | object             | sì              |                                 |
| `guest.lastName`       | object             | sì              |                                 |
| `guest.email`          | object             | sì              |                                 |
| `guest.allergies`      | object             | sì              |                                 |
| `guest.allergens`      | array              | sì              |                                 |
| `guest.notes`          | object             | sì              |                                 |
| `guest.visitCount`     | integer            | sì              |                                 |
| `guest.noShowCount`    | integer            | sì              |                                 |
| `guest.cancelledCount` | integer            | sì              |                                 |
| `guest.lastVisitAt`    | object             | sì              |                                 |
| `guest.consents`       | object             | sì              |                                 |
| `guest.campaignTags`   | array              | sì              |                                 |
| `guest.serviceTags`    | array              | sì              |                                 |
| `guest.externalRef`    | object             | sì              |                                 |
| `guest.createdAt`      | string (date-time) | sì              | Istante ISO 8601 con fuso       |
| `guest.updatedAt`      | string (date-time) | sì              | Anche la versione, per If-Match |

## Elimina un ospite

`DELETE /guests/{id}`

Scope: `guests:write`. Sposta l'ospite nel Cestino; dopo 30 giorni viene eliminato definitivamente.

### Parametri

| Nome | Posizione | Tipo          | Obbligatorio | Descrizione |
| ---- | --------- | ------------- | ------------ | ----------- |
| `id` | path      | string (uuid) | sì           |             |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `204`  | Nel Cestino                                           |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

## Imposta i tag di servizio di un ospite

`PUT /guests/{id}/tags`

Scope: `guests:write`. Sostituisce i tag dell'ospite; i nomi vengono dal catalogo (GET /service-tags). \[] li rimuove tutti.

### Parametri

| Nome | Posizione | Tipo          | Obbligatorio | Descrizione |
| ---- | --------- | ------------- | ------------ | ----------- |
| `id` | path      | string (uuid) | sì           |             |

### Body (JSON)

| Campo         | Tipo  | Obbligatorio | Descrizione                                  |
| ------------- | ----- | ------------ | -------------------------------------------- |
| `serviceTags` | array | sì           | I nomi dei tag, dopo sono esattamente questi |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                  | Tipo               | Sempre presente | Descrizione                     |
| ---------------------- | ------------------ | --------------- | ------------------------------- |
| `guest`                | object             | sì              |                                 |
| `guest.id`             | string (uuid)      | sì              |                                 |
| `guest.phone`          | string             | sì              | E.164                           |
| `guest.name`           | object             | sì              |                                 |
| `guest.firstName`      | object             | sì              |                                 |
| `guest.lastName`       | object             | sì              |                                 |
| `guest.email`          | object             | sì              |                                 |
| `guest.allergies`      | object             | sì              |                                 |
| `guest.allergens`      | array              | sì              |                                 |
| `guest.notes`          | object             | sì              |                                 |
| `guest.visitCount`     | integer            | sì              |                                 |
| `guest.noShowCount`    | integer            | sì              |                                 |
| `guest.cancelledCount` | integer            | sì              |                                 |
| `guest.lastVisitAt`    | object             | sì              |                                 |
| `guest.consents`       | object             | sì              |                                 |
| `guest.campaignTags`   | array              | sì              |                                 |
| `guest.serviceTags`    | array              | sì              |                                 |
| `guest.externalRef`    | object             | sì              |                                 |
| `guest.createdAt`      | string (date-time) | sì              | Istante ISO 8601 con fuso       |
| `guest.updatedAt`      | string (date-time) | sì              | Anche la versione, per If-Match |

## Recupera la scheda di servizio di un ospite

`GET /guests/{id}/service-card`

Scope: `guests:read`. Nome, allergie e tag di servizio dell'ospite.

### Parametri

| Nome | Posizione | Tipo          | Obbligatorio | Descrizione |
| ---- | --------- | ------------- | ------------ | ----------- |
| `id` | path      | string (uuid) | sì           |             |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                     | Tipo          | Sempre presente | Descrizione |
| ------------------------- | ------------- | --------------- | ----------- |
| `serviceCard`             | object        | sì              |             |
| `serviceCard.id`          | string (uuid) | sì              |             |
| `serviceCard.name`        | object        | sì              |             |
| `serviceCard.allergies`   | object        | sì              |             |
| `serviceCard.allergens`   | array         | sì              |             |
| `serviceCard.serviceTags` | array         | sì              |             |

## Elenca gli eventi

`GET /events`

Scope: `events:read`. Ogni evento ha la stessa busta dei webhook.

### Parametri

| Nome      | Posizione | Tipo               | Obbligatorio | Descrizione                             |
| --------- | --------- | ------------------ | ------------ | --------------------------------------- |
| `limit`   | query     | integer            | no           | Righe per pagina                        |
| `cursor`  | query     | string             | no           | Il nextCursor della risposta precedente |
| `since`   | query     | string (date-time) | no           | Solo gli eventi dopo questo istante     |
| `type`    | query     | array              | no           | Uno o più tipi                          |
| `venueId` | query     | string (uuid)      | no           | Solo questo locale                      |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo               | Tipo                                                                                                                                                                                                                                                                                                                                                            | Sempre presente | Descrizione                                                                                                                                                                                                                                                               |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data`              | array                                                                                                                                                                                                                                                                                                                                                           | sì              |                                                                                                                                                                                                                                                                           |
| `data[].id`         | string (uuid)                                                                                                                                                                                                                                                                                                                                                   | sì              | L'evento: coincide con eventId                                                                                                                                                                                                                                            |
| `data[].eventId`    | string (uuid)                                                                                                                                                                                                                                                                                                                                                   | sì              | Lo stesso eventId del webhook                                                                                                                                                                                                                                             |
| `data[].type`       | string: `reservation_created`, `reservation_confirmed`, `reservation_modified`, `reservation_cancelled`, `guest_arrived`, `guest_seated`, `table_released`, `reservation_late`, `reservation_no_show`, `meal_completed`, `waitlist_entry_created`, `compatible_table_freed`, `guest_profile_changed`, `waitlist_entry_cancelled`, `reservation_needs_attention` | sì              |                                                                                                                                                                                                                                                                           |
| `data[].createdAt`  | string (date-time)                                                                                                                                                                                                                                                                                                                                              | sì              | Quando è accaduto il fatto                                                                                                                                                                                                                                                |
| `data[].venueId`    | string (uuid)                                                                                                                                                                                                                                                                                                                                                   | sì              |                                                                                                                                                                                                                                                                           |
| `data[].apiVersion` | string                                                                                                                                                                                                                                                                                                                                                          | sì              |                                                                                                                                                                                                                                                                           |
| `data[].data`       | object                                                                                                                                                                                                                                                                                                                                                          | sì              | In /events la fotografia del fatto, com'era quando è accaduto (guest della prenotazione nullo); nel webhook la prenotazione di quando parte, e updatedAt dice quale è più nuova. guest\_profile\_changed: in /events solo l'id dell'ospite, nel webhook la scheda intera. |
| `nextCursor`        | object                                                                                                                                                                                                                                                                                                                                                          | sì              |                                                                                                                                                                                                                                                                           |

## Recupera il consuntivo di un periodo

`GET /reports/period`

Scope: `reports:read`. Una riga per giorno del periodo.

### Parametri

| Nome      | Posizione | Tipo          | Obbligatorio | Descrizione                                       |
| --------- | --------- | ------------- | ------------ | ------------------------------------------------- |
| `venueId` | query     | string (uuid) | sì           | Il locale                                         |
| `from`    | query     | string (date) | sì           | Primo giorno di servizio                          |
| `to`      | query     | string (date) | sì           | Ultimo giorno di servizio (al massimo 367 giorni) |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                      | Tipo          | Sempre presente | Descrizione                    |
| -------------------------- | ------------- | --------------- | ------------------------------ |
| `venueId`                  | string (uuid) | sì              |                                |
| `from`                     | string (date) | sì              | Giorno di servizio, YYYY-MM-DD |
| `to`                       | string (date) | sì              | Giorno di servizio, YYYY-MM-DD |
| `days`                     | array         | sì              |                                |
| `days[].serviceDate`       | string (date) | sì              | Giorno di servizio, YYYY-MM-DD |
| `days[].covers`            | integer       | sì              |                                |
| `days[].tablesTurned`      | integer       | sì              |                                |
| `days[].noShows`           | integer       | sì              |                                |
| `days[].waitlistRecovered` | integer       | sì              |                                |
| `totals`                   | object        | sì              |                                |
| `totals.covers`            | integer       | sì              |                                |
| `totals.tablesTurned`      | integer       | sì              |                                |
| `totals.noShows`           | integer       | sì              |                                |
| `totals.waitlistRecovered` | integer       | sì              |                                |

## Recupera la chiusura di fine serata

`GET /reports/eod`

Scope: `reports:read`. Include il confronto con lo stesso giorno della settimana precedente.

### Parametri

| Nome          | Posizione | Tipo          | Obbligatorio | Descrizione           |
| ------------- | --------- | ------------- | ------------ | --------------------- |
| `venueId`     | query     | string (uuid) | sì           | Il locale             |
| `serviceDate` | query     | string (date) | sì           | Il giorno di servizio |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                            | Tipo          | Sempre presente | Descrizione                    |
| -------------------------------- | ------------- | --------------- | ------------------------------ |
| `venueId`                        | string (uuid) | sì              |                                |
| `serviceDate`                    | string (date) | sì              | Giorno di servizio, YYYY-MM-DD |
| `current`                        | object        | sì              |                                |
| `current.serviceDate`            | string (date) | sì              | Giorno di servizio, YYYY-MM-DD |
| `current.covers`                 | integer       | sì              |                                |
| `current.tablesTurned`           | integer       | sì              |                                |
| `current.noShows`                | integer       | sì              |                                |
| `current.waitlistRecovered`      | integer       | sì              |                                |
| `previousWeek`                   | object        | sì              |                                |
| `previousWeek.serviceDate`       | string (date) | sì              | Giorno di servizio, YYYY-MM-DD |
| `previousWeek.covers`            | integer       | sì              |                                |
| `previousWeek.tablesTurned`      | integer       | sì              |                                |
| `previousWeek.noShows`           | integer       | sì              |                                |
| `previousWeek.waitlistRecovered` | integer       | sì              |                                |

## Esporta le prenotazioni

`GET /exports/reservations`

Scope: `reports:read` e `reservations:read`. Risposta in streaming: CSV (RFC 4180) o una prenotazione JSON per riga.

### Parametri

| Nome           | Posizione | Tipo                                                                            | Obbligatorio | Descrizione                                     |
| -------------- | --------- | ------------------------------------------------------------------------------- | ------------ | ----------------------------------------------- |
| `format`       | query     | string: `csv`, `ndjson`                                                         | no           | csv o ndjson                                    |
| `venueId`      | query     | string (uuid)                                                                   | no           | Solo questo locale                              |
| `serviceDate`  | query     | string (date)                                                                   | no           | Un giorno di servizio, in alternativa a from/to |
| `from`         | query     | string (date)                                                                   | no           | Dal giorno di servizio (compreso)               |
| `to`           | query     | string (date)                                                                   | no           | Al giorno di servizio (compreso)                |
| `status`       | query     | array                                                                           | no           | Uno o più stati                                 |
| `guestId`      | query     | string (uuid)                                                                   | no           | Solo questo ospite                              |
| `source`       | query     | string: `phone`, `voice_agent`, `floor`, `waitlist`, `walk_in`, `api`, `import` | no           | Solo questa origine                             |
| `updatedSince` | query     | string (date-time)                                                              | no           | Solo ciò che è cambiato dopo questo istante     |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | Le prenotazioni, una per riga                         |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

Formati della risposta: `text/csv`, `application/x-ndjson`

### Campi della risposta

| Campo | Tipo | Sempre presente | Descrizione |
| ----- | ---- | --------------- | ----------- |

## Elenca le consegne dei webhook

`GET /webhook-deliveries`

Scope: `webhooks:read`. Le consegne con `status=discarded` formano la coda di scarto.

### Parametri

| Nome         | Posizione | Tipo          | Obbligatorio | Descrizione                             |
| ------------ | --------- | ------------- | ------------ | --------------------------------------- |
| `limit`      | query     | integer       | no           | Righe per pagina                        |
| `cursor`     | query     | string        | no           | Il nextCursor della risposta precedente |
| `status`     | query     | array         | no           | Uno o più stati                         |
| `venueId`    | query     | string (uuid) | no           | Solo questo locale                      |
| `endpointId` | query     | string (uuid) | no           | Solo questa destinazione                |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                   | Tipo                                        | Sempre presente | Descrizione                                                                                                                                                                                     |
| ----------------------- | ------------------------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data`                  | array                                       | sì              |                                                                                                                                                                                                 |
| `data[].id`             | string (uuid)                               | sì              |                                                                                                                                                                                                 |
| `data[].venueId`        | string (uuid)                               | sì              |                                                                                                                                                                                                 |
| `data[].endpointId`     | object                                      | sì              |                                                                                                                                                                                                 |
| `data[].idempotencyKey` | string                                      | sì              | La stessa X-Gestionesala-Idempotency-Key di ogni tentativo                                                                                                                                      |
| `data[].url`            | string                                      | sì              | L'indirizzo com'era al tentativo                                                                                                                                                                |
| `data[].status`         | string: `pending`, `delivered`, `discarded` | sì              |                                                                                                                                                                                                 |
| `data[].attemptCount`   | integer                                     | sì              |                                                                                                                                                                                                 |
| `data[].nextAttemptAt`  | object                                      | sì              |                                                                                                                                                                                                 |
| `data[].lastError`      | object                                      | sì              |                                                                                                                                                                                                 |
| `data[].lastStatusCode` | object                                      | sì              |                                                                                                                                                                                                 |
| `data[].deliveredAt`    | object                                      | sì              |                                                                                                                                                                                                 |
| `data[].createdAt`      | string (date-time)                          | sì              | Istante ISO 8601 con fuso                                                                                                                                                                       |
| `data[].updatedAt`      | string (date-time)                          | sì              | Istante ISO 8601 con fuso                                                                                                                                                                       |
| `data[].body`           | object                                      | sì              | Il corpo spedito: la busta del webhook, ridotta agli scope di chi legge. Senza guests:read dell'ospite resta l'id; reservation e waitlistEntry chiedono il loro scope di lettura o events:read. |
| `nextCursor`            | object                                      | sì              |                                                                                                                                                                                                 |

## Reinvia una consegna

`POST /webhook-deliveries/{id}/redeliver`

Scope: `webhooks:write`. Rimette in coda una consegna conclusa, con la stessa chiave di idempotenza.

### Parametri

| Nome              | Posizione | Tipo          | Obbligatorio | Descrizione                                                             |
| ----------------- | --------- | ------------- | ------------ | ----------------------------------------------------------------------- |
| `id`              | path      | string (uuid) | sì           |                                                                         |
| `Idempotency-Key` | header    | string        | no           | La stessa chiave ripetuta ritrova la risorsa invece di crearne un'altra |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | La stessa Idempotency-Key: la consegna di allora      |
| `201`  | Di nuovo in coda                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `409`  | conflict, idempotency\_in\_progress                   |
| `422`  | idempotency\_key\_reused                              |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                     | Tipo                                        | Sempre presente | Descrizione                                                                                                                                                                                     |
| ------------------------- | ------------------------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `delivery`                | object                                      | sì              |                                                                                                                                                                                                 |
| `delivery.id`             | string (uuid)                               | sì              |                                                                                                                                                                                                 |
| `delivery.venueId`        | string (uuid)                               | sì              |                                                                                                                                                                                                 |
| `delivery.endpointId`     | object                                      | sì              |                                                                                                                                                                                                 |
| `delivery.idempotencyKey` | string                                      | sì              | La stessa X-Gestionesala-Idempotency-Key di ogni tentativo                                                                                                                                      |
| `delivery.url`            | string                                      | sì              | L'indirizzo com'era al tentativo                                                                                                                                                                |
| `delivery.status`         | string: `pending`, `delivered`, `discarded` | sì              |                                                                                                                                                                                                 |
| `delivery.attemptCount`   | integer                                     | sì              |                                                                                                                                                                                                 |
| `delivery.nextAttemptAt`  | object                                      | sì              |                                                                                                                                                                                                 |
| `delivery.lastError`      | object                                      | sì              |                                                                                                                                                                                                 |
| `delivery.lastStatusCode` | object                                      | sì              |                                                                                                                                                                                                 |
| `delivery.deliveredAt`    | object                                      | sì              |                                                                                                                                                                                                 |
| `delivery.createdAt`      | string (date-time)                          | sì              | Istante ISO 8601 con fuso                                                                                                                                                                       |
| `delivery.updatedAt`      | string (date-time)                          | sì              | Istante ISO 8601 con fuso                                                                                                                                                                       |
| `delivery.body`           | object                                      | sì              | Il corpo spedito: la busta del webhook, ridotta agli scope di chi legge. Senza guests:read dell'ospite resta l'id; reservation e waitlistEntry chiedono il loro scope di lettura o events:read. |

## Elenca le destinazioni dei webhook

`GET /webhook-endpoints`

Scope: `webhooks:read`. Le destinazioni dei locali accessibili alla chiave.

### Parametri

| Nome      | Posizione | Tipo          | Obbligatorio | Descrizione                             |
| --------- | --------- | ------------- | ------------ | --------------------------------------- |
| `limit`   | query     | integer       | no           | Righe per pagina                        |
| `cursor`  | query     | string        | no           | Il nextCursor della risposta precedente |
| `venueId` | query     | string (uuid) | no           | Solo questo locale                      |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                            | Tipo               | Sempre presente | Descrizione               |
| -------------------------------- | ------------------ | --------------- | ------------------------- |
| `data`                           | array              | sì              |                           |
| `data[].id`                      | string (uuid)      | sì              |                           |
| `data[].venueId`                 | string (uuid)      | sì              |                           |
| `data[].url`                     | string             | sì              |                           |
| `data[].isActive`                | boolean            | sì              |                           |
| `data[].secretVersion`           | integer            | sì              |                           |
| `data[].previousSecretExpiresAt` | object             | sì              |                           |
| `data[].createdAt`               | string (date-time) | sì              | Istante ISO 8601 con fuso |
| `data[].updatedAt`               | string (date-time) | sì              | Istante ISO 8601 con fuso |
| `nextCursor`                     | object             | sì              |                           |

## Invia un evento di prova

`POST /webhook-endpoints/test`

Scope: `webhooks:write`. Invia subito un evento di prova firmato, fuori dalla coda: nessun nuovo tentativo, l'esito è nella risposta.

### Body (JSON)

| Campo        | Tipo          | Obbligatorio | Descrizione |
| ------------ | ------------- | ------------ | ----------- |
| `endpointId` | string (uuid) | sì           |             |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo              | Tipo               | Sempre presente | Descrizione                                 |
| ------------------ | ------------------ | --------------- | ------------------------------------------- |
| `endpointId`       | string (uuid)      | sì              |                                             |
| `delivered`        | boolean            | sì              |                                             |
| `statusCode`       | object             | sì              |                                             |
| `error`            | object             | sì              |                                             |
| `event`            | object             | sì              |                                             |
| `event.id`         | string             | sì              | test:\<eventId>, anche nell'Idempotency-Key |
| `event.eventId`    | string (uuid)      | sì              |                                             |
| `event.type`       | string             | sì              |                                             |
| `event.createdAt`  | string (date-time) | sì              | Istante ISO 8601 con fuso                   |
| `event.venueId`    | string (uuid)      | sì              |                                             |
| `event.apiVersion` | string             | sì              |                                             |
| `event.data`       | object             | sì              |                                             |

## Ruota il segreto di firma

`POST /webhook-endpoints/{id}/rotate-secret`

Scope: `webhooks:write`. Genera un nuovo segreto di firma; il precedente resta valido per `overlapMinutes` minuti.

### Parametri

| Nome              | Posizione | Tipo          | Obbligatorio | Descrizione                                                             |
| ----------------- | --------- | ------------- | ------------ | ----------------------------------------------------------------------- |
| `id`              | path      | string (uuid) | sì           |                                                                         |
| `Idempotency-Key` | header    | string        | no           | La stessa chiave ripetuta ritrova la risorsa invece di crearne un'altra |

### Body (JSON)

| Campo            | Tipo    | Obbligatorio | Descrizione |
| ---------------- | ------- | ------------ | ----------- |
| `overlapMinutes` | integer | no           |             |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `409`  | conflict, idempotency\_in\_progress                   |
| `422`  | idempotency\_key\_reused                              |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                     | Tipo               | Sempre presente | Descrizione                                   |
| ------------------------- | ------------------ | --------------- | --------------------------------------------- |
| `endpointId`              | string (uuid)      | sì              |                                               |
| `secretVersion`           | integer            | sì              |                                               |
| `secret`                  | string             | sì              | Il segreto nuovo: si vede solo qui            |
| `previousSecretExpiresAt` | string (date-time) | sì              | Fino a quando firma anche il segreto di prima |

## Ruota il segreto di firma dell'organizzazione

`POST /webhook-secret/rotate`

Scope: `webhooks:write`, con una chiave non limitata a certi locali. Genera un nuovo segreto per le consegne all'indirizzo scritto nell'azione; il precedente resta valido per `overlapMinutes` minuti.

### Parametri

| Nome              | Posizione | Tipo   | Obbligatorio | Descrizione                                                             |
| ----------------- | --------- | ------ | ------------ | ----------------------------------------------------------------------- |
| `Idempotency-Key` | header    | string | no           | La stessa chiave ripetuta ritrova la risorsa invece di crearne un'altra |

### Body (JSON)

| Campo            | Tipo    | Obbligatorio | Descrizione |
| ---------------- | ------- | ------------ | ----------- |
| `overlapMinutes` | integer | no           |             |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `400`  | invalid\_request                                      |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `409`  | conflict, idempotency\_in\_progress                   |
| `422`  | idempotency\_key\_reused                              |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                     | Tipo               | Sempre presente | Descrizione                                   |
| ------------------------- | ------------------ | --------------- | --------------------------------------------- |
| `secretVersion`           | integer            | sì              |                                               |
| `secret`                  | string             | sì              | Il segreto nuovo: si vede solo qui            |
| `previousSecretExpiresAt` | string (date-time) | sì              | Fino a quando firma anche il segreto di prima |

## Importa ospiti

`POST /imports/guests`

Scope: `imports:write`. Fino a 1000 righe per richiesta. Crea o aggiorna ogni ospite per telefono. Una riga storta non ferma le altre: finisce in `rejections` col motivo. Chi importa anche le prenotazioni passate non manda visitCount/noShowCount (si conterebbero due volte).

### Parametri

| Nome              | Posizione | Tipo   | Obbligatorio | Descrizione                                                             |
| ----------------- | --------- | ------ | ------------ | ----------------------------------------------------------------------- |
| `Idempotency-Key` | header    | string | no           | La stessa chiave ripetuta ritrova la risorsa invece di crearne un'altra |

### Body (JSON)

| Campo                | Tipo    | Obbligatorio | Descrizione                                                           |
| -------------------- | ------- | ------------ | --------------------------------------------------------------------- |
| `rows`               | array   | sì           |                                                                       |
| `rows[].phone`       | string  | sì           | Il telefono, qualunque forma: la chiave con cui si crea o si aggiorna |
| `rows[].name`        | object  | no           |                                                                       |
| `rows[].firstName`   | object  | no           |                                                                       |
| `rows[].lastName`    | object  | no           |                                                                       |
| `rows[].email`       | object  | no           |                                                                       |
| `rows[].allergies`   | object  | no           |                                                                       |
| `rows[].notes`       | object  | no           |                                                                       |
| `rows[].externalRef` | object  | no           |                                                                       |
| `rows[].visitCount`  | integer | no           | Visite nel gestionale di prima: si sommano a quelle contate qui       |
| `rows[].noShowCount` | integer | no           | Mancate presentazioni nel gestionale di prima                         |
| `rows[].lastVisitAt` | object  | no           |                                                                       |

### Risposte

| Status | Descrizione                                                            |
| ------ | ---------------------------------------------------------------------- |
| `200`  | Ritrovato con la stessa Idempotency-Key                                |
| `201`  | Import eseguito: ospiti creati o aggiornati, righe scartate col motivo |
| `400`  | invalid\_request                                                       |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked                  |
| `403`  | forbidden, insufficient\_scope                                         |
| `409`  | idempotency\_in\_progress                                              |
| `422`  | idempotency\_key\_reused                                               |
| `429`  | rate\_limited                                                          |

### Campi della risposta

| Campo                         | Tipo                                        | Sempre presente | Descrizione                                                                             |
| ----------------------------- | ------------------------------------------- | --------------- | --------------------------------------------------------------------------------------- |
| `import`                      | object                                      | sì              |                                                                                         |
| `import.id`                   | string (uuid)                               | sì              |                                                                                         |
| `import.kind`                 | string: `guests`, `reservations`            | sì              |                                                                                         |
| `import.status`               | string: `processing`, `completed`, `failed` | sì              | failed: un guasto a metà, le righe già entrate restano                                  |
| `import.totalRows`            | integer                                     | sì              |                                                                                         |
| `import.createdRows`          | integer                                     | sì              |                                                                                         |
| `import.updatedRows`          | integer                                     | sì              |                                                                                         |
| `import.rejectedRows`         | integer                                     | sì              |                                                                                         |
| `import.rejections`           | array                                       | sì              |                                                                                         |
| `import.rejections[].row`     | integer                                     | sì              | Posizione nell'elenco mandato, da zero                                                  |
| `import.rejections[].code`    | string                                      | sì              | Codice d'errore v1: invalid\_request, conflict, no\_availability, not\_found, forbidden |
| `import.rejections[].message` | string                                      | sì              |                                                                                         |
| `import.rejections[].fields`  | array                                       | sì              |                                                                                         |
| `import.createdAt`            | string (date-time)                          | sì              | Istante ISO 8601 con fuso                                                               |
| `import.completedAt`          | object                                      | sì              |                                                                                         |

## Importa prenotazioni

`POST /imports/reservations`

Scope: `imports:write`. Fino a 1000 righe per richiesta, passate e future. Origine `import`. Il passato entra nel suo stato finale, senza controllo di disponibilità e senza tavolo; il futuro passa dal motore come ogni prenotazione. Nessuna automazione e nessun webhook partono.

### Parametri

| Nome              | Posizione | Tipo   | Obbligatorio | Descrizione                                                             |
| ----------------- | --------- | ------ | ------------ | ----------------------------------------------------------------------- |
| `Idempotency-Key` | header    | string | no           | La stessa chiave ripetuta ritrova la risorsa invece di crearne un'altra |

### Body (JSON)

| Campo                    | Tipo                                                                | Obbligatorio | Descrizione                                                                            |
| ------------------------ | ------------------------------------------------------------------- | ------------ | -------------------------------------------------------------------------------------- |
| `rows`                   | array                                                               | sì           |                                                                                        |
| `rows[].venueId`         | string (uuid)                                                       | sì           |                                                                                        |
| `rows[].serviceDate`     | string (date)                                                       | sì           | Giorno di servizio, YYYY-MM-DD                                                         |
| `rows[].time`            | string                                                              | sì           | Ora locale del locale, HH:mm                                                           |
| `rows[].partySize`       | integer                                                             | sì           |                                                                                        |
| `rows[].status`          | string: `created`, `confirmed`, `completed`, `no_show`, `cancelled` | sì           | Nel passato completed, no\_show o cancelled; nel futuro created, confirmed o cancelled |
| `rows[].phone`           | string                                                              | no           | Il telefono dell'ospite: riconosciuto, o creato                                        |
| `rows[].guestName`       | object                                                              | no           |                                                                                        |
| `rows[].notes`           | object                                                              | no           |                                                                                        |
| `rows[].externalRef`     | object                                                              | no           |                                                                                        |
| `rows[].channel`         | object                                                              | no           |                                                                                        |
| `rows[].durationMinutes` | integer                                                             | no           | Durata delle righe passate e cancellate, 90 se manca; le future le decide il motore    |

### Risposte

| Status | Descrizione                                                     |
| ------ | --------------------------------------------------------------- |
| `200`  | Ritrovato con la stessa Idempotency-Key                         |
| `201`  | Import eseguito: prenotazioni create, righe scartate col motivo |
| `400`  | invalid\_request                                                |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked           |
| `403`  | forbidden, insufficient\_scope                                  |
| `409`  | idempotency\_in\_progress                                       |
| `422`  | idempotency\_key\_reused                                        |
| `429`  | rate\_limited                                                   |

### Campi della risposta

| Campo                         | Tipo                                        | Sempre presente | Descrizione                                                                             |
| ----------------------------- | ------------------------------------------- | --------------- | --------------------------------------------------------------------------------------- |
| `import`                      | object                                      | sì              |                                                                                         |
| `import.id`                   | string (uuid)                               | sì              |                                                                                         |
| `import.kind`                 | string: `guests`, `reservations`            | sì              |                                                                                         |
| `import.status`               | string: `processing`, `completed`, `failed` | sì              | failed: un guasto a metà, le righe già entrate restano                                  |
| `import.totalRows`            | integer                                     | sì              |                                                                                         |
| `import.createdRows`          | integer                                     | sì              |                                                                                         |
| `import.updatedRows`          | integer                                     | sì              |                                                                                         |
| `import.rejectedRows`         | integer                                     | sì              |                                                                                         |
| `import.rejections`           | array                                       | sì              |                                                                                         |
| `import.rejections[].row`     | integer                                     | sì              | Posizione nell'elenco mandato, da zero                                                  |
| `import.rejections[].code`    | string                                      | sì              | Codice d'errore v1: invalid\_request, conflict, no\_availability, not\_found, forbidden |
| `import.rejections[].message` | string                                      | sì              |                                                                                         |
| `import.rejections[].fields`  | array                                       | sì              |                                                                                         |
| `import.createdAt`            | string (date-time)                          | sì              | Istante ISO 8601 con fuso                                                               |
| `import.completedAt`          | object                                      | sì              |                                                                                         |

## Recupera un import

`GET /imports/{id}`

Scope: `imports:write`. Restituisce il resoconto di un import.

### Parametri

| Nome | Posizione | Tipo          | Obbligatorio | Descrizione |
| ---- | --------- | ------------- | ------------ | ----------- |
| `id` | path      | string (uuid) | sì           |             |

### Risposte

| Status | Descrizione                                           |
| ------ | ----------------------------------------------------- |
| `200`  | OK                                                    |
| `401`  | unauthenticated, api\_key\_invalid, api\_key\_revoked |
| `403`  | forbidden, insufficient\_scope                        |
| `404`  | not\_found                                            |
| `429`  | rate\_limited                                         |

### Campi della risposta

| Campo                         | Tipo                                        | Sempre presente | Descrizione                                                                             |
| ----------------------------- | ------------------------------------------- | --------------- | --------------------------------------------------------------------------------------- |
| `import`                      | object                                      | sì              |                                                                                         |
| `import.id`                   | string (uuid)                               | sì              |                                                                                         |
| `import.kind`                 | string: `guests`, `reservations`            | sì              |                                                                                         |
| `import.status`               | string: `processing`, `completed`, `failed` | sì              | failed: un guasto a metà, le righe già entrate restano                                  |
| `import.totalRows`            | integer                                     | sì              |                                                                                         |
| `import.createdRows`          | integer                                     | sì              |                                                                                         |
| `import.updatedRows`          | integer                                     | sì              |                                                                                         |
| `import.rejectedRows`         | integer                                     | sì              |                                                                                         |
| `import.rejections`           | array                                       | sì              |                                                                                         |
| `import.rejections[].row`     | integer                                     | sì              | Posizione nell'elenco mandato, da zero                                                  |
| `import.rejections[].code`    | string                                      | sì              | Codice d'errore v1: invalid\_request, conflict, no\_availability, not\_found, forbidden |
| `import.rejections[].message` | string                                      | sì              |                                                                                         |
| `import.rejections[].fields`  | array                                       | sì              |                                                                                         |
| `import.createdAt`            | string (date-time)                          | sì              | Istante ISO 8601 con fuso                                                               |
| `import.completedAt`          | object                                      | sì              |                                                                                         |

## Oggetto errore

Tutte le risposte di errore hanno questo formato.

| Campo                                          | Tipo               | Obbligatorio | Descrizione                                                                                                                                                                       |
| ---------------------------------------------- | ------------------ | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `error`                                        | object             | sì           |                                                                                                                                                                                   |
| `error.code`                                   | string             | sì           | Il codice su cui ramificare                                                                                                                                                       |
| `error.message`                                | string             | sì           | Per chi legge i log                                                                                                                                                               |
| `error.details`                                | object             | sì           | Cosa serve per correggere o riprovare: fields (i campi storti), requiredScope, reason; per no\_availability anche alternatives, gli orari vicini nella forma di GET /availability |
| `error.details.fields`                         | array              | no           |                                                                                                                                                                                   |
| `error.details.requiredScope`                  | string             | no           |                                                                                                                                                                                   |
| `error.details.reason`                         | string             | no           |                                                                                                                                                                                   |
| `error.details.alternatives`                   | array              | no           |                                                                                                                                                                                   |
| `error.details.alternatives[].time`            | string             | sì           | Ora locale del locale, HH:mm                                                                                                                                                      |
| `error.details.alternatives[].startsAt`        | string (date-time) | sì           | Istante ISO 8601 con fuso                                                                                                                                                         |
| `error.details.alternatives[].endsAt`          | string (date-time) | sì           | Istante ISO 8601 con fuso                                                                                                                                                         |
| `error.details.alternatives[].turnTimeMinutes` | integer            | sì           |                                                                                                                                                                                   |
| `error.details.alternatives[].seats`           | integer            | sì           |                                                                                                                                                                                   |
| `error.details.alternatives[].overflowsShift`  | boolean            | sì           |                                                                                                                                                                                   |
| `error.requestId`                              | string             | no           | Lo stesso valore dell'header X-Request-Id                                                                                                                                         |
