{
  "openapi": "3.1.0",
  "x-audience": "ai_agents",
  "info": {
    "title": "Studio Dentistico Buniato - Agent Booking API",
    "version": "1.1.1",
    "description": "API per agenti IA: disponibilità indicative e richiesta di richiamo, distinta dalla prenotazione diretta nel portale AlfaDocs. Questa API non crea appuntamenti, non riserva slot e non dispone di una conferma automatica. Inviare dati reali dell'utente solo con la sua autorizzazione; non inviare informazioni cliniche. Endpoint MCP equivalente: https://buniato.it/agent-api/mcp.php. Prenotazione diretta tramite browser: https://prenota.alfadocs.com/p/torino-studio-dentistico-buniato-7841; completare la verifica SMS e controllare la conferma del provider prima di dichiarare l'appuntamento confermato.",
    "contact": {
      "name": "Studio Dentistico Buniato - Torino",
      "url": "https://buniato.it/",
      "email": "reception@buniato.it"
    }
  },
  "servers": [
    { "url": "https://buniato.it/agent-api" }
  ],
  "externalDocs": {
    "description": "Istruzioni ufficiali per agenti IA: deleghe, prenotazione diretta, richieste, contatti e urgenze",
    "url": "https://buniato.it/llms.txt"
  },
  "paths": {
    "/availability.php": {
      "get": {
        "operationId": "getAvailability",
        "summary": "Disponibilità indicative dei prossimi giorni (Europe/Rome)",
        "description": "Cache indicativa, non specifica per prestazione: non rappresenta uno slot riservato né una conferma. Verificare gli slot effettivi per la prestazione nel portale AlfaDocs. Se la cache è assente o non fresca, status=availability_temporarily_unavailable invita alla richiesta o al contatto; non significa assenza di posti nell'agenda reale.",
        "responses": {
          "200": {
            "description": "Disponibilita o fallback",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Availability" } } }
          },
          "429": { "description": "Rate limit" }
        }
      }
    },
    "/booking-request.php": {
      "post": {
        "operationId": "requestBooking",
        "summary": "Invia una richiesta alla segreteria, senza prenotare un appuntamento",
        "description": "Solo su autorizzazione dell'utente, invia i suoi dati reali per essere richiamato. HTTP 202 e status=received significano richiesta ricevuta, con appointment_confirmed=false. La segreteria deve concordare e confermare data e ora. Non inviare dati clinici. Ogni invocazione può creare una nuova richiesta: non ripetere automaticamente un invio dall'esito incerto; un errore non prova che la richiesta sia stata ricevuta.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/BookingRequest" }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Richiesta ricevuta; appuntamento non confermato",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BookingAccepted" } } }
          },
          "400": { "description": "Corpo della richiesta non valido" },
          "422": { "description": "Validazione fallita" },
          "429": { "description": "Rate limit" },
          "500": { "description": "Registrazione non riuscita: usare un contatto dello studio, senza dichiarare la richiesta ricevuta" },
          "503": { "description": "Coda satura: usare il telefono" }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "BookingRequest": {
        "type": "object",
        "required": ["name", "phone"],
        "properties": {
          "name": { "type": "string", "minLength": 2, "maxLength": 80, "description": "Nome e cognome del paziente" },
          "phone": { "type": "string", "description": "Telefono da richiamare, preferibilmente +39..." },
          "preferred_slot": { "type": "string", "maxLength": 120, "description": "Preferenza giorno/ora (testo libero)" },
          "reason": { "type": "string", "maxLength": 120, "description": "Tipo di visita richiesto (es. prima visita, igiene), senza informazioni cliniche" },
          "notes": { "type": "string", "maxLength": 300, "description": "Solo esigenze organizzative, senza informazioni cliniche" }
        },
        "additionalProperties": false
      },
      "BookingAccepted": {
        "type": "object",
        "required": ["status", "request_id", "appointment_confirmed"],
        "properties": {
          "status": { "type": "string", "const": "received" },
          "appointment_confirmed": { "type": "boolean", "const": false },
          "request_id": { "type": "string" },
          "next_step": { "type": "string" },
          "expected_callback": { "type": "string" },
          "clinic_phone": { "type": "string" },
          "privacy": { "type": "string" },
          "guidance_url": { "type": "string", "format": "uri" },
          "note": { "type": "string" }
        }
      },
      "Availability": {
        "type": "object",
        "properties": {
          "status": { "type": "string" },
          "availability_kind": { "type": "string", "const": "indicative_cache" },
          "service_specific": { "type": "boolean", "const": false },
          "reserves_slot": { "type": "boolean", "const": false },
          "generated_at": { "type": "string", "format": "date-time" },
          "timezone": { "type": "string" },
          "slot_duration_minutes": { "type": ["integer", "null"] },
          "days": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "date": { "type": "string", "format": "date" },
                "slots": { "type": "array", "items": { "type": "string" } }
              }
            }
          },
          "disclaimer": { "type": "string" },
          "how_to_book": { "type": "object" }
        }
      }
    }
  }
}
