Skip to main content
Indirizzo: https://api.dentalspace.ai/v1. Autenticazione: header Authorization: Bearer dsk_live_... su ogni richiesta. Specifica sorgente: openapi.json.

La chiave che sta chiamando

GET /me Clinica, chiave (scope, sedi, scadenza), limiti e modalita’. Basta una chiave valida, senza scope.

Risposte

Campi della risposta

Stato del servizio

GET /health Non richiede chiave. Senza chiave. 200 se l’API e il database rispondono, 503 unavailable altrimenti.

Risposte

Campi della risposta

Specifica OpenAPI 3.1

GET /openapi.json Non richiede chiave. Senza chiave. Generata dagli stessi schemi che validano le richieste.

Risposte

Le sedi della clinica

GET /facilities Scope: clinic:read. Indirizzo, telefono e orari di apertura. Una chiave limitata a delle sedi vede solo quelle.

Parametri

Risposte

Campi della risposta

Una sede

GET /facilities/{id} Scope: clinic:read. Dove siete e che orari fate.

Parametri

Risposte

Campi della risposta

Le poltrone attive di una sede

GET /facilities/{id}/chairs Scope: clinic:read.

Parametri

Risposte

Campi della risposta

I medici della clinica

GET /doctors Scope: clinic:read. Nome, specialita’ e sedi in cui lavorano; nessun dato di contatto. Una chiave limitata a delle sedi vede solo i medici di quelle sedi (una pagina puo’ quindi contenere meno di limit medici).

Parametri

Risposte

Campi della risposta

I calendari prenotabili

GET /calendars Scope: clinic:read. Con le regole di prenotazione: preavviso, orizzonte, disdetta e spostamento consentiti, prestazioni e medici.

Parametri

Risposte

Campi della risposta

Un calendario

GET /calendars/{id} Scope: clinic:read.

Parametri

Risposte

Campi della risposta

Il listino

GET /treatments Scope: clinic:read. Codice, nome, durata e prezzo delle prestazioni. Di default solo quelle attive. L’elenco e’ ordinato per id: updatedSince non e’ disponibile (400).

Parametri

Risposte

Campi della risposta

Una prestazione

GET /treatments/{id} Scope: clinic:read.

Parametri

Risposte

Campi della risposta

Chi e’ questo numero?

GET /patients/lookup Scope: patients:read. Confronto esatto sul numero (in qualunque formato). kind: patient se e’ di un paziente, family se lo stesso numero e’ di piu’ pazienti (genitore e figli), lead se non e’ di nessun paziente ma di un contatto commerciale, null se non lo conosciamo. I candidati hanno solo nome, anno di nascita e ultime 4 cifre.

Parametri

Risposte

Campi della risposta

Cerca un paziente

GET /patients/search Scope: patients:read. Trova la persona anche scritta male: nome, telefono in qualunque forma, codice fiscale, email. Restituisce pochi candidati con il punteggio; closeMatches dice quanti sono altrettanto probabili del migliore.

Parametri

Risposte

Campi della risposta

Elenco dei pazienti

GET /patients Scope: patients:read. Anagrafica, senza dati sanitari (quelli stanno solo nella scheda e nel /clinical, con clinical:read). Di default solo i pazienti attivi. Per cercare per nome usa /patients/search.

Parametri

Risposte

Campi della risposta

Crea un paziente

POST /patients Scope: patients:write. 409 conflict (details.patientId) se esiste gia’ un paziente con lo stesso nome e la stessa email o lo stesso telefono. Allergie, farmaci, condizioni e note richiedono anche clinical:write. Con Idempotency-Key un nuovo tentativo non crea un secondo paziente.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

La scheda di un paziente

GET /patients/{id} Scope: patients:read. Con clinical:read la scheda include allergie, farmaci, condizioni e note, e la lettura entra nel registro accessi. L’header ETag va rimandato come If-Match per modificarla.

Parametri

Risposte

Campi della risposta

Modifica un paziente

PATCH /patients/{id} Scope: patients:write. Solo i campi indicati; null svuota un campo (non il nome). If-Match col valore di ETag della scheda: se e’ cambiata, 409. Allergie, farmaci, condizioni e note richiedono anche clinical:write.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Archivia un paziente

POST /patients/{id}/archive Scope: patients:write. Non cancella niente: il paziente esce dagli elenchi (archived=true per vederli) e si puo’ riattivare. Ripeterla non cambia nulla.

Parametri

Risposte

Campi della risposta

Riattiva un paziente archiviato

POST /patients/{id}/restore Scope: patients:write. Riporta fra gli attivi un paziente archiviato. Ripeterla non cambia nulla.

Parametri

Risposte

Campi della risposta

Gli appuntamenti di un paziente

GET /patients/{id}/appointments Scope: patients:read e appointments:read. upcoming=true: solo quelli che devono ancora avvenire e non sono disdetti, saltati o conclusi. Senza note cliniche. Titolo e motivo sono testo libero: la lettura finisce nel registro accessi. Ordinati per ultima modifica.

Parametri

Risposte

Campi della risposta

I preventivi di un paziente

GET /patients/{id}/treatment-plans Scope: patients:read e treatment_plans:read. Riepilogo senza voci, denti e diagnosi (il dettaglio e’ in /treatment-plans/\{id\}). Esclusi quelli eliminati.

Parametri

Risposte

Campi della risposta

I dati sanitari di un paziente

GET /patients/{id}/clinical Scope: clinical:read. Allergie, farmaci, condizioni e odontogramma. Serve lo scope clinical:read (spento di default) e ogni lettura viene registrata nel registro accessi della clinica.

Parametri

Risposte

Campi della risposta

I documenti di un paziente

GET /patients/{id}/documents Scope: documents:read. I documenti da firmare del paziente (consensi, moduli) con lo stato della firma. Solo i metadati: il contenuto e’ in /documents/\{id\}. Il titolo e’ testo libero: la lettura finisce nel registro accessi. Ordinati per data di creazione.

Parametri

Risposte

Campi della risposta

Orari liberi di un calendario

GET /calendars/{id}/availability Scope: appointments:read. Gli orari prenotabili fra from e to, con le regole del calendario (medici, fasce, durata, preavviso, orizzonte). In un calendario «scelta del paziente» lo stesso orario compare una volta per ogni medico libero, e ognuno conta in limit. La risposta dice la finestra davvero cercata (window) e se gli orari sono tutti (complete); se no, si continua con from=nextFrom. Una pagina non spezza un orario fra i suoi medici: se a uno stesso orario i medici liberi sono piu’ di limit, 400 su limit.

Parametri

Risposte

Campi della risposta

Prenota un orario

POST /calendars/{id}/bookings Scope: appointments:write. Ricontrolla l’orario con le regole del calendario e lo prenota (stato scheduled). 409 no_availability se non e’ piu’ libero (reason: slot_taken) o non rispetta il preavviso (reason: min_notice), con details.alternatives; 409 conflict con reason: booking_disabled se il calendario non accetta prenotazioni da fuori.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Elenco degli appuntamenti

GET /appointments Scope: appointments:read. In ordine di ultima modifica (updatedSince per sincronizzare), o di orario con sort=start. Senza note ne’ note cliniche: si leggono dal dettaglio, con clinical:read. Titolo e motivo sono testo libero: la lettura finisce nel registro accessi.

Parametri

Risposte

Campi della risposta

Crea un appuntamento fuori calendario

POST /appointments Scope: appointments:write. Per i gestionali che sanno gia’ medico, sede e orario: nessuna regola di calendario, solo il controllo di sovrapposizione su medico e poltrona (409 no_availability, reason: slot_taken). Per prenotare per conto di un paziente usa /calendars/{id}/bookings.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Un appuntamento

GET /appointments/{id} Scope: appointments:read. Con l’ETag da rimandare in If-Match. Note e note cliniche solo con clinical:read.

Parametri

Risposte

Campi della risposta

Modifica titolo, motivo o note

PATCH /appointments/{id} Scope: appointments:write. Solo i testi: per l’orario c’e’ /move, per lo stato /status. Con If-Match (l’ETag ricevuto) la modifica passa solo se nessuno ha cambiato l’appuntamento nel frattempo, altrimenti 409 conflict.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Sposta un appuntamento

POST /appointments/{id}/move Scope: appointments:write. Cambia solo l’orario (medico, sede e durata restano), con le regole del calendario di provenienza. 409 no_availability (slot_taken / min_notice) con details.alternatives; 409 conflict con reason reschedule_disabled, status_not_movable, doctor_not_in_calendar o no_calendar.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Disdici un appuntamento

POST /appointments/{id}/cancel Scope: appointments:write. La disdetta del paziente, con le regole del calendario di provenienza. 409 conflict con reason cancel_disabled, min_notice, status_not_cancellable o no_calendar. Lo staff che annulla senza regole usa /status con cancelled.

Parametri

Risposte

Campi della risposta

Conferma la presenza

POST /appointments/{id}/confirm Scope: appointments:write. Porta l’appuntamento in confirmed (da draft o scheduled). 409 conflict con reason: transition_not_allowed, details.status e details.allowedTransitions; 409 no_availability se rimetterlo in agenda si sovrapporrebbe a un altro.

Parametri

Risposte

Campi della risposta

Cambia lo stato

POST /appointments/{id}/status Scope: appointments:write. Il cambio di stato dello staff, lungo lo stesso grafo dell’app (completed no: lo scrive il completamento della visita). Nessuna regola di calendario: la disdetta del paziente e’ /cancel. 409 conflict con reason: transition_not_allowed, details.status e details.allowedTransitions; 409 no_availability se rimetterlo in agenda si sovrapporrebbe a un altro.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Elenco dei preventivi

GET /treatment-plans Scope: treatment_plans:read. Senza voci e senza dati clinici; quelli nel cestino non compaiono.

Parametri

Risposte

Campi della risposta

Crea una bozza di preventivo dal listino

POST /treatment-plans Scope: treatment_plans:write. I prezzi sono quelli del listino. Nasce sempre come bozza (draft): la conferma una persona nell’app.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Un preventivo, con le voci

GET /treatment-plans/{id} Scope: treatment_plans:read. Con lo scope clinical:read anche denti, superfici, odontogramma e diagnosi (e l’accesso finisce nel registro).

Parametri

Risposte

Campi della risposta

Cambia lo stato di un preventivo

POST /treatment-plans/{id}/status Scope: treatment_plans:write. proposed → standby (presentato) · proposed/standby → accepted/rejected. Una bozza non cambia stato via API.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Elenco delle fatture

GET /invoices Scope: billing:read.

Parametri

Risposte

Campi della risposta

Una fattura, con le righe

GET /invoices/{id} Scope: billing:read.

Parametri

Risposte

Campi della risposta

Gli incassi di una fattura

GET /invoices/{id}/payments Scope: billing:read.

Parametri

Risposte

Campi della risposta

Registra un incasso

POST /invoices/{id}/payments Scope: billing:write. Solo su fatture emesse o scadute, fino al saldo. Chiede Idempotency-Key. Saldata, la fattura passa a paid.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Piani di pagamento e rate

GET /payment-plans Scope: billing:read. state=open (predefinito): rate non pagate · overdue: non pagate e scadute · all: tutte.

Parametri

Risposte

Campi della risposta

POST /payment-links Scope: billing:write. Un link Stripe (Checkout, sul conto collegato della clinica) per il residuo di una fattura emessa o scaduta, o di una rata non pagata. L’importo non si sceglie. Non invia niente: restituisce l’URL. Chiede Idempotency-Key. Con una chiave di prova verifica tutto ma non crea il link (livemode: false, url: null).

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Un documento del paziente

GET /documents/{id} Scope: documents:read. Un documento da firmare (consenso, modulo, preventivo) con lo stato della firma. Non e’ un file: con clinical:read esce il contenuto (HTML) e la firma. Niente download e niente upload: vedi la guida.

Parametri

Risposte

Campi della risposta

Elenco delle attivita’

GET /tasks Scope: tasks:read. Ordinate per ultima modifica; updatedSince per la sincronizzazione incrementale.

Parametri

Risposte

Campi della risposta

Crea un’attivita’

POST /tasks Scope: tasks:write. Con Idempotency-Key un nuovo tentativo non crea un doppione. Una chiave limitata a delle sedi deve indicare facilityId.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Modifica un’attivita’

PATCH /tasks/{id} Scope: tasks:write. Solo i campi mandati cambiano; null toglie scadenza o assegnatario. Con If-Match (l’ETag ricevuto) la modifica fallisce con 409 se qualcuno l’ha cambiata nel frattempo.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Elenco dei lead

GET /leads Scope: leads:read. Ordinati per ultima modifica. Le attivita’ si leggono dal dettaglio.

Parametri

Risposte

Campi della risposta

Crea un lead

POST /leads Scope: leads:write. Se esiste gia’ un lead con lo stesso telefono (qualunque formato: si confronta quello normalizzato) o la stessa email, NON ne crea un altro: risponde 200 con quello esistente e deduplicated: true, senza modificarlo. Una chiamata da un numero sconosciuto e’ un lead con source: "phone". Una chiave limitata a delle sedi deve indicare facilityId.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Un lead

GET /leads/{id} Scope: leads:read.

Parametri

Risposte

Campi della risposta

Modifica un lead

PATCH /leads/{id} Scope: leads:write. Solo i campi mandati cambiano; null svuota un campo facoltativo. Un cambio di status riparte il conteggio dei giorni nello stadio. Per convertire in paziente usa POST /leads/\{id\}/convert. Con If-Match la modifica fallisce con 409 se il lead e’ cambiato nel frattempo.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Aggiungi un’attivita’ a un lead

POST /leads/{id}/activities Scope: leads:write. Una nota o un contatto (chiamata, email, WhatsApp, incontro). I contatti aggiornano anche l’ultimo contatto del lead.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Converti un lead in paziente

POST /leads/{id}/convert Scope: leads:write e patients:write. Crea il paziente dai dati del lead e segna il lead come convertito. Serve il cognome: se il lead non ce l’ha, mandalo in lastName. Un lead gia’ convertito risponde 409. Chiede sia leads:write sia patients:write.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Elenco delle conversazioni WhatsApp

GET /conversations Scope: messages:read. Ordinate per ultima modifica; updatedSince per la sincronizzazione incrementale.

Parametri

Risposte

Campi della risposta

I messaggi di una conversazione

GET /conversations/{id}/messages Scope: messages:read. In ordine di arrivo. updatedSince filtra per istante di arrivo. La trascrizione dei vocali c’e’ solo con lo scope clinical:read (e patients:read) e solo se la conversazione e’ di un paziente. Il testo esce con messages:read, ma ogni lettura che lo contiene finisce nel registro accessi come accesso a dati clinici.

Parametri

Risposte

Campi della risposta

Manda un messaggio WhatsApp

POST /conversations/{id}/messages Scope: messages:write. Accoda un messaggio di testo al numero della conversazione (parte con il ritmo del numero della clinica, non subito). 409 se il paziente ha scritto STOP o se il bot e’ in pausa o spento su quel filo (una persona sta gestendo la conversazione). 409 anche se in coda ci sono gia’ 5 messaggi dell’API per quel numero (recipient_queue_full) o 200 per la clinica (queue_full). Passano dopo i promemoria e le automazioni della clinica; revocata la chiave, i suoi messaggi non ancora partiti si annullano. Chiede Idempotency-Key: un nuovo tentativo con la stessa chiave non manda due volte. Con una chiave di prova non parte nulla.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Stato del bot su una conversazione

PATCH /conversations/{id}/bot Scope: messages:write. \{ "state": "attivo" \} lo riaccende; \{ "state": "in_pausa", "pausedUntil": "<istante futuro>" \} lo mette in pausa fino a quell’istante (al massimo 7 giorni). Se una persona l’ha spento (allo_studio) si puo’ solo riaccendere, non mettere in pausa.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Registra una telefonata conclusa

POST /calls Scope: calls:write. Idempotente su externalCallId: 201 la prima volta, 200 con la riga gia’ registrata dopo. Un numero sconosciuto diventa un lead con source=phone.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Elenca le telefonate

GET /calls Scope: calls:read. In ordine di registrazione. updatedSince guarda l’istante di registrazione (una telefonata non cambia).

Parametri

Risposte

Campi della risposta

Una telefonata

GET /calls/{id} Scope: calls:read. Con lo scope clinical:read anche la trascrizione (l’accesso finisce nel registro).

Parametri

Risposte

Campi della risposta

Briefing prima della chiamata

POST /voice/context Scope: patients:read e appointments:read. Chi e’ il numero e cosa ha in sospeso, senza dati clinici. 403 reason ai_disabled se la clinica ha spento l’AI.

Corpo (JSON)

Risposte

Campi della risposta

Passa la chiamata alla segreteria

POST /voice/handoff Scope: tasks:write. Crea un’attivita’ di richiamo. Un numero sconosciuto diventa un lead con source=phone. 403 reason ai_disabled se la clinica ha spento l’AI.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Elenca gli eventi

GET /events Scope: webhooks:read. Gli eventi degli ultimi 30 giorni, nella stessa busta dei webhook. updatedSince filtra sull’istante in cui l’evento e’ diventato visibile. Si vedono solo i tipi coperti dagli scope della chiave. Gli eventi che non sono nati lasciano un events.skipped con data.reason (bulk_import: piu’ di 50 *.created insieme; no_active_key: un periodo senza chiavi attive, da data.from a data.to; error: il trigger e’ fallito), data.type, data.scope e data.count: da li’ si risincronizza con updatedSince sugli elenchi.

Parametri

Risposte

Campi della risposta

Elenca le destinazioni dei webhook

GET /webhook-endpoints Scope: webhooks:read. Le destinazioni create da questa chiave (o da quella che ha rigenerato).

Parametri

Risposte

Campi della risposta

Crea una destinazione dei webhook

POST /webhook-endpoints Scope: webhooks:write. Al massimo 20 per clinica. Il segreto si vede solo nella risposta. Gli eventi sono filtrati con gli scope e le sedi di QUESTA chiave. Ogni webhook e’ un POST JSON firmato: calcola HMAC-SHA256(segreto, “v1\n” + X-DentalSpace-Timestamp + “\n” + X-DentalSpace-Idempotency-Key + “\n” + corpo) e confrontalo con uno dei valori v1= di X-DentalSpace-Signature; rifiuta i timestamp piu’ vecchi di 5 minuti e scarta le Idempotency-Key gia’ viste. Rispondi 2xx entro 10 secondi; altrimenti si ritenta dopo 1, 5, 15 minuti e 1 ora. I redirect non si seguono.

Corpo (JSON)

Risposte

Campi della risposta

Una destinazione

GET /webhook-endpoints/{id} Scope: webhooks:read.

Parametri

Risposte

Campi della risposta

Modifica una destinazione

PATCH /webhook-endpoints/{id} Scope: webhooks:write. URL, eventi, descrizione, accesa/spenta. Con If-Match (l’ETag della GET) non sovrascrive modifiche altrui.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Elimina una destinazione

DELETE /webhook-endpoints/{id} Scope: webhooks:write. Non riceve piu’ niente e i suoi segreti si cancellano. Le consegne gia’ fatte restano leggibili 30 giorni.

Parametri

Risposte

Campi della risposta

Ruota il segreto di una destinazione

POST /webhook-endpoints/{id}/rotate-secret Scope: webhooks:write.

Parametri

Corpo (JSON)

Risposte

Campi della risposta

Manda un webhook di prova

POST /webhook-endpoints/{id}/test Scope: webhooks:write. Un evento webhook.test con data {}, firmato come gli altri. Funziona anche su una destinazione spenta.

Parametri

Risposte

Campi della risposta

Elenca le consegne dei webhook

GET /webhook-deliveries Scope: webhooks:read. Le consegne degli ultimi 30 giorni alle destinazioni di questa chiave.

Parametri

Risposte

Campi della risposta

Una consegna, con i suoi tentativi

GET /webhook-deliveries/{id} Scope: webhooks:read.

Parametri

Risposte

Campi della risposta

Rimanda una consegna

POST /webhook-deliveries/{id}/redeliver Scope: webhooks:write. Solo una consegna succeeded o discarded, verso una destinazione accesa. Parte entro una decina di secondi. Al massimo 3 volte per consegna: oltre, 409 con reason redeliver_limit.

Parametri

Risposte

Campi della risposta

Oggetto errore

Tutte le risposte di errore hanno questo formato.