Dentolize Plugin Platform — Getting Started
Dentolize plugins are external applications: you host your own service, and it integrates with a clinic's Dentolize account through a scoped REST API and signed webhooks. Your code never runs inside Dentolize, and Dentolize never stores your infrastructure's data.
How the pieces fit
- Listing — Xolize publishes your plugin into the in-app Plugin Hub after review (v1 has no self-serve portal; contact devrel@dentolize.com to start).
- Installation — a clinic owner installs your plugin from the Hub, reviews the data scopes and webhook events you request in plain language, and accepts the Data Processing Agreement (DPA). Consent is all-or-nothing over your required scopes; scopes you declare as optional get per-scope toggles (default off — see Authentication & Scopes).
- Credentials — installation mints a scoped API token (
dtz_live_…/dtz_test_…) shown once to the clinic, which configures it into your service alongside the webhook signing secret (whsec_…). - Runtime — Dentolize pushes signed webhook events to your endpoint (thin payloads: ids and minimal state, never patient names/phones). Your service pulls details through
GET /api/v1/...with the token, subject to your granted scopes. - Settings — your listing declares a JSON settings schema; Dentolize renders the form natively (Arabic + English) and your service reads the values via
GET /api/v1/installation.
Quickstart (sandbox)
- Request sandbox access; you receive a
dtz_test_…token, a demo-clinic login on the sharedplugin-devsandbox, and your draft listing. - Install the SDK:
npm i @dentolize/plugin-sdk. - Make your first call:
import { Dentolize } from '@dentolize/plugin-sdk'
const client = new Dentolize({
token: process.env.DENTOLIZE_TOKEN,
baseUrl: 'https://plugin-dev.sandbox.anastawfik.com/api/v1'
})
console.log(await client.ping())
// Discover the clinic you are installed in (clinic:read): profile, branches,
// staff and reference catalogs — the ids other resources refer to.
const clinic = await client.clinic.get()
const branches = await client.branches.list()
const doctors = await client.practitioners.list({ isDoctor: true })
console.log(clinic.name, branches.data.length, doctors.data.length)
for await (const appointment of client.appointments.iterate({ from: '2026-07-01', to: '2026-07-31' })) {
console.log(appointment.id, appointment.status)
}
- Expose a local webhook receiver with a tunnel (cloudflared/ngrok), register the endpoint from your plugin's settings page (Connection tab), press Send test event, and verify the signature with
verifyWebhookSignature(see Webhooks).
The examples/appointment-reminder-bot app in the SDK repository is a complete working reference.
Ground rules
- PII is opt-in and audited. Patient identity fields require the
patients:read.piiscope; every PII read is logged with your token id and the record ids. Webhook payloads never contain PII. - Honor deletion.
patient.deletedandinstallation.uninstalledevents oblige you (contractually, via the DPA) to purge related data within 30 days. - Respect rate limits. 300 weighted requests/min per live token (60/min test); on
429, waitRetry-After. The SDK does this automatically. - Idempotency. Every
POSTrequires anIdempotency-Keyheader; replays return the original response. - Versioning. The API is versioned by URL (
/api/v1) and aDentolize-Versiondate header (current:2026-07). Changes without a version bump are strictly additive.