{"openapi":"3.1.0","info":{"title":"PhysioHub API","version":"1.0.0","description":"API di PhysioHub. Autenticazione: `Authorization: Bearer <JWT Supabase dell'utente>` (stesso progetto Supabase di SmartBooking) oppure cookie di sessione. Tutte le autorizzazioni sono verificate dal database (Row Level Security): un token non concede mai più di quanto l'utente possa già vedere."},"servers":[{"url":"/api/v1"}],"security":[{"bearer":[]}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"responses":{"Error":{"description":"Errore","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"}}}}}}}}}},"paths":{"/integrations/smartbooking/link-patient":{"post":{"summary":"Attiva PhysioHub per un cliente SmartBooking (idempotente)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["salon_id","customer_key","full_name"],"properties":{"salon_id":{"type":"string","format":"uuid"},"customer_key":{"type":"string"},"full_name":{"type":"string"},"email":{"type":"string","format":"email"}}}}}},"responses":{"200":{"description":"Collegamento (stato invited/active)","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/integrations/smartbooking/invite":{"post":{"summary":"Crea e invia l'invito personale (scade in 7 giorni)","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":8,"maxLength":100}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["link_id"],"properties":{"link_id":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"Invito già creato con la stessa Idempotency-Key","content":{"application/json":{"schema":{"type":"object"}}}},"201":{"description":"Invito creato","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/integrations/smartbooking/revoke":{"post":{"summary":"Revoca l'accesso del paziente","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["link_id"],"properties":{"link_id":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"Revocato","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/integrations/smartbooking/status":{"get":{"summary":"Stato PhysioHub di un cliente SmartBooking","parameters":[{"name":"salon_id","in":"query","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"customer_key","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Stato, invito pendente, programmi","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/patients/me":{"get":{"summary":"Profilo del cliente autenticato","responses":{"200":{"description":"Cliente e studi collegati","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/exercises":{"post":{"summary":"Crea un esercizio in una libreria dello studio","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["library_id","name","body_region"],"properties":{"library_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"body_region":{"type":"string","enum":["spalla","collo","schiena","gomito","polso","mano","anca","ginocchio","caviglia","piede","core","mobilita","equilibrio","rinforzo"]},"description":{"type":"string"},"muscle_group":{"type":"string"},"difficulty":{"type":"integer","minimum":1,"maximum":3},"equipment":{"type":"string"},"sets":{"type":"integer"},"reps":{"type":"integer"},"duration_sec":{"type":"integer"},"rest_sec":{"type":"integer"},"frequency":{"type":"string"},"precautions":{"type":"string"},"professional_notes":{"type":"string"}}}}}},"responses":{"201":{"description":"Creato","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/exercises/{id}/upload":{"post":{"summary":"Prepara il caricamento: restituisce un URL firmato monouso (PUT del file)","parameters":[{"name":"id","in":"path","required":true,"description":"Esercizio","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["mime_type","size_bytes"],"properties":{"mime_type":{"type":"string"},"size_bytes":{"type":"integer"},"kind":{"type":"string","enum":["video","image"]}}}}}},"responses":{"201":{"description":"path, signedUrl, token","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/exercises/{id}/media":{"post":{"summary":"Conferma il file caricato (sostituisce il video o la copertina precedente)","parameters":[{"name":"id","in":"path","required":true,"description":"Esercizio","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["path","mime_type","size_bytes"],"properties":{"path":{"type":"string"},"mime_type":{"type":"string"},"size_bytes":{"type":"integer"},"kind":{"type":"string","enum":["video","image"]},"caption":{"type":"string"}}}}}},"responses":{"201":{"description":"Registrato","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/catalog":{"get":{"summary":"Catalogo: tutti gli esercizi degli studi a cui il cliente ha accesso (copertine firmate 10 min)","responses":{"200":{"description":"Esercizi","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/catalog/{id}":{"get":{"summary":"Un esercizio del catalogo con video firmato (10 min)","parameters":[{"name":"id","in":"path","required":true,"description":"Esercizio","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Esercizio","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/access-requests":{"post":{"summary":"Il cliente chiede l'accesso alla libreria di uno studio","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["clinic_slug","full_name"],"properties":{"clinic_slug":{"type":"string"},"full_name":{"type":"string"},"message":{"type":"string","maxLength":300}}}}}},"responses":{"200":{"description":"Accesso già attivo","content":{"application/json":{"schema":{"type":"object"}}}},"201":{"description":"Richiesta in attesa","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/access-requests/{id}/decision":{"post":{"summary":"Lo studio approva o rifiuta una richiesta","parameters":[{"name":"id","in":"path","required":true,"description":"Richiesta","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["approve"],"properties":{"approve":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Decisione registrata","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}}}}