OdontoX API Reference
Generated from source:server/src/routes/+server/src/lib/permissions.ts
Last updated: 2026-05-09
Base URL:https://api.odontox.io/api/v1
Role Hierarchy
| Role | Scope | Description |
|---|---|---|
| superadmin | Platform | Anthropic-level god mode. Bypasses all permission checks. Manages clinics, licenses, and impersonation. |
| admin | Clinic | Clinic owner/manager. Gets full plan-tier permissions. Template/per-user overrides do NOT apply (prevents accidental lockout). |
| doctor | Clinic | Clinical practitioner. Full clinical access + billing. IPD and Bridge are plan-gated. |
| receptionist | Clinic | Front-desk staff. Appointment + patient + billing access. No write access to clinical notes or dental charts. |
| patient | Self | Portal user. Read-only access to their own data. Can accept treatment plans, view invoices, send messages. |
Permission Resolution Layers (non-admin roles)
- Pro plan: base permission set (no IPD, no Bridge for doctors; reduced AI for receptionists)
- Pro+ / Enterprise: full permission set including inventory write for receptionist, full AI suite
Permission Key Reference
Each key maps to a namedrequirePermission(key) call in the route handlers. The role columns show which roles have this permission by default at the stated plan tier. Admins always get all plan-tier permissions.
Legend: ✓ = granted by default · P = Pro only · PP = Pro+ / Enterprise only · - = not granted
Appointments (10 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
appointments.view | See appointment list and calendar | ✓ | ✓ | ✓ (own) | Pro |
appointments.view_detail | Open a specific appointment’s detail page | ✓ | ✓ | ✓ (own) | Pro |
appointments.create | Book a new appointment | ✓ | ✓ | - | Pro |
appointments.edit | Change time, doctor, notes on an existing appointment | ✓ | ✓ | - | Pro |
appointments.delete | Cancel and remove an appointment | ✓ | ✓ | - | Pro |
appointments.change_status | Move through lifecycle: confirmed → arrived → in-chair → completed | ✓ | ✓ | - | Pro |
appointments.send_summary | Email/WhatsApp the appointment summary to the patient | ✓ | ✓ | - | Pro |
appointments.view_all_doctors | See appointments belonging to other doctors (not just own schedule) | ✓ | ✓ | - | Pro |
appointments.block_time | Mark a slot as blocked / holiday so it can’t be booked | ✓ | - | - | Pro |
appointments.export | Download appointment list as CSV/PDF | - | - | - | Admin only |
Floor:appointments.view+appointments.view_detailare irrevocable for both doctor and receptionist — these are the minimum required to practice or operate the front desk.
Patients (9 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
patients.view | See patient list and search | ✓ | ✓ | - | Pro |
patients.view_detail | Open a patient’s full profile | ✓ | ✓ | ✓ (own) | Pro |
patients.create | Register a new patient | ✓ | ✓ | - | Pro |
patients.edit | Update patient demographics and contact info | ✓ | ✓ | - | Pro |
patients.delete | Permanently delete a patient record | ✓ | - | - | Pro |
patients.invite_portal | Send a patient portal invite email | ✓ | ✓ | - | Pro |
patients.view_medical_history | Read medical history, allergies, and conditions | ✓ | ✓ | - | Pro |
patients.export | Download patient list as CSV | - | - | - | Admin only |
patients.merge | Merge duplicate patient records | - | - | - | Admin only |
Floor:patients.view+patients.view_detailare irrevocable for doctor and receptionist.
Clinical — Dental Chart (4 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
clinical.dental_chart.view | View tooth chart with status colors | ✓ | - | ✓ (own) | Pro |
clinical.dental_chart.create | Add a new chart record for a patient | ✓ | - | - | Pro |
clinical.dental_chart.edit | Update tooth conditions, treatments, notes | ✓ | - | - | Pro |
clinical.dental_chart.initialize | Set up a brand-new full-mouth chart for a patient | ✓ | - | - | Pro |
Receptionists have no chart write access — clinical integrity must remain with the treating clinician.
Clinical — Notes (4 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
clinical.notes.view | Read SOAP/clinical notes for a patient | ✓ | - | ✓ (own) | Pro |
clinical.notes.create | Write a new clinical note (SOAP, AI-assisted, free-text) | ✓ | - | - | Pro |
clinical.notes.edit | Edit a previously written note | ✓ | - | - | Pro |
clinical.notes.delete | Delete a clinical note | ✓ | - | - | Pro |
Floor:clinical.notes.view+clinical.notes.createare irrevocable for doctors. Receptionists intentionally cannot read notes — protects clinical confidentiality from front-desk staff.
Clinical — Treatment Plans (10 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
clinical.treatment_plans.view | Read treatment plans | ✓ | ✓ | ✓ (own) | Pro |
clinical.treatment_plans.create | Draft a new treatment plan | ✓ | - | - | Pro |
clinical.treatment_plans.edit | Modify procedures, pricing, timeline | ✓ | - | - | Pro |
clinical.treatment_plans.delete | Remove a plan entirely | ✓ | - | - | Pro |
clinical.treatment_plans.complete | Mark a plan as fully delivered | ✓ | - | - | Pro |
clinical.treatment_plans.approve | Doctor approves plan before presenting to patient | ✓ | - | - | Pro |
clinical.treatment_plans.accept | Patient accepts a presented plan | - | - | ✓ | Pro |
clinical.treatment_plans.ai_presentation | Generate AI patient-friendly summary of the plan | ✓ | - | - | Pro |
clinical.treatment_plans.share | Create a public share link for the patient to view | ✓ | - | - | Pro |
clinical.treatment_plans.revoke_share | Revoke a previously shared link | ✓ | - | - | Pro |
Receptionists can view plans (to assist with billing) but cannot create or modify them.
Clinical — Vital Signs & Consent (4 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
clinical.vital_signs.view | Read recorded vitals (BP, pulse, weight) | ✓ | - | - | Pro |
clinical.vital_signs.record | Enter/update vitals for a visit | ✓ | - | - | Pro |
clinical.consent.view | View signed consent forms | ✓ | ✓ | ✓ (own) | Pro |
clinical.consent.upload | Upload a signed consent PDF | ✓ | ✓ | - | Pro |
Clinical — Prescriptions (5 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
clinical.prescriptions.view | Read prescriptions | ✓ | ✓ | ✓ (own) | Pro |
clinical.prescriptions.create | Issue a new prescription | ✓ | - | - | Pro |
clinical.prescriptions.edit | Amend a prescription | ✓ | - | - | Pro |
clinical.prescriptions.delete | Void a prescription | ✓ | - | - | Pro |
clinical.prescriptions.manage_template | Edit the clinic’s prescription letterhead template | ✓ | - | - | Pro |
Floor:clinical.prescriptions.view+clinical.prescriptions.createare irrevocable for doctors.
Clinical — Medications Library (3 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
clinical.medications.view | Browse the clinic’s medication catalog | ✓ | - | - | Pro |
clinical.medications.create | Add a medication to the catalog | ✓ | - | - | Pro |
clinical.medications.delete | Remove a medication from the catalog | ✓ | - | - | Pro |
Clinical — Procedures Catalog (4 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
clinical.procedures.view | Browse the procedure catalog (used in treatment plans) | ✓ | - | - | Pro |
clinical.procedures.create | Add a new procedure with pricing | ✓ | - | - | Pro |
clinical.procedures.edit | Edit procedure name, code, or price | ✓ | - | - | Pro |
clinical.procedures.delete | Remove a procedure from the catalog | ✓ | - | - | Pro |
Floor: clinical.procedures.view is irrevocable for doctors — required to create treatment plans.
Clinical — Patient Files (4 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
clinical.patient_files.view | Browse uploaded files (X-rays, documents, DICOM) | ✓ | ✓ | ✓ (own) | Pro |
clinical.patient_files.upload | Upload new files to a patient’s record | ✓ | ✓ | - | Pro |
clinical.patient_files.edit | Rename or re-categorize a file | ✓ | - | - | Pro |
clinical.patient_files.delete | Permanently delete a patient file | ✓ | - | - | Pro |
Floor: clinical.patient_files.view is irrevocable for doctors.
Clinical — Recalls (5 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
clinical.recalls.view | See recall queue and status | ✓ | ✓ | - | Pro |
clinical.recalls.create | Schedule a recall for a patient | ✓ | ✓ | - | Pro |
clinical.recalls.edit | Change recall date or message | ✓ | ✓ | - | Pro |
clinical.recalls.delete | Cancel a recall | ✓ | ✓ | - | Pro |
clinical.recalls.batch_generate | Auto-generate recalls for a cohort of patients | ✓ | ✓ | - | Pro |
Clinical — IPD / In-Patient Department (4 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
clinical.ipd.view | See admission records | ✓ | - | - | Pro+ only |
clinical.ipd.admit | Admit a new patient to IPD | ✓ | - | - | Pro+ only |
clinical.ipd.edit | Update admission notes, ward, charges | ✓ | - | - | Pro+ only |
clinical.ipd.discharge | Discharge a patient and generate summary | ✓ | - | - | Pro+ only |
IPD is a Pro+ / Enterprise-only module. Doctors on Pro do not have these keys regardless of clinic template.
Billing — Invoices (8 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
billing.invoices.view | See invoice list | ✓ | ✓ | ✓ (own) | Pro |
billing.invoices.view_detail | Open a full invoice with line items | ✓ | ✓ | ✓ (own) | Pro |
billing.invoices.create | Draft a new invoice | ✓ | ✓ | - | Pro |
billing.invoices.edit | Modify line items, discounts, due date | ✓ | ✓ | - | Pro |
billing.invoices.send | Email invoice to patient | ✓ | ✓ | - | Pro |
billing.invoices.convert | Convert a quotation to an invoice | - | - | - | Admin only |
billing.invoices.share | Generate a public payment link for the invoice | ✓ | ✓ | - | Pro |
billing.invoices.revoke_share | Revoke a previously shared payment link | ✓ | - | - | Pro |
Floor: billing.invoices.view is irrevocable for receptionists — minimum required to handle payments at front desk.
Billing — Receipts & Payments (5 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
billing.receipts.view | View receipt history | ✓ | ✓ | ✓ (own) | Pro |
billing.receipts.create | Issue a payment receipt | ✓ | ✓ | - | Pro |
billing.receipts.send | Email receipt to patient | ✓ | ✓ | - | Pro |
billing.receipts.share | Share receipt as public link | ✓ | - | - | Pro |
billing.payments.view | View payment records | ✓ | ✓ | ✓ (own) | Pro |
billing.payments.record | Log an offline/cash payment against an invoice | ✓ | ✓ | - | Pro |
Billing — Installments (3 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
billing.installments.view | See installment plans | ✓ | ✓ | ✓ (own) | Pro |
billing.installments.create | Set up a new payment plan for a patient | ✓ | - | - | Pro |
billing.installments.generate_invoice | Trigger invoice generation for a due installment term | ✓ | - | - | Pro |
Billing — Quotations (7 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
billing.quotations.view | Browse quotations | ✓ | ✓ | ✓ (own) | Pro |
billing.quotations.create | Draft a quotation | ✓ | ✓ | - | Pro |
billing.quotations.edit | Edit line items and pricing | ✓ | - | - | Pro |
billing.quotations.delete | Delete a quotation | ✓ | - | - | Pro |
billing.quotations.send | Email quotation to patient | ✓ | ✓ | - | Pro |
billing.quotations.reissue | Re-issue an expired quotation | ✓ | - | - | Pro |
billing.quotations.share | Share as a public link | ✓ | - | - | Pro |
Billing — Expenses (4 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
billing.expenses.view | View expense records | - | - | - | Admin only |
billing.expenses.manage | Create and edit expense entries | - | - | - | Admin only |
billing.expenses.delete | Delete an expense | - | - | - | Admin only |
billing.expenses.view_eod | View end-of-day financial summary | - | - | - | Admin only |
Billing — Payroll (3 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
billing.payroll.view | View payroll periods and runs | - | - | - | Admin only |
billing.payroll.manage | Create employees and pay periods | - | - | - | Admin only |
billing.payroll.run | Execute a payroll run | - | - | - | Admin only |
Billing — Insurance Claims (4 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
billing.insurance.view | View insurance claims | ✓ | - | - | Pro+ only |
billing.insurance.create | Submit a new claim | ✓ | - | - | Pro+ only |
billing.insurance.edit | Update claim details and status | ✓ | - | - | Pro+ only |
billing.insurance.manage_attachments | Upload/delete supporting documents to a claim | ✓ | - | - | Pro+ only |
Insurance claims are Pro+ / Enterprise only. Doctors on Pro do not have these keys.
Inventory (6 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
inventory.view | Browse inventory items and stock levels | ✓ (view only) | ✓ (Pro+) | - | Pro |
inventory.create | Add a new item to inventory | - | ✓ (Pro+ only) | - | Pro+ |
inventory.edit | Edit item details and reorder point | - | ✓ (Pro+ only) | - | Pro+ |
inventory.adjust_stock | Record stock received, consumed, or adjusted | - | ✓ | - | Pro |
inventory.view_alerts | See low-stock and expiry alerts | ✓ | ✓ | - | Pro |
inventory.manage_suppliers | Add and edit supplier records | - | ✓ (Pro+ only) | - | Pro+ |
Doctors get view + alerts only — they need to see supply levels but shouldn’t manage stock. Receptionists get full inventory write access on Pro+, view/adjust on Pro.
Lab (10 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
lab.cases.view | Browse lab cases | ✓ | ✓ | - | Pro |
lab.cases.create | Open a new lab case | ✓ | ✓ | - | Pro |
lab.cases.update_status | Move case through workflow (sent → received → ready) | ✓ | ✓ | - | Pro |
lab.services.view | Browse lab service catalog | ✓ | ✓ | - | Pro |
lab.services.manage | Add/edit lab services and pricing | ✓ | - | - | Pro |
lab.services.delete | Delete a lab service | ✓ | - | - | Pro |
lab.laboratories.view | Browse external lab partners | ✓ | ✓ | - | Pro |
lab.laboratories.create | Add a new lab partner | ✓ | - | - | Pro |
lab.laboratories.edit | Update lab contact and details | ✓ | - | - | Pro |
lab.laboratories.delete | Remove a lab partner | ✓ | - | - | Pro |
Receptionists can manage the case lifecycle but cannot configure labs or services — that’s clinical territory.
Bridge / X-Ray Integration (3 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
bridge.view | See Bridge X-ray inbox and patient file matches | ✓ | ✓ | - | Pro+ only |
bridge.capture | Capture/upload an X-ray from the Bridge device | ✓ | - | - | Pro+ only |
bridge.manage | Configure the Bridge device settings | - | - | - | Admin / Pro+ only |
Bridge is a hardware X-ray integration device. Access is Pro+ only. Receptionists can only view (to assist with file matching), not capture.
Communications (9 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
comms.messages.view | Read message conversations | ✓ | ✓ | ✓ (own) | Pro |
comms.messages.send_patient | Send a message to a patient | ✓ | ✓ | ✓ | Pro |
comms.messages.send_staff | Send a message to another staff member | ✓ | ✓ | - | Pro |
comms.messages.delete | Delete a message thread | ✓ | - | - | Pro |
comms.messages.check_window | Check if 24-hour WhatsApp messaging window is open | ✓ | ✓ | - | Pro |
comms.messages.mark_read | Mark messages as read | ✓ | ✓ | ✓ | Pro |
comms.templates.view | Browse message templates | ✓ | ✓ | - | Pro |
comms.templates.manage | Create/edit message templates | - | - | - | Admin only |
comms.bulk.send | Send a broadcast message to a patient segment | - | ✓ | - | Pro |
Reports & Analytics (3 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
reports.financial | Access financial reports (revenue, collections, aging) | ✓ | - | - | Pro+ (doctor), Admin always |
reports.stats | Access operational stats (appointments, patient volume) | ✓ | ✓ | - | Pro |
reports.revenue | Access revenue breakdown reports | ✓ | - | - | Pro+ (doctor) |
On Pro plan, doctors getreports.statsonly.reports.financialandreports.revenuerequire Pro+.
AI Insights (15 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
ai.patient_brief | Generate AI patient brief before an appointment | ✓ | - | - | Pro+ |
ai.clinical_assist | AI-assisted SOAP note generation from voice/text | ✓ | - | - | Pro+ |
ai.shorten_expand | Expand shorthand → full prose, or shorten verbose notes | ✓ | - | - | Pro |
ai.recall_message | Generate personalized recall reminder message for a patient | ✓ | - | - | Pro+ |
ai.dicom_analysis.view | View existing AI DICOM X-ray analysis results | ✓ | - | - | Pro+ |
ai.dicom_analysis.run | Trigger a new AI analysis on a DICOM X-ray | ✓ | - | - | Pro+ |
ai.daily_brief | Generate the morning operational brief for the clinic | ✓ | ✓ | - | Pro |
ai.appointment_nudges | Generate appointment confirmation/reminder messages | ✓ | ✓ | - | Pro |
ai.monthly_summary | Generate monthly performance summary | ✓ | - | - | Pro+ |
ai.treatment_plan_presentation | Generate patient-friendly treatment plan explanation | ✓ | - | - | Pro |
ai.revenue_forecast | AI revenue forecast based on pipeline | ✓ | - | - | Pro+ |
ai.churn_risk | Identify at-risk patients likely to churn | ✓ | - | - | Pro+ |
ai.payment_reminder | Generate a payment reminder message for overdue invoices | ✓ | ✓ | - | Pro |
ai.eod_summary | Generate end-of-day summary | ✓ | - | - | Pro |
ai.grammar_rewrite | Fix grammar and style in clinical notes | ✓ | ✓ | - | Pro |
Settings (16 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
settings.staff.view | View staff list and their roles | - | ✓ | - | Pro |
settings.staff.create | Invite or directly create a staff account | - | - | - | Admin only |
settings.staff.edit | Edit staff name, role, or profile | - | - | - | Admin only |
settings.staff.remove | Remove a staff member from the clinic | - | - | - | Admin only |
settings.staff.manage_permissions | Override individual staff permissions | - | - | - | Admin only |
settings.staff.resend_invitation | Resend a pending staff invite email | - | - | - | Admin only |
settings.staff.refresh_access | Refresh patient portal access tokens | - | - | - | Admin only |
settings.rooms.view | View operatory/room list | - | - | - | Admin only |
settings.rooms.manage | Create, edit, delete operatory rooms | - | - | - | Admin only |
settings.branding.view | View clinic logo and branding settings | - | - | - | Admin only |
settings.branding.edit | Upload logo, favicon, set color theme | - | - | - | Admin only |
settings.email_templates.view | View automated email templates | - | - | - | Admin only |
settings.email_templates.edit | Customize email template content | - | - | - | Admin only |
settings.email_templates.test | Send a test email for a template | - | - | - | Admin only |
settings.signatures.view | View uploaded doctor signature images | ✓ | ✓ (Pro+) | - | Pro |
settings.signatures.manage | Upload or activate a signature | ✓ | ✓ (Pro+) | - | Pro+ |
settings.signatures.delete | Delete a signature | ✓ | - | - | Pro |
settings.referrals.view | View patient referral source list | - | - | - | Admin only |
settings.referrals.manage | Add/edit referral sources | - | - | - | Admin only |
settings.referrals.delete | Delete a referral source | - | - | - | Admin only |
settings.appointment_types.manage | Configure appointment type names and colors | - | - | - | Admin only |
settings.working_hours.manage | Set clinic working hours and doctor availability | - | - | - | Admin only |
settings.modules.manage | Enable/disable optional clinic modules | - | - | - | Admin only |
Notifications (2 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
notifications.view_all | View all clinic notifications (not just own) | - | - | - | Admin only |
notifications.manage | Mark notifications read, delete notifications | ✓ | ✓ | ✓ | Pro |
Audit & Compliance (3 keys)
| Permission Key | What it controls | Doctor | Receptionist | Patient | Plan |
|---|---|---|---|---|---|
audit.logs.view | View system audit log (who did what, when) | - | - | - | Admin only |
audit.logs.export | Export audit log as CSV | - | - | - | Admin only |
audit.activity.view | View entity-level activity timeline (appointment, patient, etc.) | ✓ | - | - | Pro |
Endpoint Reference
All protected endpoints require a valid session cookie/token. All clinic-scoped endpoints enforce the active clinic context.Notation:[perm]=requirePermission(perm)·[any: a, b]=requireAnyPermission([a, b])·[role]= hard-coded role check ·[auth]= authenticated only, no specific perm ·-= public
Authentication (/api/v1/auth/)
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /signup | - | Register new clinic — creates a pending approval request (manual superadmin review required) |
| POST | /signin | - | Email + password sign-in, returns session |
| POST | /mobile-signin | - | Mobile app sign-in with PIN/biometric pre-check |
| POST | /mfa/verify | - | Verify MFA code during login flow |
| POST | /mfa/setup/send-otp | - | Send OTP to begin MFA setup |
| POST | /mfa/setup/init-totp | - | Initialize TOTP authenticator app setup |
| POST | /mfa/setup/verify | - | Confirm TOTP code to complete setup |
| POST | /forgot-password | - | Send password reset email |
| POST | /verify-otp | - | Verify OTP for password reset flow |
| POST | /confirm-password-reset | - | Complete password reset with OTP |
| POST | /reset-password | - | Reset password using reset token |
| POST | /onboarding | - | Begin clinic onboarding after approval |
| GET | /onboarding/validate/:token | - | Validate onboarding token from email link |
| POST | /onboarding/send-otp | - | Send OTP during onboarding |
| POST | /onboarding/complete | - | Finalize onboarding and activate clinic |
| GET | /check-status/:requestId | - | Poll approval status for a pending signup |
| POST | /check-status/:requestId/resend-activation | - | Resend the activation email |
| GET | /invitation/:token | - | Preview a staff invitation before accepting |
| POST | /invitation/:token/accept | - | Accept a staff invitation and set password |
| POST | /verify-setup-token | - | Verify account setup link token |
| POST | /set-password | - | Set initial password for invited staff |
| POST | /generate-ott | - | Generate a one-time sign-in token |
| POST | /exchange | - | Exchange a one-time token for a session |
| POST | /impersonation/exit | [auth] | Exit superadmin impersonation session |
| POST | /refresh | - | Refresh access token using refresh token (rotation) |
| POST/GET | /logout | [auth] | Sign out and revoke session |
2FA (/api/v1/auth/2fa/)
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /setup/init | [auth] | Start 2FA setup flow |
| POST | /setup/verify | [auth] | Confirm 2FA is working, save to account |
| POST | /verify | - | Verify 2FA code during login |
| POST | /recovery | - | Use a recovery code instead of 2FA code |
| POST | /email/send | - | Send 2FA code via email |
| GET | /status | [auth] | Get 2FA enabled/type status |
| DELETE | /disable | [auth] | Disable 2FA (requires verification) |
| POST | /regenerate-codes | [auth] | Generate new backup/recovery codes |
| POST | /backup-codes/request-email | [auth] | Email the backup codes to the user |
| POST | /backup-codes/view | [auth] | View backup codes in-browser (requires re-auth) |
| POST | /reset/request | - | Request 2FA reset (for locked-out users) |
| POST | /reset/verify | - | Complete 2FA reset with identity verification |
Passkeys / WebAuthn (/api/v1/auth/passkeys/)
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /register/options | [auth] | Get WebAuthn registration challenge |
| POST | /register | [auth] | Register new passkey (FaceID, fingerprint, hardware key) |
| POST | /authenticate/options | - | Get WebAuthn authentication challenge |
| POST | /authenticate | - | Sign in with passkey |
| GET | / | [auth] | List registered passkeys |
| DELETE | /:id | [auth] | Remove a passkey |
| PATCH | /:id | [auth] | Rename a passkey |
Blog (/api/v1/blog/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | / | - | List published blog posts |
| GET | /:slug | - | Get blog post by slug |
Help Center (/api/v1/help/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /categories | - | List help documentation categories |
| GET | /articles | - | List help articles (filterable by category) |
| GET | /articles/:slug | - | Get individual help article |
| GET | /releases | - | List product release notes |
Public Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /contact | - | Submit contact/demo request form |
| POST | /guide-lead | - | Download guide lead capture (marketing) |
| POST | /public-referrals/ | - | Patient submits referral from a shareable referral link |
| POST | /appointments/respond | - | Patient confirms or cancels appointment from email link |
| GET | /branding/:clinicId/info | - | Get clinic name, logo URL for white-label embed |
| GET | /branding/:clinicId/:type | - | Serve clinic logo or favicon |
| POST | /waitlist/ | - | Join app waitlist |
| GET | /upgrade-invite/:token | - | View an upgrade invite sent by sales |
| POST | /upgrade-invite/:token/request | - | Accept / request upgrade |
| POST | /support/feature-request | - | Submit anonymous feature request |
Public Documents (/api/v1/public-documents/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /:token | - | View a shared document (invoice, prescription, treatment plan) |
| POST | /:token/accept | - | Accept a shared document (e.g., patient accepting treatment plan) |
| PUT | /:token/lab-status | - | External lab updates case status via shared link |
| POST | /:token/lab-attachments | - | External lab uploads files to a case |
WhatsApp Webhook (/api/v1/whatsapp/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET/POST | /webhook | - | Meta/WhatsApp platform verification and message ingestion |
| GET/POST | /:clinicId/webhook | - | Per-clinic WhatsApp webhook endpoint |
OTLP Telemetry (/api/v1/otlp/)
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /logs | - | OTLP log ingestion endpoint (from client/worker) |
Stripe Webhook
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /stripe/webhook | - | Stripe payment event webhook (signature-verified) |
Activity Timeline (/api/v1/protected/activity/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /:entityType/:entityId | [auth] | Timeline of all changes to an entity (appointment, patient, invoice, etc.) |
AI Insights (/api/v1/protected/ai/)
Requires ai_insights module to be enabled for the clinic.
| Method | Path | Permission | Description |
|---|---|---|---|
| POST | /clinical-notes | ai.clinical_assist | Generate SOAP note from transcript or voice input |
| POST | /patient-brief | ai.patient_brief | Generate pre-appointment patient brief |
| GET | /revenue-forecast | ai.revenue_forecast | AI revenue forecast from pipeline + history |
| GET | /treatment-followups | ai.clinical_assist | Generate follow-up messages for completed treatments |
| GET | /churn-risk | ai.churn_risk | List patients at risk of not returning |
| GET | /daily-brief | ai.daily_brief | Morning brief: today’s schedule, outstanding tasks |
| POST | /payment-reminder | ai.payment_reminder | Draft overdue payment reminder message |
| POST | /payment-reminder/send | ai.payment_reminder | Send the drafted reminder to the patient |
| POST | /rewrite | ai.grammar_rewrite | Improve clinical note style and clarity |
| POST | /grammar | ai.grammar_rewrite | Fix grammar in selected text |
| POST | /shorten | ai.shorten_expand | Condense verbose clinical notes |
| POST | /expand | ai.shorten_expand | Expand shorthand into full clinical prose |
| GET | /appointment-nudges | ai.appointment_nudges | Generate appointment reminders/confirmations |
| GET | /recall-message/:patientId | ai.recall_message | Personalized recall message for a specific patient |
| GET | /monthly-summary | ai.monthly_summary | Monthly performance summary for clinic |
| GET | /treatment-plan-presentation/:planId | ai.treatment_plan_presentation | Patient-friendly explanation of a treatment plan |
| GET | /dicom-analysis/:patientFileId | ai.dicom_analysis.view | Retrieve existing DICOM analysis result |
| POST | /dicom-analysis | ai.dicom_analysis.run | Trigger AI analysis on a DICOM X-ray file |
| GET | /dicom-quota | [auth] | Check DICOM AI usage vs plan quota |
| POST | /dicom-terms-accept | [auth] | Accept DICOM AI usage terms (one-time) |
Analytics (/api/v1/protected/analytics/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | / | [role: superadmin] | Platform-wide analytics across all clinics |
| GET | /financial-summary | [role: admin, superadmin] | Financial summary for current clinic |
Appointments (/api/v1/protected/appointments/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | appointments.view | List appointments (filterable by date, doctor, status) |
| POST | / | appointments.create | Book a new appointment |
| GET | /available-slots | [auth] | Query available time slots (used by booking form) |
| GET | /doctor-schedules | [auth] | Get all doctors’ weekly schedules |
| GET | /:id | appointments.view_detail | Get full appointment detail |
| PUT | /:id | appointments.edit | Update appointment (time, doctor, notes, type) |
| DELETE | /:id | appointments.delete | Delete appointment |
| PATCH | /:id/status | appointments.change_status | Transition appointment status |
| POST | /:id/send-summary | appointments.send_summary | Send appointment summary to patient |
| GET | /:id/share-link | [auth] | Get shareable appointment confirmation link |
| PUT | /doctor-schedules/:doctorId | [auth] | Update doctor weekly availability |
Audit Logs (/api/v1/protected/audit-logs/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | audit.logs.view | View system audit log (paginated, filterable by user/action/date) |
Billing — Subscription Billing (/api/v1/protected/billing/)
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /license-requests | [auth] | Request a license seat increase |
| GET | /license-requests | [auth] | View pending license requests |
| PATCH | /license-requests/:id | [auth] | Update a license request |
| GET | /invoices | billing.invoices.view | List OdontoX subscription invoices (not clinic invoices) |
| GET | /invoices/next-number | [auth] | Preview the next invoice number |
| POST | /invoices | billing.invoices.create | Create a subscription invoice |
| POST | /invoices/:id/send | billing.invoices.send | Email subscription invoice |
| POST | /invoices/:id/portal | [auth] | Create Stripe customer portal link |
| POST | /invoices/:id/mark-paid | billing.invoices.edit | Mark invoice as paid |
| GET | /invoices/:id/pdf | billing.invoices.view | Download invoice PDF |
| POST | /upgrade-invite-token | [auth] | Generate a sales upgrade invite link |
| POST | /upgrade-requests | [auth] | Submit an upgrade request to sales |
| GET | /payment-methods | [auth] | List saved payment methods (Stripe) |
| PATCH | /payment-methods/:id/default | [auth] | Set a payment method as default |
| DELETE | /payment-methods/:id | [auth] | Remove a payment method |
| GET | /overview | [auth] | Get subscription plan, usage, next bill date |
| POST | /referral-payouts | [auth] | Request referral program commission payout |
| GET | /referral-payouts | [auth] | List referral payout requests |
| GET | /clinics | [role: superadmin] | Get billing info for all clinics |
Blog Admin (/api/v1/protected/blog/admin/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /all | [role: superadmin] | List all posts including drafts |
| GET | /:id | [role: superadmin] | Get post (including draft) |
| POST | / | [role: superadmin] | Create blog post |
| PUT | /:id | [role: superadmin] | Update blog post |
| DELETE | /:id | [role: superadmin] | Delete blog post |
Bridge / X-Ray (/api/v1/protected/bridge/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | /patients/search | bridge.view | Search patients to attach X-ray from Bridge inbox |
Clinic API Keys (/api/v1/protected/clinic/api-keys/)
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | / | [role: admin] | Create a new API key for clinic integrations |
| GET | / | [role: admin] | List active API keys |
| DELETE | /:keyId | [role: admin] | Revoke an API key |
Clinic Modules (/api/v1/protected/clinic/modules/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /active | [auth] | Get the list of enabled modules for the current clinic |
Permission Templates (/api/v1/protected/clinic/permission-templates/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | / | [role: admin] | Get the clinic’s custom role permission templates |
| PUT | /:role | [role: admin] | Override default permissions for a role at clinic level |
| DELETE | /:role | [role: admin] | Reset a role’s permissions back to plan defaults |
Clinical Notes (/api/v1/protected/clinical-notes/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | /patient/:patientId | clinical.notes.view | Get all clinical notes for a patient |
| GET | /:id | clinical.notes.view | Get a specific note |
| POST | / | clinical.notes.create | Write a new clinical note |
| PUT | /:id | clinical.notes.edit | Edit an existing note |
| DELETE | /:id | clinical.notes.delete | Delete a note |
Clinics (/api/v1/protected/clinics/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /context | [auth] | Get current clinic context (name, plan, active modules) |
| POST | /context/switch | [auth] | Switch active clinic (multi-clinic users) |
| GET | / | [role: superadmin] | List all clinics |
| GET | /:id | [role: admin, superadmin] | Get clinic details |
| PUT | /:id | [role: admin] | Update clinic settings |
| PUT | /:id/subscription | [role: superadmin] | Update clinic subscription plan |
| POST | /:id/branding | settings.branding.edit | Upload clinic logo or favicon |
| DELETE | /:id/branding/:type | settings.branding.edit | Remove a branding asset |
| DELETE | /:id | [role: superadmin] | Delete a clinic (hard delete) |
| GET | /deletions/history | [role: superadmin] | View deleted clinic history |
| GET | /subscription-plans | [auth] | List available subscription plans and their features |
| GET | /:id/users | [role: admin, superadmin] | Get all users in a clinic |
Clinical Client Logs (/api/v1/protected/logs/client/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | / | [role: superadmin] | View client-side error logs |
| POST | / | [auth] | Submit a client error log from the browser |
Cron Jobs (/api/v1/protected/superadmin/cron-jobs/)
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | / | [role: superadmin] | Create a scheduled cron job |
| GET | / | [role: superadmin] | List cron jobs |
| PUT | /:id | [role: superadmin] | Update cron schedule or payload |
| DELETE | /:id | [role: superadmin] | Delete cron job |
| POST | /trigger-eod | [role: superadmin] | Manually fire end-of-day processing |
Dental Charts (/api/v1/protected/dental-charts/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | /patient/:patientId | clinical.dental_chart.view | Get the dental chart for a patient |
| GET | /:id | clinical.dental_chart.view | Get a specific chart record |
| POST | / | clinical.dental_chart.create | Create a new chart |
| POST | /:chartId/initialize | clinical.dental_chart.initialize | Initialize full-mouth chart for a new patient |
| PUT | /tooth/:toothId | clinical.dental_chart.edit | Update a single tooth’s status/treatment |
| POST | /tooth | clinical.dental_chart.create | Add a new tooth record to chart |
| PUT | /:chartId/teeth | clinical.dental_chart.edit | Batch update multiple teeth at once |
Document Issuance (/api/v1/protected/document-issuance/)
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | / | [auth] | Issue a document (creates share token + records metadata) |
Document Views (/api/v1/protected/document-views/)
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | / | [auth] | Record that a document was viewed (analytics) |
Email Templates (/api/v1/protected/superadmin/emails/templates/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | / | [role: superadmin] | List all email templates (system defaults + overrides) |
| POST | / | [role: superadmin] | Create a custom email template |
| GET | /:key | [role: superadmin] | Get template by key |
| PUT | /:key | [role: superadmin] | Update template content |
| POST | /:key/test | [role: superadmin] | Send a test email with this template |
| POST | /seed | [role: superadmin] | Seed default system templates |
Expenses (/api/v1/protected/expenses/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | billing.expenses.view | List clinic expenses (operational costs) |
| POST | / | billing.expenses.manage | Create an expense entry |
| PUT | /:id | billing.expenses.manage | Update an expense |
| DELETE | /:id | billing.expenses.delete | Delete an expense |
| GET | /eod-report | billing.expenses.view_eod | End-of-day financial summary |
| POST | /eod-report/ai-summary | billing.expenses.view_eod | Generate AI narrative of EOD report |
Files (/api/v1/protected/files/)
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /upload | [auth] | Upload a generic file to R2 storage |
| GET | /storage-usage | [role: admin] | Get total storage used by the clinic |
| GET | /patients-summary | [role: admin] | File count/size breakdown by patient |
| GET | /:id/download | [auth] | Download a file (generates signed R2 URL) |
| POST | /messages/:messageId/upload | [auth] | Upload attachment to a message |
| GET | /messages/:messageId/attachments/:key/download | [auth] | Download message attachment |
| GET | /bridge-inbox | bridge.view | List unassigned X-rays in the Bridge device inbox |
| GET | /:id | [auth] | Get file metadata |
| POST | /:id/convert | [auth] | Convert file format (e.g., TIFF → PNG, DICOM → PNG) |
| POST | /:id/attach-patient | [auth] | Link an unassigned Bridge file to a patient |
| DELETE | /:id | [auth] | Delete a file from storage |
Help Center Admin (/api/v1/protected/help/admin/)
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /categories | [role: superadmin] | Create a help category |
| PUT | /categories/:id | [role: superadmin] | Update category |
| POST | /articles | [role: superadmin] | Create help article |
| PUT | /articles/:id | [role: superadmin] | Update article |
| POST | /releases | [role: superadmin] | Publish release notes |
| PUT | /releases/:id | [role: superadmin] | Update release notes |
Installments (/api/v1/protected/installments/)
| Method | Path | Permission | Description |
|---|---|---|---|
| POST | / | billing.installments.create | Create a payment installment plan |
| GET | / | billing.installments.view | List all installment plans |
| GET | /:id | billing.installments.view | Get plan detail |
| GET | /by-treatment-plan/:treatmentPlanId | billing.installments.view | Get plans linked to a treatment plan |
| POST | /:termId/generate-invoice | billing.installments.generate_invoice | Generate invoice for a due term |
| POST | /cron/generate-due-invoices | [role: superadmin] | Cron: auto-generate invoices for all due terms |
Insurance Claims (/api/v1/protected/insurance-claims/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | billing.insurance.view | List all insurance claims |
| GET | /patient/:patientId | billing.insurance.view | Get claims for a patient |
| GET | /:id | billing.insurance.view | Get claim detail |
| PUT | /:id | billing.insurance.edit | Update claim status or details |
| DELETE | /:id | billing.insurance.edit | Delete a claim |
| GET | /:id/attachments | billing.insurance.view | List claim attachments |
| POST | /:id/attachments | billing.insurance.manage_attachments | Upload supporting document to claim |
| DELETE | /:id/attachments/:fileId | billing.insurance.manage_attachments | Remove attachment from claim |
| POST | / | billing.insurance.create | Submit a new insurance claim |
Inventory (/api/v1/protected/inventory/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | inventory.view | List inventory items |
| POST | / | inventory.create | Add a new inventory item |
| GET | /:id | inventory.view | Get item detail |
| PUT | /:id | inventory.edit | Edit item info, reorder point, unit |
| POST | /:id/receive | inventory.adjust_stock | Record stock received (purchase order) |
| POST | /:id/consume | inventory.adjust_stock | Record stock consumed (procedure use) |
| POST | /:id/adjust | inventory.adjust_stock | Manual stock adjustment (correction/write-off) |
| GET | /:id/transactions | inventory.view | Transaction history for an item |
| GET | /:id/movements | inventory.view | Stock movement log |
| GET | /suppliers | inventory.view | List suppliers |
| POST | /suppliers | inventory.manage_suppliers | Add a supplier |
| GET | /alerts | inventory.view_alerts | Get low-stock and expiry alerts |
| POST | /alerts/:id/acknowledge | inventory.view_alerts | Dismiss/acknowledge an alert |
| GET | /summary | inventory.view | Inventory summary (total value, alert count) |
IPD / In-Patient Department (/api/v1/protected/ipd/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | /admissions | clinical.ipd.view | List current and past admissions |
| POST | /admissions | clinical.ipd.admit | Admit a patient to IPD |
| GET | /admissions/:id | clinical.ipd.view | Get admission detail |
| PUT | /admissions/:id | clinical.ipd.edit | Update admission (ward, notes, charges) |
| POST | /admissions/:id/discharge | clinical.ipd.discharge | Discharge patient and generate discharge summary |
| GET | /admissions/:id/appointments | clinical.ipd.view | Get appointments linked to an admission |
| GET | /admissions/:id/notes | clinical.ipd.view | Get clinical notes for an admission |
Invoices (/api/v1/protected/invoices/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | billing.invoices.view | List clinic invoices |
| GET | /next-number | billing.invoices.view | Preview next auto-generated invoice number |
| POST | / | billing.invoices.create | Create a new invoice |
| GET | /:id | billing.invoices.view_detail | Get invoice with full line items |
| PUT | /:id | billing.invoices.edit | Edit invoice |
| DELETE | /:id | billing.invoices.edit | Delete invoice |
| POST | /:id/send | billing.invoices.send | Email invoice to patient |
| POST | /:id/mark-paid | billing.invoices.edit | Record as paid |
| GET | /:id/pdf | billing.invoices.view | Download invoice PDF |
| POST | /:id/share | billing.invoices.share | Generate public payment link |
| DELETE | /:id/share | billing.invoices.revoke_share | Revoke public share link |
Lab Cases (/api/v1/protected/lab-cases/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | lab.cases.view | List lab cases |
| GET | /patient/:patientId | lab.cases.view | Get cases for a patient |
| GET | /:id | lab.cases.view | Get case detail |
| POST | / | lab.cases.create | Open a new lab case |
| PUT | /:id | lab.cases.update_status | Update case status or details |
| GET | /:id/activity | lab.cases.view | Activity log for case |
| GET | /:id/attachments/:encodedKey | lab.cases.view | Download a case attachment |
Lab Services (/api/v1/protected/lab-services/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | lab.services.view | List lab services catalog |
| GET | /:id | lab.services.view | Get service detail |
| POST | / | lab.services.manage | Create a lab service |
| PUT | /:id | lab.services.manage | Update service |
| DELETE | /:id | lab.services.delete | Delete service |
Laboratories (/api/v1/protected/laboratories/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | lab.laboratories.view | List external lab partners |
| GET | /:id | lab.laboratories.view | Get lab partner detail |
| POST | / | lab.laboratories.create | Add a lab partner |
| PUT | /:id | lab.laboratories.edit | Edit lab details |
| DELETE | /:id | lab.laboratories.delete | Remove a lab partner |
Licenses (/api/v1/protected/licenses/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /:clinicId | [role: admin, superadmin] | Get license plan, seat counts |
| GET | /:clinicId/usage | [role: admin, superadmin] | Current seat usage vs limit |
| GET | /:clinicId/check/:role | [role: admin] | Check if a new user of given role would exceed seat limit |
| POST | /:clinicId/upgrade | [role: superadmin] | Apply a license upgrade |
Medications (/api/v1/protected/medications/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | clinical.medications.view | List clinic medication catalog |
| POST | / | clinical.medications.create | Add a medication |
| POST | /bulk | clinical.medications.create | Bulk import medications |
| PUT | /:id | clinical.medications.create | Update medication |
| DELETE | /:id | clinical.medications.delete | Remove medication from catalog |
Messages (/api/v1/protected/messages/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | comms.messages.view | List all messages |
| GET | /conversations | comms.messages.view | List conversation threads |
| GET | /conversations/:id | comms.messages.view | Get conversation detail |
| POST | /conversations/:id/send | comms.messages.send_patient | Reply in a conversation |
| POST | /conversations/:id/read | comms.messages.mark_read | Mark conversation as read |
| GET | /receptionists | [auth] | Get list of receptionists (for staff messaging) |
| GET | /contacts | [auth] | Get messageable contacts |
| GET | /:id | comms.messages.view | Get a specific message |
| POST | / | comms.messages.send_patient | Send a new message |
| PUT | /:id | [auth] | Update message status |
| GET | /patient/:patientId | comms.messages.view | Get all messages with a patient |
| GET | /staff/:staffId | comms.messages.view | Get all messages with a staff member |
| DELETE | /:id | comms.messages.delete | Delete a message |
| GET | /can-initiate/:patientId | comms.messages.check_window | Check if 24-hour WhatsApp window is open |
| POST | /whatsapp/send | comms.messages.send_patient | Send via WhatsApp channel |
Mobile (/api/v1/protected/mobile/)
Permissions Engine:
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /permissions | [auth] | Get mobile-specific permission config |
| GET | /permissions/clinic/:clinicId/:role | [role: admin, superadmin] | Get permission config for a role |
| PATCH | /permissions/clinic/:clinicId/:role/:module | [role: admin] | Toggle a module permission for mobile |
| Method | Path | Permission | TTL | Description |
|---|---|---|---|---|
| GET | /screen/dashboard | appointments.view | 5 min | Dashboard: today’s visits, stats, week KPIs, notifications |
| GET | /screen/appointments?view=month | appointments.view | 15 min | Appointments: list, available slots, doctor schedules, rules |
| GET | /screen/patients?page=1 | patients.view | 1 hour | Patients: list, details, prescriptions, treatment plans |
| GET | /screen/finance | billing.invoices.view | 30 min | Finance: invoices, quotes, receipts, summary (role: admin/doctor only, patient sees own) |
| GET | /screen/chat | comms.messages.view | 2 min | Chat: staff threads, patient threads, unread counts (real-time-ish) |
| GET | /screen/lab-work | lab.cases.view | 15 min | Lab work: cases, summary (role: admin/doctor/reception only) |
| GET | /screen/inventory | inventory.view | 15 min | Inventory: items, low-stock alerts (role: admin/doctor/reception only) |
source=mobile— marks request as from mobile client (for analytics)view?(appointments):'day' | 'week' | 'month'(default:'month')page?(patients, any paginated): page number (default:1)limit?(override defaults per screen)
Notifications (/api/v1/protected/notifications/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | notifications.view_all | List all clinic notifications (admin view) |
| GET | /unread-count | [auth] | Get unread notification count for current user |
| PUT | /:id | [auth] | Mark a notification as read |
| PUT | /mark-all-read | [auth] | Mark all notifications as read |
| DELETE | /:id | notifications.manage | Delete a notification |
| GET | /live-feed | [auth] | SSE stream of real-time notifications |
Patient Files (/api/v1/protected/patient-files/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | clinical.patient_files.view | List all patient files |
| GET | /patient/:patientId | clinical.patient_files.view | Get files for a patient |
| GET | /:id | clinical.patient_files.view | Get file metadata |
| POST | / | clinical.patient_files.upload | Upload a file to patient record |
| PUT | /:id | clinical.patient_files.edit | Edit file name or category |
| DELETE | /:id | clinical.patient_files.delete | Delete a patient file |
Patient Recalls (/api/v1/protected/patient-recalls/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | clinical.recalls.view | List recall queue |
| GET | /patient/:patientId | clinical.recalls.view | Get recalls for a patient |
| GET | /:id | clinical.recalls.view | Get recall detail |
| POST | / | clinical.recalls.create | Schedule a recall |
| PUT | /:id | clinical.recalls.edit | Update recall date or message |
| DELETE | /:id | clinical.recalls.delete | Cancel recall |
| POST | /batch-generate | clinical.recalls.batch_generate | Batch generate recalls for a patient cohort |
Patients (/api/v1/protected/patients/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | patients.view | List all patients (paginated) |
| GET | /search | patients.view | Full-text search patients |
| GET | /:id | patients.view_detail | Get patient profile |
| POST | / | patients.create | Register a new patient |
| PUT | /:id | patients.edit | Update patient demographics |
| DELETE | /:id | patients.delete | Delete patient record |
| PUT | /:id/medical | patients.view_medical_history | Update patient medical history |
| GET | /profile | [auth] | Patient: get own profile |
| PUT | /profile | patients.edit | Patient: update own profile |
| PUT | /profile/medical | [auth] | Patient: update own medical history |
| GET | /check-account/:email | [auth] | Check if an email already has a patient portal account |
| POST | /invite | patients.invite_portal | Send patient portal invite |
Payment / Stripe (/api/v1/protected/payment/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /status | [auth] | Get current Stripe subscription status |
| POST | /checkout | [role: admin] | Create Stripe checkout session for plan upgrade |
| POST | /portal | [role: admin] | Create Stripe customer portal link |
Payroll (/api/v1/protected/payroll/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | /employees | billing.payroll.view | List payroll employees |
| POST | /employees | billing.payroll.manage | Add employee to payroll |
| PUT | /employees/:id | billing.payroll.manage | Update employee details |
| GET | /periods | billing.payroll.view | List pay periods |
| POST | /periods | billing.payroll.manage | Create a pay period |
| GET | /runs | billing.payroll.view | List payroll runs |
| GET | /runs/:id | billing.payroll.view | Get payroll run detail |
| POST | /runs | billing.payroll.run | Execute a payroll run |
Prescription Template (/api/v1/protected/clinics/prescription-template/)
| Method | Path | Permission | Description |
|---|---|---|---|
| POST | / | clinical.prescriptions.manage_template | Create prescription template |
| PUT | / | clinical.prescriptions.manage_template | Update prescription template |
| DELETE | / | clinical.prescriptions.manage_template | Delete prescription template |
Prescriptions (/api/v1/protected/prescriptions/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | /my | clinical.prescriptions.view | Doctor: get own prescriptions issued |
| GET | /patient/:patientId | clinical.prescriptions.view | Get prescriptions for a patient |
| GET | /:id | clinical.prescriptions.view | Get prescription detail |
| POST | / | clinical.prescriptions.create | Issue a new prescription |
| PUT | /:id | clinical.prescriptions.edit | Amend prescription |
| DELETE | /:id | clinical.prescriptions.delete | Void prescription |
Procedures (/api/v1/protected/procedures/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | /categories | clinical.procedures.view | List procedure categories |
| POST | /categories | clinical.procedures.create | Create a category |
| GET | / | clinical.procedures.view | List procedures in catalog |
| GET | /:id | clinical.procedures.view | Get procedure detail |
| POST | / | clinical.procedures.create | Create procedure |
| PUT | /:id | clinical.procedures.edit | Edit procedure |
| DELETE | /:id | clinical.procedures.delete | Delete procedure |
Public Documents (Protected) (/api/v1/protected/public-documents/)
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | / | [auth] | Generate a public share link for a document |
| GET | /status | [auth] | Get share status for current documents |
| POST | /:id/revoke | [auth] | Revoke a share link |
Quotations (/api/v1/protected/quotations/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | billing.quotations.view | List quotations |
| GET | /next-number | billing.quotations.view | Preview next quotation number |
| POST | / | billing.quotations.create | Create a quotation |
| GET | /:id | billing.quotations.view | Get quotation detail |
| PUT | /:id | billing.quotations.edit | Edit quotation |
| DELETE | /:id | billing.quotations.delete | Delete quotation |
| POST | /:id/send | billing.quotations.send | Email quotation to patient |
| POST | /:id/reissue | billing.quotations.reissue | Re-issue expired quotation |
| POST | /:id/share | billing.quotations.share | Generate public share link |
| POST | /:id/convert-to-invoice | billing.invoices.create | Convert quotation to invoice |
Receipts (/api/v1/protected/receipts/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | billing.receipts.view | List receipts |
| POST | / | billing.receipts.create | Issue a receipt |
| GET | /:id | billing.receipts.view | Get receipt detail |
| POST | /:id/send | billing.receipts.send | Email receipt |
| POST | /:id/share | billing.receipts.share | Share as public link |
| GET | /:id/pdf | billing.receipts.view | Download PDF |
Referrals (/api/v1/protected/referrals/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | settings.referrals.view | List referral sources |
| GET | /:id | settings.referrals.view | Get referral source detail |
| POST | / | settings.referrals.manage | Create referral source |
| PUT | /:id | settings.referrals.manage | Update referral source |
| DELETE | /:id | settings.referrals.delete | Delete referral source |
Reports (/api/v1/protected/reports/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | /financial-statement | reports.financial | Full financial P&L statement |
| GET | /financial-summary | reports.financial | Financial summary (revenue, collections, outstanding) |
| GET | /stats | reports.stats | Operational stats (appointments, patients, revenue KPIs) |
Rooms / Operatories (/api/v1/protected/rooms/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | settings.rooms.view | List clinic operatory rooms |
| POST | / | settings.rooms.manage | Create a room |
| PUT | /:id | settings.rooms.manage | Update room name/status |
| DELETE | /:id | settings.rooms.manage | Delete a room |
Signatures (/api/v1/protected/signatures/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | settings.signatures.view | List uploaded signatures |
| GET | /active | settings.signatures.view | Get the currently active signature |
| POST | / | settings.signatures.manage | Upload a signature image |
| PUT | /:id/activate | settings.signatures.manage | Set a signature as active |
| DELETE | /:id | settings.signatures.delete | Delete a signature |
| GET | /:id/download | settings.signatures.view | Download signature image |
SSE / Real-time Events (/api/v1/protected/sse/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /clinic-events | [auth] | Server-sent event stream for live clinic notifications |
Staff (/api/v1/protected/staff/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | / | settings.staff.view | List all staff members |
| GET | /invitations | settings.staff.view | List pending invitations |
| POST | /invitations/:id/resend | settings.staff.resend_invitation | Resend invite email |
| DELETE | /invitations/:id | settings.staff.create | Cancel a pending invitation |
| POST | /invite | settings.staff.create | Send a staff invitation email |
| POST | /create | settings.staff.create | Create staff account directly (no invite flow) |
| PUT | /:id | settings.staff.edit | Edit staff profile |
| DELETE | /:id | settings.staff.remove | Remove staff from clinic |
| GET | /:id/permissions | settings.staff.view | View staff member’s effective permissions |
| PUT | /:id/permissions | settings.staff.manage_permissions | Override staff member’s permissions |
| POST | /refresh-patient-access | settings.staff.refresh_access | Regenerate patient portal access links |
Statistics / Dashboard (/api/v1/protected/stats/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /superadmin | [role: superadmin] | Platform-level stats (all clinics) |
| GET | /admin | [role: admin] | Admin dashboard stats (clinic KPIs) |
| GET | /doctor | [role: doctor] | Doctor dashboard (today’s schedule, patient summary) |
| GET | /receptionist | [role: receptionist] | Reception dashboard (today’s appointments, billing tasks) |
| GET | /patient/summary | [role: patient] | Patient portal summary |
| GET | /patient/appointments | [role: patient] | Patient’s appointment history |
| GET | /patient/billing | [role: patient] | Patient’s billing history |
| GET | /patient/records | [role: patient] | Patient’s clinical records summary |
| GET | /patient | [role: patient] | Full patient stats object |
| GET | /revenue | [auth] | Revenue breakdown (requires reports.revenue) |
| GET | /superadmin/dicom-usage | [role: superadmin] | DICOM AI usage across all clinics |
Subscription Plans (/api/v1/protected/subscription-plans/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | / | [auth] | List available plans with features |
| PATCH | /:id | [role: superadmin] | Update plan details |
| POST | /create-pro-trial | [role: superadmin] | Create a Pro trial for a clinic |
| POST | /seed-defaults | [role: superadmin] | Seed default plan configurations |
SuperAdmin Modules (/api/v1/protected/superadmin/modules/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /available | [role: superadmin] | List all available optional modules |
| GET | /clinics/:clinicId | [role: superadmin] | Get enabled modules for a clinic |
| POST | /clinics/:clinicId/toggle | [role: superadmin] | Enable or disable a module for a clinic |
| POST | /clinics/:clinicId/sync-to-plan | [role: superadmin] | Reset clinic modules to match plan defaults |
Support Tickets (/api/v1/protected/support-tickets/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | / | [auth] | List support tickets (own tickets for users, all for superadmin) |
| GET | /:id | [auth] | Get ticket detail |
| POST | / | [auth] | Open a new support ticket |
| PUT | /:id | [auth] | Update ticket status |
| POST | /:id/replies | [auth] | Add a reply to a ticket |
System Health (/api/v1/protected/system-health/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | / | [role: superadmin] | Overall system health (DB, storage, worker) |
| GET | /endpoints | [role: superadmin] | Per-endpoint health check |
| GET | /test-analytics | [role: superadmin] | Test analytics pipeline |
Treatment Plans (/api/v1/protected/treatment-plans/)
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | /my | clinical.treatment_plans.view | Doctor: get own created plans |
| GET | / | clinical.treatment_plans.view | List all treatment plans |
| GET | /patient/:patientId | clinical.treatment_plans.view | Get plans for a patient |
| GET | /:id | clinical.treatment_plans.view | Get plan detail |
| POST | / | clinical.treatment_plans.create | Draft a treatment plan |
| PUT | /:id | clinical.treatment_plans.edit | Edit plan procedures, pricing, phases |
| POST | /:id/approve | clinical.treatment_plans.approve | Doctor approves plan (before patient presentation) |
| POST | /:id/accept | clinical.treatment_plans.accept | Patient accepts presented plan |
User Devices (/api/v1/protected/user-devices/)
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | / | [auth] | Register device for push notifications |
Users (/api/v1/protected/users/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | / | [role: superadmin] | List all platform users |
| GET | /pending | [role: superadmin] | Get pending signup requests |
| GET | /pending/:requestId | [role: superadmin] | Get specific pending request |
| GET | /me/clinics | [auth] | Get current user’s clinic memberships |
| GET | /:id/clinics | [role: superadmin] | Get clinic memberships for any user |
| POST | /:id/clinics | [role: superadmin] | Add user to a clinic |
| DELETE | /:id/clinics/:clinicId | [role: superadmin] | Remove user from a clinic |
| GET | /clinics | [role: superadmin] | All user–clinic assignments |
| POST | /:id/approve | [role: superadmin] | Approve a pending signup |
| POST | /:id/reject | [role: superadmin] | Reject a pending signup |
| PUT | /role | [role: superadmin] | Change a user’s platform role |
| PATCH | /:id | [role: superadmin] | Update user account details |
WhatsApp Config (/api/v1/protected/whatsapp/)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /config | [role: admin] | Get clinic’s WhatsApp integration config |
| PUT | /config | [role: admin] | Update WhatsApp config (token, phone number ID) |
| DELETE | /config | [role: admin] | Disconnect WhatsApp integration |
| POST | /test | [role: admin] | Send a test WhatsApp message |
SuperAdmin Admin Routes (/api/v1/protected/admin/)
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /test-email-speed | [role: superadmin] | Benchmark email delivery speed |
| POST | /preview-email/feedback-review | [role: superadmin] | Preview feedback review email |
| POST | /preview-email/stock-alert | [role: superadmin] | Preview stock alert email |
| POST | /trigger-trial-emails | [role: superadmin] | Manually trigger trial onboarding emails |
| GET | /referrals | [role: superadmin] | List all clinic referral submissions |
| GET | /trial-insights | [role: superadmin] | Trial conversion insights |
| GET | /upgrade-requests | [role: superadmin] | List upgrade requests from clinics |
| POST | /upgrade-requests/:id/decision | [role: superadmin] | Approve or reject an upgrade request |
| POST | /maintenance/announce | [role: superadmin] | Broadcast a maintenance window announcement |
| GET | /referral-payouts | [role: superadmin] | List referral payout requests |
| POST | /referral-payouts/:id/decision | [role: superadmin] | Approve or reject payout |
| POST | /referral-payouts/:id/send-form | [role: superadmin] | Email payout form to clinic |
| GET | /referral-payouts/:id/pdf | [role: superadmin] | Download payout PDF |
| POST | /backfill-patient-search-text | [role: superadmin] | Backfill patient full-text search index |
| POST | /create-superadmin | [role: superadmin] | Create a new superadmin user |
| GET | /users | [role: superadmin] | List all platform users (detailed view) |
| GET | /users/multi-clinic | [role: superadmin] | Users with multi-clinic access |
| POST | /users/:id/resend-invite | [role: superadmin] | Resend staff invite |
| POST | /users/:id/reset-password | [role: superadmin] | Force password reset for user |
| PATCH | /users/:id/status | [role: superadmin] | Activate or suspend a user account |
| PATCH | /users/:id/clinics/:clinicId/permissions | [role: superadmin] | Override user permissions at a specific clinic |
| POST | /users/:id/disable-2fa | [role: superadmin] | Force-disable 2FA for a locked-out user |
| POST | /users/:id/impersonate | [role: superadmin] | Impersonate a user for debugging |
| DELETE | /users/:id | [role: superadmin] | Delete a user account |
| GET | /invitations | [role: superadmin] | List all pending invitations |
| POST | /invitations | [role: superadmin] | Create an invitation directly |
| POST | /invitations/:id/resend | [role: superadmin] | Resend invitation |
| POST | /run-migrations | [role: superadmin] | Run pending DB migrations |
| GET | /billing/logs | [role: superadmin] | View billing event logs |
| POST | /billing/custom-subscription | [role: superadmin] | Create a custom subscription for a clinic |
| POST | /cleanup/invoices | [role: superadmin] | Clean up orphaned invoices |
| GET | /cleanup/invoices/report | [role: superadmin] | Preview cleanup impact |
| POST | /imports/validate | [role: superadmin] | Validate a patient data import file |
| POST | /imports/run | [role: superadmin] | Execute a validated patient import |
| GET | /alerts/count | [role: superadmin] | Get total unacknowledged alert count |
| GET | /alerts | [role: superadmin] | List all system alerts |
| POST | /alerts/:id/acknowledge | [role: superadmin] | Dismiss a system alert |
| GET | /worker-logs | [role: superadmin] | View Cloudflare Worker execution logs |
| GET | /admin/leads | [role: superadmin] | Cross-tenant Website Leads inspector |
| DELETE | /admin/leads/:id | [role: superadmin] | Hard-delete a lead submission (compliance / GDPR) |
Website Leads (/leads) — clinic-scoped
Module-gated by lead_inbox + per-permission gates listed inline.
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | /leads | leads.view | List inbox submissions (paginated, optional status filter) |
| GET | /leads/:id | leads.view | Submission detail with decrypted PII |
| PATCH | /leads/:id | leads.manage | Update status (new / contacted / converted / archived / spam) |
| POST | /leads/:id/convert | leads.convert | Create a patient from a lead (1-click; needs gender) |
| GET | /leads/form-configs | leads.view | List the clinic’s lead forms (token shown only to leads.configure) |
| POST | /leads/form-configs | leads.configure | Create a new lead form (mints a token) |
| PATCH | /leads/form-configs/:id | leads.configure | Update label / origins / auto-reply / active |
| POST | /leads/form-configs/:id/rotate | leads.configure | Issue a fresh token; old token immediately invalid |
| DELETE | /leads/form-configs/:id | leads.configure | Disable a form (soft — submissions stop, history preserved) |
Public Website Leads (/public/leads) — no auth, token-authenticated
Used by the clinic’s own React/JS website to post contact-form submissions. CORS responds based on the form’s configured allowedOrigins. Rate-limited per token and per IP. Honeypot field website must be empty.
| Method | Path | Auth | Description |
|---|---|---|---|
| OPTIONS | /public/leads | none | CORS preflight |
| POST | /public/leads | X-OdontoX-Token header | Capture a contact-form submission. Body fields: firstName (required), lastName, email, phone, dateOfBirth, gender, subject, message, preferredDate, preferredTimeOfDay, customFields (object), sourceUrl, referrer, utm (object). Either email or phone is required. Returns { ok, leadId }. |
Plan × Role Permission Matrix Summary
| Module | Feature | Pro — Doctor | Pro — Receptionist | Pro+ — Doctor | Pro+ — Receptionist |
|---|---|---|---|---|---|
| Appointments | Full CRUD | ✓ | ✓ | ✓ | ✓ |
| Patients | Full CRUD | ✓ | create/edit (no delete) | ✓ | create/edit (no delete) |
| Clinical Notes | Full CRUD | ✓ | - | ✓ | - |
| Dental Chart | Full CRUD | ✓ | - | ✓ | - |
| Treatment Plans | Full CRUD + approve | ✓ | view only | ✓ | view only |
| Prescriptions | Full CRUD | ✓ | view only | ✓ | view only |
| Medications | Full CRUD | ✓ | - | ✓ | - |
| Procedures | Full CRUD | ✓ | - | ✓ | - |
| Patient Files | Full CRUD | ✓ | view + upload | ✓ | view + upload |
| Recalls | Full CRUD | ✓ | Full CRUD | ✓ | Full CRUD |
| IPD | - | - | - | ✓ | - |
| Invoices | create/send/share | ✓ | create/send/share | ✓ | create/send/share |
| Receipts | Full | ✓ | Full | ✓ | Full |
| Installments | create + generate | ✓ | view only | ✓ | view only |
| Quotations | Full | ✓ | create + send | ✓ | create + send |
| Expenses | - | - | - | - | - |
| Payroll | - | - | - | - | - |
| Insurance | - | - | - | ✓ | - |
| Inventory | view + alerts | view + adjust + alerts | view + alerts | Full CRUD | Full CRUD |
| Lab | Full | cases + services view | Full | cases + services view | |
| Bridge | - | view | ✓ | ✓ | view |
| Messages | Full | send patient + staff | Full | send patient + staff | |
| Reports | stats only | stats only | financial + revenue | - | |
| AI — Clinical | clinical_assist, patient_brief, DICOM | - | ✓ | - | |
| AI — Scheduling | nudges, payment reminder | nudges, reminder, daily brief | ✓ | ✓ | |
| AI — Business | revenue_forecast, churn_risk, monthly_summary | - | ✓ | - | |
| Signatures | view | - | view | manage | |
| Audit | activity.view | - | activity.view | - |
Legacy Permission Key Mapping
These old flat keys are still accepted in stored permission overrides and are transparently expanded:| Legacy Key | Expands To |
|---|---|
view_appointments | appointments.view, appointments.view_detail |
edit_appointments | appointments.create, .edit, .delete, .change_status, .send_summary |
view_patients | patients.view, patients.view_detail |
edit_patients | patients.create, .edit, .delete, .invite_portal |
view_billing | billing.invoices.view, .view_detail, receipts.view, payments.view, quotations.view, installments.view |
process_payments | billing.payments.record, receipts.create, receipts.send, invoices.create, invoices.edit, invoices.send |
view_reports | reports.financial, reports.stats, reports.revenue |
view_clinical_records | All clinical.*.view keys |
edit_clinical_records | All clinical.*.create/edit/approve keys |
manage_inventory | All inventory.* keys |
send_messages | comms.messages.view, .send_patient, .send_staff, .mark_read |
manage_lab_cases | lab.cases.*, lab.services.view, lab.laboratories.view |

