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

# Prenota

> Crea una prenotazione su un orario libero

# POST /v1/calendar/bookings

Prenota un orario. L'orario deve essere uno di quelli restituiti da [GET /v1/calendar/availability](/mycentralino-api/calendar-availability): il controllo definitivo (conflitti, capienze, preavviso) avviene qui, con un lock sul calendario, così due richieste simultanee sullo stesso orario non possono riuscire entrambe.

## Request Body

| Campo      | Tipo   | Obbligatorio | Descrizione                                                                                                                                           |
| ---------- | ------ | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `event`    | string | ✅            | Slug del tipo di appuntamento                                                                                                                         |
| `calendar` | string | dipende      | Slug del calendario. **Obbligatorio** se il tipo è `choice` con più calendari; facoltativo altrimenti (con `round_robin` si prenota col primo libero) |
| `date`     | string | ✅            | `YYYY-MM-DD`, ora locale                                                                                                                              |
| `time`     | string | ✅            | `HH:MM`, uno degli orari della disponibilità                                                                                                          |
| `name`     | string | ✅            | Nome e cognome di chi prenota (max 120)                                                                                                               |
| `phone`    | string | ❌            | Telefono (max 30): viene salvato senza spazi                                                                                                          |
| `email`    | string | ❌            | Con l'email chi prenota riceve conferma e promemoria                                                                                                  |
| `notes`    | string | ❌            | Note di chi prenota (max 2000): finiscono anche nelle email                                                                                           |
| `answers`  | object | ❌            | Risposte alle domande del tipo: `{"chiave": "risposta"}`                                                                                              |
| `status`   | string | ❌            | `pending` per forzare «da confermare»                                                                                                                 |

<Note>
  Metti sempre una **`Idempotency-Key`** (header, max 200 caratteri, per esempio l'ID dell'ordine nel tuo gestionale). Se ripeti la chiamata con la stessa chiave, ricevi la stessa prenotazione con `created: false` invece di crearne una seconda.
</Note>

## Richiesta

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.mycentralino.com/v1/calendar/bookings" \
    -H "X-API-KEY: sk_mycentralino_your_api_key" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: ordine-4711" \
    -d '{
        "event": "visita-nord",
        "calendar": "luigi",
        "date": "2026-09-17",
        "time": "10:00",
        "name": "Mario Rossi",
        "phone": "+393331234567",
        "email": "mario@example.com"
    }'
  ```

  ```php PHP theme={null}
  <?php
  $data = [
      'event' => 'visita-nord',
      'calendar' => 'luigi',
      'date' => '2026-09-17',
      'time' => '10:00',
      'name' => 'Mario Rossi',
      'phone' => '+393331234567',
      'email' => 'mario@example.com'
  ];

  $ch = curl_init('https://api.mycentralino.com/v1/calendar/bookings');
  curl_setopt_array($ch, [
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_CUSTOMREQUEST => 'POST',
      CURLOPT_POSTFIELDS => json_encode($data),
      CURLOPT_HTTPHEADER => [
          'X-API-KEY: sk_mycentralino_your_api_key',
          'Content-Type: application/json',
          'Idempotency-Key: ordine-4711'
      ]
  ]);
  $response = curl_exec($ch);
  curl_close($ch);
  print_r(json_decode($response, true));
  ```

  ```python Python theme={null}
  import requests

  headers = {'X-API-KEY': 'sk_mycentralino_your_api_key', 'Idempotency-Key': 'ordine-4711'}
  data = {"event": "visita-nord", "calendar": "luigi", "date": "2026-09-17", "time": "10:00", "name": "Mario Rossi", "phone": "+393331234567", "email": "mario@example.com"}
  response = requests.post('https://api.mycentralino.com/v1/calendar/bookings', headers=headers, json=data)
  print(response.json())
  ```
</CodeGroup>

## Risposta

`201 Created` con `"created": true`. Con una `Idempotency-Key` già usata: `200` e `"created": false`.

```json theme={null}
{
  "success": true,
  "created": true,
  "data": {
    "id": 91,
    "status": "confirmed",
    "calendar": {
      "id": 34,
      "slug": "luigi",
      "name": "Luigi"
    },
    "event": {
      "id": 12,
      "slug": "visita-nord",
      "name": "Visita",
      "duration_minutes": 60
    },
    "date": "2026-09-17",
    "time": "10:00",
    "end_date": "2026-09-17",
    "end_time": "11:00",
    "timezone": "Europe/Rome",
    "starts_at_utc": "2026-09-17T08:00:00Z",
    "ends_at_utc": "2026-09-17T09:00:00Z",
    "attendee": {
      "name": "Mario Rossi",
      "phone": "+393331234567",
      "email": "mario@example.com",
      "notes": null
    },
    "staff_notes": null,
    "answers": null,
    "source": "api",
    "source_ref": "api:gestionale",
    "created_by": "api:gestionale",
    "created_at": "2026-09-07T12:30:00+02:00",
    "updated_at": null,
    "cancelled_at": null,
    "cancel_reason": null,
    "cancelled_by": null
  }
}
```

## Campi della prenotazione

| Campo                                           | Tipo           | Descrizione                                                                                      |
| ----------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------ |
| `id`                                            | int            | ID della prenotazione                                                                            |
| `status`                                        | string         | `pending` (da confermare), `confirmed`, `cancelled`, `no_show` (assente), `completed` (conclusa) |
| `calendar`                                      | object         | Il calendario: `id`, `slug`, `name`                                                              |
| `event`                                         | object         | Il tipo di appuntamento: `id`, `slug`, `name`, `duration_minutes`                                |
| `date`, `time`                                  | string         | Inizio in ora locale del centralino: `YYYY-MM-DD` e `HH:MM`                                      |
| `end_date`, `end_time`                          | string         | Fine in ora locale                                                                               |
| `timezone`                                      | string         | Il fuso del centralino, di norma `Europe/Rome`                                                   |
| `starts_at_utc`, `ends_at_utc`                  | string         | Gli stessi istanti in UTC, in più, mai al posto dei campi locali                                 |
| `attendee`                                      | object         | Chi ha prenotato: `name`, `phone`, `email`, `notes`                                              |
| `staff_notes`                                   | string \| null | Note interne dello studio: solo nel pannello e qui, mai nelle email a chi prenota                |
| `answers`                                       | object \| null | Le risposte alle domande del tipo di appuntamento (`fields`)                                     |
| `source`                                        | string         | Da dove è arrivata: `panel`, `ai` (agente telefonico), `public` (pagina di prenotazione), `api`  |
| `source_ref`, `created_by`                      | string \| null | Riferimento e autore; per l'API il nome della chiave usata                                       |
| `created_at`, `updated_at`                      | string \| null | Date in ISO 8601 con offset                                                                      |
| `cancelled_at`, `cancel_reason`, `cancelled_by` | —              | Valorizzati solo dopo un annullamento                                                            |

## Errori

### 422 - missing\_event / missing\_name / missing\_time / missing\_date

Manca un campo obbligatorio.

### 422 - calendar\_required

Il tipo è `choice` con più calendari: indica `calendar`. La risposta elenca `calendars`.

### 422 - calendar\_not\_for\_event

Quel calendario non offre quel tipo di appuntamento.

### 409 - slot\_unavailable

L'orario è già occupato (o non c'è più un calendario libero col round robin).

### 409 - outside\_hours

L'orario è fuori dall'orario di lavoro o fuori dalla griglia degli slot.

### 409 - notice\_too\_short / beyond\_horizon

Troppo vicino (preavviso minimo del tipo) o troppo lontano (orizzonte del tipo).

### 422 - invalid\_email / invalid\_answers / invalid\_status / invalid\_attendee

Campo malformato.
