{"openapi":"3.1.0","info":{"title":"Centro Odontoiatrico Leone API","description":"API REST pubblica per agenti AI. Trova disponibilità, blocca uno slot e prenota prime visite presso il Centro Odontoiatrico Leone di Gravina in Puglia.","version":"2.1.0"},"servers":[{"url":"https://leone.ngrok.app","description":"Production"}],"paths":{"/api/v2/info":{"get":{"tags":["Informazioni"],"summary":"Informazioni sul Centro Odontoiatrico Leone","description":"Restituisce indirizzo, contatti, orari, certificazioni, area servita e valutazione Google.","operationId":"info_api_v2_info_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v2/services":{"get":{"tags":["Informazioni"],"summary":"Catalogo servizi e prezzi","description":"Restituisce l'elenco dei servizi offerti con fasce di prezzo, durata e tecnologie. Filtrabile per categoria.","operationId":"services_api_v2_services_get","parameters":[{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filtra per categoria (es. implantologia, ortodonzia, igiene)","title":"Category"},"description":"Filtra per categoria (es. implantologia, ortodonzia, igiene)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v2/quick-book":{"get":{"tags":["Prenotazioni v2"],"summary":"Prenota prima visita (per AI agent)","description":"Trova il primo slot disponibile per una prima visita, lo blocca per 15 minuti e restituisce slotId + token per confermare via /confirm-booking. Il medico e assegnato automaticamente (Dr.ssa Giulia Leone, fallback Dr. Mario Leone).","operationId":"quick_book_api_v2_quick_book_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuickBookResponse"}}}}}}},"/api/v2/confirm-booking":{"post":{"tags":["Prenotazioni v2"],"summary":"Conferma prenotazione (JSON, per AI agent)","description":"Conferma una prenotazione con dati paziente in formato JSON. Richiede slotId e token ottenuti da /quick-book. Alternativa al form HTML /confirm per agenti AI.","operationId":"confirm_booking_api_v2_confirm_booking_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmBookingRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmBookingResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ipad/pair":{"post":{"tags":["ipad"],"summary":"Pair","description":"Associa un iPad: PIN → token long-lived.\n\nRate-limit: vedi config.IPAD_PAIR_RATE_LIMIT (es. 5/hour per IP).","operationId":"pair_api_ipad_pair_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PairRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PairResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ipad/push":{"post":{"tags":["ipad"],"summary":"Push","description":"Accoda una compilazione. Chiamato dallo script CLI sui client LiveCode\n(via ngrok HTTPS) autenticato con header X-Ipad-Push-Key.","operationId":"push_api_ipad_push_post","parameters":[{"name":"x-ipad-push-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Ipad-Push-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PushResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ipad/poll":{"get":{"tags":["ipad"],"summary":"Poll","description":"Ritorna la coda viva (TTL applicato inline). Vuota se non c'è nulla.","operationId":"poll_api_ipad_poll_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PollResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/ipad/ack":{"post":{"tags":["ipad"],"summary":"Ack","description":"Rimuove un item dalla coda. 409 se già preso da un altro iPad.","operationId":"ack_api_ipad_ack_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AckRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AckResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AckRequest":{"properties":{"idPaziente":{"type":"integer","minimum":1.0,"title":"Idpaziente"},"idCompilazione":{"type":"integer","minimum":1.0,"title":"Idcompilazione"}},"type":"object","required":["idPaziente","idCompilazione"],"title":"AckRequest"},"AckResponse":{"properties":{"taken":{"type":"boolean","title":"Taken"}},"type":"object","required":["taken"],"title":"AckResponse"},"ConfirmBookingRequest":{"properties":{"slotId":{"type":"string","title":"Slotid"},"token":{"type":"string","title":"Token"},"patientName":{"type":"string","title":"Patientname"},"patientPhone":{"type":"string","title":"Patientphone"},"patientNotes":{"type":"string","title":"Patientnotes","default":""}},"type":"object","required":["slotId","token","patientName","patientPhone"],"title":"ConfirmBookingRequest"},"ConfirmBookingResponse":{"properties":{"ok":{"type":"boolean","title":"Ok"},"message":{"type":"string","title":"Message"},"date":{"type":"string","title":"Date"},"dayOfWeek":{"type":"string","title":"Dayofweek"},"startTime":{"type":"string","title":"Starttime"},"practitioner":{"type":"string","title":"Practitioner"},"patientName":{"type":"string","title":"Patientname"}},"type":"object","required":["ok","message","date","dayOfWeek","startTime","practitioner","patientName"],"title":"ConfirmBookingResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"InboxItem":{"properties":{"idPaziente":{"type":"integer","title":"Idpaziente"},"idCompilazione":{"type":"integer","title":"Idcompilazione"},"nomeCognome":{"type":"string","title":"Nomecognome"},"descrizioneModello":{"type":"string","title":"Descrizionemodello"},"ts":{"type":"integer","title":"Ts"}},"type":"object","required":["idPaziente","idCompilazione","nomeCognome","descrizioneModello","ts"],"title":"InboxItem"},"PairRequest":{"properties":{"pin":{"type":"string","maxLength":200,"minLength":1,"title":"Pin"},"etichetta":{"type":"string","maxLength":100,"minLength":1,"title":"Etichetta"}},"type":"object","required":["pin","etichetta"],"title":"PairRequest"},"PairResponse":{"properties":{"token":{"type":"string","title":"Token"},"etichetta":{"type":"string","title":"Etichetta"}},"type":"object","required":["token","etichetta"],"title":"PairResponse"},"PollResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/InboxItem"},"type":"array","title":"Items"}},"type":"object","required":["items"],"title":"PollResponse"},"PractitionerInfo":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"specialties":{"items":{"type":"string"},"type":"array","title":"Specialties"}},"type":"object","required":["id","name","specialties"],"title":"PractitionerInfo"},"PushRequest":{"properties":{"idPaziente":{"type":"integer","minimum":1.0,"title":"Idpaziente"},"idCompilazione":{"type":"integer","minimum":1.0,"title":"Idcompilazione"}},"type":"object","required":["idPaziente","idCompilazione"],"title":"PushRequest"},"PushResponse":{"properties":{"accodato":{"type":"boolean","title":"Accodato"},"nomeCognome":{"type":"string","title":"Nomecognome"},"descrizioneModello":{"type":"string","title":"Descrizionemodello"}},"type":"object","required":["accodato","nomeCognome","descrizioneModello"],"title":"PushResponse"},"QuickBookResponse":{"properties":{"slotId":{"type":"string","title":"Slotid"},"token":{"type":"string","title":"Token"},"date":{"type":"string","title":"Date"},"dayOfWeek":{"type":"string","title":"Dayofweek"},"startTime":{"type":"string","title":"Starttime"},"endTime":{"type":"string","title":"Endtime"},"practitioner":{"$ref":"#/components/schemas/PractitionerInfo"},"held":{"type":"boolean","title":"Held","default":true},"expiresAt":{"type":"string","title":"Expiresat"},"expiresInMinutes":{"type":"integer","title":"Expiresinminutes"},"confirmUrl":{"type":"string","title":"Confirmurl"}},"type":"object","required":["slotId","token","date","dayOfWeek","startTime","endTime","practitioner","expiresAt","expiresInMinutes","confirmUrl"],"title":"QuickBookResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}