{"openapi":"3.1.0","info":{"title":"API di ConsensoSicuro per il tuo account","version":"1.0.0+44c619fc12f2","summary":"Invio dei consensi, firma, documenti, pazienti, struttura e configurazione dal tuo gestionale.","description":"Le API lavorano sul perimetro del TUO account ConsensoSicuro: una chiave vede al massimo quello che il titolare vede in dashboard, nei limiti dei permessi scelti alla creazione.\n\nAutenticazione: intestazione `Authorization: Bearer ak_live_…` (produzione) o `ak_test_…` (modalità Test). Le chiavi si creano in Impostazioni → API & Integrazioni.\n\nGuide, esempi e changelog: https://consensosicuro.it/integrazioni/api","termsOfService":"https://consensosicuro.it/integrazioni/condizioni-api","license":{"name":"Condizioni per l'integrazione via API","url":"https://consensosicuro.it/integrazioni/condizioni-api"},"contact":{"name":"ConsensoSicuro","email":"info@consensosicuro.it","url":"https://consensosicuro.it/integrazioni"}},"externalDocs":{"description":"Riferimento delle API con le guide","url":"https://consensosicuro.it/integrazioni/api"},"servers":[{"url":"https://api.consensosicuro.it/api/v1/account","description":"Le chiavi ak_live_ lavorano sui dati veri, le ak_test_ su quelli di prova."}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Account","description":"Chi è l'account della chiave, il profilo e il Registro attività."},{"name":"Catalogo","description":"I codici dei trattamenti, i modelli, le lingue, le sedi e gli esecutori da usare nell'invio."},{"name":"Consensi","description":"Invio, elenco, dettaglio, consegna, evidenza della firma e annullamento."},{"name":"Ciclo di vita","description":"Reinvio, rinnovo, cambio canale, correzione del numero, difformità e controfirma."},{"name":"Documenti","description":"I PDF firmati, il fascicolo difensivo e l'invio dei PDF per email."},{"name":"Pazienti","description":"Anagrafiche, note e documenti del paziente."},{"name":"GDPR","description":"Informativa privacy, revoca, export e cancellazione dei dati."},{"name":"Visite","description":"Visite e cicli di trattamento."},{"name":"Anamnesi","description":"Le risposte complete dell'anamnesi raccolta alla firma."},{"name":"Struttura","description":"Sedi, professionisti, inviti, esecutore generico, controfirme e statistiche."},{"name":"Configurazione","description":"Modelli, trattamenti abilitati, informativa, incarico, lingue, interruttori e moduli Agorà."},{"name":"Registri","description":"Apparecchiature, lotti iniettabili, inchiostri, operatrici, motivi di consulto e domande personalizzate."},{"name":"Consumi","description":"Quota, messaggi e statistiche."},{"name":"Webhook","description":"La prova del webhook configurato in dashboard."}],"paths":{"/me":{"get":{"operationId":"getMe","summary":"Chi è l'account della chiave","description":"Restituisce il profilo dell'account, il piano, la quota dei consensi, le sedi e i professionisti. È la prima chiamata utile per verificare che la chiave funzioni.\n\n**Permesso**: `account:read`.","tags":["Account"],"x-scopes":["account:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Chi è l'account della chiave","content":{"application/json":{"example":{"account":{"id":"uuid","businessName":"Studio Rossi","accountType":"CLINIC"},"plan":{"tier":"PRO","subscriptionStatus":"ACTIVE"},"quota":{"used":42,"limit":200,"remaining":158},"structure":{"id":"uuid","name":"Studio Rossi","sedi":[],"members":[]},"context":{"sedeId":null,"allSedi":false,"mode":"LIVE"}}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"429":{"$ref":"#/components/responses/C429"}}}},"/account/profile":{"get":{"operationId":"getAccountProfile","summary":"Leggi il profilo","description":"Restituisce il profilo dell'account: identità, contatti, intestazione dei documenti, aspetto e dati di fatturazione, questi ultimi in sola lettura.\n\n**Permesso**: `account:read`.","tags":["Account"],"x-scopes":["account:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Leggi il profilo","content":{"application/json":{"example":{"profile":{"id":"uuid","email":"studio@example.com","accountType":"PROFESSIONAL","businessName":"Studio Rossi","professionTitle":"Psicologa clinica","contact":{"phone":"+39…","phoneVerified":true,"address":"Via Verdi 3","city":"Padova","cap":"35100"},"billing":{"partitaIva":"01234567890","wantsInvoice":true}}}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"429":{"$ref":"#/components/responses/C429"}}},"patch":{"operationId":"patchAccountProfile","summary":"Aggiorna il profilo","description":"Cambia solo i campi che il profilo della dashboard lascia cambiare da soli e che non toccano accesso, fatturazione o funzioni. Email di accesso, password, telefono (è un fattore di verifica), nome, dati fiscali ed etichetta della struttura si cambiano dalla dashboard. Per una struttura ragione sociale e indirizzo sono anche i dati di fatturazione, quindi via API restano in lettura. Dopo la modifica parte l'evento `configuration.updated`.\n\n**Permesso**: `account:write (delicato)`.","tags":["Account"],"x-scopes":["account:write"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"businessName":{"type":"string","minLength":1,"maxLength":200},"professionTitle":{"type":"string","maxLength":100},"professionalRegister":{"type":"string","maxLength":200},"structureEmail":{"anyOf":[{"type":"string","format":"email"},{"type":"string","const":""}]},"structurePhone":{"type":"string","maxLength":30},"address":{"type":"string","maxLength":200},"city":{"type":"string","maxLength":100},"cap":{"anyOf":[{"type":"string","pattern":"^\\d{5}$"},{"type":"string","const":""}]},"primaryColor":{"type":"string","maxLength":20},"logoBackgroundColor":{"anyOf":[{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$"},{"type":"null"}]},"logoDominantColor":{"anyOf":[{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$"},{"type":"null"}]},"logoScale":{"type":"integer","minimum":50,"maximum":160},"logoFeather":{"type":"integer","minimum":0,"maximum":30}},"additionalProperties":false},"examples":{"esempio_1":{"summary":"Nuovo titolo professionale","value":{"professionTitle":"Psicologa clinica"}}}}}},"responses":{"200":{"description":"Aggiorna il profilo","content":{"application/json":{"example":{"profile":{"id":"uuid","businessName":"Studio Rossi","professionTitle":"Psicologa clinica","contact":{"address":"Via Verdi 3","city":"Padova","cap":"35100"}}}}}},"400":{"description":"FIELD_NOT_AVAILABLE: `structureLabel`: si cambia dalla dashboard.\nINVALID_BODY: Corpo non valido: un campo non previsto, un tipo sbagliato o un valore fuori intervallo. `details` elenca ogni problema.\nEMPTY_PATCH: Corpo senza nessun campo da modificare.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"description":"PROFILE_FIELD_NOT_ALLOWED: Campo di accesso, verifica, identità o fatturazione.\nTEST_KEY_READ_ONLY: Chiave in modalità Test: legge la configurazione ma non la modifica, perché sono dati veri condivisi con la dashboard.\nAnche IP_NOT_ALLOWED, SCOPE_MISSING e gli altri comuni: components.responses.C403.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/account/audit":{"get":{"operationId":"getAccountAudit","summary":"Registro attività","description":"Restituisce il Registro attività della dashboard, pagina per pagina: azione, paziente, chi, IP, dettagli e istante, più `patientId` e `via` (dashboard o API). Con `account:read` gli indirizzi IP arrivano con l'ultima parte nascosta (203.0.113.xxx); con il permesso `audit:read` arrivano completi.\n\n**Permesso**: `account:read (oppure audit:read) (delicato)`.\n\nCon una chiave Test compaiono solo le voci prodotte dalle chiavi Test dell'account o riferite a pazienti di prova, senza IP.\n\nUna volta al giorno il registro riceve, per ogni chiave, la voce `API_BULK_READ` con quante liste di pazienti e di consensi, export e documenti ha letto il giorno prima.\n\nIl registro non si filtra per professionista: `memberId` è un errore 400 INVALID_QUERY.","tags":["Account"],"x-scopes":["account:read","audit:read"],"parameters":[{"name":"page","in":"query","description":"Pagina, da 1.","schema":{"type":"integer"},"example":1},{"name":"limit","in":"query","description":"Righe per pagina, da 1 a 100 (predefinito 25).","schema":{"type":"integer"},"example":25},{"name":"action","in":"query","description":"Nome di un'azione, per esempio CONSENT_SENT o ANAMNESIS_VIEWED.","schema":{"type":"string"},"example":"CONSENT_SENT"},{"name":"performedBy","in":"query","description":"Chi ha compiuto l'azione.","schema":{"type":"string","enum":["PROFESSIONAL","PATIENT","SYSTEM"]}},{"name":"sedeId","in":"query","description":"Strutture: solo le voci riferite ai pazienti di quella sede.","schema":{"type":"string"}},{"$ref":"#/components/parameters/query_from"},{"$ref":"#/components/parameters/query_to"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Registro attività","content":{"application/json":{"example":{"items":[{"id":"uuid","action":"CONSENT_SENT","patientId":"uuid","patientName":"Mario Rossi","performedBy":"PROFESSIONAL","via":"api","ipAddress":"203.0.113.xxx","details":{"consentId":"uuid"},"timestamp":"2026-09-23T09:00:00.000Z"}],"pagination":{"page":1,"limit":25,"total":1,"totalPages":1}}}}},"400":{"$ref":"#/components/responses/E400_7ffcc6"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_62fb41"},"404":{"description":"SEDE_NOT_FOUND: Sede altrui.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}}},"/templates":{"get":{"operationId":"getCatalog","summary":"Catalogo dell'account","description":"Restituisce il catalogo del tuo account: codici dei trattamenti per ambito, schede con i tuoi testi, modelli salvati, moduli Agorà, lingue attive, sedi ed esecutori, operatrici e apparecchiature. È la lettura che precede ogni invio.\n\n**Permesso**: `templates:read (oppure account:read)`.\n\nAccetta sia `templates:read` sia `account:read`: la superficie è la stessa.","tags":["Catalogo"],"x-scopes":["templates:read","account:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Catalogo dell'account","content":{"application/json":{"example":{"ambiti":[{"professionType":"PSYCHOLOGIST","label":"Psicologo","dualSignatureAvailable":true,"treatments":[{"code":"psi-colloquio","label":"Colloquio clinico","requiresBothParentsForMinors":false,"minorMinAge":null}]}],"privateTreatments":[{"code":"priv-…","label":"Il consenso del nostro centro","category":"Trattamenti del centro","sendFields":[{"key":"regime","label":"Regime dell'intervento","type":"select","options":["Day surgery","Ricovero ordinario"],"required":true}],"patientChoices":[{"key":"punto_15","question":"Uso delle fotografie per scopi scientifici (facoltativo)","options":[{"value":"si","label":"SÌ, ACCONSENTO"},{"value":"no","label":"NON ACCONSENTO"}],"required":true}]}],"agora":[{"code":"agora-iv-therapy","label":"IV Therapy — infusioni vitaminiche endovenose"}],"configurations":[{"id":"ck…","name":"Prima visita","isDefault":true,"treatments":["psi-colloquio"]}],"languages":["it","en"],"structure":{"sedi":[{"id":"uuid","name":"Sede Padova","city":"Padova"}],"executors":[{"memberId":"uuid","name":"Carla Esecutrice","sedeIds":["uuid"],"professions":["PHYSIOTHERAPIST"],"canExecute":true}]},"businessOperators":[],"equipment":[],"medicalEquipment":[]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"429":{"$ref":"#/components/responses/C429"}}}},"/consents":{"get":{"operationId":"listConsents","summary":"Elenco dei consensi","description":"Restituisce i consensi dal più recente, con filtri per stato, periodo, paziente, sede ed esecutore.\n\n**Permesso**: `consents:read`.\n\nCon una chiave in modalità Test la lista mostra sempre e solo i consensi di prova.","tags":["Consensi"],"x-scopes":["consents:read"],"parameters":[{"name":"status","in":"query","description":"Uno stato del vocabolario dell'API (PENDING_SIGNATURE, PARTIALLY_SIGNED, ACTION_REQUIRED, COMPLETED, REFUSED, EXPIRED, CANCELLED) oppure uno stato interno, per la granularità piena.","schema":{"type":"string"},"example":"COMPLETED"},{"name":"from","in":"query","description":"Creati da questo istante (ISO 8601 con ora).","schema":{"type":"string"},"example":"2026-09-01T00:00:00Z"},{"name":"to","in":"query","description":"Creati fino a questo istante (ISO 8601 con ora).","schema":{"type":"string"},"example":"2026-09-30T23:59:59Z"},{"name":"search","in":"query","description":"Nome, cognome o telefono del paziente.","schema":{"type":"string"}},{"$ref":"#/components/parameters/query_sedeId"},{"name":"executorMemberId","in":"query","description":"Professionista esecutore.","schema":{"type":"string"}},{"name":"patientExternalId","in":"query","description":"Il tuo riferimento passato all'invio (`patient.externalId`).","schema":{"type":"string"},"example":"CRM-4412"},{"name":"expiringWithinHours","in":"query","description":"Solo i consensi ancora in attesa il cui link scade entro N ore (da 1 a 2160).","schema":{"type":"integer"},"example":48},{"name":"signingMode","in":"query","description":"REMOTE (telefono del paziente) o IN_STUDIO (tablet della sede).","schema":{"type":"string","enum":["REMOTE","IN_STUDIO"]}},{"name":"apiTest","in":"query","description":"`true` = solo i consensi di prova, `false` = solo quelli veri.","schema":{"type":"string","enum":["true","false"]}},{"$ref":"#/components/parameters/query_limit"},{"name":"cursor","in":"query","description":"Cursore della pagina successiva (campo `nextCursor`). Un cursore non riconosciuto è un errore (400 INVALID_CURSOR), non un ritorno silenzioso alla prima pagina.","schema":{"type":"string"}},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Elenco dei consensi","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Consent"}},"pagination":{"$ref":"#/components/schemas/CursorPagination"}}},"example":{"data":[{"id":"uuid","status":"COMPLETED","patient":{"firstName":"Mario","lastName":"Rossi"}}],"pagination":{"limit":25,"total":130,"hasMore":true,"nextCursor":"cDoy"}}}}},"400":{"description":"INVALID_QUERY: Un parametro non è valido (stato inesistente, ore non numeriche, limite fuori intervallo).\nINVALID_CURSOR: Il cursore non è uno di quelli restituiti da questa API.\nAnche STRUCTURE_AMBIGUOUS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_62fb41"},"404":{"$ref":"#/components/responses/E404_83506c"},"429":{"$ref":"#/components/responses/C429"}}},"post":{"operationId":"createConsent","summary":"Invia un consenso","description":"Invia un consenso al paziente con le stesse opzioni della dashboard. Consuma la quota del piano come un invio fatto a mano; con una chiave in modalità Test il consenso si crea ma non parte nessun messaggio. La risposta 201 ha la stessa forma di `GET /consents/{id}`.\n\n**Permesso**: `consents:create`.\n\nLa risposta 201 contiene già il dettaglio completo. Un GET /consents/{id} lanciato nello stesso istante può rispondere 404 per qualche millisecondo, perché la scrittura si chiude alla fine della richiesta: usa il corpo del 201, oppure attendi il webhook consent.created.\n\nCon `X-Idempotency-Key` conserviamo per 24 ore solo il riferimento al consenso creato, mai nomi, telefoni o link: la ripetizione riceve la risposta ricostruita dal consenso di allora. Se nel frattempo la persona ha chiesto la cancellazione dei dati, la ripetizione riceve 404 `CONSENT_NOT_FOUND` e non parte nessun nuovo invio.","tags":["Consensi"],"x-scopes":["consents:create"],"parameters":[{"$ref":"#/components/parameters/XIdempotencyKey"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"patient":{"type":"object","properties":{"firstName":{"type":"string","minLength":1,"maxLength":100},"lastName":{"type":"string","minLength":1,"maxLength":100},"phone":{"type":"string","minLength":8,"maxLength":24},"dateOfBirth":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"isMinor":{"type":"boolean"},"externalId":{"type":"string","minLength":1,"maxLength":120},"fiscalCode":{"type":"string"},"id":{"type":"string","format":"uuid"}},"required":["firstName","lastName"],"additionalProperties":false},"guardians":{"minItems":1,"maxItems":2,"type":"array","items":{"type":"object","properties":{"relation":{"type":"string","enum":["MOTHER","FATHER","LEGAL_GUARDIAN"]},"firstName":{"type":"string","minLength":1,"maxLength":100},"lastName":{"type":"string","minLength":1,"maxLength":100},"phone":{"type":"string","minLength":8,"maxLength":24}},"required":["relation","firstName","lastName","phone"],"additionalProperties":false}},"consentType":{"default":"FULL","type":"string","enum":["FULL","TREATMENT_ONLY","PRIVACY_ONLY"]},"template":{"type":"object","properties":{"configurationId":{"type":"string","minLength":1,"maxLength":40},"treatments":{"maxItems":50,"type":"array","items":{"type":"string","minLength":1,"maxLength":80}},"privateTreatmentIds":{"maxItems":50,"type":"array","items":{"type":"string","minLength":1,"maxLength":80}},"mode":{"type":"string","enum":["GENERIC","SPECIFIC"]},"templateType":{"type":"string","enum":["PSYCHOLOGIST","PSYCHOTHERAPIST","PSYCHIATRIST"]},"professionType":{"type":"string","minLength":1,"maxLength":40},"secondaryProfessionId":{"type":"string","format":"uuid"},"agoraModule":{"type":"object","properties":{"indication":{"type":"string","maxLength":300},"device":{"type":"string","maxLength":300},"zones":{"type":"string","maxLength":400},"notes":{"type":"string","maxLength":1500}}},"privateSendValues":{"type":"object","propertyNames":{"type":"string","maxLength":60},"additionalProperties":{"type":"string","maxLength":5000}}},"additionalProperties":false},"executor":{"type":"object","properties":{"memberId":{"type":"string","format":"uuid"},"owner":{"type":"boolean"},"generic":{"type":"boolean"}},"additionalProperties":false},"structureSedeId":{"type":"string","format":"uuid"},"officeId":{"type":"string","format":"uuid"},"delivery":{"type":"object","properties":{"channel":{"type":"string","enum":["WHATSAPP","SMS"]},"language":{"type":"string","enum":["it","en","fr","de"]},"scheduledFor":{"type":"string","format":"date-time"},"signingMode":{"type":"string","enum":["REMOTE","IN_STUDIO"]}},"additionalProperties":false},"engagement":{"type":"object","properties":{"include":{"type":"boolean"},"overrides":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}}},"additionalProperties":false},"anamnesisAck":{"type":"boolean"},"equipmentIds":{"maxItems":30,"type":"array","items":{"type":"string","format":"uuid"}},"medicalEquipmentIds":{"maxItems":30,"type":"array","items":{"type":"string","format":"uuid"}},"requestMedicalClearance":{"type":"boolean"},"businessOperatorId":{"type":"string","format":"uuid"},"metadata":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"}]}}},"required":["patient"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Professionista singolo","value":{"patient":{"firstName":"Mario","lastName":"Rossi","phone":"+393331234567"},"template":{"treatments":["psi-colloquio"]},"delivery":{"channel":"WHATSAPP","language":"it"},"metadata":{"cartella":"CRT-119"}}},"esempio_2":{"summary":"Struttura: esecutore e sede","value":{"patient":{"firstName":"Luisa","lastName":"Bianchi","phone":"3339876543"},"template":{"treatments":["fis-terapia-manuale"],"professionType":"PHYSIOTHERAPIST"},"executor":{"memberId":"6b7c8d9e-0f1a-4b2c-9d3e-4f5a6b7c8d9e"},"structureSedeId":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d","delivery":{"channel":"SMS"}}},"esempio_3":{"summary":"Minore con doppia firma genitoriale","value":{"patient":{"firstName":"Sofia","lastName":"Verdi","isMinor":true,"dateOfBirth":"2014-05-09"},"guardians":[{"relation":"MOTHER","firstName":"Elena","lastName":"Verdi","phone":"+393331111111"},{"relation":"FATHER","firstName":"Marco","lastName":"Verdi","phone":"+393332222222"}],"template":{"treatments":["psi-colloquio","psi-sostegno"],"mode":"SPECIFIC"},"delivery":{"channel":"WHATSAPP"},"metadata":{"cartella":"CRT-120"}}}}}}},"responses":{"201":{"description":"Invia un consenso","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Consent"},"example":{"id":"uuid","status":"PENDING_SIGNATURE","internalStatus":"PENDING","consentType":"FULL","language":"it","isMinor":false,"isTutelato":false,"isTest":false,"source":{"channel":"api","apiKeyId":"ck…","apiKeyName":"Gestionale","apiKeyPrefix":"ak_live_…","test":false},"metadata":{"cartella":"CRT-119"},"dualSignatureRequired":false,"channel":"WHATSAPP","createdAt":"2026-09-16T09:00:00.000Z","scheduledAt":null,"expiresAt":"2026-09-23T09:00:00.000Z","signedAt":null,"validUntil":null,"patient":{"id":"uuid","firstName":"Mario","lastName":"Rossi","phoneHint":"***567"},"minor":null,"signers":[{"slot":"P1","role":"PATIENT","firstName":"Mario","lastName":"Rossi","phoneHint":"***567","expiresAt":"2026-09-23T09:00:00.000Z","status":"PENDING"}],"signatures":[{"slot":"P1","role":"PATIENT","firstName":"Mario","lastName":"Rossi","phoneHint":"***567","link":"https://…","status":"PENDING"}],"expectedSignatures":1,"receivedSignatures":0,"mismatch":null,"treatments":[{"id":"psi-colloquio"}],"sede":null,"office":null,"executor":null,"actingProfession":"PSYCHOLOGIST","actingProfessionTitle":null,"otp":{},"delivery":{"P1":{"slot":"P1","state":"IN_CORSO","channel":"WHATSAPP","phoneHint":"***567","inStudio":false,"attempts":[{"channel":"WHATSAPP","at":"2026-09-16T09:00:00.000Z","outcome":"inviato"}],"smsFallbackAlreadySent":false,"smsFallbackInProgress":false,"canSwitchToSms":false,"canCorrectPhone":false,"correctionsLeft":3}},"signingMode":"REMOTE","studioDevice":null,"engagement":{"included":false,"hasDocument":false},"anamnesis":{"collected":false,"hasAbsoluteContraindications":false,"hasRelativeContraindications":false,"flags":[],"findingCount":0},"lots":[],"privateChoices":[],"countersign":{"required":false,"status":"NOT_REQUIRED"},"documents":{"consentPdfAvailable":false,"privacyPdfAvailable":false,"engagementPdfAvailable":false,"dossierAvailable":false},"apiKey":{"id":"ck…","name":"Gestionale"},"apiMetadata":{"cartella":"CRT-119"},"timeline":[{"event":"sent","at":"2026-09-16T09:00:00.000Z"}],"privacy":{"revokeTotal":false,"revokedLabels":[]},"signatureLinks":[{"slot":"P1","link":"https://…"}],"messages":[{"slot":"P1","channel":"WHATSAPP","sent":true}],"scheduled":false,"test":false}}}},"400":{"description":"INVALID_BODY: Campi mancanti o non validi (anche dentro `patient`, `guardians`, `template`, `delivery`): `details` elenca ognuno.\nINVALID_JSON: Il corpo non è JSON valido (richiesta troncata, encoding sbagliato).\nTEMPLATE_AMBIGUOUS: `configurationId` e `treatments` insieme: indica una sola sorgente.\nACCOUNT_MODEL_TREATMENTS_UNAVAILABLE: Account «solo modelli»: i trattamenti del modello indicato non risolvono per questo invio (ambito diverso, modello senza ambito, catalogo non attivo). Nessun consenso creato: scegli un altro modello o scrivici.\nPROFESSION_NOT_ENABLED / UNKNOWN_SECONDARY_PROFESSION / SEDE_NOT_ALLOWED: Ambito, identità secondaria o sede non di questo account.\nPATIENT_PHONE_REQUIRED: Telefono mancante per un adulto. Per un minore il numero non serve: il link va ai `guardians`.\nENGAGEMENT_NOT_AVAILABLE: Hai passato `engagement.overrides` ma l'incarico non è attivo per questo invio.\nMETADATA_RESERVED_KEY: `metadata` usa una chiave che riempie l'API (externalId, fiscalCode, minor).\nPATIENT_ID_REQUIRED: «Solo consenso» richiede un paziente che ha già firmato l'informativa.\nGUARDIANS_REQUIRED / GUARDIANS_FOR_ADULT: Per un minore servono i firmatari; per un adulto non vanno indicati.\nDUAL_SIGNATURE_NOT_AVAILABLE: La professione dell'invio non prevede la doppia firma genitoriale.\nDUAL_SIGNATURE_REQUIRED: Su un minore, il trattamento richiede il consenso di entrambi i genitori: indica 2 firmatari.\nDUAL_SIGNATURE_TREATMENT_NOT_ELIGIBLE: Due firmatari su un trattamento che non li richiede.\nDUAL_SIGNATURE_SAME_PHONE: I due genitori hanno lo stesso numero.\nIN_STUDIO_NOT_SCHEDULABLE / IN_STUDIO_NO_DEVICE: Limiti della firma sul tablet di studio: non si programma e serve un tablet collegato a quella sede. Con due `guardians` il flusso è misto: il 1° genitore firma sul tablet, al 2° parte il link sul suo telefono.\nLANGUAGE_NOT_ENABLED: Lingua non attivata nelle Impostazioni dell'account.\nCLINIC_SEDE_REQUIRED / INVALID_CLINIC_SEDE / SEDE_CONTEXT_MISMATCH: Sede mancante, non tua, o in contrasto con l'intestazione.\nCLINIC_MEMBER_REQUIRED / INVALID_CLINIC_MEMBER / CLINIC_MEMBER_NOT_IN_SEDE: Esecutore mancante, non tuo, o che non opera in quella sede.\nSECRETARY_CANNOT_EXECUTE: La segreteria non può essere l'esecutore.\nEXECUTOR_AMBIGUOUS / EXECUTOR_CAPABILITY: Più esecutori insieme, o esecutore che non esegue quei trattamenti.\nANAMNESIS_ACK_REQUIRED: Controindicazioni assolute: conferma con anamnesisAck: true.\nPRIVATE_TREATMENT_NOT_AVAILABLE / METADATA_TOO_MANY_KEYS / METADATA_TOO_LARGE: Scheda privata non tua; metadata oltre i limiti.\nPRIVATE_SEND_VALUE_REQUIRED / PRIVATE_SEND_VALUE_INVALID / PRIVATE_SEND_VALUE_TOO_LONG / PRIVATE_SEND_VALUE_UNKNOWN: Campi da compilare della scheda con i tuoi testi: obbligatorio mancante, scelta fuori dalle opzioni o data non valida, testo troppo lungo, chiave che la scheda non prevede.\nPRIVACY_ONLY_NO_DUAL_SIGNATURE: La doppia firma genitoriale non si applica alla sola informativa privacy.\nPRIVACY_ONLY_WITH_PRIVACY_DISABLED: Hai chiesto la sola informativa, ma la struttura non invia l'informativa privacy.\nDUAL_SIGNATURE_NOT_SCHEDULABLE: Un consenso a doppia firma non si programma: i due link partono insieme al momento dell'invio.\nDUAL_SIGNATURE_PROFESSION_NOT_SUPPORTED: La doppia firma è disponibile solo per psicologi, psicoterapeuti, psichiatri e medici estetici.\nDUAL_SIGNATURE_SECOND_PARENT_MISSING: Mancano nome, cognome o telefono del secondo genitore.\nINVALID_PROFESSION_TYPE: Il profilo dell'account non ha una professione valida: va aggiornato in dashboard.\nLANGUAGE_NOT_AVAILABLE / LANGUAGE_NOT_AVAILABLE_FOR_TEMPLATE: La lingua scelta non ha la traduzione per questa professione o per questo modello.\nLANGUAGE_WITH_CUSTOM_PRIVACY / PRIVATE_TREATMENT_IT_ONLY / CUSTOM_ENGAGEMENT_IT_ONLY: Un testo del centro (informativa, scheda o incarico personalizzato) esiste solo in italiano: invia in italiano.\nCUSTOM_ENGAGEMENT_INCOMPLETE: Le condizioni d'incarico hanno una voce da compilare: indicala in `engagement.overrides` o escludi l'incarico da questo invio.\nCLINIC_NO_SCOPES / CLINIC_SCOPE_REQUIRED / CLINIC_SCOPE_NOT_ALLOWED: Strutture: ambiti non impostati, ambito mancante (`template.professionType`) o non della struttura.\nCLINIC_MEMBER_SCOPE_MISMATCH: Il professionista esecutore non esercita l'ambito dell'invio.\nEXECUTOR_REQUIRED: Strutture: manca il professionista che esegue (`executor`).\nSEND_GENERIC_NOT_ALLOWED_FOR_PROFESSION: Per questa professione il consenso generico non è ammesso: indica almeno un trattamento.\nINVALID_BUSINESS_OPERATOR / INVALID_EQUIPMENT: Operatrice o apparecchiatura non valida per questo account.\nIDEMPOTENCY_KEY_INVALID: `X-Idempotency-Key` vuota o più lunga di 128 caratteri.\nAnche STRUCTURE_AMBIGUOUS, INVALID_CHARACTERS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"402":{"description":"SUBSCRIPTION_GRACE_PERIOD / SUBSCRIPTION_REQUIRED: Abbonamento scaduto o non attivo (solo chiavi di produzione).\nCONSENT_QUOTA_EXCEEDED: Quota consensi del piano esaurita: la risposta riporta `consentsUsed` e `consentsLimit`.\nPAYMENT_FAILED: Rinnovo dell'abbonamento non riuscito: aggiorna il metodo di pagamento.\nSTRUCTURE_PLAN_INACTIVE: Struttura o studio senza un piano attivo e con la prova finita: per inviare va attivato un piano.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"PROFILE_INCOMPLETE: Profilo del titolare incompleto: il documento non si può intestare. Vale anche in modalità Test.\nACCOUNT_MODELS_ONLY: L'account invia solo dai suoi modelli (impostazione concordata con noi): serve `template.configurationId` di un modello dell'account, e trattamenti, modalità e ambito vengono dal modello. La sola informativa (`PRIVACY_ONLY`) non lo richiede.\nAnche IP_NOT_ALLOWED, SCOPE_MISSING e gli altri comuni: components.responses.C403.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"CONFIGURATION_NOT_FOUND / OFFICE_NOT_FOUND / EQUIPMENT_NOT_FOUND: Un id indicato non esiste o non è di questo account.\nPATIENT_NOT_FOUND: `patient.id` inesistente o di un altro account.\n—: Ripetizione con una `X-Idempotency-Key` già usata, ma il consenso di allora non esiste più (per esempio perché la persona ha chiesto la cancellazione dei dati): la risposta è identica a quella di `GET /consents/{id}` con un id inesistente, e nessun nuovo invio parte.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"IDEMPOTENCY_KEY_REUSED / IDEMPOTENCY_IN_PROGRESS: Stessa chiave con un corpo diverso, o richiesta ancora in corso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"$ref":"#/components/responses/C413"},"422":{"description":"UNKNOWN_TREATMENT_CODE: Codice del catalogo inesistente (probabile refuso): l'elenco è in GET /templates.\nTEMPLATE_NOT_ENABLED_FOR_ACCOUNT: Il codice appartiene a un ambito che il tuo account non esercita.\nMESSAGE_NOT_DELIVERED: Il numero non è raggiungibile: nessun consenso è stato creato.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"DAILY_SEND_LIMIT: Tetto giornaliero di invii via API per questo account (chiavi di produzione).\nTEST_DAILY_LIMIT: Tetto della modalità Test: 50 invii e 20 anagrafiche nuove al giorno.\nAnche RATE_LIMIT_EXCEEDED: components.responses.C429.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/consents/{id}":{"get":{"operationId":"getConsent","summary":"Dettaglio di un consenso","description":"Restituisce il dettaglio completo del consenso: firmatari (uno per link), difformità sui dati del minore, esiti di consegna, evidenza dell'OTP, incarico, anamnesi in forma di semaforo, registro dei lotti, controfirma, documenti disponibili e cronologia.\n\n**Permesso**: `consents:read`.\n\nCon una chiave Test esistono solo i consensi di prova: un consenso vero risponde 404 `CONSENT_NOT_FOUND`, come un id inesistente.\n\n**Campi della risposta**\n- `status`: Stato nel vocabolario dell'API. `internalStatus` porta quello interno del prodotto.\n- `signers[] / signatures[]`: Un elemento per firmatario: slot (P1/P2), ruolo (PATIENT, MOTHER, FATHER, LEGAL_GUARDIAN, FIRST_PARENT, SECOND_PARENT), nome, suffisso del numero, stato (PENDING, SIGNED, REFUSED, EXPIRED), firma e verifica OTP.\n- `mismatch`: C'è solo se i due genitori hanno dichiarato dati del minore diversi: i campi divergenti con i due valori e l'endpoint che risolve.\n- `delivery`: Stato di consegna per firmatario (P1/P2) con i tentativi.\n- `countersign`: Tatuaggi e piercing: se serve la controfirma, chi deve darla, quando è arrivata e come sollecitarla.\n- `anamnesis`: Semaforo (GREEN/YELLOW/RED) e flag di rischio. Le risposte cliniche restano in GET /consents/{id}/anamnesis.\n- `privateChoices[]`: Schede con i testi del centro che contengono scelte del paziente (es. uso delle fotografie): per ciascuna domanda, opzioni (`value`, `label`), `required` e la risposta data alla firma (`answer`, `answerLabel`; null prima della firma o se una scelta facoltativa resta senza risposta). Vuoto se il documento non ha scelte.\n- `timeline`: Passi in ordine: creato, inviato, consegnato, letto, firmato (per slot), controfirmato, completato, annullato, scaduto.","tags":["Consensi"],"x-scopes":["consents:read"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Dettaglio di un consenso","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Consent"},"example":{"id":"uuid","status":"PENDING_SIGNATURE","internalStatus":"PENDING","consentType":"FULL","language":"it","isMinor":false,"isTutelato":false,"isTest":false,"source":{"channel":"api","apiKeyId":"ck…","apiKeyName":"Gestionale","apiKeyPrefix":"ak_live_…","test":false},"metadata":{"cartella":"CRT-119"},"dualSignatureRequired":false,"channel":"WHATSAPP","createdAt":"2026-09-16T09:00:00.000Z","scheduledAt":null,"expiresAt":"2026-09-23T09:00:00.000Z","signedAt":null,"validUntil":null,"patient":{"id":"uuid","firstName":"Mario","lastName":"Rossi","phoneHint":"***567"},"minor":null,"signers":[{"slot":"P1","role":"PATIENT","firstName":"Mario","lastName":"Rossi","phoneHint":"***567","expiresAt":"2026-09-23T09:00:00.000Z","status":"PENDING"}],"signatures":[{"slot":"P1","role":"PATIENT","firstName":"Mario","lastName":"Rossi","phoneHint":"***567","expiresAt":"2026-09-23T09:00:00.000Z","status":"PENDING"}],"expectedSignatures":1,"receivedSignatures":0,"mismatch":null,"treatments":[{"id":"psi-colloquio"}],"sede":null,"office":null,"executor":null,"actingProfession":"PSYCHOLOGIST","actingProfessionTitle":null,"otp":{},"delivery":{"P1":{"slot":"P1","state":"IN_CORSO","channel":"WHATSAPP","phoneHint":"***567","inStudio":false,"attempts":[{"channel":"WHATSAPP","at":"2026-09-16T09:00:00.000Z","outcome":"inviato"}],"smsFallbackAlreadySent":false,"smsFallbackInProgress":false,"canSwitchToSms":false,"canCorrectPhone":false,"correctionsLeft":3}},"signingMode":"REMOTE","studioDevice":null,"engagement":{"included":false,"hasDocument":false},"anamnesis":{"collected":false,"hasAbsoluteContraindications":false,"hasRelativeContraindications":false,"flags":[],"findingCount":0},"lots":[],"privateChoices":[],"countersign":{"required":false,"status":"NOT_REQUIRED"},"documents":{"consentPdfAvailable":false,"privacyPdfAvailable":false,"engagementPdfAvailable":false,"dossierAvailable":false},"apiKey":{"id":"ck…","name":"Gestionale"},"apiMetadata":{"cartella":"CRT-119"},"timeline":[{"event":"sent","at":"2026-09-16T09:00:00.000Z"}],"privacy":{"revokeTotal":false,"revokedLabels":[]}}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_cc628f"},"429":{"$ref":"#/components/responses/C429"}}}},"/consents/{id}/delivery":{"get":{"operationId":"getConsentDelivery","summary":"Esiti di consegna","description":"Restituisce gli esiti di consegna per firmatario: ogni tentativo su WhatsApp e per SMS, ripieghi automatici compresi, con esito e motivo. È la lettura che dice se serve correggere un numero.\n\n**Permesso**: `consents:read`.\n\nCon una chiave Test esistono solo i consensi di prova: un consenso vero risponde 404 `CONSENT_NOT_FOUND`, come un id inesistente.","tags":["Consensi"],"x-scopes":["consents:read"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Esiti di consegna","content":{"application/json":{"example":{"consentId":"uuid","status":"PENDING_SIGNATURE","internalStatus":"PENDING","signers":[{"slot":"P1","state":"NON_CONSEGNATO","channel":"SMS","phoneHint":"***221","attempts":[{"channel":"WHATSAPP","at":"2026-09-16T09:00:05.000Z","outcome":"fallito","failureCode":"131026"},{"channel":"SMS","at":"2026-09-16T09:00:12.000Z","outcome":"fallito","failureCode":"UNDELIVERABLE"}],"smsFallbackAlreadySent":true,"canCorrectPhone":true,"correctionsLeft":3}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_cc628f"},"429":{"$ref":"#/components/responses/C429"}}}},"/consents/{id}/evidence":{"get":{"operationId":"getConsentEvidence","summary":"Evidenza della firma","description":"Restituisce le prove della firma per ogni firmatario: canale e numero mascherato dell'OTP, ora di invio e di verifica, IP e dispositivo di chi ha firmato, codici di controllo SHA-256 dei documenti. Con la doppia firma c'è una voce per genitore.\n\n**Permesso**: `consents:read`.\n\nCon una chiave Test esistono solo i consensi di prova: un consenso vero risponde 404 `CONSENT_NOT_FOUND`, come un id inesistente.\n\nL'indirizzo IP di ogni firmatario arriva con l'ultima parte nascosta (203.0.113.xxx); completo solo con il permesso `audit:read`.","tags":["Consensi"],"x-scopes":["consents:read"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Evidenza della firma","content":{"application/json":{"example":{"consentId":"uuid","status":"PENDING_SIGNATURE","internalStatus":"PENDING","expectedSignatures":2,"receivedSignatures":2,"signers":[{"slot":"P1","role":"FIRST_PARENT","signed":true,"signedAt":"2026-09-16T09:12:00.000Z","otp":{"channel":"WHATSAPP","phoneMasked":"+39*******1221","sentAt":"2026-09-16T09:11:00.000Z","verifiedAt":"2026-09-16T09:11:40.000Z"},"ipAddress":"93.51.12.xxx","signatureHash":"a1b2…"},{"slot":"P2","role":"SECOND_PARENT","signed":true,"signedAt":"2026-09-16T10:02:00.000Z","otp":{"channel":"SMS","phoneMasked":"+39*******2332","verifiedAt":"2026-09-16T10:01:30.000Z"}}],"countersign":{"required":false,"status":"NOT_REQUIRED","at":null,"method":null},"documents":{"consentPdfSha256":"a1b2…"}}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_cc628f"},"429":{"$ref":"#/components/responses/C429"}}}},"/consents/{id}/audit":{"get":{"operationId":"getConsentAudit","summary":"Registro del consenso","description":"Restituisce il registro del consenso: cosa è successo, quando e per opera di chi (dashboard o integrazione), con l'anello della catena hash di ogni riga. Numeri di telefono, email e risposte cliniche restano fuori.\n\n**Permesso**: `consents:read`.\n\nCon una chiave Test esistono solo i consensi di prova: un consenso vero risponde 404 `CONSENT_NOT_FOUND`, come un id inesistente.","tags":["Consensi"],"x-scopes":["consents:read"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Registro del consenso","content":{"application/json":{"example":{"consentId":"uuid","total":7,"entries":[{"action":"CONSENT_SENT","label":"Consenso inviato","at":"2026-09-16T09:00:00.000Z","by":"PROFESSIONAL","via":"api","details":{"consentType":"FULL","dualSignature":true},"entryHash":"c3d4…"},{"action":"CONSENT_SIGNED_BY_PARENT_1","label":"Firma del 1° genitore","at":"2026-09-16T09:12:00.000Z","by":"PATIENT","via":"dashboard","details":{"slot":"P1"}}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_cc628f"},"429":{"$ref":"#/components/responses/C429"}}}},"/consents/{id}/cancel":{"post":{"operationId":"cancelConsent","summary":"Annulla un consenso","description":"Annulla un consenso non ancora firmato, con le stesse regole della dashboard. Un consenso vero torna nella quota del piano; uno di prova non l'aveva consumata. Parte l'evento `consent.cancelled`.\n\n**Permesso**: `consents:cancel`.","tags":["Consensi"],"x-scopes":["consents:cancel"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Annulla un consenso","content":{"application/json":{"example":{"ok":true,"consentId":"uuid"}}}},"400":{"description":"—: Il consenso è in uno stato che non si annulla (per esempio è già firmato).\nAnche STRUCTURE_AMBIGUOUS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_cc628f"},"429":{"$ref":"#/components/responses/C429"}}}},"/consents/{id}/resend":{"post":{"operationId":"resendConsent","summary":"Reinvia un consenso scaduto","description":"Reinvia un consenso scaduto. Nasce un consenso nuovo, con un link nuovo, e consuma un'unità di quota come un invio fatto a mano. La risposta è il dettaglio del consenso nuovo, con `replacesConsentId` che punta a quello sostituito.\n\n**Permesso**: `consents:create`.\n\nVale per l'intero consenso: `slot` qui non si usa (400 SLOT_NOT_APPLICABLE).","tags":["Ciclo di vita"],"x-scopes":["consents:create"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/XIdempotencyKey"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"201":{"description":"Reinvia un consenso scaduto","content":{"application/json":{"example":{"id":"uuid","status":"PENDING_SIGNATURE","internalStatus":"PENDING","consentType":"FULL","language":"it","isMinor":false,"isTutelato":false,"isTest":false,"source":{"channel":"dashboard","test":false},"metadata":null,"dualSignatureRequired":false,"channel":"WHATSAPP","createdAt":"2026-09-16T09:00:00.000Z","scheduledAt":null,"expiresAt":"2026-09-23T09:00:00.000Z","signedAt":null,"validUntil":null,"patient":{"id":"uuid","firstName":"Mario","lastName":"Rossi","phoneHint":"***567"},"minor":null,"signers":[{"slot":"P1","role":"PATIENT","firstName":"Mario","lastName":"Rossi","phoneHint":"***567","expiresAt":"2026-09-23T09:00:00.000Z","status":"PENDING"}],"signatures":[{"slot":"P1","link":"https://…","expiresAt":"2026-09-23T09:00:00.000Z"}],"expectedSignatures":1,"receivedSignatures":0,"mismatch":null,"treatments":[{"id":"psi-colloquio"}],"sede":null,"office":null,"executor":null,"actingProfession":"PSYCHOLOGIST","actingProfessionTitle":null,"otp":{},"delivery":{"P1":{"slot":"P1","state":"IN_CORSO","channel":"WHATSAPP","phoneHint":"***567","inStudio":false,"attempts":[{"channel":"WHATSAPP","at":"2026-09-16T09:00:00.000Z","outcome":"inviato"}],"smsFallbackAlreadySent":false,"smsFallbackInProgress":false,"canSwitchToSms":false,"canCorrectPhone":false,"correctionsLeft":3}},"signingMode":"REMOTE","studioDevice":null,"engagement":{"included":false,"hasDocument":false},"anamnesis":{"collected":false,"hasAbsoluteContraindications":false,"hasRelativeContraindications":false,"flags":[],"findingCount":0},"lots":[],"privateChoices":[],"countersign":{"required":false,"status":"NOT_REQUIRED"},"documents":{"consentPdfAvailable":false,"privacyPdfAvailable":false,"engagementPdfAvailable":false,"dossierAvailable":false},"apiKey":null,"apiMetadata":null,"timeline":[{"event":"created","at":"2026-09-16T09:00:00.000Z"}],"privacy":{"revokeTotal":false,"revokedLabels":[]},"kind":"resend","replacesConsentId":"uuid"}}}},"400":{"description":"CONSENT_NOT_EXPIRED: Si reinvia solo un consenso scaduto senza firma. Un consenso firmato a scadenza si rinnova.\nRESEND_DUAL_SIGNATURE: Doppia firma per minori: il consenso nuovo nascerebbe a firma singola. Rifai l'invio con i due `guardians`.\nIN_STUDIO_NO_MESSAGE_TO_RESEND: Firma sul tablet: nessun messaggio è mai partito. Usa /reopen-in-studio.\nAPI_TEST_CONSENT: La copia di un consenso di prova sarebbe un consenso vero: creane uno nuovo.\nSLOT_NOT_APPLICABLE: `slot` si usa su /channel e /correct-phone, non qui.\nIDEMPOTENCY_KEY_INVALID: `X-Idempotency-Key` vuota o più lunga di 128 caratteri.\nAnche STRUCTURE_AMBIGUOUS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"402":{"description":"CONSENT_QUOTA_EXCEEDED: Il reinvio consuma quota come un invio nuovo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_cc628f"},"409":{"description":"ALREADY_RESENT: Questo consenso è già stato reinviato: `newConsentId` dice quale. Se è scaduto anche quello, reinvia quello.\nIDEMPOTENCY_KEY_REUSED / IDEMPOTENCY_IN_PROGRESS: La stessa `X-Idempotency-Key` è già stata usata con un corpo diverso, oppure la prima richiesta con quella chiave è ancora in corso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"},"502":{"description":"RESEND_FAILED: Il reinvio non è riuscito e nessun consenso nuovo è stato creato: riprova.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/consents/{id}/renew":{"post":{"operationId":"renewConsent","summary":"Rinnova un consenso a scadenza","description":"Rinnova un consenso firmato con validità a termine, cioè creato da un modello con scadenza. Funziona come il reinvio: nasce un consenso nuovo e l'originale viene segnato come rinnovato.\n\n**Permesso**: `consents:create`.","tags":["Ciclo di vita"],"x-scopes":["consents:create"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/XIdempotencyKey"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"201":{"description":"Rinnova un consenso a scadenza","content":{"application/json":{"example":{"id":"uuid-nuovo","kind":"renew","replacesConsentId":"uuid-vecchio","status":"PENDING_SIGNATURE"}}}},"400":{"description":"CONSENT_NOT_RENEWABLE: Il consenso non è firmato o non ha una validità a termine.\nRENEWAL_DUAL_SIGNATURE: Doppia firma: servono di nuovo entrambe le firme, quindi un invio nuovo.\nIDEMPOTENCY_KEY_INVALID: `X-Idempotency-Key` vuota o più lunga di 128 caratteri.\nAnche STRUCTURE_AMBIGUOUS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"description":"CONSENT_NOT_FOUND: Consenso inesistente, di un altro account, oppure vero mentre usi una chiave in modalità Test.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"ALREADY_RENEWED: Questo consenso è già stato rinnovato: il consenso nuovo esiste già.\nIDEMPOTENCY_KEY_REUSED / IDEMPOTENCY_IN_PROGRESS: La stessa `X-Idempotency-Key` è già stata usata con un corpo diverso, oppure la prima richiesta con quella chiave è ancora in corso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}}},"/consents/{id}/channel":{"post":{"operationId":"switchConsentChannel","summary":"Sposta un firmatario su SMS","description":"Sposta su SMS il link di un firmatario quando la consegna su WhatsApp non è riuscita. Il link resta lo stesso e la quota non si consuma. È il «Reinvia via SMS» della dashboard e va in una sola direzione, da WhatsApp a SMS.\n\n**Permesso**: `consents:create`.","tags":["Ciclo di vita"],"x-scopes":["consents:create"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string","enum":["SMS","WHATSAPP"]},"slot":{"type":"string","maxLength":10}},"required":["channel"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Al 2° genitore","value":{"channel":"SMS","slot":"P2"}}}}}},"responses":{"200":{"description":"Sposta un firmatario su SMS","content":{"application/json":{"example":{"ok":true,"consentId":"uuid","slot":"P2","channel":"SMS","sameLink":true}}}},"400":{"description":"CHANNEL_SWITCH_NOT_AVAILABLE: Hai chiesto WHATSAPP: il passaggio esiste solo verso SMS.\nNOT_DUAL_SIGNATURE: \"P2\" su un consenso con un solo firmatario.\nINVALID_SLOT: `slot` diverso da P1 / P2.\nIN_STUDIO_NO_MESSAGE_TO_RESEND: Firma sul tablet: nessun messaggio da spostare.\nDELIVERY_NOT_FAILED: La consegna su WhatsApp a quel firmatario non risulta fallita: il passaggio a SMS non serve.\nNOT_SENT_VIA_WHATSAPP: Quel firmatario non è stato contattato su WhatsApp, oppure è già passato a SMS.\nCONSENT_NOT_PENDING: Quel firmatario non è più in attesa di firmare.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_cc628f"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"},"502":{"description":"SMS_SEND_FAILED: L'SMS non è partito: riprova più tardi.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/consents/{id}/correct-phone":{"post":{"operationId":"correctConsentPhone","summary":"Correggi il numero di un firmatario","description":"Corregge il numero di un firmatario e gli rimanda lo stesso link. Non nasce un consenso nuovo e la quota non si consuma. Puoi correggere il numero al massimo tre volte per ogni firmatario.\n\n**Permesso**: `consents:create`.","tags":["Ciclo di vita"],"x-scopes":["consents:create"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","minLength":6,"maxLength":24},"slot":{"type":"string","maxLength":10}},"required":["phone"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Numero del 1° genitore","value":{"phone":"+393334445566","slot":"P1"}}}}}},"responses":{"200":{"description":"Correggi il numero di un firmatario","content":{"application/json":{"example":{"ok":true,"consentId":"uuid","slot":"P1","channel":"WHATSAPP","sameLink":true,"messageSent":true,"correctionsLeft":2}}}},"400":{"description":"INVALID_PHONE / SAME_NUMBER: Numero malformato o identico a quello già usato.\nDUAL_SIGNATURE_SAME_PHONE: I due genitori avrebbero lo stesso numero: ciascuno firma dal proprio.\nCONSENT_NOT_PENDING / CONSENT_LINK_EXPIRED: Il firmatario ha già firmato, o il suo link è scaduto.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_cc628f"},"409":{"description":"PHONE_BELONGS_TO_OTHER_PATIENT: Quel numero è già di un altro paziente in archivio.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"$ref":"#/components/responses/C413"},"429":{"description":"PHONE_CORRECTION_LIMIT: Tre correzioni già fatte per questo firmatario.\nAnche RATE_LIMIT_EXCEEDED: components.responses.C429.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/consents/{id}/resolve-mismatch":{"post":{"operationId":"resolveConsentMismatch","summary":"Risolvi una difformità sui dati del minore","description":"Serve con la doppia firma, quando i due genitori hanno dichiarato dati del minore diversi e il consenso è fermo in ACTION_REQUIRED. Scegli quale versione vale: il PDF con le due firme viene generato e il consenso diventa COMPLETED.\n\n**Permesso**: `consents:create`.","tags":["Ciclo di vita"],"x-scopes":["consents:create"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"acceptFrom":{"type":"string","enum":["P1","P2"]}},"required":["acceptFrom"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Vale la versione della madre","value":{"acceptFrom":"P1"}}}}}},"responses":{"200":{"description":"Risolvi una difformità sui dati del minore","content":{"application/json":{"example":{"ok":true,"acceptedFrom":"P1","consent":{"id":"uuid","status":"COMPLETED","receivedSignatures":2}}}}},"400":{"description":"NO_DATA_MISMATCH: Il consenso non è fermo su una difformità.\nINVALID_BODY: `acceptFrom` diverso da P1 / P2.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_cc628f"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/consents/{id}/cancel-mismatch":{"post":{"operationId":"cancelConsentMismatch","summary":"Chiudi una difformità non risolvibile","description":"Chiude un consenso quando la difformità sui dati del minore non si può risolvere, per esempio per uno scambio di persona. Il consenso prende uno stato suo, diverso da quello di un annullamento a mano.\n\n**Permesso**: `consents:cancel`.","tags":["Ciclo di vita"],"x-scopes":["consents:cancel"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Chiudi una difformità non risolvibile","content":{"application/json":{"example":{"ok":true,"consentId":"uuid","status":"CANCELLED","internalStatus":"CANCELLED_DATA_MISMATCH"}}}},"400":{"description":"NO_DATA_MISMATCH: Per annullare un consenso normale usa /cancel.\nAnche STRUCTURE_AMBIGUOUS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_cc628f"},"429":{"$ref":"#/components/responses/C429"}}}},"/consents/{id}/reopen-in-studio":{"post":{"operationId":"reopenConsentInStudio","summary":"Riapri sul tablet","description":"È il «Riapri sul tablet» della dashboard. Un consenso da firmare in studio esce dalla coda del tablet dopo 12 ore: se il paziente torna, questa chiamata lo rimette in coda con lo stesso link e senza consumare quota.\n\n**Permesso**: `consents:create`.","tags":["Ciclo di vita"],"x-scopes":["consents:create"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Riapri sul tablet","content":{"application/json":{"example":{"ok":true,"consentId":"uuid","signingMode":"IN_STUDIO"}}}},"400":{"description":"NOT_IN_STUDIO: Il consenso non è in modalità firma sul tablet.\nCONSENT_NOT_PENDING / CONSENT_LINK_EXPIRED: Già firmato, oppure link scaduto: serve un nuovo invio.\nIN_STUDIO_NO_DEVICE: Nessun tablet collegato per quella sede.\nAnche STRUCTURE_AMBIGUOUS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_cc628f"},"429":{"$ref":"#/components/responses/C429"}}}},"/consents/{id}/countersign/remind":{"post":{"operationId":"remindConsentCountersign","summary":"Sollecita la controfirma","description":"Tatuaggi e piercing: manda all'esecutore il link per controfirmare, come «Invia ora» in dashboard. La controfirma vera non passa dall'API: è una sottoscrizione personale dell'esecutore, con un suo fattore (app di autenticazione o codice sul suo telefono), e deve restare sua. Puoi mandare il link una volta ogni 10 minuti per esecutore.\n\n**Permesso**: `consents:countersign`.","tags":["Ciclo di vita"],"x-scopes":["consents:countersign"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Sollecita la controfirma","content":{"application/json":{"example":{"ok":true,"consentId":"uuid","sent":true,"channel":"WHATSAPP","sentAt":"2026-09-16T11:00:00.000Z","expiresAt":"2026-09-17T11:00:00.000Z","consentsInReminder":3}}}},"400":{"description":"COUNTERSIGN_NOT_REQUIRED: Questo consenso non prevede la controfirma.\nAPI_TEST_CONSENT: Consenso di prova: non entra nel giro della controfirma (il link all'esecutore è un messaggio vero).\nALREADY_COUNTERSIGNED: L'esecutore ha già controfirmato.\nCOUNTERSIGN_NOT_PENDING: Il cliente non ha ancora firmato.\nCOUNTERSIGNER_NOT_ASSIGNED: Nessun esecutore associato: assegnalo dalla dashboard.\nSTRUCTURE_REQUIRED: La controfirma con link all'esecutore esiste solo negli studi con professionisti configurati.\nAnche STRUCTURE_AMBIGUOUS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_cc628f"},"409":{"description":"COUNTERSIGN_PHONE_NOT_VERIFIED: Il numero dell'esecutore non è verificato: il link non può partire.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"COUNTERSIGN_SESSION_RATE_LIMITED: Link già mandato da meno di 10 minuti.\nAnche RATE_LIMIT_EXCEEDED: components.responses.C429.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/consents/{id}/pdf":{"get":{"operationId":"downloadConsentPdf","summary":"PDF del consenso firmato","description":"Restituisce un link temporaneo al PDF del consenso firmato, valido un'ora. Il file resta in uno spazio privato e non ha un indirizzo pubblico.\n\n**Permesso**: `consents:documents`.","tags":["Documenti"],"x-scopes":["consents:documents"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/query_redirect"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"PDF del consenso firmato","content":{"application/json":{"example":{"kind":"pdf","downloadUrl":"https://…","expiresInSeconds":3600}}}},"302":{"description":"Con `?redirect=1`: reindirizzamento all'URL firmata del file.","headers":{"Location":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_60f951"},"429":{"$ref":"#/components/responses/C429"}}}},"/consents/{id}/privacy-pdf":{"get":{"operationId":"downloadPrivacyPdf","summary":"PDF dell'informativa privacy","description":"Restituisce un link temporaneo al PDF dell'informativa privacy firmata dal paziente, valido un'ora.\n\n**Permesso**: `consents:documents`.","tags":["Documenti"],"x-scopes":["consents:documents"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/query_redirect"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"PDF dell'informativa privacy","content":{"application/json":{"example":{"kind":"privacy","downloadUrl":"https://…","expiresInSeconds":3600}}}},"302":{"description":"Con `?redirect=1`: reindirizzamento all'URL firmata del file.","headers":{"Location":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_60f951"},"429":{"$ref":"#/components/responses/C429"}}}},"/consents/{id}/engagement-pdf":{"get":{"operationId":"downloadEngagementPdf","summary":"PDF della lettera d'incarico","description":"Restituisce un link temporaneo al PDF della lettera d'incarico sottoscritta dal paziente, valido un'ora.\n\n**Permesso**: `consents:documents`.","tags":["Documenti"],"x-scopes":["consents:documents"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/query_redirect"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"PDF della lettera d'incarico","content":{"application/json":{"example":{"kind":"engagement","downloadUrl":"https://…","expiresInSeconds":3600}}}},"302":{"description":"Con `?redirect=1`: reindirizzamento all'URL firmata del file.","headers":{"Location":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_60f951"},"429":{"$ref":"#/components/responses/C429"}}}},"/consents/{id}/dossier":{"get":{"operationId":"downloadConsentDossier","summary":"Fascicolo difensivo del consenso","description":"Restituisce il fascicolo difensivo: un PDF unico con consenso, anamnesi, registro dei lotti e prova d'integrità della catena di audit. Si genera al momento, quindi arriva direttamente nel corpo come application/pdf, oppure in base64 con `?format=json`.\n\n**Permesso**: `consents:documents`.","tags":["Documenti"],"x-scopes":["consents:documents"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/query_format"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Fascicolo difensivo del consenso. Il PDF arriva nel corpo; con `?format=json` arriva in base64 dentro un JSON.","content":{"application/pdf":{"schema":{"type":"string","contentMediaType":"application/pdf"}},"application/json":{"example":{"kind":"dossier","filename":"fascicolo-…pdf","contentType":"application/pdf","sizeBytes":148213,"contentBase64":"JVBERi0…"}}}},"400":{"$ref":"#/components/responses/E400_c00cc7"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"description":"DOCUMENT_NOT_AVAILABLE: Il documento esiste solo dopo la firma: il consenso non è ancora completato, oppure l'invio non comprendeva questo documento.\nDOSSIER_NOT_AVAILABLE: Il fascicolo non è disponibile per questo consenso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"},"502":{"description":"DOSSIER_GENERATION_FAILED: Uno dei documenti firmati non è leggibile: il fascicolo non è stato composto.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/consents/{id}/send-pdf-email":{"post":{"operationId":"sendConsentPdfEmail","summary":"Manda i PDF al paziente per email","description":"Manda, o rimanda, i PDF firmati al paziente per email. Senza `email` usa l'indirizzo lasciato alla firma.\n\n**Permesso**: `consents:documents`.","tags":["Documenti"],"x-scopes":["consents:documents"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":200,"format":"email"}},"additionalProperties":false},"examples":{"esempio_1":{"summary":"A un indirizzo nuovo","value":{"email":"archivio@studio.it"}}}}}},"responses":{"200":{"description":"Manda i PDF al paziente per email","content":{"application/json":{"example":{"ok":true,"consentId":"uuid","email":"ar*******@studio.it","messageId":"uuid","sentAt":"2026-09-16T10:30:00.000Z"}}}},"400":{"description":"INVALID_BODY: Indirizzo email non valido.\nAPI_TEST_CONSENT: Il PDF di prova porta la filigrana e sparisce dopo 7 giorni: non si spedisce.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_60f951"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/patients":{"get":{"operationId":"listPatients","summary":"Elenco e ricerca dei pazienti","description":"Restituisce le anagrafiche, con la ricerca. Il telefono esce in chiaro: sei il titolare del trattamento e in dashboard lo vedi già per intero. Ogni riga porta lo stato della privacy, così sai subito se puoi mandare un «solo consenso» o se serve l'informativa completa.\n\n**Permesso**: `patients:read`.\n\nUna chiave in modalità Test lavora in un archivio parallelo: le anagrafiche che crea hanno telefono, codice fiscale ed externalId in uno spazio dei nomi separato, quindi non collidono mai con quelle vere e non le toccano. Con una chiave Test l'esito di una creazione è sempre lo stesso (l'anagrafica di prova viene creata, o ritrovata se è una prova che hai già creato tu), che telefono, codice fiscale o externalId siano o non siano di un tuo paziente. Per questo una chiave di prova non permette di scoprire chi è in archivio.\n\nCon una chiave Test la lista mostra solo le anagrafiche di prova, che cancelliamo in automatico quando restano senza consensi.\n\nVale anche al contrario: per una chiave di produzione le anagrafiche di prova non esistono, e un invio col loro id risponde 404.","tags":["Pazienti"],"x-scopes":["patients:read"],"parameters":[{"name":"search","in":"query","description":"Nome, cognome o telefono. Un valore che è un codice fiscale ben formato viene cercato come tale (per hash).","schema":{"type":"string"}},{"name":"fiscalCode","in":"query","description":"Codice fiscale esatto: ricerca per hash, mai in chiaro a database.","schema":{"type":"string"},"example":"RSSMRA80A01F205X"},{"name":"externalId","in":"query","description":"Il tuo riferimento del gestionale, esatto.","schema":{"type":"string"},"example":"CRM-4412"},{"$ref":"#/components/parameters/query_sedeId"},{"name":"executorMemberId","in":"query","description":"Solo i pazienti con almeno un consenso eseguito da quel professionista.","schema":{"type":"string"}},{"name":"apiTest","in":"query","description":"`true` = solo le anagrafiche di prova, `false` = solo quelle vere.","schema":{"type":"string","enum":["true","false"]}},{"$ref":"#/components/parameters/query_limit"},{"name":"cursor","in":"query","description":"Cursore della pagina successiva (campo `nextCursor`).","schema":{"type":"string"}},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Elenco e ricerca dei pazienti","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Patient"}},"pagination":{"$ref":"#/components/schemas/CursorPagination"}}},"example":{"data":[{"id":"uuid","firstName":"Mario","lastName":"Rossi","phone":"+393331112233","externalId":"CRM-4412","hasFiscalCode":true,"isTest":false,"consentsCount":3,"visitsCount":5,"privacy":{"state":"ACTIVE","signedAt":"2026-05-02T10:00:00.000Z","consentId":"uuid"}}],"pagination":{"limit":25,"total":240,"hasMore":true,"nextCursor":"cDoy"}}}}},"400":{"description":"INVALID_QUERY: Un parametro non è valido (limite fuori intervallo, codice fiscale malformato).\nINVALID_CURSOR: Il cursore non è uno di quelli restituiti da questa API.\nAnche STRUCTURE_AMBIGUOUS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_62fb41"},"404":{"$ref":"#/components/responses/E404_83506c"},"429":{"$ref":"#/components/responses/C429"}}},"post":{"operationId":"createPatient","summary":"Crea o ritrova un paziente","description":"Crea l'anagrafica, oppure ritrova quella che esiste già. La ricerca dei doppioni è la stessa dell'archivio: prima il codice fiscale, poi `externalId`, poi il telefono. Se telefono e nome coincidono è la stessa persona e ricevi 200 con `created: false`. Se il telefono coincide ma il nome no, ricevi 409, come in dashboard. Se due anagrafiche si rivelano la stessa persona vengono unite: ricevi `merged: true` e il webhook `patient.merged` con l'id che da quel momento non vale più.\n\n**Permesso**: `patients:write`.\n\nCon `X-Idempotency-Key` a database conserviamo solo gli identificativi della risposta, mai nome e telefono.","tags":["Pazienti"],"x-scopes":["patients:write"],"parameters":[{"$ref":"#/components/parameters/XIdempotencyKey"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"firstName":{"type":"string","minLength":1,"maxLength":80},"lastName":{"type":"string","minLength":1,"maxLength":80},"phone":{"type":"string","pattern":"^\\+[1-9]\\d{6,14}$"},"fiscalCode":{"type":"string","pattern":"^[A-Za-z]{6}\\d{2}[A-Za-z]\\d{2}[A-Za-z]\\d{3}[A-Za-z]$"},"externalId":{"type":"string","minLength":1,"maxLength":120},"notes":{"type":"string","maxLength":5000},"sedeId":{"type":"string","format":"uuid"}},"required":["firstName","lastName"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Anagrafica nuova","value":{"firstName":"Mario","lastName":"Rossi","phone":"+393331112233","fiscalCode":"RSSMRA80A01F205X","externalId":"CRM-4412","notes":"Inviato dal gestionale"}},"esempio_2":{"summary":"Solo telefono (la persona si aggancia a quella che già esiste)","value":{"firstName":"Mario","lastName":"Rossi","phone":"+393331112233"}}}}}},"responses":{"200":{"description":"L'anagrafica esisteva già: `created: false`.","content":{"application/json":{}}},"201":{"description":"Crea o ritrova un paziente","content":{"application/json":{"example":{"patient":{"id":"uuid","externalId":"CRM-4412","isTest":false},"created":true,"merged":false}}}},"400":{"description":"INVALID_BODY: Campi mancanti o telefono non in E.164.\nSEDE_REQUIRED: Account struttura senza `sedeId` né intestazione di sede.\nINVALID_SEDE: `sedeId` non è una sede della tua struttura (o l'account non è una struttura).\nIDEMPOTENCY_KEY_INVALID: `X-Idempotency-Key` vuota o più lunga di 128 caratteri.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_62fb41"},"409":{"description":"PHONE_BELONGS_TO_OTHER: Quel numero appartiene già a un'altra persona in archivio, con la stessa regola dell'invio dalla dashboard. Se il paziente ha cambiato numero, usa `PATCH /patients/{patientId}`.\nIDEMPOTENCY_KEY_REUSED / IDEMPOTENCY_IN_PROGRESS: La stessa `X-Idempotency-Key` è già stata usata con un corpo diverso, oppure la prima richiesta con quella chiave è ancora in corso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"$ref":"#/components/responses/C413"},"422":{"description":"IDENTITY_CONFLICT: Codice fiscale ed externalId puntano a due persone diverse già registrate: lo risolve il tuo gestionale, non lo indoviniamo noi.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"TEST_DAILY_LIMIT: Chiave Test: 20 anagrafiche di prova nuove al giorno.\nAnche RATE_LIMIT_EXCEEDED: components.responses.C429.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/patients/identity":{"put":{"operationId":"upsertPatientIdentity","summary":"Allinea un paziente dal tuo CRM","description":"Registra, o ritrova, una persona per `externalId` o `fiscalCode`. Puoi ripetere la chiamata quante volte vuoi senza creare doppioni. È la chiamata con cui allinei il tuo CRM prima ancora di avere un consenso da mandare.\n\n**Permesso**: `patients:write`.","tags":["Pazienti"],"x-scopes":["patients:write"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"externalId":{"type":"string","minLength":1,"maxLength":120},"fiscalCode":{"type":"string","pattern":"^[A-Za-z]{6}\\d{2}[A-Za-z]\\d{2}[A-Za-z]\\d{3}[A-Za-z]$"},"firstName":{"type":"string","minLength":1,"maxLength":80},"lastName":{"type":"string","minLength":1,"maxLength":80},"phone":{"type":"string","pattern":"^\\+[1-9]\\d{6,14}$"},"sedeId":{"type":"string","format":"uuid"}},"required":["firstName","lastName"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Allineamento dal CRM","value":{"externalId":"CRM-4412","fiscalCode":"RSSMRA80A01F205X","firstName":"Mario","lastName":"Rossi","phone":"+393331112233"}}}}}},"responses":{"200":{"description":"La persona era già registrata: la risposta ha `created: false` e i dati sono allineati.","content":{"application/json":{}}},"201":{"description":"Allinea un paziente dal tuo CRM","content":{"application/json":{"example":{"patient":{"id":"uuid","externalId":"CRM-4412","hasFiscalCode":true,"isTest":false,"sedeId":null},"created":true,"merged":false,"idempotent":false}}}},"400":{"description":"INVALID_BODY: Manca sia `externalId` sia `fiscalCode`, oppure un campo non è valido.\nINVALID_SEDE: `sedeId` non è una sede della tua struttura (o l'account non è una struttura).\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_62fb41"},"413":{"$ref":"#/components/responses/C413"},"422":{"description":"IDENTITY_CONFLICT: Le due chiavi puntano a due persone diverse già registrate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}}},"/patients/{patientId}":{"get":{"operationId":"getPatient","summary":"Scheda del paziente","description":"Restituisce la scheda completa: anagrafica, identità (`externalId` e se il codice fiscale è registrato), privacy per soggetto con le clausole accettate e rifiutate, anamnesi in forma di semaforo, consensi, visite e cicli, documenti e note.\n\n**Permesso**: `patients:read`.\n\nCon una chiave Test esistono solo le anagrafiche di prova: l'id di un paziente vero risponde 404 `PATIENT_NOT_FOUND`, con lo stesso corpo di un id inesistente.\n\n**Campi della risposta**\n- `privacy[]`: Una voce per soggetto (l'adulto e ciascun minore o tutelato): documento firmato, quando, codice di controllo, clausole accettate e rifiutate, eventuale revoca.\n- `anamnesis[]`: Semaforo GREEN/YELLOW/RED e flag di rischio per consenso. Le risposte cliniche si leggono con GET /consents/{id}/anamnesis.\n- `identity`: Il codice fiscale è conservato solo come hash e non viene mai restituito in chiaro: `hasFiscalCode` dice se c'è.","tags":["Pazienti"],"x-scopes":["patients:read"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Scheda del paziente","content":{"application/json":{"example":{"id":"uuid","firstName":"Mario","lastName":"Rossi","phone":"+393331112233","notes":null,"identity":{"externalId":"CRM-4412","hasFiscalCode":true},"isTest":false,"sedeId":null,"createdAt":"2026-09-16T09:00:00.000Z","updatedAt":"2026-09-16T09:00:00.000Z","counts":{"consents":3,"visits":5,"cycles":1,"documents":2},"privacy":[{"subject":{"kind":"PATIENT"},"state":"ACTIVE","consentId":"uuid","clauses":{"accepted":["marketing"],"refused":["profilazione"],"shown":["marketing","profilazione"]}}],"anamnesis":[{"consentId":"uuid","severity":"YELLOW","flags":["anticoagulanti"]}],"consents":[],"engagements":[],"cycles":[],"visits":[],"documents":[]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_f87668"},"429":{"$ref":"#/components/responses/C429"}}},"patch":{"operationId":"patchPatient","summary":"Modifica l'anagrafica","description":"Modifica i soli campi anagrafici: nome, cognome, telefono, `externalId`, note e sede. Un campo fuori da questo elenco è un errore 400, non una riga ignorata in silenzio. I dati che il paziente ha dichiarato e firmato nel consenso (nascita, residenza, codice fiscale sul documento) non si toccano: sono congelati sul consenso perché sono la prova di cosa aveva davanti quando ha firmato.\n\n**Permesso**: `patients:write`.\n\nCon una chiave Test esistono solo le anagrafiche di prova: l'id di un paziente vero risponde 404 `PATIENT_NOT_FOUND`, con lo stesso corpo di un id inesistente.","tags":["Pazienti"],"x-scopes":["patients:write"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"firstName":{"type":"string","minLength":1,"maxLength":80},"lastName":{"type":"string","minLength":1,"maxLength":80},"phone":{"type":"string","pattern":"^\\+[1-9]\\d{6,14}$"},"externalId":{"anyOf":[{"type":"string","minLength":1,"maxLength":120},{"type":"null"}]},"notes":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}]},"sedeId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]}},"additionalProperties":false},"examples":{"esempio_1":{"summary":"Nuovo numero","value":{"phone":"+393339998877"}}}}}},"responses":{"200":{"description":"Modifica l'anagrafica","content":{"application/json":{"example":{"patient":{"id":"uuid","phone":"+393339998877"},"changed":["phone"]}}}},"400":{"description":"INVALID_BODY: Campo non previsto, valore non valido o corpo vuoto.\nINVALID_SEDE: `sedeId` non è una sede della tua struttura (o l'account non è una struttura).\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_62fb41"},"404":{"$ref":"#/components/responses/E404_f87668"},"413":{"$ref":"#/components/responses/C413"},"422":{"description":"IDENTITY_CONFLICT: Il telefono o l'externalId indicati sono già di un'altra anagrafica di questo account. Su un'anagrafica di prova il confronto avviene solo fra le prove: il numero di una persona vera non genera mai questo errore.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}}},"/patients/{patientId}/consents":{"get":{"operationId":"getPatientConsents","summary":"Consensi del paziente","description":"Restituisce l'elenco breve dei consensi del paziente, senza il resto della scheda. Per il dettaglio di uno usa `GET /consents/{id}`.\n\n**Permesso**: `patients:read`.","tags":["Pazienti"],"x-scopes":["patients:read"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Consensi del paziente","content":{"application/json":{"example":{"patientId":"uuid","data":[{"id":"uuid","status":"COMPLETED","consentType":"FULL","isMinor":false,"isTutelato":false,"minorName":null,"language":"it","createdAt":"2026-09-16T09:00:00.000Z","signedAt":"2026-09-16T09:12:00.000Z","expiresAt":null,"hasConsentPdf":true,"hasPrivacyPdf":true,"privacyRevokedAt":null}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_f87668"},"429":{"$ref":"#/components/responses/C429"}}}},"/patients/{patientId}/notes":{"get":{"operationId":"getPatientNotes","summary":"Leggi le note della scheda","description":"Restituisce le note della scheda. Nel prodotto le note sono un unico campo libero, non un elenco di note con un id ciascuna: per questo non esiste un `DELETE /notes/{noteId}`.\n\n**Permesso**: `patients:read`.","tags":["Pazienti"],"x-scopes":["patients:read"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Leggi le note della scheda","content":{"application/json":{"example":{"patientId":"uuid","notes":"[2026-09-16 · Segreteria] Richiamare per il controllo.","updatedAt":"2026-09-16T09:00:00.000Z"}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_f87668"},"429":{"$ref":"#/components/responses/C429"}}},"put":{"operationId":"putPatientNotes","summary":"Sostituisci le note","description":"Sostituisce l'intero testo delle note.\n\n**Permesso**: `patients:write`.","tags":["Pazienti"],"x-scopes":["patients:write"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","maxLength":5000}},"required":["notes"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Testo nuovo","value":{"notes":"Preferisce essere contattato al mattino."}}}}}},"responses":{"200":{"description":"Sostituisci le note","content":{"application/json":{"example":{"patientId":"uuid","notes":"Preferisce essere contattato al mattino."}}}},"400":{"description":"INVALID_BODY: `notes` mancante o troppo lungo.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_f87668"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}},"post":{"operationId":"appendPatientNote","summary":"Aggiungi una riga alle note","description":"Accoda in fondo una riga datata, nella forma «[2026-09-16 · Autore] testo»: è quello che fa a mano chi scrive in quel riquadro.\n\n**Permesso**: `patients:write`.","tags":["Pazienti"],"x-scopes":["patients:write"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":2000},"author":{"type":"string","maxLength":80}},"required":["text"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Nota della segreteria","value":{"text":"Richiamare per il controllo.","author":"Segreteria"}}}}}},"responses":{"201":{"description":"Aggiungi una riga alle note","content":{"application/json":{"example":{"patientId":"uuid","notes":"[2026-09-16 · Segreteria] Richiamare per il controllo.","appended":"[2026-09-16 · Segreteria] Richiamare per il controllo."}}}},"400":{"description":"INVALID_BODY: `text` mancante o troppo lungo.\nNOTES_TOO_LONG: Con la riga nuova le note supererebbero i 5000 caratteri: sostituiscile con `PUT /notes`.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_f87668"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}},"delete":{"operationId":"clearPatientNotes","summary":"Svuota le note","description":"Svuota il campo delle note della scheda.\n\n**Permesso**: `patients:write`.","tags":["Pazienti"],"x-scopes":["patients:write"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Svuota le note","content":{"application/json":{"example":{"patientId":"uuid","notes":null}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_f87668"},"429":{"$ref":"#/components/responses/C429"}}}},"/patients/{patientId}/documents":{"get":{"operationId":"listPatientDocuments","summary":"Documenti del paziente","description":"Restituisce l'elenco dei documenti del paziente (nulla osta del medico, prescrizioni, allegati) con tipo, nome, dimensione, chi l'ha caricato e consenso collegato.\n\n**Permesso**: `patients:read`.","tags":["Pazienti"],"x-scopes":["patients:read"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Documenti del paziente","content":{"application/json":{"example":{"patientId":"uuid","data":[{"id":"uuid","type":"MEDICAL_CLEARANCE","fileName":"nulla-osta.pdf","mimeType":"application/pdf","sizeBytes":182044,"uploadedBy":"PROFESSIONAL","note":"Nulla osta del medico curante","consentId":null,"createdAt":"2026-09-16T09:00:00.000Z"}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_f87668"},"429":{"$ref":"#/components/responses/C429"}}},"post":{"operationId":"uploadPatientDocument","summary":"Carica un documento","description":"Carica un documento del paziente in `multipart/form-data` con il campo `file`, oppure in JSON con `fileName`, `mimeType` e `contentBase64`. Accettati JPG, PNG, WebP e PDF fino a 10 MB: il tipo dichiarato viene confrontato col contenuto reale del file, quindi un PDF rinominato .jpg viene rifiutato.\n\n**Permesso**: `patients:write`.","tags":["Pazienti"],"x-scopes":["patients:write"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/XIdempotencyKey"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fileName":{"type":"string","minLength":1,"maxLength":200},"contentBase64":{"type":"string","minLength":1},"mimeType":{"type":"string","enum":["image/jpeg","image/png","image/webp","application/pdf"]},"note":{"type":"string","maxLength":500}},"required":["fileName","contentBase64","mimeType"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"PDF in base64","value":{"fileName":"nulla-osta.pdf","mimeType":"application/pdf","contentBase64":"JVBERi0xLjQKJcOkw7zDtsOfCjEgMCBvYmoKPDwvVHlwZS9DYXRhbG9nL1BhZ2VzIDIgMCBSPj4KZW5kb2JqCjIgMCBvYmoKPDwvVHlwZS9QYWdlcy9LaWRzWzMgMCBSXS9Db3VudCAxPj4KZW5kb2JqCjMgMCBvYmoKPDwvVHlwZS9QYWdlL1BhcmVudCAyIDAgUi9NZWRpYUJveFswIDAgNjEyIDc5Ml0+PgplbmRvYmoKdHJhaWxlcgo8PC9Sb290IDEgMCBSPj4KJSVFT0YK","note":"Nulla osta del medico curante"}}}},"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","description":"Il file (JPG, PNG, WebP o PDF, fino a 10 MB)."},"note":{"type":"string","description":"Facoltativa: una nota sul documento."}}}}}},"responses":{"201":{"description":"Carica un documento","content":{"application/json":{"example":{"patientId":"uuid","document":{"id":"uuid","type":"MEDICAL_CLEARANCE","fileName":"nulla-osta.pdf","mimeType":"application/pdf","sizeBytes":182044,"uploadedBy":"PROFESSIONAL","note":"Nulla osta del medico curante","consentId":null,"createdAt":"2026-09-16T09:00:00.000Z"}}}}},"400":{"description":"UNSUPPORTED_FORMAT: Formato non ammesso.\nFILE_TOO_LARGE: Oltre i 10 MB.\nFILE_REQUIRED: Nessun file: manca il campo `file` in multipart o `contentBase64` in JSON.\nINVALID_BASE64: `contentBase64` non è un base64 valido, oppure è vuoto.\nIDEMPOTENCY_KEY_INVALID: `X-Idempotency-Key` vuota o più lunga di 128 caratteri.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_f87668"},"409":{"$ref":"#/components/responses/E409_9b1101"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/patients/{patientId}/documents/{docId}":{"get":{"operationId":"downloadPatientDocument","summary":"Scarica un documento","description":"Restituisce un link temporaneo al documento, valido un'ora. Il file resta in uno spazio privato e non ha un indirizzo pubblico.\n\n**Permesso**: `consents:documents`.\n\nScaricare un documento sanitario porta un file fuori: serve lo stesso permesso dei PDF dei consensi, non `patients:read`.","tags":["Pazienti"],"x-scopes":["consents:documents"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/path_docId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Scarica un documento","content":{"application/json":{"example":{"url":"https://…","fileName":"nulla-osta.pdf","expiresInSeconds":3600}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_3e6f05"},"429":{"$ref":"#/components/responses/C429"}}},"delete":{"operationId":"deletePatientDocument","summary":"Elimina un documento","description":"Elimina un documento caricato dal centro. Quelli che il paziente carica durante la firma fanno parte del fascicolo probatorio e non si eliminano.\n\n**Permesso**: `patients:write`.","tags":["Pazienti"],"x-scopes":["patients:write"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/path_docId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Elimina un documento","content":{"application/json":{"example":{"success":true}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"description":"DOCUMENT_PROTECTED: Documento caricato dal paziente durante la firma: fa parte del fascicolo probatorio.\nAnche IP_NOT_ALLOWED, SCOPE_MISSING e gli altri comuni: components.responses.C403.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/E404_3e6f05"},"429":{"$ref":"#/components/responses/C429"}}}},"/patients/{patientId}/privacy":{"get":{"operationId":"getPatientPrivacy","summary":"Stato dell'informativa privacy","description":"Restituisce lo stato dell'informativa privacy per soggetto: una voce per l'adulto e per ciascun minore o tutelato, con documento, data, codice di controllo, clausole ed eventuale revoca.\n\n**Permesso**: `patients:read`.","tags":["GDPR"],"x-scopes":["patients:read"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Stato dell'informativa privacy","content":{"application/json":{"example":{"patientId":"uuid","subjects":[{"subject":{"kind":"PATIENT"},"state":"ACTIVE","consentId":"uuid","clauses":{"accepted":["marketing"],"refused":["profilazione"],"shown":["marketing","profilazione"]}}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_f87668"},"429":{"$ref":"#/components/responses/C429"}}}},"/patients/{patientId}/privacy/{consentId}/revocable":{"get":{"operationId":"getPatientRevocable","summary":"Clausole revocabili","description":"Dice quali clausole facoltative si possono revocare su quel documento privacy firmato e cosa è già stato revocato.\n\n**Permesso**: `patients:read`.","tags":["GDPR"],"x-scopes":["patients:read"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/path_consentId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Clausole revocabili","content":{"application/json":{"example":{"consentId":"uuid","signedAt":"2026-05-02T10:00:00.000Z","items":[{"id":"consent-marketing","label":"Marketing"}],"revokedAt":null,"revokedItems":null,"patientId":"uuid"}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_f87668"},"429":{"$ref":"#/components/responses/C429"}}}},"/patients/{patientId}/privacy/revoke":{"post":{"operationId":"revokePatientPrivacy","summary":"Revoca consensi privacy facoltativi","description":"Revoca i consensi facoltativi (art. 7.3 GDPR). La revoca si registra su un documento firmato, quindi serve `consentId`: un paziente può avere più informative (una per soggetto, o rifirmate nel tempo) e revocarle tutte insieme sarebbe un atto che nessuno ha chiesto. Gli effetti sono identici alla dashboard, conferma scritta al firmatario compresa.\n\n**Permesso**: `patients:delete (delicato)`.\n\nIl permesso `patients:delete` si concede solo a una chiave con gli IP consentiti impostati.","tags":["GDPR"],"x-scopes":["patients:delete"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"consentId":{"type":"string","format":"uuid"},"items":{"anyOf":[{"type":"string","const":"ALL"},{"minItems":1,"maxItems":40,"type":"array","items":{"type":"string","maxLength":80}}]},"reason":{"type":"string","maxLength":300},"confirm":{"type":"boolean","const":true}},"required":["consentId","items","confirm"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Revoca di alcune clausole","value":{"consentId":"3f2a8c1e-5b7d-4e2a-9c41-7d8e2b6a1f09","items":["consent-marketing"],"confirm":true}},"esempio_2":{"summary":"Revoca totale","value":{"consentId":"3f2a8c1e-5b7d-4e2a-9c41-7d8e2b6a1f09","items":"ALL","confirm":true,"reason":"Richiesta scritta"}}}}}},"responses":{"200":{"description":"Revoca consensi privacy facoltativi","content":{"application/json":{"example":{"success":true,"patientId":"uuid","consentId":"uuid","revokedAt":"2026-09-16T09:00:00.000Z","totale":false,"revokedLabels":["Marketing"],"emailSent":true}}}},"400":{"description":"INVALID_BODY: `confirm: true` mancante.\nALREADY_REVOKED: I consensi di quel documento risultano già revocati.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"description":"DELETE_REQUIRES_IP_ALLOWLIST: La chiave non ha IP consentiti impostati.\nTEST_KEY_DESTRUCTIVE: Chiave in modalità Test: la revoca non si prova, si legge.\nAnche IP_NOT_ALLOWED, SCOPE_MISSING e gli altri comuni: components.responses.C403.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"CONSENT_NOT_FOUND: `consentId` non è un documento privacy di questo paziente.\nPATIENT_NOT_FOUND: Il paziente non esiste, non è di questo account, è fuori dal contesto di sede o ha una cancellazione programmata (stessa risposta).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/patients/{patientId}/export":{"get":{"operationId":"exportPatient","summary":"Esporta i dati del paziente","description":"Esporta i dati del paziente per l'accesso e la portabilità (art. 15 e 20 GDPR): anagrafica, consensi decifrati, registro attività e i link temporanei ai PDF sottoscritti, validi un'ora. Ogni export finisce nel Registro attività.\n\n**Permesso**: `patients:export (delicato)`.\n\nPermesso delicato: `patients:export` non è mai preselezionato alla creazione della chiave.","tags":["GDPR"],"x-scopes":["patients:export"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Esporta i dati del paziente","content":{"application/json":{"example":{"exportedAt":"2026-09-16T09:00:00.000Z","patient":{"id":"uuid","firstName":"Mario","externalId":"CRM-4412"},"consents":[{"id":"uuid","status":"COMPLETED"}],"auditLogs":[{"action":"PATIENT_VIEWED","timestamp":"2026-09-16T09:00:00.000Z","performedBy":"PROFESSIONAL"}],"documents":[{"consentId":"uuid","consentPdf":{"url":"https://…","sha256":"…"}}],"patientDocuments":[],"documentUrlsExpireInSeconds":3600}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_f87668"},"429":{"$ref":"#/components/responses/C429"}}}},"/patients/{patientId}/dossier":{"get":{"operationId":"downloadPatientDossier","summary":"Fascicolo difensivo del paziente","description":"Restituisce il fascicolo difensivo del paziente in un PDF unico, generato al momento. Arriva nel corpo come application/pdf, oppure in base64 con `?format=json`.\n\n**Permesso**: `patients:export (delicato)`.","tags":["GDPR"],"x-scopes":["patients:export"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/query_format"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Fascicolo difensivo del paziente. Il PDF arriva nel corpo; con `?format=json` arriva in base64 dentro un JSON.","content":{"application/pdf":{"schema":{"type":"string","contentMediaType":"application/pdf"}},"application/json":{"example":{"fileName":"fascicolo-rossi.pdf","mimeType":"application/pdf","contentBase64":"JVBERi0…"}}}},"400":{"$ref":"#/components/responses/E400_c00cc7"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_f87668"},"429":{"$ref":"#/components/responses/C429"},"500":{"description":"DOSSIER_UNAVAILABLE: Il fascicolo non è stato generato: riprova, e se succede ancora scrivici.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/patients/{patientId}/gdpr-delete":{"post":{"operationId":"gdprDeletePatient","summary":"Chiedi la cancellazione (art. 17)","description":"Programma la cancellazione definitiva (art. 17 GDPR) senza eseguirla subito. L'anagrafica sparisce all'istante da liste, ricerche, scheda e invii, e da quel momento risponde 404 ovunque tranne sull'annullamento; i dati vengono distrutti dopo 7 giorni. Fino ad allora il titolare può fermare tutto dalla dashboard, e tu con `POST /gdpr-delete/cancel`. In dashboard la cancellazione la autorizza una persona che digita la propria password in quel momento; qui la autorizza una chiave configurata una volta, e un ciclo sbagliato del gestionale distruggerebbe in pochi minuti la prova di consenso di centinaia di prestazioni. Se ti serve cancellare all'istante, si fa dalla dashboard.\n\n**Permesso**: `patients:delete (delicato)`.\n\nTetto: al massimo 5 richieste al giorno per chiave, contate sul giorno italiano. Il contatore riparte a mezzanotte, e annullare una cancellazione non libera un posto per oggi (429 `DELETE_DAILY_LIMIT`). Oltre il tetto al titolare arriva un avviso. Il tetto è per chiave: un'altra chiave dello stesso account ne ha altre cinque.\n\nRevocare la chiave non annulla le cancellazioni già programmate: la richiesta è dell'account, non della chiave, e la cancellazione automatica avviene lo stesso. Per fermarle le annulli una per una, da qui o dalla scheda del paziente in dashboard.\n\nSe durante i 7 giorni la persona firma altri consensi, alla scadenza la cancellazione non viene eseguita. Viene rimandata una sola volta di altri 7 giorni, parte `patient.deletion_postponed` e il titolare riceve un avviso. Per procedere annulli e rifai la richiesta con `acknowledgeRetention: true`. Se alla seconda scadenza nessuno l'ha riconfermata, la cancellazione viene annullata d'ufficio: il paziente torna visibile, al titolare arriva un avviso e parte `patient.deletion_cancelled` con `deletion.reason: \"NEW_SIGNED_CONSENTS\"`.\n\nUna seconda richiesta su un paziente che ha già una cancellazione programmata non sposta la scadenza: risponde 409 `PATIENT_DELETION_SCHEDULED` con `executeAfter` e `cancelEndpoint`. Per riconfermarla (per esempio dopo nuove firme) annullala e rifai la richiesta.\n\nLa cancellazione elimina il paziente e tutti i suoi consensi, anche quelli firmati, con i PDF, le firme, i documenti sanitari, le visite, i cicli, le anamnesi, gli indirizzi email nei registri di consegna e le eventuali anagrafiche doppie unite a lui. Restano il Registro attività, che dice che la cancellazione è avvenuta e da quale chiave ma non chi fosse la persona, e le righe delle consegne webhook che la riguardavano, ridotte a evento, stato e codice di risposta: il corpo inviato viene cancellato e un replay risponde 409 `DELIVERY_REDACTED`. Durante i 7 giorni di attesa il replay e i nuovi tentativi delle consegne che portano il suo nome sono sospesi (409 `PATIENT_DELETION_SCHEDULED`).","tags":["GDPR"],"x-scopes":["patients:delete"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirm":{"type":"boolean","const":true},"acknowledgeRetention":{"type":"boolean","const":true},"reason":{"type":"string","maxLength":300}},"required":["confirm"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Paziente senza consensi firmati","value":{"confirm":true,"reason":"Richiesta dell'interessato del 16/09/2026"}},"esempio_2":{"summary":"Paziente con consensi firmati","value":{"confirm":true,"acknowledgeRetention":true,"reason":"Richiesta dell'interessato del 16/09/2026"}}}}}},"responses":{"200":{"description":"Chiedi la cancellazione (art. 17)","content":{"application/json":{"example":{"success":true,"scheduled":true,"patientId":"uuid","externalId":"CRM-4412","hiddenNow":true,"executeAfter":"2026-09-23T09:00:00.000Z","cancelUntil":"2026-09-23T09:00:00.000Z","cancelEndpoint":"/api/v1/account/patients/uuid/gdpr-delete/cancel","graceDays":7,"consentsToDelete":3,"signedConsents":2,"dailyCap":5,"scheduledToday":1,"message":"Cancellazione programmata. Il paziente non è più raggiungibi…"}}}},"400":{"description":"INVALID_BODY: `confirm: true` mancante.\nRETENTION_ACK_REQUIRED: Il paziente ha consensi firmati e manca `acknowledgeRetention: true`.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"description":"DELETE_REQUIRES_IP_ALLOWLIST: La chiave deve avere gli IP consentiti impostati. Si scelgono alla creazione della chiave e non si cambiano dopo.\nTEST_KEY_DESTRUCTIVE: Chiave in modalità Test: una cancellazione non si prova, si esegue.\nAnche IP_NOT_ALLOWED, SCOPE_MISSING e gli altri comuni: components.responses.C403.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"PATIENT_NOT_FOUND: Non esiste, non è di questo account oppure è fuori dal contesto di sede.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"PATIENT_DELETION_SCHEDULED: La cancellazione di questo paziente è già programmata: la risposta porta `executeAfter` (quando verrà eseguita) e `cancelEndpoint` (per annullarla e rifarla, se serve riconfermarla).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"$ref":"#/components/responses/C413"},"429":{"description":"DELETE_DAILY_LIMIT: Tetto giornaliero della chiave raggiunto.\nAnche RATE_LIMIT_EXCEEDED: components.responses.C429.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/patients/{patientId}/gdpr-delete/cancel":{"post":{"operationId":"cancelPatientDeletion","summary":"Annulla una cancellazione programmata","description":"Ferma una cancellazione programmata: il paziente torna raggiungibile e i dati non vengono distrutti. È l'unico endpoint che vede un'anagrafica già nascosta. Lo stesso pulsante c'è nella scheda del paziente in dashboard, e il titolare lo riceve nell'email di avviso.\n\n**Permesso**: `patients:delete (delicato)`.","tags":["GDPR"],"x-scopes":["patients:delete"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Annulla una cancellazione programmata","content":{"application/json":{"example":{"success":true,"patientId":"uuid","cancelledScheduledFor":"2026-09-23T09:00:00.000Z","message":"Cancellazione annullata: il paziente è di nuovo raggiungibile."}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"description":"PATIENT_NOT_FOUND: Non c'è nessuna cancellazione programmata per questo paziente (o è già stata eseguita).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}}},"/patients/{patientId}/visits":{"get":{"operationId":"listPatientVisits","summary":"Visite del paziente","description":"Restituisce le visite del paziente raggruppate per ciclo di trattamento, e le stesse visite in un elenco semplice per chi non usa i cicli.\n\n**Permesso**: `visits:read`.","tags":["Visite"],"x-scopes":["visits:read"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Visite del paziente","content":{"application/json":{"example":{"patientId":"uuid","cycles":[{"id":"uuid","title":"Riabilitazione spalla","isActive":true,"startedAt":"2026-09-02T09:00:00.000Z","visits":[{"id":"uuid","visitNumber":7,"visitDate":"2026-09-16T09:00:00.000Z","cycleId":"uuid"}]}],"data":[{"id":"uuid","visitNumber":7,"visitDate":"2026-09-16T09:00:00.000Z","cycleId":"uuid"}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_f87668"},"429":{"$ref":"#/components/responses/C429"}}},"post":{"operationId":"createPatientVisit","summary":"Registra una visita","description":"Registra una visita. Può essere collegata a un consenso firmato e può essere intestata a un minore o a un tutelato indicando `subjectConsentId`. Il ciclo nasce con la prima visita (`cycleTitle`): è così anche in dashboard, non esiste un «crea ciclo» a sé.\n\n**Permesso**: `visits:write`.","tags":["Visite"],"x-scopes":["visits:write"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/XIdempotencyKey"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"visitDate":{"type":"string","format":"date-time"},"reason":{"type":"string","maxLength":200},"reasonId":{"type":"string","format":"uuid"},"pathology":{"type":"string","maxLength":2000},"notes":{"type":"string","maxLength":5000},"sedeId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"consentId":{"type":"string","format":"uuid"},"subjectConsentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"cycleId":{"type":"string","format":"uuid"},"cycleTitle":{"type":"string","maxLength":200},"isFirstVisit":{"type":"boolean"}},"additionalProperties":false},"examples":{"esempio_1":{"summary":"Prima visita di un ciclo nuovo","value":{"reason":"Dolore alla spalla","cycleTitle":"Riabilitazione spalla","isFirstVisit":true}}}}}},"responses":{"201":{"description":"Registra una visita","content":{"application/json":{"example":{"patientId":"uuid","visit":{"id":"uuid","visitNumber":7,"visitDate":"2026-09-16T09:00:00.000Z","cycleId":"uuid"}}}}},"400":{"description":"INVALID_BODY: Campo non previsto o valore non valido.\nIDEMPOTENCY_KEY_INVALID: `X-Idempotency-Key` vuota o più lunga di 128 caratteri.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_8ec84f"},"404":{"description":"CONSENT_NOT_FOUND: `consentId` o `subjectConsentId` non esiste o non è di questo paziente.\nPATIENT_NOT_FOUND: Il paziente non esiste, non è di questo account, è fuori dal contesto di sede o ha una cancellazione programmata (stessa risposta).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"$ref":"#/components/responses/E409_9b1101"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/patients/{patientId}/visits/{visitId}":{"patch":{"operationId":"patchPatientVisit","summary":"Modifica una visita","description":"Modifica motivo, patologia, note, soggetto e il segno di prima visita.\n\n**Permesso**: `visits:write`.","tags":["Visite"],"x-scopes":["visits:write"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/path_visitId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","maxLength":200},"reasonId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"pathology":{"type":"string","maxLength":2000},"notes":{"type":"string","maxLength":5000},"subjectConsentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"isFirstVisit":{"type":"boolean"}}},"examples":{"esempio_1":{"summary":"Aggiungi una nota","value":{"notes":"Migliora la mobilità."}}}}}},"responses":{"200":{"description":"Modifica una visita","content":{"application/json":{"example":{"patientId":"uuid","visit":{"id":"uuid"}}}}},"400":{"$ref":"#/components/responses/E400_cc85d9"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_8ec84f"},"404":{"$ref":"#/components/responses/E404_682e37"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}},"delete":{"operationId":"deletePatientVisit","summary":"Elimina una visita","description":"Elimina la visita, come in dashboard.\n\n**Permesso**: `visits:write`.","tags":["Visite"],"x-scopes":["visits:write"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/path_visitId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Elimina una visita","content":{"application/json":{"example":{"success":true}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_682e37"},"429":{"$ref":"#/components/responses/C429"}}}},"/patients/{patientId}/cycles":{"get":{"operationId":"listPatientCycles","summary":"Cicli di trattamento","description":"Restituisce i cicli di trattamento del paziente, con il numero di visite di ciascuno.\n\n**Permesso**: `visits:read`.","tags":["Visite"],"x-scopes":["visits:read"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Cicli di trattamento","content":{"application/json":{"example":{"patientId":"uuid","data":[{"id":"uuid","title":"Riabilitazione spalla","isActive":true,"isMinor":false,"isTutelato":false,"startedAt":"2026-09-02T09:00:00.000Z","visitsCount":4}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_f87668"},"429":{"$ref":"#/components/responses/C429"}}}},"/patients/{patientId}/cycles/{cycleId}":{"patch":{"operationId":"patchPatientCycle","summary":"Modifica un ciclo","description":"Cambia il titolo del percorso o lo chiude (`isActive: false`).\n\n**Permesso**: `visits:write`.","tags":["Visite"],"x-scopes":["visits:write"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/path_cycleId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","maxLength":200},"isActive":{"type":"boolean"}}},"examples":{"esempio_1":{"summary":"Chiudi il ciclo","value":{"isActive":false}}}}}},"responses":{"200":{"description":"Modifica un ciclo","content":{"application/json":{"example":{"patientId":"uuid","cycle":{"id":"uuid","title":"Riabilitazione spalla","isActive":false,"startedAt":"2026-09-02T09:00:00.000Z"}}}}},"400":{"$ref":"#/components/responses/E400_cc85d9"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_8ec84f"},"404":{"$ref":"#/components/responses/E404_bba791"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}},"delete":{"operationId":"deletePatientCycle","summary":"Elimina un ciclo","description":"Elimina il ciclo di trattamento. Cancellare un ciclo cancella anche le sue visite.\n\n**Permesso**: `visits:write`.","tags":["Visite"],"x-scopes":["visits:write"],"parameters":[{"$ref":"#/components/parameters/path_patientId"},{"$ref":"#/components/parameters/path_cycleId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Elimina un ciclo","content":{"application/json":{"example":{"success":true}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_bba791"},"429":{"$ref":"#/components/responses/C429"}}}},"/consents/{id}/anamnesis":{"get":{"operationId":"getConsentAnamnesis","summary":"Anamnesi completa di un consenso","description":"Restituisce l'anamnesi completa raccolta alla firma del consenso: risposte decifrate, risposte positive già etichettate, flag di rischio con la loro etichetta, fototipo e semaforo sui trattamenti di quel consenso. Copre l'anamnesi medica (sanità, se attiva sull'account), quella estetica (centri estetici e account ibridi) e le domande personalizzate delle strutture «Associazione». Sono dati sanitari: ogni lettura finisce nel Registro attività, come la consultazione dalla dashboard.\n\n**Permesso**: `anamnesis:read (delicato)`.\n\nLegge solo i consensi di prova con una chiave Test: un consenso vero risponde 404 CONSENT_NOT_FOUND, come un id inesistente.\n\nPermesso delicato: `anamnesis:read` non è mai preselezionato alla creazione della chiave.\n\n**Campi della risposta**\n- `anamnesis.kind`: MEDICAL o AESTHETIC. null se sul consenso non c'è un'anamnesi strutturata.\n- `anamnesis.answers`: Tutte le risposte, con chiave l'id interno della domanda: { value, detail?, answeredAt }.\n- `anamnesis.positives`: Le sole risposte positive ancora valide, già con l'etichetta della domanda.\n- `anamnesis.severity`: GREEN, YELLOW o RED sui trattamenti del consenso; `evaluation.findings` dice perché.\n- `customQuestions`: Le domande personalizzate com'erano quando il paziente ha risposto, con la risposta.","tags":["Anamnesi"],"x-scopes":["anamnesis:read"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Anamnesi completa di un consenso","content":{"application/json":{"example":{"consentId":"uuid","collected":true,"anamnesis":{"kind":"MEDICAL","collectedAt":"2026-09-16T09:12:00.000Z","expiresAt":"2027-09-16T09:12:00.000Z","severity":"YELLOW","flags":[{"code":"MED_CARDIOPATIE","label":"Cardiopatie"}],"fototipo":"III","positives":[{"id":"med-cardiopatie","label":"Cardiopatie","detail":"Aritmia in terapia"}],"answers":{"med-cardiopatie":{"value":true,"detail":"Aritmia in terapia","answeredAt":"2026-09-16T09:10:00.000Z"}}},"customQuestions":null}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"description":"ANAMNESIS_NOT_AVAILABLE: Nessuna anamnesi è attiva sull'account (in dashboard la funzione non c'è).\nCONSENT_NOT_FOUND: Il consenso non esiste, non è di questo account, è fuori dal contesto di sede o, con una chiave Test, non è di prova (stessa risposta).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}}},"/structure":{"get":{"operationId":"getStructure","summary":"Riepilogo della struttura","description":"Restituisce il riepilogo della struttura: tipo di account, sedi, professionisti con «chi esegue cosa», esecutore generico per ambito, controfirme in attesa aggregate e se c'è una segreteria. Risponde anche al professionista singolo, con `type: INDIVIDUAL` e liste vuote.\n\n**Permesso**: `structure:read`.\n\nCon una chiave Test le controfirme in attesa contano solo i consensi di prova.\n\n**Campi della risposta**\n- `type`: CLINIC (struttura sanitaria), STUDIO (studio con collaboratori, per esempio tatuaggi) o INDIVIDUAL.\n- `members[]`: Professionisti (mai la segreteria): professioni, trattamenti abilitati, solo modelli assegnati, capacità tattoo, sedi, accesso.\n- `secretary`: { present, count }: se la struttura ha una segreteria. I dati della segreteria non escono.","tags":["Struttura"],"x-scopes":["structure:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Riepilogo della struttura","content":{"application/json":{"example":{"type":"CLINIC","structure":{"id":"uuid","name":"Poliambulatorio Alfa","label":"Poliambulatorio"},"sedi":[{"id":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d","name":"Sede Padova","address":"Via Roma 1","city":"Padova","cap":"35100","province":"PD"}],"members":[{"id":"uuid","firstName":"Carla","lastName":"Esecutrice","role":"COLLABORATOR","status":"ACTIVE","relationshipType":"EMPLOYEE","sedeIds":["uuid-sede"],"professions":["PHYSIOTHERAPIST"],"enabledTreatmentIds":null,"onlyAssignedModels":false,"tattooCapabilities":[],"access":{"hasAccess":false,"email":null,"linked":false,"pendingInvite":false},"canExecute":true}],"genericExecutor":{"available":true,"enabled":true,"scopes":["PSYCHOLOGIST"],"text":null},"countersign":{"total":0,"byMember":[],"bySede":[]},"secretary":{"present":true,"count":1}}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"429":{"$ref":"#/components/responses/C429"}}}},"/structure/sedi":{"get":{"operationId":"listSedi","summary":"Elenco delle sedi","description":"Restituisce le sedi attive della struttura.\n\n**Permesso**: `structure:read`.","tags":["Struttura"],"x-scopes":["structure:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Elenco delle sedi","content":{"application/json":{"example":{"type":"CLINIC","sedi":[{"id":"uuid","name":"Sede Verona","address":"Via Roma 1","city":"Verona","cap":"37100","province":"VR"}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_f8d9f9"},"429":{"$ref":"#/components/responses/C429"}}},"post":{"operationId":"createSede","summary":"Aggiungi una sede","description":"Aggiunge una sede con le regole della dashboard: nelle strutture sanitarie la gestisce solo il titolare, negli studi le sedi dello studio coincidono con quelle del profilo.\n\n**Permesso**: `structure:write (delicato)`.\n\nPermesso delicato: `structure:write` cambia chi può eseguire cosa e non è mai preselezionato alla creazione della chiave.","tags":["Struttura"],"x-scopes":["structure:write"],"parameters":[{"$ref":"#/components/parameters/XIdempotencyKey"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"address":{"type":"string","maxLength":200},"city":{"type":"string","maxLength":120},"cap":{"type":"string","maxLength":10},"province":{"type":"string","maxLength":120}},"required":["name"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Nuova sede","value":{"name":"Sede Verona","address":"Via Roma 1","city":"Verona","cap":"37100","province":"VR"}}}}}},"responses":{"201":{"description":"Aggiungi una sede","content":{"application/json":{"example":{"sede":{"id":"uuid","name":"Sede Verona","address":"Via Roma 1","city":"Verona","cap":"37100","province":"VR"}}}}},"400":{"$ref":"#/components/responses/E400_0007ef"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_f8d9f9"},"409":{"$ref":"#/components/responses/E409_9b1101"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/structure/sedi/{sedeId}":{"get":{"operationId":"getSede","summary":"Dettaglio di una sede","description":"Restituisce una sede con i professionisti che ci lavorano.\n\n**Permesso**: `structure:read`.","tags":["Struttura"],"x-scopes":["structure:read"],"parameters":[{"$ref":"#/components/parameters/path_sedeId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Dettaglio di una sede","content":{"application/json":{"example":{"sede":{"id":"uuid","name":"Sede Verona","address":"Via Roma 1","city":"Verona","cap":"37100","province":"VR"},"members":[{"id":"uuid","firstName":"Carla","lastName":"Esecutrice","role":"COLLABORATOR","status":"ACTIVE","relationshipType":"EMPLOYEE","sedeIds":["uuid-sede"],"professions":["PHYSIOTHERAPIST"],"enabledTreatmentIds":null,"onlyAssignedModels":false,"tattooCapabilities":[],"access":{"hasAccess":false,"email":null,"linked":false,"pendingInvite":false},"canExecute":true}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"description":"SEDE_NOT_FOUND: Sede inesistente, disattivata o di un altro account (stessa risposta).\nNOT_A_STRUCTURE: L'account è un professionista singolo: sedi e professionisti esistono solo per strutture e studi.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}},"patch":{"operationId":"patchSede","summary":"Modifica una sede","description":"Modifica nome e indirizzo di una sede. Tutti i campi sono facoltativi, ma ne serve almeno uno.\n\n**Permesso**: `structure:write (delicato)`.\n\nPermesso delicato: `structure:write` cambia chi può eseguire cosa e non è mai preselezionato alla creazione della chiave.","tags":["Struttura"],"x-scopes":["structure:write"],"parameters":[{"$ref":"#/components/parameters/path_sedeId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"address":{"type":"string","maxLength":200},"city":{"type":"string","maxLength":120},"cap":{"type":"string","maxLength":10},"province":{"type":"string","maxLength":120}},"additionalProperties":false},"examples":{"esempio_1":{"summary":"Nuovo indirizzo","value":{"address":"Via Mazzini 12","cap":"37121"}}}}}},"responses":{"200":{"description":"Modifica una sede","content":{"application/json":{"example":{"sede":{"id":"uuid","name":"Sede Verona","address":"Via Roma 1","city":"Verona","cap":"37100","province":"VR"}}}}},"400":{"$ref":"#/components/responses/E400_ea3988"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"description":"SEDE_NOT_FOUND: Sede inesistente o altrui.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}},"delete":{"operationId":"deleteSede","summary":"Disattiva una sede","description":"Disattiva la sede come in dashboard (la storia dei consensi resta). Chi lavora anche in altre sedi perde solo questa. Chi lavora solo qui va spostato: nelle strutture sanitarie sulla sede indicata in `reassignToSedeId` (o sulla prima rimasta), negli studi la disattivazione si ferma con 409 `SEDE_HAS_MEMBERS` e l'elenco, finché non indichi `reassignToSedeId`. La segreteria rimasta senza sedi viene sospesa. L'ultima sede attiva non si toglie.\n\n**Permesso**: `structure:write (delicato)`.\n\nPermesso delicato: `structure:write` cambia chi può eseguire cosa e non è mai preselezionato alla creazione della chiave.","tags":["Struttura"],"x-scopes":["structure:write"],"parameters":[{"$ref":"#/components/parameters/path_sedeId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reassignToSedeId":{"type":"string"}},"additionalProperties":false},"examples":{"esempio_1":{"summary":"Sposta chi lavorava solo qui","value":{"reassignToSedeId":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"}}}}}},"responses":{"200":{"description":"Disattiva una sede","content":{"application/json":{"example":{"success":true,"sedeId":"uuid","deactivated":true,"suspendedSecretaries":[]}}}},"400":{"description":"LAST_SEDE: È l'ultima sede attiva.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"description":"SEDE_NOT_FOUND: Sede (o `reassignToSedeId`) inesistente, disattivata o di un altro account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"SEDE_HAS_MEMBERS: Studi: alcuni professionisti lavorano solo qui; `members` li elenca.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/structure/members":{"get":{"operationId":"listMembers","summary":"Elenco dei professionisti","description":"Restituisce i professionisti della struttura, con «chi esegue cosa» e l'accesso. La segreteria non compare.\n\n**Permesso**: `structure:read`.","tags":["Struttura"],"x-scopes":["structure:read"],"parameters":[{"name":"sedeId","in":"query","description":"Solo i professionisti di quella sede.","schema":{"type":"string"}},{"name":"status","in":"query","description":"Stato del professionista.","schema":{"type":"string","enum":["ACTIVE","SUSPENDED","PENDING"]}},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Elenco dei professionisti","content":{"application/json":{"example":{"type":"CLINIC","members":[{"id":"uuid","firstName":"Carla","lastName":"Esecutrice","role":"COLLABORATOR","status":"ACTIVE","relationshipType":"EMPLOYEE","sedeIds":["uuid-sede"],"professions":["PHYSIOTHERAPIST"],"enabledTreatmentIds":null,"onlyAssignedModels":false,"tattooCapabilities":[],"access":{"hasAccess":false,"email":null,"linked":false,"pendingInvite":false},"canExecute":true}]}}}},"400":{"description":"INVALID_QUERY: Stato non valido.\nAnche STRUCTURE_AMBIGUOUS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"description":"SEDE_NOT_FOUND: Sede altrui.\nNOT_A_STRUCTURE: L'account è un professionista singolo: sedi e professionisti esistono solo per strutture e studi.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}},"post":{"operationId":"createMember","summary":"Aggiungi un professionista senza accesso","description":"Crea un professionista senza accesso (un'anagrafica che esegue, come in dashboard): per dargli un accesso si usa un invito. Nelle strutture sanitarie si indicano professioni, trattamenti abilitati e «solo modelli assegnati»; negli studi tatuaggi telefono (per la controfirma) e capacità, e al professionista parte il link per confermare il numero (al massimo 10 link al giorno per account).\n\n**Permesso**: `structure:write (delicato)`.\n\nPermesso delicato: `structure:write` cambia chi può eseguire cosa e non è mai preselezionato alla creazione della chiave.\n\nIl corpo segue il tipo di account: le strutture sanitarie usano la prima variante, gli studi la seconda.","tags":["Struttura"],"x-scopes":["structure:write"],"parameters":[{"$ref":"#/components/parameters/XIdempotencyKey"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"firstName":{"type":"string","minLength":1,"maxLength":100},"lastName":{"type":"string","minLength":1,"maxLength":100},"fiscalCode":{"type":"string","maxLength":32},"professionalRegister":{"type":"string","maxLength":200},"specialization":{"type":"string","maxLength":200},"partitaIva":{"type":"string","maxLength":32},"relationshipType":{"type":"string","enum":["EMPLOYEE","EXTERNAL_COLLABORATOR"]},"role":{"type":"string","enum":["COLLABORATOR","REFERENTE"]},"sedeIds":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"string"}},"professions":{"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":40}},"enabledTreatmentIds":{"maxItems":500,"type":"array","items":{"type":"string","minLength":1,"maxLength":80}},"onlyAssignedModels":{"type":"boolean"}},"required":["firstName","lastName","relationshipType"],"additionalProperties":false},{"type":"object","properties":{"firstName":{"type":"string","minLength":1,"maxLength":80},"lastName":{"type":"string","minLength":1,"maxLength":80},"phone":{"type":"string","minLength":6,"maxLength":30},"contactEmail":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}]},"sedeIds":{"minItems":1,"maxItems":20,"type":"array","items":{"type":"string"}},"officeId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"tattooCapabilities":{"maxItems":3,"type":"array","items":{"type":"string","enum":["TATTOO","PMU","PIERCING"]}},"relationshipType":{"type":"string","enum":["EMPLOYEE","EXTERNAL_COLLABORATOR"]},"channel":{"type":"string","enum":["WHATSAPP","SMS"]}},"required":["firstName","lastName","phone","sedeIds"],"additionalProperties":false}]},"examples":{"esempio_1":{"summary":"Struttura sanitaria","value":{"firstName":"Paola","lastName":"Fisio","relationshipType":"EMPLOYEE","sedeIds":["5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"],"professions":["PHYSIOTHERAPIST"],"enabledTreatmentIds":["fis-terapia-manuale"],"onlyAssignedModels":false}},"esempio_2":{"summary":"Studio tatuaggi","value":{"firstName":"Tino","lastName":"Tatuatore","phone":"+393331234567","sedeIds":["5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"],"tattooCapabilities":["TATTOO"]}}}}}},"responses":{"201":{"description":"Aggiungi un professionista senza accesso","content":{"application/json":{"examples":{"esempio":{"$ref":"#/components/examples/Risposta_a94cc7"}}}}},"400":{"description":"INVALID_BODY: Corpo non valido: un campo non previsto, un tipo sbagliato o un valore fuori intervallo. `details` elenca ogni problema.\nPROFESSION_NOT_IN_SCOPES: Professioni fuori dagli ambiti della struttura; `rejected` le elenca.\nTREATMENT_NOT_IN_SCOPES: Trattamenti che non sono nel catalogo delle professioni del professionista.\nIDEMPOTENCY_KEY_INVALID: `X-Idempotency-Key` vuota o più lunga di 128 caratteri.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"description":"ACCESS_NOT_MANAGED_VIA_API: Il corpo contiene email di accesso o attivazione dell'utenza: si passa da POST /structure/invites.\nTEST_KEY_READ_ONLY: Chiave in modalità Test: legge la configurazione ma non la modifica, perché sono dati veri condivisi con la dashboard.\nAnche IP_NOT_ALLOWED, SCOPE_MISSING e gli altri comuni: components.responses.C403.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"SEDE_NOT_FOUND: Una delle sedi non è di questa struttura.\nSTUDIO_TATTOO_ONLY: Studio che in dashboard non gestisce professionisti senza accesso (per esempio un centro estetico).\nNOT_A_STRUCTURE: L'account è un professionista singolo: sedi e professionisti esistono solo per strutture e studi.\nOFFICE_NOT_FOUND: Studi: `officeId` non è una sede fisica di questo account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"$ref":"#/components/responses/E409_9b1101"},"413":{"$ref":"#/components/responses/C413"},"429":{"description":"VERIFICATION_LIMIT: Studi: raggiunto il limite giornaliero di link di verifica del telefono.\nAnche RATE_LIMIT_EXCEEDED: components.responses.C429.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/structure/members/{memberId}":{"get":{"operationId":"getMember","summary":"Dettaglio di un professionista","description":"Restituisce un professionista nella stessa forma dell'elenco.\n\n**Permesso**: `structure:read`.","tags":["Struttura"],"x-scopes":["structure:read"],"parameters":[{"$ref":"#/components/parameters/path_memberId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Dettaglio di un professionista","content":{"application/json":{"examples":{"esempio":{"$ref":"#/components/examples/Risposta_a94cc7"}}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"description":"MEMBER_NOT_FOUND: Professionista inesistente, rimosso o di un altro account (stessa risposta).\nNOT_A_STRUCTURE: L'account è un professionista singolo: sedi e professionisti esistono solo per strutture e studi.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}},"patch":{"operationId":"patchMember","summary":"Modifica un professionista","description":"Cambia «chi esegue cosa», sedi, stato (ACTIVE / SUSPENDED) e dati dei documenti. Di chi ha un accesso (utenza collegata o invito aperto) nome, codice fiscale e, negli studi, telefono ed email restano della dashboard. Negli studi la sospensione segue le regole della dashboard: con controfirme in attesa chiede prima a chi passarle (409). Negli studi un cambio di numero manda un nuovo link di verifica (al massimo 5 al giorno per professionista).\n\n**Permesso**: `structure:write (delicato)`.\n\nPermesso delicato: `structure:write` cambia chi può eseguire cosa e non è mai preselezionato alla creazione della chiave.\n\nGli altri campi sono gli stessi della creazione, tutti facoltativi.","tags":["Struttura"],"x-scopes":["structure:write"],"parameters":[{"$ref":"#/components/parameters/path_memberId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"firstName":{"type":"string","minLength":1,"maxLength":100},"lastName":{"type":"string","minLength":1,"maxLength":100},"fiscalCode":{"type":"string","maxLength":32},"professionalRegister":{"type":"string","maxLength":200},"specialization":{"type":"string","maxLength":200},"partitaIva":{"type":"string","maxLength":32},"relationshipType":{"type":"string","enum":["EMPLOYEE","EXTERNAL_COLLABORATOR"]},"role":{"type":"string","enum":["COLLABORATOR","REFERENTE"]},"sedeIds":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"string"}},"professions":{"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":40}},"enabledTreatmentIds":{"maxItems":500,"type":"array","items":{"type":"string","minLength":1,"maxLength":80}},"onlyAssignedModels":{"type":"boolean"},"status":{"type":"string","enum":["ACTIVE","SUSPENDED"]}},"additionalProperties":false},{"type":"object","properties":{"firstName":{"type":"string","minLength":1,"maxLength":80},"lastName":{"type":"string","minLength":1,"maxLength":80},"phone":{"type":"string","minLength":6,"maxLength":30},"contactEmail":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}]},"sedeIds":{"minItems":1,"maxItems":20,"type":"array","items":{"type":"string"}},"officeId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"tattooCapabilities":{"maxItems":3,"type":"array","items":{"type":"string","enum":["TATTOO","PMU","PIERCING"]}},"relationshipType":{"type":"string","enum":["EMPLOYEE","EXTERNAL_COLLABORATOR"]},"channel":{"type":"string","enum":["WHATSAPP","SMS"]},"status":{"type":"string","enum":["ACTIVE","SUSPENDED"]},"countersignDigestTime":{"anyOf":[{"type":"string","pattern":"^([01]\\d|2[0-3]):(00|15|30|45)$"},{"type":"null"}]},"countersignDigestEnabled":{"type":"boolean"},"countersignRequireCode":{"type":"boolean"}},"additionalProperties":false}]},"examples":{"esempio_1":{"summary":"Solo modelli assegnati","value":{"onlyAssignedModels":true}}}}}},"responses":{"200":{"description":"Modifica un professionista","content":{"application/json":{"examples":{"esempio":{"$ref":"#/components/examples/Risposta_a94cc7"}}}}},"400":{"description":"PROFESSION_NOT_IN_SCOPES: Professioni fuori dagli ambiti della struttura.\nTREATMENT_NOT_IN_SCOPES: Trattamenti fuori dal catalogo delle professioni risultanti.\nINVALID_BODY: Corpo non valido: un campo non previsto, un tipo sbagliato o un valore fuori intervallo. `details` elenca ogni problema.\nEMPTY_PATCH: Corpo senza nessun campo da modificare.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"description":"MEMBER_IDENTITY_READ_ONLY: Nome, codice fiscale (e negli studi telefono ed email) di un professionista che ha un accesso.\nTEST_KEY_READ_ONLY: Chiave in modalità Test: legge la configurazione ma non la modifica, perché sono dati veri condivisi con la dashboard.\nAnche IP_NOT_ALLOWED, SCOPE_MISSING e gli altri comuni: components.responses.C403.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"MEMBER_NOT_FOUND: Professionista inesistente o di un altro account.\nOFFICE_NOT_FOUND: Studi: `officeId` non è una sede fisica di questo account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"MEMBER_REVOKED: Il professionista è stato rimosso dall'organico: non si modifica né si riattiva.\nMEMBER_HAS_PENDING_COUNTERSIGN: Studi: sospensione con controfirme in attesa.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"$ref":"#/components/responses/C413"},"429":{"description":"VERIFICATION_LIMIT: Studi: troppi link di verifica oggi per questo professionista.\nAnche RATE_LIMIT_EXCEEDED: components.responses.C429.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteMember","summary":"Rimuovi un professionista","description":"Rimuove il professionista dall'organico come in dashboard (stato REVOKED, i consensi eseguiti restano suoi). Negli studi tatuaggi, con controfirme in attesa, serve `reassignTo` con il professionista che le prende.\n\n**Permesso**: `structure:write (delicato)`.\n\nPermesso delicato: `structure:write` cambia chi può eseguire cosa e non è mai preselezionato alla creazione della chiave.","tags":["Struttura"],"x-scopes":["structure:write"],"parameters":[{"$ref":"#/components/parameters/path_memberId"},{"name":"reassignTo","in":"query","description":"Studi: id del professionista a cui passano le controfirme in attesa. Si può mandare anche nel corpo JSON.","schema":{"type":"string"}},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Rimuovi un professionista","content":{"application/json":{"example":{"success":true,"memberId":"uuid","status":"REVOKED"}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"description":"MEMBER_NOT_FOUND: Professionista (o `reassignTo`) inesistente, rimosso o altrui.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"MEMBER_HAS_PENDING_COUNTERSIGN: Studi: controfirme in attesa, serve `reassignTo`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}}},"/structure/invites":{"get":{"operationId":"listInvites","summary":"Inviti in attesa","description":"Restituisce gli inviti con accesso che aspettano di essere accettati.\n\n**Permesso**: `structure:read`.","tags":["Struttura"],"x-scopes":["structure:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Inviti in attesa","content":{"application/json":{"example":{"invites":[{"id":"uuid","email":"irene@example.com","name":"Irene Invitata","role":"REFERENTE","status":"PENDING","sedeIds":["uuid-sede"],"invitedAt":"2026-09-23T09:00:00.000Z"}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_f8d9f9"},"429":{"$ref":"#/components/responses/C429"}}},"post":{"operationId":"createInvite","summary":"Invita un collaboratore con accesso","description":"Invita un collaboratore con accesso: parte l'email con il link per creare o collegare l'account. Nelle strutture sanitarie l'invito porta con sé l'anagrafica del medico (stessi campi di POST /structure/members più `email`); negli studi email, nome, ruolo e capacità. Tetti: 10 inviti al giorno per account e 3 allo stesso indirizzo (giornata di Roma). Non si invita l'indirizzo del titolare, né chi è già un professionista della struttura; un invito ancora in attesa per lo stesso indirizzo è un 409 con il suo id.\n\n**Permesso**: `structure:write (delicato)`.\n\nPermesso delicato: `structure:write` cambia chi può eseguire cosa e non è mai preselezionato alla creazione della chiave.","tags":["Struttura"],"x-scopes":["structure:write"],"parameters":[{"$ref":"#/components/parameters/XIdempotencyKey"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"firstName":{"type":"string","minLength":1,"maxLength":100},"lastName":{"type":"string","minLength":1,"maxLength":100},"fiscalCode":{"type":"string","maxLength":32},"professionalRegister":{"type":"string","maxLength":200},"specialization":{"type":"string","maxLength":200},"partitaIva":{"type":"string","maxLength":32},"relationshipType":{"type":"string","enum":["EMPLOYEE","EXTERNAL_COLLABORATOR"]},"role":{"type":"string","enum":["COLLABORATOR","REFERENTE"]},"sedeIds":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"string"}},"professions":{"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":40}},"enabledTreatmentIds":{"maxItems":500,"type":"array","items":{"type":"string","minLength":1,"maxLength":80}},"onlyAssignedModels":{"type":"boolean"},"email":{"type":"string","format":"email"}},"required":["firstName","lastName","relationshipType","email"],"additionalProperties":false},{"type":"object","properties":{"email":{"type":"string","format":"email"},"name":{"type":"string","minLength":1,"maxLength":160},"role":{"type":"string","enum":["COLLABORATOR","REFERENTE"]},"officeId":{"type":"string","format":"uuid"},"tattooCapabilities":{"maxItems":3,"type":"array","items":{"type":"string","enum":["TATTOO","PMU","PIERCING"]}}},"required":["email","name"],"additionalProperties":false}]},"examples":{"esempio_1":{"summary":"Struttura sanitaria","value":{"firstName":"Irene","lastName":"Invitata","email":"irene@example.com","relationshipType":"EMPLOYEE","role":"REFERENTE","sedeIds":["5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"]}},"esempio_2":{"summary":"Studio","value":{"email":"collega@example.com","name":"Collega Invitato","tattooCapabilities":["PIERCING"]}}}}}},"responses":{"201":{"description":"Invita un collaboratore con accesso","content":{"application/json":{"example":{"invite":{"id":"uuid","email":"irene@example.com","name":"Irene Invitata","role":"REFERENTE","status":"PENDING","sedeIds":["uuid-sede"],"invitedAt":"2026-09-23T09:00:00.000Z"}}}}},"400":{"description":"INVALID_BODY: Corpo non valido: un campo non previsto, un tipo sbagliato o un valore fuori intervallo. `details` elenca ogni problema.\nPROFESSION_NOT_IN_SCOPES: Strutture sanitarie: professioni fuori dagli ambiti.\nIDEMPOTENCY_KEY_INVALID: `X-Idempotency-Key` vuota o più lunga di 128 caratteri.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"description":"NOT_A_STRUCTURE: L'account è un professionista singolo: sedi e professionisti esistono solo per strutture e studi.\nOFFICE_NOT_FOUND: Studi: `officeId` non è una sede fisica di questo account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"DUPLICATE_EMAIL: C'è già un invito in attesa per questo indirizzo; `inviteId` è il suo id.\nMEMBER_ALREADY_PRESENT: L'indirizzo è già di un professionista della struttura.\nINVITE_OWN_EMAIL: È l'indirizzo del titolare dell'account.\nIDEMPOTENCY_KEY_REUSED / IDEMPOTENCY_IN_PROGRESS: La stessa `X-Idempotency-Key` è già stata usata con un corpo diverso, oppure la prima richiesta con quella chiave è ancora in corso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"$ref":"#/components/responses/C413"},"429":{"description":"INVITE_LIMIT: Raggiunti i 10 inviti di oggi.\nINVITE_LIMIT_ADDRESS: Questo indirizzo ha già ricevuto 3 inviti oggi.\nAnche RATE_LIMIT_EXCEEDED: components.responses.C429.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/structure/invites/{inviteId}":{"delete":{"operationId":"deleteInvite","summary":"Revoca un invito","description":"Revoca un invito non ancora accettato: il link smette di funzionare.\n\n**Permesso**: `structure:write (delicato)`.\n\nPermesso delicato: `structure:write` cambia chi può eseguire cosa e non è mai preselezionato alla creazione della chiave.","tags":["Struttura"],"x-scopes":["structure:write"],"parameters":[{"$ref":"#/components/parameters/path_inviteId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Revoca un invito","content":{"application/json":{"example":{"success":true,"inviteId":"uuid","status":"REVOKED"}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"description":"INVITE_NOT_FOUND: Non c'è un invito in attesa con quell'id in questa struttura.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}}},"/structure/generic-executor":{"get":{"operationId":"getGenericExecutor","summary":"Esecutore generico per ambito","description":"Restituisce la configurazione dell'invio «senza professionista nominato» per ambito, che esiste solo nelle strutture sanitarie: il consenso esce intestato alla struttura con una qualifica al posto del medico. Il tatuaggio è escluso per legge.\n\n**Permesso**: `structure:read`.\n\n**Campi della risposta**\n- `genericExecutor.eligibleScopes`: Ambiti ammessi, ciascuno col testo salvato e quello suggerito.","tags":["Struttura"],"x-scopes":["structure:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Esecutore generico per ambito","content":{"application/json":{"example":{"genericExecutor":{"available":true,"enabled":true,"scopes":["PSYCHOLOGIST"],"eligibleScopes":[{"scope":"PSYCHOLOGIST","label":"Psicologia","text":null,"suggestedText":"…"}],"text":null,"texts":{}}}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"description":"GENERIC_EXECUTOR_NOT_AVAILABLE: Studi: l'esecutore controfirma, la modalità non esiste.\nNOT_A_STRUCTURE: L'account è un professionista singolo: sedi e professionisti esistono solo per strutture e studi.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}},"put":{"operationId":"putGenericExecutor","summary":"Imposta l'esecutore generico","description":"Accende o spegne la modalità «senza professionista nominato» e ne imposta ambiti e testi, con le regole del profilo della dashboard.\n\n**Permesso**: `structure:write (delicato)`.\n\nPermesso delicato: `structure:write` cambia chi può eseguire cosa e non è mai preselezionato alla creazione della chiave.","tags":["Struttura"],"x-scopes":["structure:write"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"scopes":{"maxItems":30,"type":"array","items":{"type":"string","minLength":1,"maxLength":40}},"texts":{"type":"object","propertyNames":{"type":"string","maxLength":40},"additionalProperties":{"type":"string","maxLength":1500}},"text":{"type":"string","maxLength":1500}},"required":["enabled"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Un ambito","value":{"enabled":true,"scopes":["PSYCHOLOGIST"],"texts":{"PSYCHOLOGIST":"Psicologo iscritto all'Albo della struttura"}}}}}}},"responses":{"200":{"description":"Imposta l'esecutore generico","content":{"application/json":{"example":{"genericExecutor":{"available":true,"enabled":true,"scopes":["PSYCHOLOGIST"],"texts":{"PSYCHOLOGIST":"Psicologo iscritto all'Albo della struttura"}}}}}},"400":{"description":"GENERIC_EXECUTOR_SCOPE_INVALID: Ambito non della struttura o escluso (tatuaggio).\nINVALID_BODY: Corpo non valido: un campo non previsto, un tipo sbagliato o un valore fuori intervallo. `details` elenca ogni problema.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"description":"GENERIC_EXECUTOR_NOT_AVAILABLE: Studi: la modalità non esiste.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/structure/countersigns/pending":{"get":{"operationId":"getPendingCountersigns","summary":"Controfirme in attesa","description":"Restituisce i consensi firmati dal cliente che aspettano la controfirma dell'esecutore (tatuaggi e piercing), per professionista e per sede: lo stesso riquadro della dashboard.\n\n**Permesso**: `structure:read`.\n\nCon una chiave Test contano solo i consensi di prova.","tags":["Struttura"],"x-scopes":["structure:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Controfirme in attesa","content":{"application/json":{"example":{"total":3,"byMember":[{"memberId":"uuid","professionalId":"uuid","name":"Tino Tatuatore","count":3,"oldestAt":"2026-09-20T18:00:00.000Z","oldestConsentId":"uuid"}],"bySede":[{"sedeId":"uuid","count":3}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_f8d9f9"},"429":{"$ref":"#/components/responses/C429"}}}},"/structure/stats":{"get":{"operationId":"getStructureStats","summary":"Statistiche della struttura","description":"Restituisce la panoramica storica per sede e professionista della pagina Struttura, più le statistiche della dashboard con i filtri richiesti (e, nelle strutture sanitarie, quelle per medico).\n\n**Permesso**: `structure:read`.","tags":["Struttura"],"x-scopes":["structure:read"],"parameters":[{"name":"sedeId","in":"query","description":"Solo quella sede (di questa struttura). In conflitto con X-Structure-Sede-Id è 403.","schema":{"type":"string"}},{"name":"memberId","in":"query","description":"Solo quel professionista.","schema":{"type":"string"}},{"$ref":"#/components/parameters/query_from_128d60"},{"name":"to","in":"query","description":"Fine del periodo (AAAA-MM-GG): comprende tutta la giornata.","schema":{"type":"string"},"example":"2026-09-30"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Statistiche della struttura","content":{"application/json":{"example":{"type":"CLINIC","filters":{"sedeId":null,"memberId":null,"from":"2026-09-01","to":"2026-09-30T23:59:59.999Z"},"overview":{"totalConsents":130,"completedConsents":118,"sedi":[{"sedeId":"uuid","sedeName":"Sede Padova","consents":80}]},"statistics":{"overview":{"totalConsents":42}},"members":{"members":[]}}}}},"400":{"$ref":"#/components/responses/E400_ba007d"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_62fb41"},"404":{"description":"SEDE_NOT_FOUND: Sede di un altro account.\nMEMBER_NOT_FOUND: Professionista di un altro account.\nNOT_A_STRUCTURE: L'account è un professionista singolo: sedi e professionisti esistono solo per strutture e studi.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}}},"/configurations":{"get":{"operationId":"listConfigurations","summary":"Elenco dei modelli","description":"Restituisce i modelli di consenso dell'account con il limite dei modelli personalizzati: 10, oppure 30 per le strutture. I moduli Agorà non contano.\n\n**Permesso**: `templates:read`.","tags":["Configurazione"],"x-scopes":["templates:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Elenco dei modelli","content":{"application/json":{"example":{"configurations":[{"id":"ck…","name":"Prima visita","source":"CUSTOM","mode":"SPECIFIC","professionType":"PSYCHOLOGIST","treatments":["psi-colloquio","psi-valutazione"],"isDefault":true,"dualSignatureEnabled":false,"medicalClearanceEnabled":null,"sendMethod":"WHATSAPP","memberIds":[],"validityMonths":null,"autoRenewReminder":false}],"limits":{"customModels":10}}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"429":{"$ref":"#/components/responses/C429"}}},"post":{"operationId":"createConfiguration","summary":"Crea un modello","description":"Crea un modello con tutte le validazioni della dashboard: un modello sbagliato bloccherebbe gli invii, quindi qui non passa. Nessun valore viene corretto in silenzio: professionisti non ammessi o doppia firma non prevista sono errori.\n\n**Permesso**: `configurations:write (delicato)`.\n\nPermesso delicato: un modello sbagliato blocca gli invii, quindi `configurations:write` non è mai preselezionato alla creazione della chiave.","tags":["Configurazione"],"x-scopes":["configurations:write"],"parameters":[{"$ref":"#/components/parameters/XIdempotencyKey"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Corpo_7e7429"},"examples":{"esempio_1":{"summary":"Modello specifico","value":{"name":"Prima visita","mode":"SPECIFIC","professionType":"PSYCHOLOGIST","treatments":["psi-colloquio","psi-valutazione"],"isDefault":true}},"esempio_2":{"summary":"Consenso a scadenza","value":{"name":"Laser annuale","mode":"SPECIFIC","professionType":"BEAUTICIAN","treatments":["bea-laser-diodo"],"validityMonths":12,"autoRenewReminder":true}}}}}},"responses":{"201":{"description":"Crea un modello","content":{"application/json":{"examples":{"esempio":{"$ref":"#/components/examples/Risposta_22db9c"}}}}},"400":{"description":"INVALID_BODY: Corpo non valido: un campo non previsto, un tipo sbagliato o un valore fuori intervallo. `details` elenca ogni problema.\nCONFIG_TEMPLATE_TYPE_NOT_ALLOWED: Professione non esercitata dall'account.\nCONFIG_SPECIFIC_NO_TREATMENTS: Modello specifico senza trattamenti.\nCONFIG_INVALID_TREATMENTS: Trattamenti che non sono del catalogo della professione.\nDUAL_SIGNATURE_NOT_AVAILABLE: Doppia firma su una professione o su trattamenti che non la prevedono.\nMEMBER_PROFESSION_MISMATCH: Un professionista di `memberIds` non esercita l'ambito del modello.\nCONFIG_MAX_REACHED: Limite di modelli raggiunto.\nIDEMPOTENCY_KEY_INVALID: `X-Idempotency-Key` vuota o più lunga di 128 caratteri.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"description":"MEMBER_NOT_FOUND: Un professionista di `memberIds` non esiste, non è attivo, è la segreteria o è di un altro account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"$ref":"#/components/responses/E409_9b1101"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/configurations/{configId}":{"get":{"operationId":"getConfiguration","summary":"Dettaglio di un modello","description":"Restituisce un modello nella stessa forma dell'elenco.\n\n**Permesso**: `templates:read`.","tags":["Configurazione"],"x-scopes":["templates:read"],"parameters":[{"$ref":"#/components/parameters/path_configId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Dettaglio di un modello","content":{"application/json":{"examples":{"esempio":{"$ref":"#/components/examples/Risposta_22db9c"}}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_78f260"},"429":{"$ref":"#/components/responses/C429"}}},"put":{"operationId":"putConfiguration","summary":"Sostituisci un modello","description":"Sostituisce il modello intero, come il salvataggio della dashboard: i campi facoltativi non inviati tornano al valore predefinito (nessun canale, nessuna scadenza, nessun rinnovo, documento medico automatico, nessun professionista associato). Per cambiare solo alcuni campi usa PATCH. Nei modelli Agorà e in quelli con il testo del centro vale come PATCH e si cambiano solo canale, predefinito, doppia firma, documento medico e professionisti.\n\n**Permesso**: `configurations:write (delicato)`.\n\nPermesso delicato: un modello sbagliato blocca gli invii, quindi `configurations:write` non è mai preselezionato alla creazione della chiave.","tags":["Configurazione"],"x-scopes":["configurations:write"],"parameters":[{"$ref":"#/components/parameters/path_configId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Corpo_7e7429"},"examples":{"esempio_1":{"summary":"Modello intero","value":{"name":"Prima visita","mode":"SPECIFIC","professionType":"PSYCHOLOGIST","treatments":["psi-colloquio"],"isDefault":true,"sendMethod":"WHATSAPP"}}}}}},"responses":{"200":{"description":"Sostituisci un modello","content":{"application/json":{"examples":{"esempio":{"$ref":"#/components/examples/Risposta_22db9c"}}}}},"400":{"description":"AGORA_CONFIG_LOCKED: Modello Agorà: testo e identità non si cambiano.\nPRIVATE_CONFIG_LOCKED: Modello col testo del centro: non si cambia da qui.\nCONFIG_SOURCE_IMMUTABLE: La sorgente di un modello non si cambia.\nINVALID_BODY: Corpo non valido: un campo non previsto, un tipo sbagliato o un valore fuori intervallo. `details` elenca ogni problema.\nCONFIG_TEMPLATE_TYPE_NOT_ALLOWED: Professione non esercitata dall'account.\nCONFIG_SPECIFIC_NO_TREATMENTS: Modello specifico senza trattamenti.\nCONFIG_INVALID_TREATMENTS: Trattamenti che non sono del catalogo della professione.\nDUAL_SIGNATURE_NOT_AVAILABLE: Doppia firma su una professione o su trattamenti che non la prevedono.\nMEMBER_PROFESSION_MISMATCH: Un professionista di `memberIds` non esercita l'ambito del modello.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_cf8178"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}},"patch":{"operationId":"patchConfiguration","summary":"Modifica un modello","description":"Cambia solo i campi inviati: tutti gli altri restano come sono salvati. Le validazioni valgono sul modello che risulterebbe. I campi sono gli stessi di POST /configurations, tutti facoltativi; ne serve almeno uno.\n\n**Permesso**: `configurations:write (delicato)`.\n\nPermesso delicato: un modello sbagliato blocca gli invii, quindi `configurations:write` non è mai preselezionato alla creazione della chiave.","tags":["Configurazione"],"x-scopes":["configurations:write"],"parameters":[{"$ref":"#/components/parameters/path_configId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":50},"mode":{"type":"string","enum":["STANDARD","SPECIFIC"]},"source":{"type":"string","enum":["CUSTOM","AGORA","PRIVATE"]},"professionType":{"anyOf":[{"type":"string","enum":["OSTEOPATH","PHYSIOTHERAPIST","CHIROPRACTOR","PODIATRIST","PSYCHOLOGIST","PSYCHOTHERAPIST","PSYCHIATRIST","NUTRITIONIST","SPEECH_THERAPIST","AESTHETIC_DOCTOR","COMPLEMENTARY_MEDICINE","OCCUPATIONAL_THERAPIST","TNPEE","GYNECOLOGIST","DERMATOLOGIST","BEAUTICIAN","TATTOO_PIERCER","DENTIST","OPHTHALMOLOGIST","DENTAL_HYGIENIST","NURSE","OTHER"]},{"type":"null"}]},"treatments":{"maxItems":300,"type":"array","items":{"type":"string","minLength":1,"maxLength":80}},"dualSignatureEnabled":{"type":"boolean"},"medicalClearanceEnabled":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"sendMethod":{"anyOf":[{"type":"string","enum":["SMS","WHATSAPP"]},{"type":"null"}]},"isDefault":{"type":"boolean"},"memberIds":{"maxItems":50,"type":"array","items":{"type":"string"}},"validityMonths":{"anyOf":[{"type":"integer","minimum":1,"maximum":120},{"type":"null"}]},"autoRenewReminder":{"type":"boolean"}},"additionalProperties":false},"examples":{"esempio_1":{"summary":"Solo il canale","value":{"sendMethod":"SMS"}}}}}},"responses":{"200":{"description":"Modifica un modello","content":{"application/json":{"examples":{"esempio":{"$ref":"#/components/examples/Risposta_22db9c"}}}}},"400":{"description":"AGORA_CONFIG_LOCKED: Modello Agorà: testo e identità non si cambiano.\nPRIVATE_CONFIG_LOCKED: Modello col testo del centro: non si cambia da qui.\nCONFIG_SOURCE_IMMUTABLE: La sorgente di un modello non si cambia.\nEMPTY_PATCH: Corpo senza nessun campo da modificare.\nINVALID_BODY: Corpo non valido: un campo non previsto, un tipo sbagliato o un valore fuori intervallo. `details` elenca ogni problema.\nCONFIG_TEMPLATE_TYPE_NOT_ALLOWED: Professione non esercitata dall'account.\nCONFIG_SPECIFIC_NO_TREATMENTS: Modello specifico senza trattamenti.\nCONFIG_INVALID_TREATMENTS: Trattamenti che non sono del catalogo della professione.\nDUAL_SIGNATURE_NOT_AVAILABLE: Doppia firma su una professione o su trattamenti che non la prevedono.\nMEMBER_PROFESSION_MISMATCH: Un professionista di `memberIds` non esercita l'ambito del modello.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_cf8178"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}},"delete":{"operationId":"deleteConfiguration","summary":"Elimina un modello","description":"Elimina un modello. I consensi già inviati o programmati con quel modello restano e perdono solo il riferimento.\n\n**Permesso**: `configurations:write (delicato)`.\n\nPermesso delicato: un modello sbagliato blocca gli invii, quindi `configurations:write` non è mai preselezionato alla creazione della chiave.","tags":["Configurazione"],"x-scopes":["configurations:write"],"parameters":[{"$ref":"#/components/parameters/path_configId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Elimina un modello","content":{"application/json":{"example":{"success":true,"configurationId":"ck…"}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_78f260"},"429":{"$ref":"#/components/responses/C429"}}}},"/configurations/{configId}/default":{"post":{"operationId":"setDefaultConfiguration","summary":"Rendi predefinito un modello","description":"Rende il modello predefinito: gli altri perdono il segno.\n\n**Permesso**: `configurations:write (delicato)`.\n\nPermesso delicato: un modello sbagliato blocca gli invii, quindi `configurations:write` non è mai preselezionato alla creazione della chiave.","tags":["Configurazione"],"x-scopes":["configurations:write"],"parameters":[{"$ref":"#/components/parameters/path_configId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Rendi predefinito un modello","content":{"application/json":{"examples":{"esempio":{"$ref":"#/components/examples/Risposta_22db9c"}}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_78f260"},"429":{"$ref":"#/components/responses/C429"}}},"delete":{"operationId":"unsetDefaultConfiguration","summary":"Togli il predefinito","description":"Toglie il predefinito senza sceglierne un altro.\n\n**Permesso**: `configurations:write (delicato)`.\n\nPermesso delicato: un modello sbagliato blocca gli invii, quindi `configurations:write` non è mai preselezionato alla creazione della chiave.","tags":["Configurazione"],"x-scopes":["configurations:write"],"parameters":[{"$ref":"#/components/parameters/path_configId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Togli il predefinito","content":{"application/json":{"example":{"configuration":{"id":"ck…","name":"Prima visita","source":"CUSTOM","mode":"SPECIFIC","professionType":"PSYCHOLOGIST","treatments":["psi-colloquio","psi-valutazione"],"isDefault":false,"dualSignatureEnabled":false,"medicalClearanceEnabled":null,"sendMethod":"WHATSAPP","memberIds":[],"validityMonths":null,"autoRenewReminder":false}}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_78f260"},"429":{"$ref":"#/components/responses/C429"}}}},"/configurations/{configId}/preview":{"get":{"operationId":"previewConfiguration","summary":"Anteprima di un modello","description":"Restituisce l'anteprima del consenso (Doc 2) che firmerà il paziente con questo modello, senza dati del paziente. Si genera al momento e arriva come PDF nel corpo (con `?format=json` in base64). È in italiano come in dashboard; per i testi in un'altra lingua attiva c'è GET /template-config/preview.\n\n**Permesso**: `templates:read`.","tags":["Configurazione"],"x-scopes":["templates:read"],"parameters":[{"$ref":"#/components/parameters/path_configId"},{"$ref":"#/components/parameters/query_format_b4d6ef"},{"name":"lang","in":"query","description":"Solo `it`. Un'altra lingua è 400 PREVIEW_LANGUAGE_NOT_AVAILABLE.","schema":{"type":"string","enum":["it"]}},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Anteprima di un modello. Il PDF arriva nel corpo; con `?format=json` arriva in base64 dentro un JSON.","content":{"application/pdf":{"schema":{"type":"string","contentMediaType":"application/pdf"}},"application/json":{"example":{"fileName":"consenso-prima-visita.pdf","contentType":"application/pdf","sizeBytes":48211,"contentBase64":"JVBERi0x…"}}}},"400":{"description":"PREVIEW_LANGUAGE_NOT_AVAILABLE: Anteprima di un modello in una lingua diversa dall'italiano.\nINVALID_QUERY: Formato non valido.\nAnche STRUCTURE_AMBIGUOUS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_78f260"},"429":{"$ref":"#/components/responses/C429"}}}},"/template-config":{"get":{"operationId":"getTemplateConfig","summary":"Trattamenti abilitati e impostazioni","description":"Restituisce i trattamenti abilitati per professione (la preselezione all'invio senza modello), le impostazioni, i trattamenti personalizzati e le clausole privacy facoltative, che sono condivise fra le professioni e vivono sulla principale.\n\n**Permesso**: `templates:read`.","tags":["Configurazione"],"x-scopes":["templates:read"],"parameters":[{"name":"professionType","in":"query","description":"Professione o ambito della riga (predefinito: la principale).","schema":{"type":"string"},"example":"PSYCHOLOGIST"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Trattamenti abilitati e impostazioni","content":{"application/json":{"example":{"professionType":"PSYCHOLOGIST","professions":["PSYCHOLOGIST"],"config":{"treatments":["psi-colloquio"],"settings":{},"customTreatments":[],"updatedAt":"2026-09-23T09:00:00.000Z"},"enabledOptionalConsents":["consent-reminders"],"availableTreatments":[{"code":"psi-colloquio","label":"Colloquio clinico","category":"Tipo di intervento","source":"PSYCHOLOGIST"}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_e63ffc"},"429":{"$ref":"#/components/responses/C429"}}},"put":{"operationId":"putTemplateConfig","summary":"Aggiorna trattamenti e impostazioni","description":"Scrive trattamenti abilitati, impostazioni, trattamenti personalizzati e clausole facoltative. Tutto è validato prima di scrivere.\n\n**Permesso**: `configurations:write (delicato)`.\n\nPermesso delicato: un modello sbagliato blocca gli invii, quindi `configurations:write` non è mai preselezionato alla creazione della chiave.","tags":["Configurazione"],"x-scopes":["configurations:write"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"professionType":{"type":"string","minLength":1,"maxLength":40},"treatments":{"maxItems":500,"type":"array","items":{"type":"string","minLength":1,"maxLength":80}},"settings":{"type":"object","properties":{"templateMode":{"type":"string","enum":["generic","specific"]},"customMode":{"type":"boolean"}},"additionalProperties":false},"customTreatments":{"maxItems":100,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","pattern":"^custom-[A-Za-z0-9_-]{1,60}$"},"label":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":2000}},"required":["id","label"],"additionalProperties":false}},"enabledOptionalConsents":{"maxItems":50,"type":"array","items":{"type":"string","minLength":1,"maxLength":80}}},"additionalProperties":false},"examples":{"esempio_1":{"summary":"Clausole e trattamenti","value":{"treatments":["psi-colloquio"],"enabledOptionalConsents":["consent-reminders","consent-marketing"],"settings":{"templateMode":"specific"}}}}}}},"responses":{"200":{"description":"Aggiorna trattamenti e impostazioni","content":{"application/json":{"example":{"professionType":"PSYCHOLOGIST","professions":["PSYCHOLOGIST"],"config":{"treatments":["psi-colloquio"],"settings":{"templateMode":"specific"},"customTreatments":[],"updatedAt":"2026-09-23T09:00:00.000Z"},"enabledOptionalConsents":["consent-reminders","consent-marketing"],"availableTreatments":[]}}}},"400":{"description":"UNKNOWN_OPTIONAL_CONSENT: Clausola facoltativa inesistente.\nDUPLICATE_CUSTOM_TREATMENT: Due trattamenti personalizzati con lo stesso id.\nINVALID_BODY: Corpo non valido: un campo non previsto, un tipo sbagliato o un valore fuori intervallo. `details` elenca ogni problema.\nEMPTY_PATCH: Corpo senza nessun campo da modificare.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_e63ffc"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/template-config/preview":{"get":{"operationId":"previewTemplate","summary":"Anteprima dei documenti dell'account","description":"Restituisce l'anteprima dei documenti dell'account (1 = informativa privacy, 2 = consenso), anche in una lingua attiva: è la stessa della pagina «Il tuo consenso».\n\n**Permesso**: `templates:read`.","tags":["Configurazione"],"x-scopes":["templates:read"],"parameters":[{"name":"doc","in":"query","required":true,"description":"1 per l'informativa privacy, 2 per il consenso.","schema":{"type":"string","enum":["1","2"]}},{"name":"lang","in":"query","description":"it, en, fr o de. Le lingue diverse dall'italiano devono essere attive (GET /languages).","schema":{"type":"string","enum":["it","en","fr","de"]}},{"name":"professionType","in":"query","description":"Professione o ambito.","schema":{"type":"string"}},{"$ref":"#/components/parameters/query_format_b4d6ef"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Anteprima dei documenti dell'account. Il PDF arriva nel corpo; con `?format=json` arriva in base64 dentro un JSON.","content":{"application/pdf":{"schema":{"type":"string","contentMediaType":"application/pdf"}},"application/json":{"example":{"fileName":"anteprima-doc2.pdf","contentType":"application/pdf","sizeBytes":51200,"contentBase64":"JVBERi0x…"}}}},"400":{"description":"INVALID_QUERY: `doc` mancante o diverso da 1 e 2, formato non valido.\nLANGUAGE_NOT_ACTIVE: Lingua non attiva sull'account.\nAnche STRUCTURE_AMBIGUOUS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"429":{"$ref":"#/components/responses/C429"}}}},"/privacy-policy":{"get":{"operationId":"getPrivacyPolicy","summary":"Informativa privacy e clausole facoltative","description":"Restituisce l'informativa personalizzata dell'account, se c'è, le clausole facoltative attive con il loro catalogo e, per le strutture, se l'informativa si invia.\n\n**Permesso**: `templates:read`.","tags":["Configurazione"],"x-scopes":["templates:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Informativa privacy e clausole facoltative","content":{"application/json":{"example":{"customPolicy":null,"privacyInformativaEnabled":true,"privacyToggleAvailable":false,"enabledOptionalConsents":["consent-reminders"],"optionalConsents":[{"id":"consent-reminders","label":"Promemoria","description":"…","informational":false}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"429":{"$ref":"#/components/responses/C429"}}},"put":{"operationId":"putPrivacyPolicy","summary":"Scegli le clausole facoltative","description":"Sceglie le clausole facoltative e, per le strutture, se inviare l'informativa. I testi di un'informativa personalizzata li carica ConsensoSicuro: non si scrivono né dalla dashboard né via API.\n\n**Permesso**: `configurations:write (delicato)`.\n\nPermesso delicato: un modello sbagliato blocca gli invii, quindi `configurations:write` non è mai preselezionato alla creazione della chiave.","tags":["Configurazione"],"x-scopes":["configurations:write"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabledOptionalConsents":{"maxItems":50,"type":"array","items":{"type":"string","minLength":1,"maxLength":80}},"privacyInformativaEnabled":{"type":"boolean"}},"additionalProperties":false},"examples":{"esempio_1":{"summary":"Due clausole","value":{"enabledOptionalConsents":["consent-reminders","consent-photos"]}}}}}},"responses":{"200":{"description":"Scegli le clausole facoltative","content":{"application/json":{"example":{"customPolicy":null,"privacyInformativaEnabled":true,"privacyToggleAvailable":false,"enabledOptionalConsents":["consent-photos"],"optionalConsents":[]}}}},"400":{"description":"PRIVACY_TOGGLE_CLINIC_ONLY: L'interruttore dell'informativa esiste solo per le strutture.\nUNKNOWN_OPTIONAL_CONSENT: Clausola inesistente.\nEMPTY_PATCH: Corpo senza nessun campo da modificare.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"description":"CUSTOM_PRIVACY_ADMIN_ONLY: Il corpo contiene testi dell'informativa (intro, sections, …).\nTEST_KEY_READ_ONLY: Chiave in modalità Test: legge la configurazione ma non la modifica, perché sono dati veri condivisi con la dashboard.\nAnche IP_NOT_ALLOWED, SCOPE_MISSING e gli altri comuni: components.responses.C403.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/engagement":{"get":{"operationId":"getEngagement","summary":"Lettera d'incarico","description":"Restituisce la lettera d'incarico (sanità) o le condizioni di servizio (centri con un modello assegnato), cioè la configurazione della dashboard con il catalogo delle clausole. Le strutture la leggono per singolo medico con `memberId`.\n\n**Permesso**: `templates:read`.","tags":["Configurazione"],"x-scopes":["templates:read"],"parameters":[{"name":"memberId","in":"query","description":"Strutture: incarico di quel medico (la polizza resta quella della struttura).","schema":{"type":"string"}},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Lettera d'incarico","content":{"application/json":{"example":{"enabled":true,"clauses":{},"insurance":{"company":"Assicurazioni Prova","policyNumber":"RC-123","coverage":"1.000.000 €","expiresAt":"2027-12-31"},"membershipId":null,"membershipName":null,"isClinic":false,"baseEnabled":false,"includeByDefault":true,"priceList":null,"perSendVars":["C1-modalita.modalita_esecuzione"],"professionVars":{},"professions":[{"type":"PSYCHOLOGIST","label":"Psicologo","description":"percorso di sostegno psicologico e consulenza, con colloqui individuali","specificExample":"quelle oggetto del consenso informato sottoscritto contestua…","fiscal":{}}],"catalog":{"version":"draft-2026-08"},"memberId":null}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"description":"ENGAGEMENT_NOT_AVAILABLE: L'incarico non esiste per questo account (verticale estetica senza condizioni di servizio).\nMEMBER_NOT_FOUND: `memberId` non è un medico attivo di questa struttura.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}},"put":{"operationId":"putEngagement","summary":"Aggiorna la lettera d'incarico","description":"Scrive la configurazione dell'incarico con le regole della dashboard: con l'incarico attivo servono gli estremi della polizza RC in corso di validità e il massimale.\n\n**Permesso**: `configurations:write (delicato)`.\n\nPermesso delicato: un modello sbagliato blocca gli invii, quindi `configurations:write` non è mai preselezionato alla creazione della chiave.","tags":["Configurazione"],"x-scopes":["configurations:write"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"clauses":{"default":{},"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"enabled":{"type":"boolean"},"vars":{"default":{},"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"required":["enabled"]}},"insurance":{"anyOf":[{"type":"object","properties":{"company":{"type":"string","minLength":1,"maxLength":120},"policyNumber":{"type":"string","minLength":1,"maxLength":60},"coverage":{"type":"string","maxLength":60},"expiresAt":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},"required":["company","policyNumber","expiresAt"]},{"type":"null"}]},"priceList":{"anyOf":[{"maxItems":50,"type":"array","items":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":120},"amountCents":{"type":"integer","minimum":0,"maximum":5000000},"notes":{"type":"string","maxLength":200}},"required":["label","amountCents"]}},{"type":"null"}]},"perSendVars":{"maxItems":50,"type":"array","items":{"type":"string","maxLength":80}},"professionVars":{"type":"object","propertyNames":{"type":"string","maxLength":40},"additionalProperties":{"type":"object","propertyNames":{"type":"string","maxLength":40},"additionalProperties":{"type":"object","propertyNames":{"type":"string","maxLength":60},"additionalProperties":{}}}},"customValues":{"type":"object","propertyNames":{"type":"string","maxLength":60},"additionalProperties":{}},"includeByDefault":{"type":"boolean"},"memberId":{"type":"string"}},"required":["enabled"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Incarico attivo","value":{"enabled":true,"clauses":{},"insurance":{"company":"Assicurazioni Prova","policyNumber":"RC-123","coverage":"1.000.000 €","expiresAt":"2027-12-31"}}}}}}},"responses":{"200":{"description":"Aggiorna la lettera d'incarico","content":{"application/json":{"example":{"success":true,"enabled":true,"includeByDefault":true,"catalogVersion":"draft-2026-08","memberId":null}}}},"400":{"description":"INVALID_BODY: Polizza mancante o scaduta, massimale assente, clausola non valida.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"description":"ENGAGEMENT_NOT_AVAILABLE: L'incarico non esiste per questo account.\nMEMBER_NOT_FOUND: `memberId` non è un medico attivo di questa struttura.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/engagement/send-state":{"get":{"operationId":"getEngagementSendState","summary":"Incarico valido all'invio","description":"Dice quale incarico vale all'invio e se la polizza è valida, come il dialog di invio della dashboard. Con l'incarico spento la risposta è ridotta a `available`, `enabled` e `catalog`; con l'incarico acceso porta anche `isBase` (vale la configurazione della struttura o quella del medico), `insuranceValid`, `clauses`, `priceList` e `perSendVars`.\n\n**Permesso**: `templates:read`.\n\n**Campi della risposta**\n- `available, enabled`: Se l'incarico esiste per l'account e se è acceso.\n- `catalog`: Il catalogo delle clausole, delle sezioni e delle variabili da compilare a ogni invio.\n- `isCustom, custom`: Presenti quando l'account usa un modello personalizzato.\n- `membershipId, membershipName`: Strutture: il medico di cui vale la configurazione, oppure null.\n- `isBase`: true quando vale la configurazione della struttura invece di quella del medico.\n- `clauses, priceList, perSendVars`: Le clausole scelte, il listino e le variabili che chiedi a ogni invio.\n- `insuranceValid`: false quando la polizza indicata è scaduta.\n- `includeByDefault`: Come parte il cursore nel dialog della dashboard (true allegato, false escluso). Le API di invio non lo seguono: con l'incarico attivo allegano il documento, salvo `engagement.include: false`.","tags":["Configurazione"],"x-scopes":["templates:read"],"parameters":[{"name":"memberId","in":"query","description":"Strutture: il medico esecutore scelto.","schema":{"type":"string"}},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Incarico valido all'invio","content":{"application/json":{"example":{"available":true,"enabled":false,"catalog":{"version":"2026-09-16","clauses":[{}],"sections":[{}],"draftNotice":"Modelli standard verificati legalmente e aggiornati alla nor…","perSendVarKeys":["C1-modalita.modalita_esecuzione"],"professionDescriptions":{}}}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"description":"ENGAGEMENT_NOT_AVAILABLE: L'incarico non esiste per questo account (stessa risposta di GET /engagement).\nMEMBER_NOT_FOUND: `memberId` non è un medico attivo di questa struttura.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}}},"/engagement/preview":{"get":{"operationId":"previewEngagement","summary":"Anteprima dell'incarico","description":"Restituisce l'anteprima del documento d'incarico salvato, come lo vedrà il paziente con un consenso generico.\n\n**Permesso**: `templates:read`.","tags":["Configurazione"],"x-scopes":["templates:read"],"parameters":[{"name":"memberId","in":"query","description":"Strutture: incarico di quel medico.","schema":{"type":"string"}},{"name":"professionType","in":"query","description":"Professione con cui simulare l'invio.","schema":{"type":"string"}},{"name":"language","in":"query","description":"en, fr o de per i modelli personalizzati tradotti.","schema":{"type":"string","enum":["it","en","fr","de"]}},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Anteprima dell'incarico","content":{"application/json":{"example":{"snapshot":{"sections":[]},"draftNotice":"…"}}}},"400":{"description":"INVALID_QUERY: Lingua non valida.\nAnche STRUCTURE_AMBIGUOUS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"description":"ENGAGEMENT_NOT_AVAILABLE: Incarico non disponibile.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}}},"/languages":{"get":{"operationId":"getLanguages","summary":"Lingue attive","description":"Restituisce le lingue in cui l'account può inviare. L'italiano c'è sempre, e `available` dice quali altre si possono attivare.\n\n**Permesso**: `templates:read`.","tags":["Configurazione"],"x-scopes":["templates:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Lingue attive","content":{"application/json":{"example":{"languages":["it","en"],"extraLanguages":["en"],"available":["en","fr","de"],"eligible":true}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"429":{"$ref":"#/components/responses/C429"}}},"put":{"operationId":"putLanguages","summary":"Imposta le lingue","description":"Imposta le lingue attive con le regole del profilo: solo per le professioni coperte dalle traduzioni (psicologia, psicoterapia, tatuaggi) e mai per le strutture.\n\n**Permesso**: `configurations:write (delicato)`.\n\nPermesso delicato: un modello sbagliato blocca gli invii, quindi `configurations:write` non è mai preselezionato alla creazione della chiave.","tags":["Configurazione"],"x-scopes":["configurations:write"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"languages":{"maxItems":4,"type":"array","items":{"type":"string","enum":["it","en","fr","de"]}}},"required":["languages"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Italiano e inglese","value":{"languages":["it","en"]}}}}}},"responses":{"200":{"description":"Imposta le lingue","content":{"application/json":{"example":{"languages":["it","en"],"extraLanguages":["en"],"available":["en","fr","de"],"eligible":true}}}},"400":{"description":"CONSENT_LANGUAGES_NOT_AVAILABLE: Account struttura.\nCONSENT_LANGUAGES_PROFESSION_NOT_SUPPORTED: Nessuna professione dell'account ha le traduzioni.\nINVALID_BODY: Corpo non valido: un campo non previsto, un tipo sbagliato o un valore fuori intervallo. `details` elenca ogni problema.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/settings":{"get":{"operationId":"getSettings","summary":"Interruttori del profilo","description":"Restituisce gli interruttori del profilo, ciascuno con il suo valore e con `available`, che dice se per questo account l'interruttore esiste.\n\n**Permesso**: `templates:read`.","tags":["Configurazione"],"x-scopes":["templates:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Interruttori del profilo","content":{"application/json":{"example":{"settings":{"medicalAnamnesisEnabled":{"value":true,"available":true},"medicalTraceabilityEnabled":{"value":false,"available":true},"customQuestionsEnabled":{"value":false,"available":false},"messageChannel":{"value":"WHATSAPP","available":true,"locked":false}},"businessFeatures":false}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"429":{"$ref":"#/components/responses/C429"}}},"patch":{"operationId":"patchSettings","summary":"Cambia gli interruttori","description":"Cambia gli interruttori che il titolare cambia da solo: anamnesi medica, tracciabilità, domande personalizzate (con il loro titolo), informativa privacy (strutture) e canale dei messaggi. Un interruttore che per questo account non esiste è 400.\n\n**Permesso**: `configurations:write (delicato)`.\n\nPermesso delicato: un modello sbagliato blocca gli invii, quindi `configurations:write` non è mai preselezionato alla creazione della chiave.","tags":["Configurazione"],"x-scopes":["configurations:write"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"medicalAnamnesisEnabled":{"type":"boolean"},"medicalTraceabilityEnabled":{"type":"boolean"},"customQuestionsEnabled":{"type":"boolean"},"customQuestionsTitle":{"type":"string","maxLength":100},"privacyInformativaEnabled":{"type":"boolean"},"messageChannel":{"type":"string","enum":["SMS","WHATSAPP"]}},"additionalProperties":false},"examples":{"esempio_1":{"summary":"Anamnesi medica accesa","value":{"medicalAnamnesisEnabled":true}}}}}},"responses":{"200":{"description":"Cambia gli interruttori","content":{"application/json":{"example":{"settings":{"medicalAnamnesisEnabled":{"value":true,"available":true}},"businessFeatures":false}}}},"400":{"description":"SETTING_NOT_AVAILABLE: L'interruttore non esiste per questo account.\nMESSAGE_CHANNEL_LOCKED: Pacchetto annuale: i messaggi partono su WhatsApp.\nEMPTY_PATCH: Corpo senza nessun campo da modificare.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/agora":{"get":{"operationId":"getAgora","summary":"Moduli Agorà","description":"Restituisce i moduli Agorà di medicina estetica e dice quali sono attivi.\n\n**Permesso**: `templates:read`.\n\n**Campi della risposta**\n- `subscriptionRequired`: true se l'account non ha un abbonamento attivo: i moduli ufficiali non si attivano in prova.","tags":["Configurazione"],"x-scopes":["templates:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Moduli Agorà","content":{"application/json":{"example":{"subscriptionRequired":false,"treatments":[{"code":"agora-iv-therapy","label":"IV therapy","activatable":true,"active":true,"configurationId":"ck…"}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"description":"AGORA_NOT_ELIGIBLE: L'account non esercita la medicina estetica.\nAGORA_DISABLED: Moduli Agorà non disponibili.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}}},"/agora/{code}/activate":{"post":{"operationId":"activateAgora","summary":"Attiva un modulo Agorà","description":"Attiva un modulo: nasce il modello `source: AGORA`, come dalla card della dashboard. Si può ripetere: se il modulo è già attivo risponde 200 con lo stesso modello e `idempotent: true`.\n\n**Permesso**: `configurations:write (delicato)`.\n\nPermesso delicato: un modello sbagliato blocca gli invii, quindi `configurations:write` non è mai preselezionato alla creazione della chiave.","tags":["Configurazione"],"x-scopes":["configurations:write"],"parameters":[{"name":"code","in":"path","required":true,"description":"Codice del modulo Agorà, come compare in GET /agora.","schema":{"type":"string"},"example":"agora-filler-ialuronico"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Il modulo era già attivo: ricevi lo stesso modello con `idempotent: true`.","content":{"application/json":{}}},"201":{"description":"Attiva un modulo Agorà","content":{"application/json":{"example":{"activated":true,"idempotent":false,"configuration":{"id":"ck…","name":"IV therapy","source":"AGORA","mode":"SPECIFIC","professionType":"PSYCHOLOGIST","treatments":["agora-iv-therapy"],"isDefault":true,"dualSignatureEnabled":false,"medicalClearanceEnabled":null,"sendMethod":"WHATSAPP","memberIds":[],"validityMonths":null,"autoRenewReminder":false}}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"description":"AGORA_SUBSCRIPTION_REQUIRED: Serve un abbonamento attivo.\nTEST_KEY_READ_ONLY: Chiave in modalità Test: legge la configurazione ma non la modifica, perché sono dati veri condivisi con la dashboard.\nAnche IP_NOT_ALLOWED, SCOPE_MISSING e gli altri comuni: components.responses.C403.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"AGORA_TREATMENT_NOT_AVAILABLE: Codice inesistente o non ancora attivabile.\nAGORA_NOT_ELIGIBLE: L'account non esercita la medicina estetica.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}}},"/agora/{code}/deactivate":{"post":{"operationId":"deactivateAgora","summary":"Disattiva un modulo Agorà","description":"Disattiva un modulo: il modello si elimina, i consensi già inviati restano intatti.\n\n**Permesso**: `configurations:write (delicato)`.\n\nPermesso delicato: un modello sbagliato blocca gli invii, quindi `configurations:write` non è mai preselezionato alla creazione della chiave.","tags":["Configurazione"],"x-scopes":["configurations:write"],"parameters":[{"name":"code","in":"path","required":true,"description":"Codice del modulo Agorà, come compare in GET /agora.","schema":{"type":"string"},"example":"agora-filler-ialuronico"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Disattiva un modulo Agorà","content":{"application/json":{"example":{"activated":false,"treatmentCode":"agora-iv-therapy","removed":1}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"description":"AGORA_NOT_ACTIVE: Il modulo non è attivo.\nAGORA_TREATMENT_NOT_AVAILABLE: Codice inesistente.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}}},"/equipment":{"get":{"operationId":"listEquipment","summary":"Apparecchiature estetiche","description":"Restituisce le apparecchiature elettromeccaniche del centro (D.M. 206/2015) con marca, modello, scheda ministeriale e ultima manutenzione.\n\n**Permesso**: `registries:read`.","tags":["Registri"],"x-scopes":["registries:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Apparecchiature estetiche","content":{"application/json":{"example":{"equipment":[{"id":"uuid","brand":"Luxor","model":"IPL 3000","dmScheda":"Scheda 16c, luce pulsata","lastMaintenanceAt":null,"active":true}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_d7bb52"},"429":{"$ref":"#/components/responses/C429"}}},"post":{"operationId":"createEquipment","summary":"Aggiungi un'apparecchiatura estetica","description":"Aggiunge un'apparecchiatura. Il registro ne tiene al massimo 30.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/XIdempotencyKey"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"brand":{"type":"string","minLength":1,"maxLength":100},"model":{"type":"string","minLength":1,"maxLength":100},"dmScheda":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"lastMaintenanceAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["brand","model"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Apparecchiatura","value":{"brand":"Luxor","model":"IPL 3000","dmScheda":"Scheda 16c, luce pulsata","lastMaintenanceAt":"2026-06-01T00:00:00.000Z"}}}}}},"responses":{"201":{"description":"Aggiungi un'apparecchiatura estetica","content":{"application/json":{"example":{"equipment":{"id":"uuid","brand":"Luxor","model":"IPL 3000","dmScheda":"Scheda 16c, luce pulsata","lastMaintenanceAt":"2026-06-01T00:00:00.000Z","active":true}}}}},"400":{"$ref":"#/components/responses/E400_4ed29e"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_d7bb52"},"409":{"$ref":"#/components/responses/E409_9b1101"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/equipment/{equipmentId}":{"patch":{"operationId":"patchEquipment","summary":"Modifica un'apparecchiatura estetica","description":"Modifica un'apparecchiatura. Con `active` la riattivi o la disattivi.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/path_equipmentId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"brand":{"type":"string","minLength":1,"maxLength":100},"model":{"type":"string","minLength":1,"maxLength":100},"dmScheda":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"lastMaintenanceAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"active":{"type":"boolean"}},"additionalProperties":false},"examples":{"esempio_1":{"summary":"Ultima manutenzione","value":{"lastMaintenanceAt":"2026-09-01T09:00:00Z"}}}}}},"responses":{"200":{"description":"Modifica un'apparecchiatura estetica","content":{"application/json":{"example":{"equipment":{"id":"uuid","brand":"Luxor","model":"IPL 3500","active":true}}}}},"400":{"$ref":"#/components/responses/E400_11ffc2"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_07f543"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}},"delete":{"operationId":"deleteEquipment","summary":"Elimina un'apparecchiatura estetica","description":"Elimina l'apparecchiatura. Se compare in un consenso la disattiva invece di eliminarla, così la riga di conformità nei documenti firmati resta leggibile.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/path_equipmentId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Elimina un'apparecchiatura estetica","content":{"application/json":{"example":{"deleted":false,"deactivated":true}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_07f543"},"429":{"$ref":"#/components/responses/C429"}}}},"/medical-equipment":{"get":{"operationId":"listMedicalEquipment","summary":"Apparecchiature MDR","description":"Restituisce le apparecchiature MDR della medicina estetica. Il registro esiste quando sull'account è attiva la tracciabilità.\n\n**Permesso**: `registries:read`.","tags":["Registri"],"x-scopes":["registries:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Apparecchiature MDR","content":{"application/json":{"example":{"equipment":[{"id":"uuid","brand":"Fotona","model":"SP Dynamis","serialNumber":"SN-1","ceMarking":"CE 0123 · MDR classe IIb","active":true}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_d7bb52"},"429":{"$ref":"#/components/responses/C429"}}},"post":{"operationId":"createMedicalEquipment","summary":"Aggiungi un'apparecchiatura MDR","description":"Aggiunge un'apparecchiatura MDR. Il registro ne tiene al massimo 30.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/XIdempotencyKey"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"brand":{"type":"string","minLength":1,"maxLength":100},"model":{"type":"string","minLength":1,"maxLength":100},"serialNumber":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}]},"ceMarking":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"lastMaintenanceAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}]}},"required":["brand","model"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Laser","value":{"brand":"Fotona","model":"SP Dynamis","serialNumber":"FT-2231","ceMarking":"CE 0123"}}}}}},"responses":{"201":{"description":"Aggiungi un'apparecchiatura MDR","content":{"application/json":{"example":{"equipment":{"id":"uuid","brand":"Fotona","model":"SP Dynamis","serialNumber":null,"ceMarking":null,"active":true}}}}},"400":{"$ref":"#/components/responses/E400_4ed29e"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_d7bb52"},"409":{"$ref":"#/components/responses/E409_9b1101"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/medical-equipment/{equipmentId}":{"patch":{"operationId":"patchMedicalEquipment","summary":"Modifica un'apparecchiatura MDR","description":"Modifica un'apparecchiatura MDR.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/path_equipmentId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"brand":{"type":"string","minLength":1,"maxLength":100},"model":{"type":"string","minLength":1,"maxLength":100},"serialNumber":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}]},"ceMarking":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"lastMaintenanceAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}]},"active":{"type":"boolean"}},"additionalProperties":false},"examples":{"esempio_1":{"summary":"Nota di revisione","value":{"notes":"Revisione annuale"}}}}}},"responses":{"200":{"description":"Modifica un'apparecchiatura MDR","content":{"application/json":{"example":{"equipment":{"id":"uuid","brand":"Fotona","model":"SP Dynamis","notes":"Revisione annuale","active":true}}}}},"400":{"$ref":"#/components/responses/E400_11ffc2"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_07f543"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}},"delete":{"operationId":"deleteMedicalEquipment","summary":"Elimina un'apparecchiatura MDR","description":"Elimina l'apparecchiatura MDR. Se compare in un consenso la disattiva invece di eliminarla.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/path_equipmentId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Elimina un'apparecchiatura MDR","content":{"application/json":{"example":{"deleted":true,"deactivated":false}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_07f543"},"429":{"$ref":"#/components/responses/C429"}}}},"/lots/pending":{"get":{"operationId":"listPendingLots","summary":"Consensi senza lotto","description":"Restituisce i consensi con iniettabili firmati negli ultimi 90 giorni che non hanno ancora un lotto registrato.\n\n**Permesso**: `registries:read`.","tags":["Registri"],"x-scopes":["registries:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Consensi senza lotto","content":{"application/json":{"example":{"pending":[{"consentId":"uuid","signedAt":"2026-09-20T10:00:00.000Z","patient":{"id":"uuid","firstName":"Giulia","lastName":"Vera"},"treatments":["Tossina botulinica"]}],"count":1}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_d7bb52"},"429":{"$ref":"#/components/responses/C429"}}}},"/lots/config":{"get":{"operationId":"getLotsConfig","summary":"Configurazione del registro lotti","description":"Restituisce i trattamenti iniettabili del catalogo, i tipi di prodotto e i prodotti già usati dall'account.\n\n**Permesso**: `registries:read`.","tags":["Registri"],"x-scopes":["registries:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Configurazione del registro lotti","content":{"application/json":{"example":{"injectableTreatments":[{"id":"est-botulino","label":"Tossina botulinica"}],"productTypes":["FILLER","TOSSINA","BIOSTIMOLATORE","Altro"],"products":[]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_d7bb52"},"429":{"$ref":"#/components/responses/C429"}}}},"/lots":{"get":{"operationId":"listLots","summary":"Registro dei lotti iniettabili","description":"Restituisce il registro dei lotti iniettabili: chi ha ricevuto quale lotto, quando e con quale esecutore. `search` serve per il richiamo di un lotto. Con la chiave Test il registro contiene solo i pazienti di prova (totale e pagine compresi).\n\n**Permesso**: `registries:read`.","tags":["Registri"],"x-scopes":["registries:read"],"parameters":[{"$ref":"#/components/parameters/query_search"},{"$ref":"#/components/parameters/query_patientId"},{"$ref":"#/components/parameters/query_memberId"},{"$ref":"#/components/parameters/query_from_128d60"},{"$ref":"#/components/parameters/query_to_283408"},{"$ref":"#/components/parameters/query_page"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Registro dei lotti iniettabili","content":{"application/json":{"example":{"lots":[{"id":"uuid","treatmentLabel":"Tossina botulinica","productName":"Vistabel","lotNumber":"C1234","expired":false,"patient":{"id":"uuid","firstName":"Giulia","lastName":"Vera"}}],"total":1,"page":1,"pageSize":50,"stats":{"month":0,"distinctProducts":0,"total":0}}}}},"400":{"$ref":"#/components/responses/E400_f7d0da"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_d7bb52"},"429":{"$ref":"#/components/responses/C429"}}},"post":{"operationId":"createLot","summary":"Registra un lotto","description":"Registra un lotto iniettabile. La registrazione finisce nel Registro attività.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/XIdempotencyKey"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"patientId":{"type":"string","format":"uuid"},"consentId":{"anyOf":[{"type":"string","minLength":1,"maxLength":60},{"type":"null"}]},"productName":{"type":"string","minLength":1,"maxLength":200},"productType":{"anyOf":[{"type":"string","enum":["FILLER","TOSSINA","BIOSTIMOLATORE","ALTRO"]},{"type":"null"}]},"lotNumber":{"anyOf":[{"type":"string","minLength":1,"maxLength":100},{"type":"null"}]},"expiryDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"udiRaw":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"usedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"treatedArea":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"quantity":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}]},"notes":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}]},"memberId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"treatmentCode":{"type":"string","minLength":1,"maxLength":60}},"required":["patientId","productName","treatmentCode"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Lotto di tossina","value":{"patientId":"8b1d4f6a-2c3e-4a5b-9d7e-1f2a3b4c5d6e","treatmentCode":"est-botulino","productName":"Vistabel","productType":"TOSSINA","lotNumber":"C1234","expiryDate":"2027-05-31","quantity":"20 U"}}}}}},"responses":{"201":{"description":"Registra un lotto","content":{"application/json":{"example":{"lot":{"id":"uuid","treatmentLabel":"Tossina botulinica","productName":"Vistabel","lotNumber":"C1234","expired":false,"patient":{"id":"uuid","firstName":"Giulia","lastName":"Vera"}}}}}},"400":{"$ref":"#/components/responses/E400_0007ef"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"description":"FEATURE_NOT_AVAILABLE: Il registro non esiste per questo account (verticale, funzione spenta o tracciabilità non attiva), come in dashboard.\nPATIENT_NOT_FOUND: Paziente inesistente o altrui.\nCONSENT_NOT_FOUND: Consenso inesistente, altrui o di un altro paziente.\nMEMBER_NOT_FOUND: Esecutore inesistente o altrui.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"$ref":"#/components/responses/E409_9b1101"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/lots/{lotId}":{"patch":{"operationId":"patchLot","summary":"Correggi un lotto","description":"Corregge una registrazione del registro lotti, che finisce nel Registro attività. Paziente, consenso ed esecutore restano quelli di prima.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/path_lotId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"productName":{"type":"string","minLength":1,"maxLength":200},"productType":{"anyOf":[{"type":"string","enum":["FILLER","TOSSINA","BIOSTIMOLATORE","ALTRO"]},{"type":"null"}]},"lotNumber":{"anyOf":[{"type":"string","minLength":1,"maxLength":100},{"type":"null"}]},"expiryDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"udiRaw":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"usedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"treatedArea":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"quantity":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}]},"notes":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}]},"treatmentCode":{"type":"string","minLength":1,"maxLength":60}},"additionalProperties":false},"examples":{"esempio_1":{"summary":"Correggi il numero di lotto","value":{"lotNumber":"C1235","notes":"Numero di lotto corretto"}}}}}},"responses":{"200":{"description":"Correggi un lotto","content":{"application/json":{"example":{"lot":{"id":"uuid","treatmentLabel":"Tossina botulinica","productName":"Vistabel","lotNumber":"C1234","expired":false,"patient":{"id":"uuid","firstName":"Giulia","lastName":"Vera"},"quantity":"25 U"}}}}},"400":{"$ref":"#/components/responses/E400_ea3988"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_852ca1"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}},"delete":{"operationId":"deleteLot","summary":"Elimina un lotto","description":"Elimina una registrazione del registro lotti. L'eliminazione finisce nel Registro attività.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/path_lotId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Elimina un lotto","content":{"application/json":{"example":{"deleted":true}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_852ca1"},"429":{"$ref":"#/components/responses/C429"}}}},"/consents/{id}/lots":{"get":{"operationId":"listConsentLots","summary":"Lotti di un consenso","description":"Restituisce i lotti iniettabili e gli inchiostri registrati su un consenso, nel perimetro di sede della richiesta.\n\n**Permesso**: `registries:read`.","tags":["Registri"],"x-scopes":["registries:read"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Lotti di un consenso","content":{"application/json":{"example":{"consentId":"uuid","lots":[{"id":"uuid","treatmentCode":"est-botulino","productName":"Vistabel","lotNumber":"C1234"}],"inks":[]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"description":"REGISTRY_NOT_AVAILABLE: Nessun registro dei lotti attivo sull'account.\nCONSENT_NOT_FOUND: Consenso inesistente, altrui o fuori dal contesto di sede.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}},"post":{"operationId":"createConsentLot","summary":"Registra un lotto su un consenso","description":"Registra un lotto iniettabile sul consenso. Paziente e consenso li ricaviamo dal percorso; le altre regole sono quelle del registro lotti.\n\n**Permesso**: `registries:write`.\n\nI campi sono quelli di POST /lots senza `patientId` e `consentId`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/path_id"},{"$ref":"#/components/parameters/XIdempotencyKey"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"productName":{"type":"string","minLength":1,"maxLength":200},"productType":{"anyOf":[{"type":"string","enum":["FILLER","TOSSINA","BIOSTIMOLATORE","ALTRO"]},{"type":"null"}]},"lotNumber":{"anyOf":[{"type":"string","minLength":1,"maxLength":100},{"type":"null"}]},"expiryDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"udiRaw":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"usedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"treatedArea":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"quantity":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}]},"notes":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}]},"memberId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"treatmentCode":{"type":"string","minLength":1,"maxLength":60}},"required":["productName","treatmentCode"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Lotto di tossina","value":{"treatmentCode":"est-botulino","productName":"Vistabel","productType":"TOSSINA","lotNumber":"C1234","quantity":"20 U"}}}}}},"responses":{"201":{"description":"Registra un lotto su un consenso","content":{"application/json":{"example":{"lot":{"id":"uuid","treatmentLabel":"Tossina botulinica","productName":"Vistabel","lotNumber":"C1234","expired":false,"patient":{"id":"uuid","firstName":"Giulia","lastName":"Vera"}}}}}},"400":{"$ref":"#/components/responses/E400_0007ef"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"description":"CONSENT_NOT_FOUND: Consenso inesistente, altrui o fuori dal contesto di sede.\nFEATURE_NOT_AVAILABLE: Il registro non esiste per questo account (verticale, funzione spenta o tracciabilità non attiva), come in dashboard.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"$ref":"#/components/responses/E409_9b1101"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/inks/pending":{"get":{"operationId":"listPendingInks","summary":"Consensi senza inchiostro registrato","description":"Restituisce i consensi con inchiostro firmati negli ultimi 90 giorni che non hanno ancora un lotto registrato.\n\n**Permesso**: `registries:read`.","tags":["Registri"],"x-scopes":["registries:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Consensi senza inchiostro registrato","content":{"application/json":{"example":{"pending":[],"count":0}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_d7bb52"},"429":{"$ref":"#/components/responses/C429"}}}},"/inks/config":{"get":{"operationId":"getInksConfig","summary":"Configurazione del registro inchiostri","description":"Restituisce i trattamenti con inchiostro, i tipi di inchiostro e le marche già usate.\n\n**Permesso**: `registries:read`.","tags":["Registri"],"x-scopes":["registries:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Configurazione del registro inchiostri","content":{"application/json":{"example":{"inkTreatments":[{"id":"tat-tatuaggio","label":"Tatuaggio"}],"inkTypes":["TATTOO_INK","PMU_PIGMENT","OTHER"],"brands":[]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_d7bb52"},"429":{"$ref":"#/components/responses/C429"}}}},"/inks":{"get":{"operationId":"listInks","summary":"Registro degli inchiostri","description":"Restituisce il registro degli inchiostri e dei pigmenti (tatuaggi e PMU). Con la chiave Test contiene solo i pazienti di prova.\n\n**Permesso**: `registries:read`.","tags":["Registri"],"x-scopes":["registries:read"],"parameters":[{"$ref":"#/components/parameters/query_search"},{"$ref":"#/components/parameters/query_patientId"},{"$ref":"#/components/parameters/query_memberId"},{"$ref":"#/components/parameters/query_from_128d60"},{"$ref":"#/components/parameters/query_to_283408"},{"$ref":"#/components/parameters/query_page"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Registro degli inchiostri","content":{"application/json":{"example":{"inks":[{"id":"uuid","brand":"Eternal","color":"Nero","lotNumber":"ET-77","reachCompliant":true}],"total":1,"page":1,"pageSize":50,"stats":{"month":0,"distinctBrands":0,"total":0}}}}},"400":{"$ref":"#/components/responses/E400_f7d0da"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_d7bb52"},"429":{"$ref":"#/components/responses/C429"}}},"post":{"operationId":"createInk","summary":"Registra un inchiostro","description":"Registra un lotto di inchiostro. La registrazione finisce nel Registro attività.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/XIdempotencyKey"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"patientId":{"type":"string","format":"uuid"},"consentId":{"anyOf":[{"type":"string","minLength":1,"maxLength":60},{"type":"null"}]},"brand":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[^\\p{C}]*$"},"productName":{"anyOf":[{"type":"string","maxLength":200,"pattern":"^[^\\p{C}]*$"},{"type":"null"}]},"color":{"anyOf":[{"type":"string","maxLength":100,"pattern":"^[^\\p{C}]*$"},{"type":"null"}]},"inkType":{"anyOf":[{"type":"string","enum":["TATTOO_INK","PMU_PIGMENT","OTHER"]},{"type":"null"}]},"lotNumber":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[^\\p{C}]*$"},"reachCompliant":{"type":"boolean"},"reachRef":{"anyOf":[{"type":"string","maxLength":300,"pattern":"^[^\\p{C}]*$"},{"type":"null"}]},"expiryDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"usedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"treatedArea":{"anyOf":[{"type":"string","maxLength":200,"pattern":"^[^\\p{C}]*$"},{"type":"null"}]},"quantity":{"anyOf":[{"type":"string","maxLength":100,"pattern":"^[^\\p{C}]*$"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string","maxLength":500,"pattern":"^(?:[^\\p{C}]|[\\n\\r\\t])*$"},{"type":"null"}]},"memberId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"treatmentCode":{"type":"string","minLength":1,"maxLength":60}},"required":["patientId","brand","lotNumber","treatmentCode"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Inchiostro nero","value":{"patientId":"8b1d4f6a-2c3e-4a5b-9d7e-1f2a3b4c5d6e","treatmentCode":"tat-tatuaggio","brand":"Eternal","color":"Nero","lotNumber":"ET-77","reachCompliant":true}}}}}},"responses":{"201":{"description":"Registra un inchiostro","content":{"application/json":{"example":{"ink":{"id":"uuid","brand":"Eternal","color":"Nero","lotNumber":"ET-77","reachCompliant":true}}}}},"400":{"$ref":"#/components/responses/E400_0007ef"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"description":"FEATURE_NOT_AVAILABLE: Il registro non esiste per questo account (verticale, funzione spenta o tracciabilità non attiva), come in dashboard.\nPATIENT_NOT_FOUND: Cliente inesistente o altrui.\nCONSENT_NOT_FOUND: Consenso inesistente o altrui.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"$ref":"#/components/responses/E409_9b1101"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/inks/{inkId}":{"patch":{"operationId":"patchInk","summary":"Correggi un inchiostro","description":"Corregge una registrazione del registro inchiostri, che finisce nel Registro attività. Paziente, consenso ed esecutore restano quelli di prima.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/path_inkId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"brand":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[^\\p{C}]*$"},"productName":{"anyOf":[{"type":"string","maxLength":200,"pattern":"^[^\\p{C}]*$"},{"type":"null"}]},"color":{"anyOf":[{"type":"string","maxLength":100,"pattern":"^[^\\p{C}]*$"},{"type":"null"}]},"inkType":{"anyOf":[{"type":"string","enum":["TATTOO_INK","PMU_PIGMENT","OTHER"]},{"type":"null"}]},"lotNumber":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[^\\p{C}]*$"},"reachCompliant":{"type":"boolean"},"reachRef":{"anyOf":[{"type":"string","maxLength":300,"pattern":"^[^\\p{C}]*$"},{"type":"null"}]},"expiryDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"usedAt":{"anyOf":[{"type":"string"},{"type":"null"}]},"treatedArea":{"anyOf":[{"type":"string","maxLength":200,"pattern":"^[^\\p{C}]*$"},{"type":"null"}]},"quantity":{"anyOf":[{"type":"string","maxLength":100,"pattern":"^[^\\p{C}]*$"},{"type":"null"}]},"notes":{"anyOf":[{"type":"string","maxLength":500,"pattern":"^(?:[^\\p{C}]|[\\n\\r\\t])*$"},{"type":"null"}]},"treatmentCode":{"type":"string","minLength":1,"maxLength":60}},"additionalProperties":false},"examples":{"esempio_1":{"summary":"Colore","value":{"color":"Nero intenso"}}}}}},"responses":{"200":{"description":"Correggi un inchiostro","content":{"application/json":{"example":{"ink":{"id":"uuid","brand":"Eternal","color":"Nero intenso","lotNumber":"ET-77","reachCompliant":true}}}}},"400":{"$ref":"#/components/responses/E400_11ffc2"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_7e5f59"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}},"delete":{"operationId":"deleteInk","summary":"Elimina un inchiostro","description":"Elimina una registrazione del registro inchiostri. L'eliminazione finisce nel Registro attività.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/path_inkId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Elimina un inchiostro","content":{"application/json":{"example":{"deleted":true}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_7e5f59"},"429":{"$ref":"#/components/responses/C429"}}}},"/materials":{"get":{"operationId":"listMaterials","summary":"Materiali della seduta","description":"Restituisce i materiali registrati nelle sedute di tatuaggio, PMU e piercing: aghi, cartucce, grip o manipoli, caps monouso, pomate e altri materiali, con marca, lotto, scadenza o ciclo di sterilizzazione. Gli inchiostri sono in `/inks`. Con la chiave Test contiene solo i pazienti di prova.\n\n**Permesso**: `registries:read`.","tags":["Registri"],"x-scopes":["registries:read"],"parameters":[{"$ref":"#/components/parameters/query_search"},{"$ref":"#/components/parameters/query_patientId"},{"$ref":"#/components/parameters/query_memberId"},{"$ref":"#/components/parameters/query_from_128d60"},{"$ref":"#/components/parameters/query_to_283408"},{"$ref":"#/components/parameters/query_page"},{"name":"consentId","in":"query","description":"Solo i materiali registrati su quel consenso.","schema":{"type":"string"}},{"name":"kind","in":"query","description":"Solo un tipo: NEEDLE, CARTRIDGE, GRIP, CAP, OINTMENT oppure OTHER.","schema":{"type":"string"},"example":"NEEDLE"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Materiali della seduta","content":{"application/json":{"example":{"materials":[{"id":"uuid","kind":"NEEDLE","kindLabel":"Aghi","brand":"Cheyenne","productName":"Safety 0,30 RL 7","lotNumber":"CH-889921","expiryDate":"2029-03-31T00:00:00.000Z","sterilizationRef":null,"quantity":"3","treatmentCode":"tat-tatuaggio","consentId":"uuid","memberId":null}],"total":1,"page":1,"pageSize":50}}}},"400":{"description":"INVALID_QUERY: Data, pagina o tipo non validi.\nAnche STRUCTURE_AMBIGUOUS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_d7bb52"},"429":{"$ref":"#/components/responses/C429"}}}},"/supply-presets":{"get":{"operationId":"listSupplyPresets","summary":"I prodotti dello studio","description":"Restituisce la libreria «I miei prodotti» dello studio di tatuaggio: inchiostri e materiali salvati con il lotto attuale e la scadenza, nell'ordine scelto dallo studio. I prodotti archiviati si vedono solo con `includeArchived=true`.\n\n**Permesso**: `registries:read`.","tags":["Registri"],"x-scopes":["registries:read"],"parameters":[{"name":"includeArchived","in":"query","description":"true per vedere anche i prodotti archiviati.","schema":{"type":"string"},"example":"false"},{"name":"kind","in":"query","description":"Solo un tipo: INK, NEEDLE, CARTRIDGE, GRIP, CAP, OINTMENT oppure OTHER.","schema":{"type":"string"},"example":"INK"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"I prodotti dello studio","content":{"application/json":{"example":{"presets":[{"id":"uuid","kind":"INK","kindLabel":"Inchiostro","brand":"Eternal","productName":null,"color":"Nero","lotNumber":"ET-77","expiryDate":"2027-06-30T00:00:00.000Z","useCount":12,"archivedAt":null}],"kinds":[{"value":"INK","label":"Inchiostro","plural":"Inchiostri"}]}}}},"400":{"$ref":"#/components/responses/E400_7ffcc6"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_d7bb52"},"429":{"$ref":"#/components/responses/C429"}}}},"/operators":{"get":{"operationId":"listOperators","summary":"Operatrici del centro","description":"Restituisce le operatrici del centro estetico che non hanno un accesso alla dashboard.\n\n**Permesso**: `registries:read`.","tags":["Registri"],"x-scopes":["registries:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Operatrici del centro","content":{"application/json":{"example":{"operators":[{"id":"uuid","firstName":"Olga","lastName":"Operatrice","qualification":"Estetista qualificata (L. 1/1990)","active":true}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_d7bb52"},"429":{"$ref":"#/components/responses/C429"}}},"post":{"operationId":"createOperator","summary":"Aggiungi un'operatrice","description":"Aggiunge un'operatrice. Il registro ne tiene al massimo 30.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/XIdempotencyKey"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"firstName":{"type":"string","minLength":1,"maxLength":100},"lastName":{"type":"string","minLength":1,"maxLength":100},"qualification":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]}},"required":["firstName","lastName"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Operatrice","value":{"firstName":"Olga","lastName":"Operatrice","qualification":"Estetista qualificata"}}}}}},"responses":{"201":{"description":"Aggiungi un'operatrice","content":{"application/json":{"example":{"operator":{"id":"uuid","firstName":"Olga","lastName":"Operatrice","qualification":null,"active":true}}}}},"400":{"description":"OPERATOR_LIMIT: Massimo 30 operatrici.\nINVALID_BODY: Corpo non valido: un campo non previsto, un tipo sbagliato o un valore fuori intervallo. `details` elenca ogni problema.\nIDEMPOTENCY_KEY_INVALID: `X-Idempotency-Key` vuota o più lunga di 128 caratteri.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_d7bb52"},"409":{"$ref":"#/components/responses/E409_9b1101"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/operators/{operatorId}":{"patch":{"operationId":"patchOperator","summary":"Modifica un'operatrice","description":"Modifica un'operatrice. Con `active` la riattivi o la disattivi.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/path_operatorId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"firstName":{"type":"string","minLength":1,"maxLength":100},"lastName":{"type":"string","minLength":1,"maxLength":100},"qualification":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"active":{"type":"boolean"}},"additionalProperties":false},"examples":{"esempio_1":{"summary":"Qualifica","value":{"qualification":"Estetista qualificata"}}}}}},"responses":{"200":{"description":"Modifica un'operatrice","content":{"application/json":{"example":{"operator":{"id":"uuid","firstName":"Olga","lastName":"Operatrice","qualification":null,"active":false}}}}},"400":{"$ref":"#/components/responses/E400_11ffc2"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_2ff6db"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}},"delete":{"operationId":"deleteOperator","summary":"Elimina un'operatrice","description":"Elimina l'operatrice. Se compare in un consenso la disattiva invece di eliminarla.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/path_operatorId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Elimina un'operatrice","content":{"application/json":{"example":{"deleted":true,"deactivated":false}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_2ff6db"},"429":{"$ref":"#/components/responses/C429"}}}},"/consultation-reasons":{"get":{"operationId":"listReasons","summary":"Motivi di consulto","description":"Restituisce i motivi di consulto usati nelle visite, dal più usato.\n\n**Permesso**: `registries:read`.","tags":["Registri"],"x-scopes":["registries:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Motivi di consulto","content":{"application/json":{"example":{"reasons":[{"id":"uuid","label":"Ansia da prestazione","usageCount":4,"createdAt":"2026-09-01T09:00:00.000Z"}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"429":{"$ref":"#/components/responses/C429"}}},"post":{"operationId":"createReason","summary":"Aggiungi un motivo di consulto","description":"Aggiunge un motivo di consulto. Un testo uguale a uno esistente, a parte maiuscole e spazi, è lo stesso motivo: ricevi quello che c'è già.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/XIdempotencyKey"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":120}},"required":["label"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Motivo nuovo","value":{"label":"Dolore lombare"}}}}}},"responses":{"201":{"description":"Aggiungi un motivo di consulto","content":{"application/json":{"example":{"reason":{"id":"uuid","label":"Ansia da prestazione","usageCount":0,"createdAt":"2026-09-23T09:00:00.000Z"}}}}},"400":{"$ref":"#/components/responses/E400_0007ef"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_b6af56"},"409":{"$ref":"#/components/responses/E409_9b1101"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/consultation-reasons/{reasonId}":{"patch":{"operationId":"patchReason","summary":"Rinomina un motivo di consulto","description":"Rinomina un motivo, anche nelle visite che lo usano.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/path_reasonId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":120}},"required":["label"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Rinomina","value":{"label":"Lombalgia"}}}}}},"responses":{"200":{"description":"Rinomina un motivo di consulto","content":{"application/json":{"example":{"reason":{"id":"uuid","label":"Ansia","usageCount":4,"createdAt":"2026-09-01T09:00:00.000Z"}}}}},"400":{"$ref":"#/components/responses/E400_1123b3"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_b6af56"},"404":{"$ref":"#/components/responses/E404_6f6ef5"},"409":{"description":"REASON_ALREADY_EXISTS: Esiste già un motivo con quel testo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}},"delete":{"operationId":"deleteReason","summary":"Elimina un motivo di consulto","description":"Elimina un motivo. Le visite che lo usavano restano intatte.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/path_reasonId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Elimina un motivo di consulto","content":{"application/json":{"example":{"success":true}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_6f6ef5"},"429":{"$ref":"#/components/responses/C429"}}}},"/custom-questions/stats":{"get":{"operationId":"getCustomQuestionsStats","summary":"Statistiche delle domande personalizzate","description":"Restituisce i totali delle risposte per ogni domanda attiva. Le risposte a testo libero non vengono mostrate.\n\n**Permesso**: `registries:read`.","tags":["Registri"],"x-scopes":["registries:read"],"parameters":[{"name":"sedeId","in":"query","description":"Strutture: solo quella sede.","schema":{"type":"string"}},{"$ref":"#/components/parameters/query_from_128d60"},{"$ref":"#/components/parameters/query_to_283408"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Statistiche delle domande personalizzate","content":{"application/json":{"example":{"kpi":{},"questions":[]}}}},"400":{"description":"INVALID_QUERY: Data non valida.\nAnche STRUCTURE_AMBIGUOUS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"description":"FEATURE_NOT_AVAILABLE: Il registro non esiste per questo account (verticale, funzione spenta o tracciabilità non attiva), come in dashboard.\nSEDE_NOT_FOUND: Sede altrui.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}}},"/custom-questions/reorder":{"post":{"operationId":"reorderCustomQuestions","summary":"Riordina le domande personalizzate","description":"Riordina le domande: passa in `ids` gli id nell'ordine che vuoi.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"minItems":1,"maxItems":200,"type":"array","items":{"type":"string"}}},"required":["ids"],"additionalProperties":false},"examples":{"esempio_1":{"summary":"Nuovo ordine","value":{"ids":["3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f"]}}}}}},"responses":{"200":{"description":"Riordina le domande personalizzate","content":{"application/json":{"example":{"success":true}}}},"400":{"$ref":"#/components/responses/E400_1123b3"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"description":"FEATURE_NOT_AVAILABLE: Il registro non esiste per questo account (verticale, funzione spenta o tracciabilità non attiva), come in dashboard.\nQUESTION_NOT_FOUND: Un id è inesistente o altrui.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/custom-questions":{"get":{"operationId":"listCustomQuestions","summary":"Domande personalizzate","description":"Restituisce le domande personalizzate dell'anamnesi delle strutture «Associazione», in ordine e comprese quelle disattivate.\n\n**Permesso**: `registries:read`.","tags":["Registri"],"x-scopes":["registries:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Domande personalizzate","content":{"application/json":{"example":{"enabled":true,"maxActive":20,"questions":[{"id":"uuid","label":"Come ci hai conosciuto?","type":"MULTIPLE_CHOICE","required":false,"active":true}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"404":{"$ref":"#/components/responses/E404_d7bb52"},"429":{"$ref":"#/components/responses/C429"}}},"post":{"operationId":"createCustomQuestion","summary":"Aggiungi una domanda personalizzata","description":"Aggiunge una domanda. Le domande attive possono essere al massimo 20.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/XIdempotencyKey"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Corpo_9f1558"},"examples":{"esempio_1":{"summary":"Scelta multipla","value":{"label":"Come ci hai conosciuto?","type":"MULTIPLE_CHOICE","options":[{"label":"Passaparola"},{"label":"Internet"}]}}}}}},"responses":{"201":{"description":"Aggiungi una domanda personalizzata","content":{"application/json":{"example":{"question":{"id":"uuid","label":"Come ci hai conosciuto?","type":"MULTIPLE_CHOICE","options":[{"key":"opt-1","label":"Passaparola"}],"required":false,"active":true}}}}},"400":{"description":"CUSTOM_QUESTIONS_LIMIT: Massimo 20 domande attive.\nCUSTOM_QUESTIONS_OPTIONS_INVALID: La scelta multipla ha meno di 2 o più di 10 opzioni.\nCUSTOM_QUESTIONS_EXPIRY_REQUIRED: Con askPolicy EXPIRES servono i mesi in expiryMonths.\nINVALID_BODY: Corpo non valido: un campo non previsto, un tipo sbagliato o un valore fuori intervallo. `details` elenca ogni problema.\nIDEMPOTENCY_KEY_INVALID: `X-Idempotency-Key` vuota o più lunga di 128 caratteri.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_d7bb52"},"409":{"$ref":"#/components/responses/E409_9b1101"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}}},"/custom-questions/{questionId}":{"put":{"operationId":"putCustomQuestion","summary":"Sostituisci una domanda personalizzata","description":"Sostituisce la domanda intera, come il salvataggio della dashboard.\n\n**Permesso**: `registries:write`.\n\nI campi sono gli stessi della creazione.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/path_questionId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Corpo_9f1558"},"examples":{"esempio_1":{"summary":"Domanda sì o no","value":{"label":"Hai già fatto sedute simili?","type":"YES_NO"}}}}}},"responses":{"200":{"description":"Sostituisci una domanda personalizzata","content":{"application/json":{"example":{"question":{"id":"uuid","label":"Come ci hai conosciuto?","type":"MULTIPLE_CHOICE","required":false,"active":true}}}}},"400":{"description":"CUSTOM_QUESTIONS_LIMIT: Massimo 20 domande attive.\nCUSTOM_QUESTIONS_OPTIONS_INVALID: La scelta multipla ha meno di 2 o più di 10 opzioni.\nCUSTOM_QUESTIONS_EXPIRY_REQUIRED: Con askPolicy EXPIRES servono i mesi in expiryMonths.\nINVALID_BODY: Corpo non valido: un campo non previsto, un tipo sbagliato o un valore fuori intervallo. `details` elenca ogni problema.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_7b2797"},"413":{"$ref":"#/components/responses/C413"},"429":{"$ref":"#/components/responses/C429"}}},"delete":{"operationId":"deleteCustomQuestion","summary":"Elimina una domanda personalizzata","description":"Elimina la domanda. Se ha già delle risposte la disattiva invece di eliminarla, così le risposte passate restano leggibili.\n\n**Permesso**: `registries:write`.","tags":["Registri"],"x-scopes":["registries:write"],"parameters":[{"$ref":"#/components/parameters/path_questionId"},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Elimina una domanda personalizzata","content":{"application/json":{"example":{"deleted":false,"deactivated":true}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_e67711"},"404":{"$ref":"#/components/responses/E404_7b2797"},"429":{"$ref":"#/components/responses/C429"}}}},"/account/usage":{"get":{"operationId":"getAccountUsage","summary":"Quota e consumi","description":"Restituisce la quota del periodo (la stessa che decide se un invio passa), il piano, il pacchetto prepagato o extra, i messaggi WhatsApp e SMS del periodo e i consumi degli ultimi 12 mesi. I consensi di prova e quelli annullati non contano.\n\n**Permesso**: `account:read`.\n\n**Campi della risposta**\n- `monthly[]`: Dal mese più vecchio al corrente: consensi inviati, completati, WhatsApp, SMS.","tags":["Consumi"],"x-scopes":["account:read"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Quota e consumi","content":{"application/json":{"example":{"plan":{"tier":"PROFESSIONAL","subscriptionStatus":"ACTIVE","billingInterval":"MONTHLY"},"period":{"start":"2026-09-05T00:00:00.000Z","end":"2026-10-05T00:00:00.000Z"},"quota":{"used":42,"limit":200,"remaining":158,"isLifetime":false,"mode":"plan","packOnly":false},"pack":null,"extraPackCatalog":[{"size":50,"priceEur":20}],"messages":{"periodStart":"2026-09-05T00:00:00.000Z","whatsapp":38,"sms":6,"total":44},"monthly":[{"month":"2026-09","consentsSent":42,"consentsCompleted":37,"whatsapp":38,"sms":6}]}}}},"400":{"$ref":"#/components/responses/C400_1b513c"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"429":{"$ref":"#/components/responses/C429"}}}},"/account/stats":{"get":{"operationId":"getAccountStats","summary":"Statistiche","description":"Restituisce le statistiche della dashboard (consensi per stato, andamento, trattamenti) con gli stessi filtri.\n\n**Permesso**: `account:read`.","tags":["Consumi"],"x-scopes":["account:read"],"parameters":[{"$ref":"#/components/parameters/query_from"},{"$ref":"#/components/parameters/query_to"},{"name":"sedeId","in":"query","description":"Strutture: solo quella sede (di questo account, altrimenti 404). In conflitto con X-Structure-Sede-Id è 403.","schema":{"type":"string"}},{"name":"memberId","in":"query","description":"Strutture: solo quel professionista (di questo account, altrimenti 404).","schema":{"type":"string"}},{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Statistiche","content":{"application/json":{"example":{"filters":{"from":"2026-01-01","to":null,"sedeId":null,"memberId":null},"statistics":{"overview":{"totalConsents":130}},"treatments":{}}}}},"400":{"$ref":"#/components/responses/E400_ba007d"},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/E403_62fb41"},"429":{"$ref":"#/components/responses/C429"}}}},"/webhooks/test":{"post":{"operationId":"sendWebhookTest","summary":"Prova il webhook","description":"Invia un evento `ping` firmato all'indirizzo del webhook configurato in dashboard. Serve a verificare che il tuo server riceva e controlli la firma prima di aspettare un consenso vero.\n\n**Permesso**: `webhooks:test`.\n\nAl massimo 10 prove all'ora per account: ogni prova è una chiamata vera verso il tuo server.","tags":["Webhook"],"x-scopes":["webhooks:test"],"parameters":[{"$ref":"#/components/parameters/XStructureSedeId"}],"responses":{"200":{"description":"Prova il webhook","content":{"application/json":{"example":{"delivered":true,"deliveryId":"uuid","responseStatus":200}}}},"400":{"description":"WEBHOOK_NOT_CONFIGURED: Non c'è nessun webhook: si configura in Impostazioni → API & Integrazioni.\nWEBHOOK_DISABLED: Il webhook è configurato ma disattivato.\nAnche STRUCTURE_AMBIGUOUS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/C401"},"403":{"$ref":"#/components/responses/C403"},"409":{"description":"WEBHOOK_SECRET_UNAVAILABLE: Il segreto del webhook non si legge più (succede solo per un guasto nostro): va rigenerato in dashboard. Finché non lo fai nessun evento parte, e ti avvisiamo per email.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/C429"}}}}},"webhooks":{"consent.created":{"post":{"operationId":"webhook_consent_created","summary":"consent.created","description":"Consenso inviato al paziente (da dashboard o da API).","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"consent.resent":{"post":{"operationId":"webhook_consent_resent","summary":"consent.resent","description":"Consenso scaduto reinviato: nasce un consenso nuovo, `consent.replacesConsentId` è quello vecchio.\n\n`consent.id` è il consenso nuovo; `consent.replacesConsentId` quello sostituito.","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"consent.renewed":{"post":{"operationId":"webhook_consent_renewed","summary":"consent.renewed","description":"Consenso a scadenza rinnovato (manualmente o dal promemoria automatico): anche qui il consenso è nuovo.\n\n`consent.id` è il consenso nuovo; `consent.replacesConsentId` quello sostituito.","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"consent.phone_corrected":{"post":{"operationId":"webhook_consent_phone_corrected","summary":"consent.phone_corrected","description":"Numero di un firmatario corretto: stesso link, nessuna quota consumata. `signerSlot` dice a chi.\n\n`consent.signerSlot` (P1/P2), `consent.channel`, `consent.sameLink: true`.","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"consent.delivery_failed":{"post":{"operationId":"webhook_consent_delivery_failed","summary":"consent.delivery_failed","description":"Messaggio non consegnato a un firmatario nemmeno dopo il ripiego automatico su SMS: serve correggere il numero.\n\n`consent.signerSlot` e `consent.delivery` con stato, tentativi, se il ripiego SMS è stato provato e l'endpoint per correggere il numero.","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"consent.partially_signed":{"post":{"operationId":"webhook_consent_partially_signed","summary":"consent.partially_signed","description":"Doppia firma: uno dei due genitori ha firmato (`signedSlot`, `receivedSignatures` su `expectedSignatures`).\n\n`consent.signedSlot`, `consent.receivedSignatures` / `expectedSignatures`, `consent.signatures[]`.","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"},"example":{"event":"consent.partially_signed","timestamp":"2026-09-16T09:12:00.000Z","consent":{"id":"uuid","status":"PARTIALLY_SIGNED","internalStatus":"PENDING_SECOND_PARENT","apiStatus":"PARTIALLY_SIGNED","consentType":"FULL","isMinor":true,"isTest":false,"source":"api","metadata":{"cartella":"CRT-119"},"dualSignatureRequired":true,"expectedSignatures":2,"receivedSignatures":1,"signedSlot":"P1","signatures":[{"slot":"P1","role":"FIRST_PARENT","firstName":"Elena","lastName":"Verdi","status":"SIGNED","signedAt":"2026-09-16T09:12:00.000Z"},{"slot":"P2","role":"SECOND_PARENT","firstName":"Marco","lastName":"Verdi","status":"PENDING","signedAt":null}],"patient":{"id":"uuid","firstName":"Sofia","lastName":"Verdi"},"countersign":{"required":false,"status":"NOT_REQUIRED"},"language":"it","isTutelato":false,"channel":"WHATSAPP","createdAt":"2026-09-16T09:00:00.000Z","scheduledAt":null,"expiresAt":"2026-09-23T09:00:00.000Z","signedAt":null,"secondParentSignedAt":null,"otpVerifiedAt":null,"sede":null,"executor":null,"signingMode":"REMOTE","validUntil":null,"replacesConsentId":null}}}}},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"consent.action_required":{"post":{"operationId":"webhook_consent_action_required","summary":"consent.action_required","description":"Serve un intervento dello studio: dati del minore divergenti tra i due genitori, oppure controfirma dell'esecutore mancante.\n\n`consent.actionReason` (MINOR_DATA_MISMATCH o COUNTERSIGN_PENDING) e, per la difformità, `consent.mismatch` con i campi e gli endpoint di risoluzione. I valori del minore non escono nel webhook: stanno nel dettaglio autenticato.","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"consent.countersigned":{"post":{"operationId":"webhook_consent_countersigned","summary":"consent.countersigned","description":"Tatuaggi e piercing: l'esecutore ha controfirmato. Subito dopo arriva consent.completed.\n\n`consent.countersign` con metodo e istante. Subito dopo arriva consent.completed.","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"consent.completed":{"post":{"operationId":"webhook_consent_completed","summary":"consent.completed","description":"Tutte le firme ricevute: i PDF sono disponibili (URL firmate a 1 ora).\n\n`consent.signatures[]` con gli orari di tutte le firme e il blocco `documents` con le URL firmate (valide 1 ora).","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"consent.refused":{"post":{"operationId":"webhook_consent_refused","summary":"consent.refused","description":"Il paziente (o un genitore) ha rifiutato di firmare: `refusedSlot` e `refusalReason`.\n\n`consent.refusedSlot` e `consent.refusalReason` (PATIENT o PARENT_DISAGREEMENT).","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"consent.expired":{"post":{"operationId":"webhook_consent_expired","summary":"consent.expired","description":"Il link è scaduto senza firma.","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"consent.cancelled":{"post":{"operationId":"webhook_consent_cancelled","summary":"consent.cancelled","description":"Il consenso è stato annullato.","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"patient.created":{"post":{"operationId":"webhook_patient_created","summary":"patient.created","description":"Nuova anagrafica in archivio: `patient.id`, il tuo `externalId` se lo hai passato, nome e cognome. Mai il telefono né il codice fiscale.\n\n`patient` con `id`, `externalId`, nome e cognome. Mai il telefono né il codice fiscale: ce li hai già nel tuo sistema e non servono a rimbalzare qui. `patient.updated` porta `changed`, cioè i nomi dei campi toccati, non i valori.","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"patient.updated":{"post":{"operationId":"webhook_patient_updated","summary":"patient.updated","description":"Anagrafica modificata (dati, note, sede o riferimento del gestionale): `changed` elenca i campi toccati, non i valori.\n\n`patient` con `id`, `externalId`, nome e cognome. Mai il telefono né il codice fiscale: ce li hai già nel tuo sistema e non servono a rimbalzare qui. `patient.updated` porta `changed`, cioè i nomi dei campi toccati, non i valori.","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"patient.deleted":{"post":{"operationId":"webhook_patient_deleted","summary":"patient.deleted","description":"Anagrafica cancellata definitivamente (art. 17 GDPR). Porta solo gli identificativi: il nome è stato cancellato e non lo si rispedisce fuori.\n\nIl corpo porta solo `patient.id`, `externalId`, `consentsDeleted` e `deletedAt`. Il nome è appena stato cancellato su richiesta dell'interessato: rispedirlo fuori nell'evento che ne annuncia la cancellazione la vanificherebbe.","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"patient.privacy_revoked":{"post":{"operationId":"webhook_patient_privacy_revoked","summary":"patient.privacy_revoked","description":"Consensi facoltativi revocati su un documento privacy firmato (art. 7.3): `consentId`, le clausole revocate e se la revoca è totale.\n\n`privacy` con `consentId`, `revokedLabels` (etichette di clausola, non dati della persona), `totale` e `revokedAt`.","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"patient.merged":{"post":{"operationId":"webhook_patient_merged","summary":"patient.merged","description":"Due anagrafiche si sono rivelate la stessa persona: `mergedFrom` è l'id che da ora risponde 404, `patient.id` quello buono. Aggiorna il riferimento nel tuo gestionale.\n\n`mergedFrom` è l'id che non vale più, `patient.id` quello buono. Arriva anche un `patient.updated` sull'id assorbito con `changed: [\"mergedInto\"]`, per chi cerca per id.","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"patient.deletion_scheduled":{"post":{"operationId":"webhook_patient_deletion_scheduled","summary":"patient.deletion_scheduled","description":"Cancellazione GDPR chiesta via API: l'anagrafica è già sparita da liste e invii, ma i dati vengono distrutti solo dopo `cancelUntil`. Fino ad allora si può annullare.\n\n`deletion` con `cancelUntil` (entro quando si può fermare), `signedConsents` (quante prove di consenso verranno distrutte) e `cancelEndpoint`.","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"patient.deletion_postponed":{"post":{"operationId":"webhook_patient_deletion_postponed","summary":"patient.deletion_postponed","description":"Una cancellazione programmata non è stata eseguita alla scadenza: nella finestra sono arrivati nuovi consensi firmati e nessuno ha dichiarato di voler distruggere anche quelli. La cancellazione viene rimandata una sola volta di altri 7 giorni: serve una nuova presa d'atto, altrimenti alla scadenza successiva viene annullata.\n\n`deletion.newSignedConsents` (le firme arrivate dopo la richiesta) e `deletion.cancelUntil` (la nuova scadenza). La cancellazione non è avvenuta: serve una nuova richiesta con `acknowledgeRetention: true`. Il rinvio avviene una volta sola: alla scadenza successiva, se nessuno ha riconfermato, la cancellazione viene annullata (`patient.deletion_cancelled`).","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"patient.deletion_cancelled":{"post":{"operationId":"webhook_patient_deletion_cancelled","summary":"patient.deletion_cancelled","description":"Una cancellazione programmata è stata annullata, dal gestionale o dalla dashboard (`deletion.reason: REQUESTED`) oppure d'ufficio perché dopo il rinvio nessuno l'ha riconfermata (`NEW_SIGNED_CONSENTS`): l'anagrafica è di nuovo raggiungibile.\n\n`patient` e `deletion.reason`: `REQUESTED` se l'ha fermata qualcuno (dal gestionale o dalla dashboard), `NEW_SIGNED_CONSENTS` se l'abbiamo annullata d'ufficio perché dopo il rinvio nessuno ha riconfermato (in quel caso c'è anche `deletion.newSignedConsents` e `deletion.automatic: true`). L'anagrafica è di nuovo raggiungibile; per cancellarla comunque rifai la richiesta con `acknowledgeRetention: true`.","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"configuration.updated":{"post":{"operationId":"webhook_configuration_updated","summary":"configuration.updated","description":"È cambiata la configurazione dell'account (modelli, trattamenti abilitati, clausole privacy, incarico, lingue, interruttori del profilo, registri): `change.resource` dice quale risorsa (`type`, e `id` quando c'è) e `change.action` quale azione, senza dati. Rileggi la configurazione.","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"structure.updated":{"post":{"operationId":"webhook_structure_updated","summary":"structure.updated","description":"È cambiata la struttura (sedi, professionisti, inviti, esecutore generico): `change.resource` dice quale risorsa (`type`, e `id` quando c'è) e `change.action` quale azione, senza nomi. Rileggi GET /structure.","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}},"ping":{"post":{"operationId":"webhook_ping","summary":"ping","description":"Evento di prova, inviato dalla dashboard o con `POST /webhooks/test`.","tags":["Webhook"],"security":[],"parameters":[{"$ref":"#/components/parameters/XConsensoSicuroSignature"},{"$ref":"#/components/parameters/XConsensoSicuroTimestamp"},{"$ref":"#/components/parameters/XConsensoSicuroEvent"},{"$ref":"#/components/parameters/XConsensoSicuroDeliveryId"}],"requestBody":{"$ref":"#/components/requestBodies/WebhookEvent"},"responses":{"200":{"$ref":"#/components/responses/WebhookOk"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"ak_live_… / ak_test_…","description":"Chiave API dell'account, creata dal titolare in Impostazioni → API & Integrazioni. È mostrata una volta sola. I permessi segnati «(delicato)» non sono mai preselezionati alla creazione della chiave."}},"parameters":{"XStructureSedeId":{"name":"X-Structure-Sede-Id","in":"header","description":"Strutture: la sede su cui lavora la richiesta, come nella dashboard. La chiave resta confinata alle sedi della sua struttura.","schema":{"type":"string"}},"path_id":{"name":"id","in":"path","required":true,"description":"Id del consenso.","schema":{"type":"string"},"example":"3f2a8c1e-5b7d-4e2a-9c41-7d8e2b6a1f09"},"path_patientId":{"name":"patientId","in":"path","required":true,"description":"Id del paziente.","schema":{"type":"string"},"example":"8b1d4f6a-2c3e-4a5b-9d7e-1f2a3b4c5d6e"},"path_docId":{"name":"docId","in":"path","required":true,"description":"Id del documento del paziente.","schema":{"type":"string"},"example":"c4d5e6f7-0a1b-4c2d-8e3f-4a5b6c7d8e9f"},"path_visitId":{"name":"visitId","in":"path","required":true,"description":"Id della visita.","schema":{"type":"string"},"example":"d1e2f3a4-b5c6-4d7e-8f9a-0b1c2d3e4f5a"},"path_cycleId":{"name":"cycleId","in":"path","required":true,"description":"Id del ciclo di trattamento.","schema":{"type":"string"},"example":"e2f3a4b5-c6d7-4e8f-9a0b-1c2d3e4f5a6b"},"path_consentId":{"name":"consentId","in":"path","required":true,"description":"Id del consenso che porta l'informativa privacy firmata.","schema":{"type":"string"},"example":"3f2a8c1e-5b7d-4e2a-9c41-7d8e2b6a1f09"},"path_sedeId":{"name":"sedeId","in":"path","required":true,"description":"Id della sede.","schema":{"type":"string"},"example":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"},"path_memberId":{"name":"memberId","in":"path","required":true,"description":"Id del professionista della struttura.","schema":{"type":"string"},"example":"6b7c8d9e-0f1a-4b2c-9d3e-4f5a6b7c8d9e"},"path_inviteId":{"name":"inviteId","in":"path","required":true,"description":"Id dell'invito.","schema":{"type":"string"},"example":"7c8d9e0f-1a2b-4c3d-8e4f-5a6b7c8d9e0f"},"path_configId":{"name":"configId","in":"path","required":true,"description":"Id del modello di consenso.","schema":{"type":"string"},"example":"clx8k2m4p0001qz7h3v5n9b2d"},"path_equipmentId":{"name":"equipmentId","in":"path","required":true,"description":"Id dell'apparecchiatura.","schema":{"type":"string"},"example":"8d9e0f1a-2b3c-4d4e-9f5a-6b7c8d9e0f1a"},"path_lotId":{"name":"lotId","in":"path","required":true,"description":"Id della riga del registro lotti.","schema":{"type":"string"},"example":"9e0f1a2b-3c4d-4e5f-8a6b-7c8d9e0f1a2b"},"path_inkId":{"name":"inkId","in":"path","required":true,"description":"Id della riga del registro inchiostri.","schema":{"type":"string"},"example":"0f1a2b3c-4d5e-4f6a-9b7c-8d9e0f1a2b3c"},"path_operatorId":{"name":"operatorId","in":"path","required":true,"description":"Id dell'operatrice.","schema":{"type":"string"},"example":"1a2b3c4d-5e6f-4a7b-8c8d-9e0f1a2b3c4d"},"path_reasonId":{"name":"reasonId","in":"path","required":true,"description":"Id del motivo di consulto.","schema":{"type":"string"},"example":"2b3c4d5e-6f7a-4b8c-9d9e-0f1a2b3c4d5e"},"path_questionId":{"name":"questionId","in":"path","required":true,"description":"Id della domanda personalizzata.","schema":{"type":"string"},"example":"3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f"},"XConsensoSicuroSignature":{"name":"X-ConsensoSicuro-Signature","in":"header","required":true,"description":"Uno o due valori `v1=<hex>` separati da virgola. Ogni valore è l'HMAC-SHA256, in esadecimale, della stringa `{timestamp}.{corpo}`: il valore di X-ConsensoSicuro-Timestamp, un punto e il corpo esatto che ricevi, calcolato con il segreto del webhook. Dopo una rotazione del segreto, per 24 ore, ci sono due valori (segreto nuovo e precedente): la consegna è autentica se UNO dei due torna.","schema":{"type":"string"},"example":"v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"XConsensoSicuroTimestamp":{"name":"X-ConsensoSicuro-Timestamp","in":"header","required":true,"description":"Istante dell'invio in secondi Unix (cambia a ogni tentativo) ed è parte della stringa firmata. Rifiuta le consegne con un timestamp lontano più di 5 minuti dal tuo orologio: una consegna registrata e rispedita da qualcun altro non passa.","schema":{"type":"string"},"example":"1790000000"},"XConsensoSicuroEvent":{"name":"X-ConsensoSicuro-Event","in":"header","required":true,"description":"Nome dell'evento.","schema":{"type":"string"}},"XConsensoSicuroDeliveryId":{"name":"X-ConsensoSicuro-Delivery-Id","in":"header","required":true,"description":"Id della consegna: uguale fra un tentativo e le sue riprove, serve a deduplicare.","schema":{"type":"string"}},"query_from":{"name":"from","in":"query","description":"Inizio del periodo: una data (AAAA-MM-GG) o un istante ISO 8601.","schema":{"type":"string"},"example":"2026-09-01"},"query_to":{"name":"to","in":"query","description":"Fine del periodo, compresa: una data (AAAA-MM-GG) o un istante ISO 8601.","schema":{"type":"string"},"example":"2026-09-30"},"query_sedeId":{"name":"sedeId","in":"query","description":"Sede della struttura (in alternativa all'intestazione X-Structure-Sede-Id).","schema":{"type":"string"}},"query_limit":{"name":"limit","in":"query","description":"Da 1 a 100 (predefinito 25).","schema":{"type":"integer"},"example":25},"XIdempotencyKey":{"name":"X-Idempotency-Key","in":"header","description":"Facoltativa, fino a 128 caratteri. Un nuovo tentativo con la stessa chiave e lo stesso corpo riceve la risposta della prima volta invece di creare un doppione. Vale 24 ore.","schema":{"type":"string"},"example":"visita-119"},"query_redirect":{"name":"redirect","in":"query","description":"`1` (o `true`) per ricevere un 302 verso il file invece del JSON.","schema":{"type":"string"},"example":"1"},"query_format":{"name":"format","in":"query","description":"`json` per ricevere `contentBase64` invece dei byte del PDF; `pdf` (o nessun valore) per il file.","schema":{"type":"string","enum":["json","pdf"]}},"query_from_128d60":{"name":"from","in":"query","description":"Inizio del periodo (AAAA-MM-GG).","schema":{"type":"string"},"example":"2026-09-01"},"query_format_b4d6ef":{"name":"format","in":"query","description":"`pdf` (predefinito) o `json`.","schema":{"type":"string","enum":["pdf","json"]}},"query_search":{"name":"search","in":"query","description":"Numero di lotto o nome del prodotto, anche parziale: è la ricerca per il richiamo. `lotNumber` è un sinonimo.","schema":{"type":"string"},"example":"C1234"},"query_patientId":{"name":"patientId","in":"query","description":"Solo le registrazioni di quel paziente.","schema":{"type":"string"}},"query_memberId":{"name":"memberId","in":"query","description":"Solo quelle di quell'esecutore.","schema":{"type":"string"}},"query_to_283408":{"name":"to","in":"query","description":"Fine del periodo (AAAA-MM-GG).","schema":{"type":"string"},"example":"2026-09-30"},"query_page":{"name":"page","in":"query","description":"Pagina, da 1; 50 righe per pagina.","schema":{"type":"integer"},"example":1}},"schemas":{"Error":{"type":"object","description":"Forma di ogni errore: un messaggio in italiano e, quasi sempre, un codice stabile da usare nel tuo codice.","required":["error"],"properties":{"error":{"type":"string","description":"Messaggio leggibile, in italiano."},"code":{"type":"string","description":"Codice stabile dell'errore. L'elenco completo, uno per codice, è in `examples`; il significato su ogni operazione è nella descrizione della risposta.","examples":["ACCESS_NOT_MANAGED_VIA_API","ACCOUNT_MODELS_ONLY","ACCOUNT_MODEL_TREATMENTS_UNAVAILABLE","ACCOUNT_NOT_FOUND","AGORA_CONFIG_LOCKED","AGORA_DISABLED","AGORA_NOT_ACTIVE","AGORA_NOT_ELIGIBLE","AGORA_SUBSCRIPTION_REQUIRED","AGORA_TREATMENT_NOT_AVAILABLE","ALREADY_COUNTERSIGNED","ALREADY_RENEWED","ALREADY_RESENT","ALREADY_REVOKED","ANAMNESIS_ACK_REQUIRED","ANAMNESIS_NOT_AVAILABLE","API_KEY_INVALID","API_KEY_REQUIRED","API_TEST_CONSENT","CHANNEL_SWITCH_NOT_AVAILABLE","CLINIC_MEMBER_NOT_IN_SEDE","CLINIC_MEMBER_REQUIRED","CLINIC_MEMBER_SCOPE_MISMATCH","CLINIC_NO_SCOPES","CLINIC_SCOPE_NOT_ALLOWED","CLINIC_SCOPE_REQUIRED","CLINIC_SEDE_REQUIRED","CONFIGURATION_NOT_FOUND","CONFIG_INVALID_TREATMENTS","CONFIG_MAX_REACHED","CONFIG_NOT_FOUND","CONFIG_SOURCE_IMMUTABLE","CONFIG_SPECIFIC_NO_TREATMENTS","CONFIG_TEMPLATE_TYPE_NOT_ALLOWED","CONSENT_LANGUAGES_NOT_AVAILABLE","CONSENT_LANGUAGES_PROFESSION_NOT_SUPPORTED","CONSENT_LINK_EXPIRED","CONSENT_NOT_EXPIRED","CONSENT_NOT_FOUND","CONSENT_NOT_PENDING","CONSENT_NOT_RENEWABLE","CONSENT_QUOTA_EXCEEDED","COUNTERSIGNER_NOT_ASSIGNED","COUNTERSIGN_NOT_PENDING","COUNTERSIGN_NOT_REQUIRED","COUNTERSIGN_PHONE_NOT_VERIFIED","COUNTERSIGN_SESSION_RATE_LIMITED","CUSTOM_ENGAGEMENT_INCOMPLETE","CUSTOM_ENGAGEMENT_IT_ONLY","CUSTOM_PRIVACY_ADMIN_ONLY","CUSTOM_QUESTIONS_EXPIRY_REQUIRED","CUSTOM_QUESTIONS_LIMIT","CUSTOM_QUESTIONS_OPTIONS_INVALID","CYCLE_NOT_FOUND","DAILY_SEND_LIMIT","DELETE_DAILY_LIMIT","DELETE_REQUIRES_IP_ALLOWLIST","DELIVERY_NOT_FAILED","DOCUMENT_NOT_AVAILABLE","DOCUMENT_NOT_FOUND","DOCUMENT_PROTECTED","DOSSIER_GENERATION_FAILED","DOSSIER_NOT_AVAILABLE","DOSSIER_UNAVAILABLE","DUAL_SIGNATURE_NOT_AVAILABLE","DUAL_SIGNATURE_NOT_SCHEDULABLE","DUAL_SIGNATURE_PROFESSION_NOT_SUPPORTED","DUAL_SIGNATURE_REQUIRED","DUAL_SIGNATURE_SAME_PHONE","DUAL_SIGNATURE_SECOND_PARENT_MISSING","DUAL_SIGNATURE_TREATMENT_NOT_ELIGIBLE","DUPLICATE_CUSTOM_TREATMENT","DUPLICATE_EMAIL","EMPTY_PATCH","ENGAGEMENT_NOT_AVAILABLE","EQUIPMENT_LIMIT","EQUIPMENT_NOT_FOUND","EXECUTOR_AMBIGUOUS","EXECUTOR_CAPABILITY","EXECUTOR_REQUIRED","FEATURE_NOT_AVAILABLE","FIELD_NOT_AVAILABLE","FILE_REQUIRED","FILE_TOO_LARGE","GENERIC_EXECUTOR_NOT_AVAILABLE","GENERIC_EXECUTOR_SCOPE_INVALID","GUARDIANS_FOR_ADULT","GUARDIANS_REQUIRED","IDEMPOTENCY_IN_PROGRESS","IDEMPOTENCY_KEY_INVALID","IDEMPOTENCY_KEY_REUSED","IDENTITY_CONFLICT","INK_NOT_FOUND","INVALID_BASE64","INVALID_BODY","INVALID_BUSINESS_OPERATOR","INVALID_CHARACTERS","INVALID_CLINIC_MEMBER","INVALID_CLINIC_SEDE","INVALID_CURSOR","INVALID_EQUIPMENT","INVALID_JSON","INVALID_PHONE","INVALID_PROFESSION_TYPE","INVALID_QUERY","INVALID_SEDE","INVALID_SLOT","INVITE_LIMIT","INVITE_LIMIT_ADDRESS","INVITE_NOT_FOUND","INVITE_OWN_EMAIL","IN_STUDIO_NOT_SCHEDULABLE","IN_STUDIO_NO_DEVICE","IN_STUDIO_NO_MESSAGE_TO_RESEND","IP_NOT_ALLOWED","KEY_NOT_OWNER","LANGUAGE_NOT_ACTIVE","LANGUAGE_NOT_AVAILABLE","LANGUAGE_NOT_AVAILABLE_FOR_TEMPLATE","LANGUAGE_NOT_ENABLED","LANGUAGE_WITH_CUSTOM_PRIVACY","LAST_SEDE","LOT_NOT_FOUND","MEMBER_ALREADY_PRESENT","MEMBER_HAS_PENDING_COUNTERSIGN","MEMBER_IDENTITY_READ_ONLY","MEMBER_NOT_FOUND","MEMBER_PROFESSION_MISMATCH","MEMBER_REVOKED","MESSAGE_CHANNEL_LOCKED","MESSAGE_NOT_DELIVERED","METADATA_RESERVED_KEY","METADATA_TOO_LARGE","METADATA_TOO_MANY_KEYS","NOTES_TOO_LONG","NOT_A_STRUCTURE","NOT_DUAL_SIGNATURE","NOT_IN_STUDIO","NOT_SENT_VIA_WHATSAPP","NO_DATA_MISMATCH","OFFICE_NOT_FOUND","OPERATOR_LIMIT","OPERATOR_NOT_FOUND","ORIGIN_NOT_ALLOWED","PATIENT_DELETION_SCHEDULED","PATIENT_ID_REQUIRED","PATIENT_NOT_FOUND","PATIENT_PHONE_REQUIRED","PAYLOAD_TOO_LARGE","PAYMENT_FAILED","PHONE_BELONGS_TO_OTHER","PHONE_BELONGS_TO_OTHER_PATIENT","PHONE_CORRECTION_LIMIT","PREVIEW_LANGUAGE_NOT_AVAILABLE","PRIVACY_ONLY_NO_DUAL_SIGNATURE","PRIVACY_ONLY_WITH_PRIVACY_DISABLED","PRIVACY_TOGGLE_CLINIC_ONLY","PRIVATE_CONFIG_LOCKED","PRIVATE_SEND_VALUE_INVALID","PRIVATE_SEND_VALUE_REQUIRED","PRIVATE_SEND_VALUE_TOO_LONG","PRIVATE_SEND_VALUE_UNKNOWN","PRIVATE_TREATMENT_IT_ONLY","PRIVATE_TREATMENT_NOT_AVAILABLE","PROFESSION_NOT_ENABLED","PROFESSION_NOT_FOUND","PROFESSION_NOT_IN_SCOPES","PROFILE_FIELD_NOT_ALLOWED","PROFILE_INCOMPLETE","QUESTION_NOT_FOUND","RATE_LIMIT_EXCEEDED","REASON_ALREADY_EXISTS","REASON_NOT_FOUND","REGISTRY_NOT_AVAILABLE","RENEWAL_DUAL_SIGNATURE","RESEND_DUAL_SIGNATURE","RESEND_FAILED","RETENTION_ACK_REQUIRED","SAME_NUMBER","SCOPE_MISSING","SECRETARY_CANNOT_EXECUTE","SEDE_CONTEXT_MISMATCH","SEDE_HAS_MEMBERS","SEDE_NOT_ACCESSIBLE","SEDE_NOT_ALLOWED","SEDE_NOT_FOUND","SEDE_REQUIRED","SEND_GENERIC_NOT_ALLOWED_FOR_PROFESSION","SETTING_NOT_AVAILABLE","SLOT_NOT_APPLICABLE","SMS_SEND_FAILED","STRUCTURE_AMBIGUOUS","STRUCTURE_CONTEXT_REQUIRED","STRUCTURE_FROZEN","STRUCTURE_PLAN_INACTIVE","STRUCTURE_REQUIRED","STUDIO_TATTOO_ONLY","SUBSCRIPTION_GRACE_PERIOD","SUBSCRIPTION_REQUIRED","TEMPLATE_AMBIGUOUS","TEMPLATE_NOT_ENABLED_FOR_ACCOUNT","TEST_DAILY_LIMIT","TEST_KEY_DESTRUCTIVE","TEST_KEY_READ_ONLY","TREATMENT_NOT_IN_SCOPES","UNKNOWN_OPTIONAL_CONSENT","UNKNOWN_SECONDARY_PROFESSION","UNKNOWN_TREATMENT_CODE","UNSUPPORTED_FORMAT","VERIFICATION_LIMIT","VISITS_DISABLED","VISIT_NOT_FOUND","WEBHOOK_DISABLED","WEBHOOK_NOT_CONFIGURED","WEBHOOK_SECRET_UNAVAILABLE"]},"details":{"type":"array","description":"Sui corpi non validi: un elemento per ogni problema trovato.","items":{"type":"object"}}},"additionalProperties":true},"CursorPagination":{"type":"object","description":"Paginazione a cursore: passa `nextCursor` come `cursor` per la pagina dopo.","required":["limit","hasMore"],"properties":{"limit":{"type":"integer"},"total":{"type":"integer"},"hasMore":{"type":"boolean"},"nextCursor":{"type":["string","null"]}}},"Signer":{"type":"object","description":"Un firmatario del consenso: uno per link. Con la doppia firma per i minori sono due, P1 e P2.","required":["slot","status"],"properties":{"slot":{"type":"string","enum":["P1","P2"]},"role":{"type":"string","enum":["PATIENT","MOTHER","FATHER","LEGAL_GUARDIAN","FIRST_PARENT","SECOND_PARENT"]},"firstName":{"type":"string"},"lastName":{"type":"string"},"phoneHint":{"type":"string","description":"Ultime cifre del numero, per riconoscerlo."},"link":{"type":"string","description":"Link di firma (solo nella risposta all'invio)."},"status":{"type":"string","enum":["PENDING","SIGNED","REFUSED","EXPIRED"]},"signedAt":{"type":["string","null"],"format":"date-time"}},"additionalProperties":true},"Consent":{"type":"object","description":"Il consenso nella forma di `GET /consents/{id}`. Qui ci sono i campi principali; la risposta ne porta altri (consegna, controfirma, documenti, cronologia).","required":["id","status"],"properties":{"id":{"type":"string"},"status":{"type":"string","enum":["PENDING_SIGNATURE","PARTIALLY_SIGNED","ACTION_REQUIRED","COMPLETED","REFUSED","EXPIRED","CANCELLED"],"description":"Stato nel vocabolario dell'API."},"internalStatus":{"type":"string","description":"Stato interno del prodotto, per la granularità piena."},"consentType":{"type":"string","enum":["FULL","TREATMENT_ONLY","PRIVACY_ONLY"]},"isTest":{"type":"boolean","description":"true per i consensi creati con una chiave Test."},"expectedSignatures":{"type":"integer"},"receivedSignatures":{"type":"integer"},"signatures":{"type":"array","items":{"$ref":"#/components/schemas/Signer"}},"metadata":{"type":"object","additionalProperties":true,"description":"I tuoi riferimenti passati all'invio."}},"additionalProperties":true},"Patient":{"type":"object","description":"Un'anagrafica nella forma dell'elenco. Il codice fiscale non esce mai in chiaro: `hasFiscalCode` dice se c'è.","required":["id","firstName","lastName"],"properties":{"id":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"phone":{"type":["string","null"]},"externalId":{"type":["string","null"]},"hasFiscalCode":{"type":"boolean"},"isTest":{"type":"boolean"}},"additionalProperties":true},"WebhookEvent":{"type":"object","description":"Corpo di ogni consegna del webhook. Timestamp e corpo sono firmati con HMAC-SHA256: vedi le intestazioni X-ConsensoSicuro-Signature e X-ConsensoSicuro-Timestamp.","required":["event","timestamp"],"properties":{"event":{"type":"string","enum":["consent.created","consent.resent","consent.renewed","consent.phone_corrected","consent.delivery_failed","consent.partially_signed","consent.action_required","consent.countersigned","consent.completed","consent.refused","consent.expired","consent.cancelled","patient.created","patient.updated","patient.deleted","patient.privacy_revoked","patient.merged","patient.deletion_scheduled","patient.deletion_postponed","patient.deletion_cancelled","configuration.updated","structure.updated","ping"]},"timestamp":{"type":"string","format":"date-time"},"consent":{"type":"object","additionalProperties":true},"patient":{"type":"object","additionalProperties":true}},"additionalProperties":true},"Corpo_7e7429":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":50},"mode":{"type":"string","enum":["STANDARD","SPECIFIC"]},"source":{"type":"string","enum":["CUSTOM","AGORA","PRIVATE"]},"professionType":{"anyOf":[{"type":"string","enum":["OSTEOPATH","PHYSIOTHERAPIST","CHIROPRACTOR","PODIATRIST","PSYCHOLOGIST","PSYCHOTHERAPIST","PSYCHIATRIST","NUTRITIONIST","SPEECH_THERAPIST","AESTHETIC_DOCTOR","COMPLEMENTARY_MEDICINE","OCCUPATIONAL_THERAPIST","TNPEE","GYNECOLOGIST","DERMATOLOGIST","BEAUTICIAN","TATTOO_PIERCER","DENTIST","OPHTHALMOLOGIST","DENTAL_HYGIENIST","NURSE","OTHER"]},{"type":"null"}]},"treatments":{"default":[],"maxItems":300,"type":"array","items":{"type":"string","minLength":1,"maxLength":80}},"dualSignatureEnabled":{"default":false,"type":"boolean"},"medicalClearanceEnabled":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"sendMethod":{"anyOf":[{"type":"string","enum":["SMS","WHATSAPP"]},{"type":"null"}]},"isDefault":{"default":false,"type":"boolean"},"memberIds":{"default":[],"maxItems":50,"type":"array","items":{"type":"string"}},"validityMonths":{"anyOf":[{"type":"integer","minimum":1,"maximum":120},{"type":"null"}]},"autoRenewReminder":{"type":"boolean"}},"required":["name","mode"],"additionalProperties":false},"Corpo_9f1558":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":300},"help":{"anyOf":[{"type":"string","maxLength":500},{"type":"string","const":""}]},"type":{"type":"string","enum":["YES_NO","MULTIPLE_CHOICE","FREE_TEXT"]},"options":{"maxItems":10,"type":"array","items":{"type":"object","properties":{"key":{"type":"string","pattern":"^opt-\\d+$"},"label":{"type":"string","minLength":1,"maxLength":200}},"required":["label"]}},"displayDropdown":{"type":"boolean"},"allowOther":{"type":"boolean"},"multiSelect":{"type":"boolean"},"required":{"type":"boolean"},"active":{"type":"boolean"},"askPolicy":{"type":"string","enum":["ONCE","EVERY_CONSENT","EXPIRES"]},"expiryMonths":{"anyOf":[{"type":"integer","minimum":1,"maximum":120},{"type":"null"}]}},"required":["label","type"],"additionalProperties":false}},"responses":{"C400_1b513c":{"description":"STRUCTURE_AMBIGUOUS: L'account lavora per più strutture: la richiesta non dice quale.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"STRUCTURE_AMBIGUOUS":{"$ref":"#/components/examples/STRUCTURE_AMBIGUOUS"}}}}},"C401":{"description":"API_KEY_REQUIRED: Manca l'intestazione `Authorization: Bearer ak_live_…` (o `ak_test_…`). API_KEY_INVALID: La chiave non esiste, è scritta male, è stata revocata o è scaduta. La risposta è la stessa di proposito: chi trova una chiave vecchia non scopre se era vera. Il motivo preciso lo vedi nel registro richieste della dashboard.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"API_KEY_REQUIRED":{"$ref":"#/components/examples/API_KEY_REQUIRED"},"API_KEY_INVALID":{"$ref":"#/components/examples/API_KEY_INVALID"}}}}},"C403":{"description":"IP_NOT_ALLOWED: La richiesta arriva da un indirizzo IP che la chiave non consente. SCOPE_MISSING: La chiave non ha il permesso richiesto dalla rotta: `required` dice quale, `granted` quelli che ha. KEY_NOT_OWNER: L'intestazione `X-Structure-Sede-Id` indica una sede fuori dalla struttura della chiave. SEDE_NOT_ACCESSIBLE: La sede dell'intestazione `X-Structure-Sede-Id` non esiste o non è accessibile. STRUCTURE_FROZEN: La struttura è sospesa: le richieste si fermano finché il titolare non la riattiva. STRUCTURE_CONTEXT_REQUIRED: L'account lavora solo nel contesto di una struttura: indica la sede con `X-Structure-Sede-Id`. ORIGIN_NOT_ALLOWED: La richiesta arriva da un browser su un dominio che non è il nostro. Le API si chiamano dal tuo server.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"IP_NOT_ALLOWED":{"$ref":"#/components/examples/IP_NOT_ALLOWED"},"SCOPE_MISSING":{"$ref":"#/components/examples/SCOPE_MISSING"},"KEY_NOT_OWNER":{"$ref":"#/components/examples/KEY_NOT_OWNER"},"SEDE_NOT_ACCESSIBLE":{"$ref":"#/components/examples/SEDE_NOT_ACCESSIBLE"},"STRUCTURE_FROZEN":{"$ref":"#/components/examples/STRUCTURE_FROZEN"},"STRUCTURE_CONTEXT_REQUIRED":{"$ref":"#/components/examples/STRUCTURE_CONTEXT_REQUIRED"},"ORIGIN_NOT_ALLOWED":{"$ref":"#/components/examples/ORIGIN_NOT_ALLOWED"}}}}},"C413":{"description":"PAYLOAD_TOO_LARGE: Il corpo supera 1 MB (16 MB solo sul caricamento di un documento del paziente).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"PAYLOAD_TOO_LARGE":{"$ref":"#/components/examples/PAYLOAD_TOO_LARGE"}}}}},"C429":{"description":"RATE_LIMIT_EXCEEDED: Più di 300 richieste al minuto con la stessa chiave, o più di 900 al minuto sull'account (tutte le chiavi insieme). PDF, fascicoli, export e allegati: 120 all'ora per chiave; `POST /webhooks/test`: 10 all'ora per account. Oltre 600 al minuto dallo stesso IP la risposta è 429 senza `code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"RATE_LIMIT_EXCEEDED":{"$ref":"#/components/examples/RATE_LIMIT_EXCEEDED"}}}}},"E400_0007ef":{"description":"INVALID_BODY: Corpo non valido: un campo non previsto, un tipo sbagliato o un valore fuori intervallo. `details` elenca ogni problema.\nIDEMPOTENCY_KEY_INVALID: `X-Idempotency-Key` vuota o più lunga di 128 caratteri.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E400_1123b3":{"description":"INVALID_BODY: Corpo non valido: un campo non previsto, un tipo sbagliato o un valore fuori intervallo. `details` elenca ogni problema.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E400_11ffc2":{"description":"EMPTY_PATCH: Corpo senza nessun campo da modificare.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E400_4ed29e":{"description":"EQUIPMENT_LIMIT: Massimo 30 apparecchiature.\nINVALID_BODY: Corpo non valido: un campo non previsto, un tipo sbagliato o un valore fuori intervallo. `details` elenca ogni problema.\nIDEMPOTENCY_KEY_INVALID: `X-Idempotency-Key` vuota o più lunga di 128 caratteri.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E400_7ffcc6":{"description":"INVALID_QUERY: Parametro non valido.\nAnche STRUCTURE_AMBIGUOUS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E400_ba007d":{"description":"INVALID_QUERY: Data non valida o periodo invertito.\nAnche STRUCTURE_AMBIGUOUS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E400_c00cc7":{"description":"INVALID_QUERY: `format` diverso da `json` e `pdf`.\nAnche STRUCTURE_AMBIGUOUS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E400_cc85d9":{"description":"INVALID_BODY: Corpo vuoto o valore non valido.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E400_ea3988":{"description":"INVALID_BODY: Corpo non valido: un campo non previsto, un tipo sbagliato o un valore fuori intervallo. `details` elenca ogni problema.\nEMPTY_PATCH: Corpo senza nessun campo da modificare.\nAnche INVALID_JSON, STRUCTURE_AMBIGUOUS e gli altri comuni: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E400_f7d0da":{"description":"INVALID_QUERY: Data o pagina non valida.\nAnche STRUCTURE_AMBIGUOUS: components.responses.C400.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E403_62fb41":{"description":"SEDE_CONTEXT_MISMATCH: `sedeId` in contrasto con l'intestazione X-Structure-Sede-Id.\nAnche IP_NOT_ALLOWED, SCOPE_MISSING e gli altri comuni: components.responses.C403.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E403_8ec84f":{"description":"VISITS_DISABLED: La funzione visita non è attiva per questo account (o per la struttura per cui lavori): letture ed eliminazioni restano disponibili.\nAnche IP_NOT_ALLOWED, SCOPE_MISSING e gli altri comuni: components.responses.C403.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E403_b6af56":{"description":"TEST_KEY_READ_ONLY: Chiave in modalità Test: legge la configurazione ma non la modifica, perché sono dati veri condivisi con la dashboard.\nVISITS_DISABLED: La funzione visita non è attiva per questo account (o per la struttura per cui lavori): letture ed eliminazioni restano disponibili.\nAnche IP_NOT_ALLOWED, SCOPE_MISSING e gli altri comuni: components.responses.C403.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E403_e67711":{"description":"TEST_KEY_READ_ONLY: Chiave in modalità Test: legge la configurazione ma non la modifica, perché sono dati veri condivisi con la dashboard.\nAnche IP_NOT_ALLOWED, SCOPE_MISSING e gli altri comuni: components.responses.C403.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404_07f543":{"description":"FEATURE_NOT_AVAILABLE: Il registro non esiste per questo account (verticale, funzione spenta o tracciabilità non attiva), come in dashboard.\nEQUIPMENT_NOT_FOUND: Inesistente o altrui.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404_2ff6db":{"description":"FEATURE_NOT_AVAILABLE: Il registro non esiste per questo account (verticale, funzione spenta o tracciabilità non attiva), come in dashboard.\nOPERATOR_NOT_FOUND: Inesistente o altrui.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404_3e6f05":{"description":"DOCUMENT_NOT_FOUND: Il documento non esiste o non è di questo paziente.\nPATIENT_NOT_FOUND: Il paziente non esiste, non è di questo account, è fuori dal contesto di sede o ha una cancellazione programmata (stessa risposta).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404_60f951":{"description":"DOCUMENT_NOT_AVAILABLE: Il documento esiste solo dopo la firma: il consenso non è ancora completato, oppure l'invio non comprendeva questo documento.\nCONSENT_NOT_FOUND: Il consenso non esiste, non è di questo account o è di un paziente con una cancellazione programmata. Con una chiave Test risponde così anche un consenso vero. Con una chiave di produzione, su un id inesistente, il 404 può arrivare senza `code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404_682e37":{"description":"VISIT_NOT_FOUND: La visita non esiste o non è di questo paziente.\nPATIENT_NOT_FOUND: Il paziente non esiste, non è di questo account, è fuori dal contesto di sede o ha una cancellazione programmata (stessa risposta).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404_6f6ef5":{"description":"REASON_NOT_FOUND: Inesistente o altrui.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404_78f260":{"description":"CONFIG_NOT_FOUND: Modello inesistente o di un altro account (stessa risposta).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404_7b2797":{"description":"FEATURE_NOT_AVAILABLE: Il registro non esiste per questo account (verticale, funzione spenta o tracciabilità non attiva), come in dashboard.\nQUESTION_NOT_FOUND: Inesistente o altrui.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404_7e5f59":{"description":"FEATURE_NOT_AVAILABLE: Il registro non esiste per questo account (verticale, funzione spenta o tracciabilità non attiva), come in dashboard.\nINK_NOT_FOUND: Registrazione inesistente o altrui.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404_83506c":{"description":"SEDE_NOT_FOUND: `sedeId` non è di questo account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404_852ca1":{"description":"FEATURE_NOT_AVAILABLE: Il registro non esiste per questo account (verticale, funzione spenta o tracciabilità non attiva), come in dashboard.\nLOT_NOT_FOUND: Registrazione inesistente o altrui.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404_bba791":{"description":"CYCLE_NOT_FOUND: Il ciclo non esiste o non è di questo paziente.\nPATIENT_NOT_FOUND: Il paziente non esiste, non è di questo account, è fuori dal contesto di sede o ha una cancellazione programmata (stessa risposta).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404_cc628f":{"description":"CONSENT_NOT_FOUND: Il consenso non esiste, non è di questo account o è di un paziente con una cancellazione programmata. Con una chiave Test risponde così anche un consenso vero. Con una chiave di produzione, su un id inesistente, il 404 può arrivare senza `code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404_cf8178":{"description":"CONFIG_NOT_FOUND: Modello inesistente o di un altro account (stessa risposta).\nMEMBER_NOT_FOUND: Un professionista di `memberIds` non esiste, non è attivo, è la segreteria o è di un altro account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404_d7bb52":{"description":"FEATURE_NOT_AVAILABLE: Il registro non esiste per questo account (verticale, funzione spenta o tracciabilità non attiva), come in dashboard.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404_e63ffc":{"description":"PROFESSION_NOT_FOUND: Professione non esercitata dall'account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404_f87668":{"description":"PATIENT_NOT_FOUND: Il paziente non esiste, non è di questo account, è fuori dal contesto di sede o ha una cancellazione programmata (stessa risposta).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404_f8d9f9":{"description":"NOT_A_STRUCTURE: L'account è un professionista singolo: sedi e professionisti esistono solo per strutture e studi.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E409_9b1101":{"description":"IDEMPOTENCY_KEY_REUSED / IDEMPOTENCY_IN_PROGRESS: La stessa `X-Idempotency-Key` è già stata usata con un corpo diverso, oppure la prima richiesta con quella chiave è ancora in corso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"WebhookOk":{"description":"Qualunque risposta 2xx conferma la consegna. Un altro codice, o nessuna risposta entro 10 secondi, fa partire le riprove."}},"requestBodies":{"WebhookEvent":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}}},"examples":{"API_KEY_INVALID":{"value":{"error":"Messaggio in italiano","code":"API_KEY_INVALID"}},"API_KEY_REQUIRED":{"value":{"error":"Messaggio in italiano","code":"API_KEY_REQUIRED"}},"IP_NOT_ALLOWED":{"value":{"error":"Messaggio in italiano","code":"IP_NOT_ALLOWED"}},"KEY_NOT_OWNER":{"value":{"error":"Messaggio in italiano","code":"KEY_NOT_OWNER"}},"ORIGIN_NOT_ALLOWED":{"value":{"error":"Messaggio in italiano","code":"ORIGIN_NOT_ALLOWED"}},"PAYLOAD_TOO_LARGE":{"value":{"error":"Messaggio in italiano","code":"PAYLOAD_TOO_LARGE"}},"RATE_LIMIT_EXCEEDED":{"value":{"error":"Messaggio in italiano","code":"RATE_LIMIT_EXCEEDED"}},"SCOPE_MISSING":{"value":{"error":"Messaggio in italiano","code":"SCOPE_MISSING"}},"SEDE_NOT_ACCESSIBLE":{"value":{"error":"Messaggio in italiano","code":"SEDE_NOT_ACCESSIBLE"}},"STRUCTURE_AMBIGUOUS":{"value":{"error":"Messaggio in italiano","code":"STRUCTURE_AMBIGUOUS"}},"STRUCTURE_CONTEXT_REQUIRED":{"value":{"error":"Messaggio in italiano","code":"STRUCTURE_CONTEXT_REQUIRED"}},"STRUCTURE_FROZEN":{"value":{"error":"Messaggio in italiano","code":"STRUCTURE_FROZEN"}},"Risposta_a94cc7":{"value":{"member":{"id":"uuid","firstName":"Carla","lastName":"Esecutrice","role":"COLLABORATOR","status":"ACTIVE","relationshipType":"EMPLOYEE","sedeIds":["uuid-sede"],"professions":["PHYSIOTHERAPIST"],"enabledTreatmentIds":null,"onlyAssignedModels":false,"tattooCapabilities":[],"access":{"hasAccess":false,"email":null,"linked":false,"pendingInvite":false},"canExecute":true}}},"Risposta_22db9c":{"value":{"configuration":{"id":"ck…","name":"Prima visita","source":"CUSTOM","mode":"SPECIFIC","professionType":"PSYCHOLOGIST","treatments":["psi-colloquio","psi-valutazione"],"isDefault":true,"dualSignatureEnabled":false,"medicalClearanceEnabled":null,"sendMethod":"WHATSAPP","memberIds":[],"validityMonths":null,"autoRenewReminder":false}}}}}}
