# Integrazione dei calendari con un servizio di terze parti

Le API – in formato ReST – messe a disposizione dalla piattaforma consentono le integrazioni necessarie con i sistemi esterni. \
Sono previste chiamate senza autenticazione per l’accesso a informazioni pubbliche e un meccanismo di autenticazione per la consultazione di dati non pubblici e per le operazioni di scrittura dove previste.&#x20;

**Verranno presi in esame 2 use-case specifici:**

* L'integrazione con un sistema Taglia code
* L'integrazione di un IVR (Interactive Voice Response)

&#x20;Le API dei calendari di **Opencity Italia** verranno interrogate al fine di:

* Recuperare configurazioni dei servizi e delle agende
* Ottenere disponibilità e slot prenotabili
* Effettuare prenotazioni (opzionale)
* Recuperare appuntamenti per una sede

La documentazione e i test delle API sono disponibili tramite interfaccia di tipo swagger.

* **Catalogo servizi e configurazione agende**

{% embed url="<https://www.comune.bugliano.pi.it/openapi/doc>" %}

* **Calendari, disponibilità, appuntamenti**

{% embed url="<https://servizi.comune.bugliano.pi.it/lang/api/doc>" %}

***

## **1. Integrazione IVR**

### **1.1 Flusso generale**

Il sistema IVR consente la prenotazione di appuntamenti tramite scelta vocale tra diverse tipologie di servizio, ad esempio:

* Rilascio documenti
* Certificati
* Identità digitale
* Autentiche

Per ogni servizio selezionato il flusso prevede due passaggi principali:

1. **Recupero configurazione del servizio**\
   Uffici, sedi e calendari associati.
2. **Recupero disponibilità**\
   Individuazione delle prime disponibilità nei calendari della sede scelta.

***

## **1.2 Recupero configurazione del servizio**

#### **Endpoint**

```
GET /api/openapi/booking-config?id={service_id}
```

#### **Descrizione**

Questa chiamata restituisce:

* Informazioni sul servizio
* Uffici che lo erogano
* Sedi
* Calendari associati alla sede

#### **Esempio di risposta (estratto)**

```json
{
  "items": [
    {
      "id": 2240,
      "link": "https://www.comune.bugliano.pi.it/api//servizi/47b0fb50deb217bfcceb5b6b4c32ba5b",
      "name": "Attivazione della TARI",
      "offices": [
        {
          "id": 856,
          "link": "https://www.comune.bugliano.pi.it/api//amministrazione/uffici/2c1aad31d1f20d6189ee5d1881a125e4",
          "name": "Ufficio Ambiente",
          "places": [
            {
              "id": 213,
              "link": "https://www.comune.bugliano.pi.it/api//vivere-il-comune/luoghi/4c246236f96f06a1a73a8ca05ebf71e7",
              "name": "Palazzo del municipio",
              "location": {
                "lat": 44.611185,
                "lng": 11.661106,
                "address": "Via Niccolò Macchiavelli 40062 Molinella"
              },
              "calendars": [...]
              ],
              ...              
            }
          ]
        }
      ],
      "categories": [
        "Tributi, finanze e contravvenzioni"
      ]
    }
  ],
  "self": "https://www.comune.bugliano.pi.it/api/openapi/booking-config?offset=0&limit=200&id=2240",
  "next": null,
  "prev": null,
  "count": 1
}
```

Il servizio è erogato dall’Ufficio Anagrafe in due sedi, è necessario individuare la sede desiderata per la quale si vogliono trovare le disponibilità. \
Ipotizziamo che ci interessino le disponibilità della sede di  Via Niccolò Macchiavelli: dobbiamo entrare quindi nella struttura calendars, che è fatta come segue:

```json
{
  ...
  "calendars": [
    {
      "id": "b95b5409-2b3d-44d1-b534-12bb99206b1b",
      "link": "https://servizi.comune.bugliano.pi.it/lang/api/calendars/b95b5409-2b3d-44d1-b534-12bb99206b1b",
      "availabilities_link": "https://servizi.comune.bugliano.pi.it/lang/api/availabilities?available=true&calendar_ids=b95b5409-2b3d-44d1-b534-12bb99206b1b"
    },
    {
      "id": "d35879fc-2047-47ed-8dd1-e317dc6c5cd0",
      "link": "https://servizi.comune.bugliano.pi.it/lang/api/calendars/d35879fc-2047-47ed-8dd1-e317dc6c5cd0",
      "availabilities_link": "https://servizi.comune.bugliano.pi.it/lang/api/availabilities?available=true&calendar_ids=d35879fc-2047-47ed-8dd1-e317dc6c5cd0"
    },
    {
      "id": "2e1e0f6c-3b51-4877-86bc-c9331f46b423",
      "link": "https://servizi.comune.bugliano.pi.it/lang/api/calendars/2e1e0f6c-3b51-4877-86bc-c9331f46b423",
      "availabilities_link": "https://servizi.comune.bugliano.pi.it/lang/api/availabilities?available=true&calendar_ids=2e1e0f6c-3b51-4877-86bc-c9331f46b423"
    }
  ],
  "merge_availabilities": true,
  "merged_availabilities_link": "https://servizi.comune.bugliano.pi.it/lang/api/availabilities?available=true&calendar_ids=b95b5409-2b3d-44d1-b534-12bb99206b1b%2Cd35879fc-2047-47ed-8dd1-e317dc6c5cd0%2C2e1e0f6c-3b51-4877-86bc-c9331f46b423",
  ...
}

```

***

## **1.3 Recupero disponibilità**

Una volta selezionato il servizio è possibile fare la seconda chiamata che restituisce le disponibilità per i calendari collegati al servizio e alla sede selezionata<br>

Questa API è pensata per restituire **X slot ottimali** nell’ambito di un intervallo dinamico di giorni, utile per sistemi IVR che devono proporre appuntamenti.

#### **Endpoint**

```
GET /lang/api/availabilities/windowed?window_size=Y&limit=X&reserve=true|false&calendar_ids=...
```

#### **Parametri**

| Parametro      | Validazione e default                      | Descrizione                                                                                                            |
| -------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| `window_size`  | <p>intero, tra 1 e 30</p><p>default: 8</p> | Numero di giorni per i quali si vogliono degli appuntamenti liberi                                                     |
| `limit`        | <p>intero, tra 1 e 10<br>default: 3</p>    | Numero di appuntamenti che si vogliono suggerire nell’IVR                                                              |
| `reserve`      | <p>booleano<br>default: false</p>          | Riserva gli appuntamenti contestualmente alla chiamata, senza necessità di ulteriori chiamate per riservare i tre slot |
| `calendar_ids` | obbligatorio                               | Lista di UUID separati da virgola                                                                                      |

#### **Logica di selezione**

Per scegliere gli appuntamenti liberi viene individuato un intervallo di giorni in cui è presente almeno uno slot libero. È possibile quindi che vengano elencati dei giorni non consecutivi e questo rende indeterminabile a priori l’intervallo coperto da questa chiamata. Nell’esempio che segue vengono ritornati per esempio 8 giorni tra il 1 settembre e il 16 settembre. Su servizi con calendari molto saturi anche se vengono richiesti 8 giorni potrebbero esserci un numero minore di giorni tra cui scegliere.&#x20;

Nel caso di servizi con calendari molto liberi di fatto stiamo individuando il numero massimo di giorni tra il primo e l’ultimo appuntamento suggerito. Nel caso di servizi con calendari saturati in modo molto disomogeneo potrebbero esserci intervalli di tempo anche molto ampi tra il primo e l’ultimo appuntamento suggerito.&#x20;

<br>

Indichiamo i tre slot proposti con A, B, C

| <p><br></p> | 1 disp      | 2           | 3           | 4           | 5           | 6           | 7           | 8           |
| ----------- | ----------- | ----------- | ----------- | ----------- | ----------- | ----------- | ----------- | ----------- |
| <p><br></p> | 1/9/25      | 2/9/25      | 5/9/25      | 7/9/25      | 8/9/25      | 10/9/25     | 11/9/25     | 16/9/25     |
| Matt        | A           | <p><br></p> | <p><br></p> | <p><br></p> | <p><br></p> | <p><br></p> | <p><br></p> | C           |
| Pom         | <p><br></p> | <p><br></p> | <p><br></p> | B           | <p><br></p> | <p><br></p> | <p><br></p> | <p><br></p> |

<br>

Nell’intervallo di giorni individuati restituisce la prima (A) e l’ultima disponibilità (C) di quei giorni: questo favorisce al massimo la differenza della fascia oraria negli slot suggeriti.

La seconda disponibilità è nel giorno di mezzo dell’intervallo di 8 giorni, la piattaforma cerca, se è possibile, di restituire un periodo del giorno diverso da quello del PRIMO meeting (A).

&#x20;Se A è di mattina B è nel pomeriggio e viceversa.

<br>

#### **Esempio**&#x20;

Calendario con disponibilità Lu, Ma, Me, Gio, Ve | 09:00 - 18:00

```json
{
  "meta": {
    "count": 3,
    "parameter": {
      "calendar_ids": "83bb67e1-2137-4852-b6b1-d68809df43b1",
      "reserve": false,
      "window_size": "8",
      "limit": "3"
    }
  },
  "links": {
    "self": null,
    "prev": null,
    "next": null
  },
  "data": [
    {
      "date": "2025-07-31",
      "start_time": "10:30",
      "end_time": "11:00",
      "slots_available": 1,
      "availability": true,
      "opening_hour_id": "a90d71fe-0d56-4a1b-a1cf-11a567541041",
      "calendar_id": "83bb67e1-2137-4852-b6b1-d68809df43b1",
      "meeting_id": null, // null|Uuid meeting in bozza, valorizzato solo se reserve = true
      "meeting_code": "K001"// null|string 
    },
    {
      "date": "2025-08-05",
      "start_time": "12:00",
      "end_time": "12:30",
      "slots_available": 1,
      "availability": true,
      "opening_hour_id": "a90d71fe-0d56-4a1b-a1cf-11a567541041",
      "calendar_id": "83bb67e1-2137-4852-b6b1-d68809df43b1",
      "meeting_id": null, // null|Uuid meeting in bozza, valorizzato solo se reserve = true
      "meeting_code": "K002"// null|string
    },
    {
      "date": "2025-08-08",
      "start_time": "09:00",
      "end_time": "09:30",
      "slots_available": 1,
      "availability": true,
      "opening_hour_id": "a90d71fe-0d56-4a1b-a1cf-11a567541041",
      "calendar_id": "83bb67e1-2137-4852-b6b1-d68809df43b1",
      "meeting_id": null, // null|Uuid meeting in bozza, valorizzato solo se reserve = true
      "meeting_code": "K003" // null|string 
    }
  ]
}
```

***

## **1.5 Conferma degli appuntamenti**

In caso di `reserve = true` il campo `meetind_id` sarà valorizzato con uuid del meeting in bozza, per poter confermare un meeting andrà fatta una PUT/PATCH sul meeting selezionato cambiando lo stato ed inserendo anche i dati generali del meeting (Nome del richiedente, email, numero di telefono ecc ecc)

<br>

#### **Endpoint**

```
PATCH /lang/api/meetings/{meeting_id}
```

#### **Esempio**

```json
{
  "status": "1", // Stato confermato
  "name": "Mario Rossi",
  "email": "",
  "phone_number": "",
  "reason": "",
  "user_message": "",
  "motivation_outcome": "",
  "videoconference_link": "",
  "opening_hour": "",
  "locale": "it",
  "calendar_group_config_id": "5916", // Id del servizio 
  "calendar_group_office_id": "964",  // Id dell’ufficio
  "calendar_group_place_id": "780",   // Id della sede
  "location": ""
}

```

***

## **2. Integrazione Sistemi Tagliacode**

I sistemi di gestione code possono sincronizzare ogni giorno gli appuntamenti previsti per una sede specifica.

Poiché i calendari accettano tipicamente prenotazioni solo fino al giorno successivo, **è sufficiente un’unica sincronizzazione giornaliera**.

***

## **2.1 Recupero agende relative a una sede**

#### **Endpoint**

```
GET /api/openapi/booking-config?place_id={place_id}
```

Questa chiamata restituisce:

* Tutti i servizi erogati nella sede
* Tutti i calendari da cui provengono gli appuntamenti

I calendar ID ottenuti saranno utilizzati nella chiamata successiva.

#### **Esempio di risposta**&#x20;

```json
{
  "items": [
    {
      "id": 2240,
      "link": "https://www.comune.bugliano.pi.it/api//servizi/47b0fb50deb217bfcceb5b6b4c32ba5b",
      "name": "Attivazione della TARI",
      "offices": [
        {
          "id": 856,
          "link": "https://www.comune.bugliano.pi.it/api//amministrazione/uffici/2c1aad31d1f20d6189ee5d1881a125e4",
          "name": "Ufficio Ambiente",
          "places": [
            {
              "id": 213,
              "link": "https://www.comune.bugliano.pi.it/api//vivere-il-comune/luoghi/4c246236f96f06a1a73a8ca05ebf71e7",
              "name": "Palazzo del municipio",
              "location": {
                "lat": 44.611185,
                "lng": 11.661106,
                "address": "Via Niccol&ograve; Macchiavelli 40062 Molinella"
              },
              "calendars": [
                {
                  "id": "b95b5409-2b3d-44d1-b534-12bb99206b1b",
                  "link": "https://servizi.comune.bugliano.pi.it/lang/api/calendars/b95b5409-2b3d-44d1-b534-12bb99206b1b",
                  "availabilities_link": "https://servizi.comune.bugliano.pi.it/lang/api/availabilities?available=true&calendar_ids=b95b5409-2b3d-44d1-b534-12bb99206b1b"
                },
                {
                  "id": "d35879fc-2047-47ed-8dd1-e317dc6c5cd0",
                  "link": "https://servizi.comune.bugliano.pi.it/lang/api/calendars/d35879fc-2047-47ed-8dd1-e317dc6c5cd0",
                  "availabilities_link": "https://servizi.comune.bugliano.pi.it/lang/api/availabilities?available=true&calendar_ids=d35879fc-2047-47ed-8dd1-e317dc6c5cd0"
                },
                {
                  "id": "2e1e0f6c-3b51-4877-86bc-c9331f46b423",
                  "link": "https://servizi.comune.bugliano.pi.it/lang/api/calendars/2e1e0f6c-3b51-4877-86bc-c9331f46b423",
                  "availabilities_link": "https://servizi.comune.bugliano.pi.it/lang/api/availabilities?available=true&calendar_ids=2e1e0f6c-3b51-4877-86bc-c9331f46b423"
                }
              ],
              "merge_availabilities": true,
              "merged_availabilities_link": "https://servizi.comune.bugliano.pi.it/lang/api/availabilities?available=true&calendar_ids=b95b5409-2b3d-44d1-b534-12bb99206b1b%2Cd35879fc-2047-47ed-8dd1-e317dc6c5cd0%2C2e1e0f6c-3b51-4877-86bc-c9331f46b423"
            }
          ]
        }
      ],
      "categories": [
        "Tributi, finanze e contravvenzioni"
      ],
      "show_howto_in_motivation": true,
      "view_type": "select"
    }
  ]
}
```

***

## **2.2 Recupero appuntamenti del giorno**

La chiamata è autenticata, si dovranno utilizzare le credenziali fornite per reperire un token JWT da allegare alla chiamata come indicato nella documentazione:

{% embed url="<https://docs.opencityitalia.it/developers/integrazioni/integrazioni-con-il-flusso-delle-pratiche/api-rest#autenticazione>" %}

#### **Endpoint**

```
GET /lang/api/meetings?calendars_ids=C1,C2,C3&from_time=...&to_time=...
```

Il risultato è una struttura dati di questo tipo (si omettono volutamente i campi non strettamente necessari): ogni elemento dell’array contiene un appuntamento per una persona con codice breve code.

#### **Esempio di risposta (estratto)**

```json
[
  {
    "id": "5b00796e-ef10-4c98-b9f5-b0f7ffd7a17d",
    "user": "5300188a-fc05-4f49-8933-6d2d7d5c9ebc",
    "email": "string",
    "phone_number": "string",
    "fiscal_code": "string",
    "name": "string",
    "from_time": "2025-06-03T10:00:00+02:00",
    "to_time": "2025-06-03T10:20:00+02:00",
    "status": 1,
    "code": "K123",
    "calendar_group_config_id": "2282",
    "calendar_group_office_id": "964",
    "calendar_group_place_id": "4864"
  }
]

```

Nel json dell’appuntamento verranno riportate anche le indicazioni relative al servizio, alla sede ed all’ufficio.&#x20;

* id del servizio → calendar\_group\_config\_id
* id dell’ufficio → calendar\_group\_office\_id
* id della sede → calendar\_group\_place\_id
