Skip to main content

Escape Dental API (1.0.0)

Download OpenAPI specification:Download

Practice management platform API for Escape Dental.

Scheduling

Appointments, day sheet, templates, overrides, recalls

practice_scheduling_appointment_list

List and create appointments. Staff-only.

List supports filtering by date range (from / to), status, patient, and provider. Results are ordered by date_time ascending with a pk tiebreaker (see :class:AppointmentPagination).

Status vocabulary -- the Django state machine uses its own status slugs, distinct from any PMS-side arrival_status value carried by sync tools. The three statuses that matter for the No-show report are:

  • broken -- patient did not arrive (no-show). The Status.BROKEN choice is labelled Broken/No-Show in the model. This is the value the No-show report filters on.
  • cancelled -- patient cancelled ahead of time (slot could be refilled; does not count as a no-show).
  • complete -- patient arrived and the visit finished normally.

For convenience, ?status=no_show is accepted as an alias for ?status=broken so the web app can keep semantic URLs.

No-show shortcut -- ?no_show_between=YYYY-MM-DD,YYYY-MM-DD expands to status=no_show plus from/to using the supplied dates. Explicit from / to / status query params still win if passed alongside, so the shortcut is purely additive.

No-show annotations -- when the resolved status is broken / no_show, each row is additionally annotated with:

  • patient_no_show_count -- lifetime count of broken appointments for the patient scoped to this practice (ignores other practices).
  • patient_phone -- patient's best reach-out number (phone_mobile preferred, then phone_home, then phone_work).
  • patient_outstanding_balance -- the patient's current aged receivables snapshot (Patient.balance_current).
  • cancel_reason -- the appointment's cancellation_reason if set.

These fields are null on rows that are not no-shows, keeping the payload lean for normal schedule queries.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
from
string <date>
Examples:
  • from=2025-06-01 - Month start

Inclusive lower bound on date_time (ISO 8601 date, YYYY-MM-DD). Interpreted in the practice's local timezone -- a from=2025-06-01 filter returns appointments whose local-time start is on or after midnight on June 1 in the practice's zone.

no_show_between
string
Examples:
  • no_show_between=2025-06-01,2025-06-30 - June 2025

Shortcut for the No-show report: two ISO dates separated by a comma (YYYY-MM-DD,YYYY-MM-DD) expands to status=no_show + from=<first> + to=<second>. Explicit from / to / status query params still win if supplied alongside. Example: no_show_between=2025-06-01,2025-06-30.

page
integer

1-indexed page number. Pagination is keyed by date_time with a pk tiebreaker for stability.

page_size
integer

Results per page. Default 50, max 100 for regular clients. First-party sync tools (escape-eaglesoft, escape-opendental) bypass the cap via StandardPageNumberPagination so they can fetch large historical windows.

patient
integer

Filter by patient integer PK. Combine with from/to for a patient visit history slice.

provider
integer

Filter by primary provider integer PK.

status
string
Enum: "arrived" "broken" "cancelled" "complete" "no_show" "note" "other" "planned" "ready_for_doctor" "ready_for_walkout" "scheduled" "seated" "unscheduled"

Filter by appointment status slug. Status vocabulary used by the Django state machine (distinct from any PMS-specific arrival_status values on the sync side):

  • broken -- patient did not arrive for the appointment (a.k.a. no-show). The model's Status.BROKEN choice is labelled Broken/No-Show; this is the value the No-show report filters on.
  • cancelled -- patient cancelled the appointment ahead of time.
  • scheduled / arrived / seated / ready_for_doctor / ready_for_walkout / complete -- normal patient-flow states.

status=no_show is accepted as an alias for status=broken so the web-facing report URLs can stay semantic.

to
string <date>
Examples:
  • to=2025-06-30 - Month end

Inclusive upper bound on date_time (ISO 8601 date, YYYY-MM-DD). Interpreted in the practice's local timezone -- the full to day is included (the filter resolves to midnight at the start of the following day).

Responses

Response samples

Content type
application/json

A typical staff-app response when fetching a week of appointments. Results are ordered by date_time; the response envelope is the project-wide paginator shape (count, next, previous, results).

{
  • "count": 123,
  • "results": [
    ]
}

practice_scheduling_appointment_create

List and create appointments. Staff-only.

List supports filtering by date range (from / to), status, patient, and provider. Results are ordered by date_time ascending with a pk tiebreaker (see :class:AppointmentPagination).

Status vocabulary -- the Django state machine uses its own status slugs, distinct from any PMS-side arrival_status value carried by sync tools. The three statuses that matter for the No-show report are:

  • broken -- patient did not arrive (no-show). The Status.BROKEN choice is labelled Broken/No-Show in the model. This is the value the No-show report filters on.
  • cancelled -- patient cancelled ahead of time (slot could be refilled; does not count as a no-show).
  • complete -- patient arrived and the visit finished normally.

For convenience, ?status=no_show is accepted as an alias for ?status=broken so the web app can keep semantic URLs.

No-show shortcut -- ?no_show_between=YYYY-MM-DD,YYYY-MM-DD expands to status=no_show plus from/to using the supplied dates. Explicit from / to / status query params still win if passed alongside, so the shortcut is purely additive.

No-show annotations -- when the resolved status is broken / no_show, each row is additionally annotated with:

  • patient_no_show_count -- lifetime count of broken appointments for the patient scoped to this practice (ignores other practices).
  • patient_phone -- patient's best reach-out number (phone_mobile preferred, then phone_home, then phone_work).
  • patient_outstanding_balance -- the patient's current aged receivables snapshot (Patient.balance_current).
  • cancel_reason -- the appointment's cancellation_reason if set.

These fields are null on rows that are not no-shows, keeping the payload lean for normal schedule queries.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
header Parameters
Idempotency-Key
string [ 8 .. 128 ] characters ^[A-Za-z0-9._:-]{8,128}$

Optional client-generated key (8–128 chars, alphabet [A-Za-z0-9._:-]) that makes a POST idempotent for 24 hours. If the key has been seen before with the same request body, the original response is returned byte-for-byte with Idempotency-Status: replayed. If the key has been seen with a different body, the server returns 422. If a concurrent request using the same key is still in flight, the server returns 409 with retry_after_seconds. Absent the header, the request proceeds normally with no idempotency guarantee.

Request Body schema:
patient
string or null <uuid>
provider
string or null <uuid>
provider_hygienist
string or null <uuid>
operatory
string or null <uuid>
treatment_plan
string or null <uuid>

Treatment plan this appointment was scheduled from

date_time
string or null <date-time>
duration_minutes
integer [ 0 .. 2147483647 ]
status
string (AppointmentStatusEnum)
Enum: "scheduled" "arrived" "seated" "ready_for_doctor" "ready_for_walkout" "complete" "broken" "cancelled" "unscheduled" "planned" "other" "note" "self_booked_pending_review"
  • scheduled - Scheduled
  • arrived - Arrived
  • seated - Seated
  • ready_for_doctor - Ready for Doctor
  • ready_for_walkout - Ready for Walkout
  • complete - Complete
  • broken - Broken/No-Show
  • cancelled - Cancelled
  • unscheduled - Unscheduled
  • planned - Planned
  • other - Other
  • note - Note
  • self_booked_pending_review - Self-booked (pending review)
ConfirmedStatusEnum (string) or BlankEnum (any)
appointment_type
string <= 100 characters

e.g. New Patient Exam, Crown Prep

is_hygiene
boolean
procedure_description
string
note
string
cancellation_reason
string

Patient-supplied reason for cancellation

reschedule_requested
boolean

Patient asked the front desk to reschedule

arrived_at
string or null <date-time>
seated_at
string or null <date-time>
ready_for_doctor_at
string or null <date-time>

When hygienist signaled ready for doctor exam

ready_for_walkout_at
string or null <date-time>

When patient is ready for walkout (checkout/scheduling)

dismissed_at
string or null <date-time>
dollars_scheduled
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Scheduled procedure total from the source PMS; nullable when unknown

Array of objects (AppointmentProcedureRequest)
lab_case_id
string or null <uuid>

Link an existing lab case to this appointment. The case must belong to the same practice AND the same patient as the appointment; cross-tenant or cross-patient PKs are rejected with HTTP 400.

custom_data
any
allow_overbooking
boolean
Default: false
skip_validation
boolean
Default: false

Responses

Request samples

Content type

Minimal payload to create a scheduled appointment. date_time MUST be an ISO 8601 string with a timezone offset — the API rejects naive datetimes. duration_minutes is required for conflict-checking. Set allow_overbooking=true to skip the double-book guard (used by import/sync tools).

{
  • "patient": "11111111-1111-4111-8111-111111111111",
  • "provider": "22222222-2222-4222-8222-222222222222",
  • "operatory": "44444444-4444-4444-8444-444444444444",
  • "date_time": "2026-05-14T09:00:00-07:00",
  • "duration_minutes": 60,
  • "appointment_type": "Crown Prep",
  • "is_hygiene": false,
  • "procedure_description": "D2740 Crown - porcelain/ceramic substrate",
  • "note": "Patient prefers morning appointments.",
  • "scheduled_procedures": [
    ]
}

Response samples

Content type
application/json

Response returned after successfully creating the appointment above.

{
  • "id": "55555555-5555-4555-8555-555555555555",
  • "patient": "11111111-1111-4111-8111-111111111111",
  • "provider": "22222222-2222-4222-8222-222222222222",
  • "provider_hygienist": "33333333-3333-4333-8333-333333333333",
  • "operatory": "44444444-4444-4444-8444-444444444444",
  • "treatment_plan": null,
  • "date_time": "2026-05-14T09:00:00-07:00",
  • "duration_minutes": 60,
  • "status": "scheduled",
  • "confirmed_status": "not_called",
  • "appointment_type": "Crown Prep",
  • "is_hygiene": false,
  • "procedure_description": "D2740 Crown - porcelain/ceramic substrate",
  • "note": "Patient prefers morning appointments.",
  • "cancellation_reason": "",
  • "reschedule_requested": false,
  • "arrived_at": null,
  • "seated_at": null,
  • "ready_for_doctor_at": null,
  • "ready_for_walkout_at": null,
  • "dismissed_at": null,
  • "patient_name": "Example, Jane",
  • "provider_name": "Synthetic, Dr. Dana",
  • "provider_hygienist_name": "Synthetic, Hollis",
  • "scheduled_procedures": [
    ],
  • "custom_data": { }
}

practice_scheduling_appointment_bulk_partial_update

Handle PATCH on the list endpoint for bulk updates.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
patient
string or null <uuid>
provider
string or null <uuid>
provider_hygienist
string or null <uuid>
operatory
string or null <uuid>
treatment_plan
string or null <uuid>

Treatment plan this appointment was scheduled from

date_time
string or null <date-time>
duration_minutes
integer [ 0 .. 2147483647 ]
ConfirmedStatusEnum (string) or BlankEnum (any)
appointment_type
string <= 100 characters

e.g. New Patient Exam, Crown Prep

is_hygiene
boolean
procedure_description
string
note
string
cancellation_reason
string

Patient-supplied reason for cancellation

reschedule_requested
boolean

Patient asked the front desk to reschedule

arrived_at
string or null <date-time>
seated_at
string or null <date-time>
ready_for_doctor_at
string or null <date-time>

When hygienist signaled ready for doctor exam

ready_for_walkout_at
string or null <date-time>

When patient is ready for walkout (checkout/scheduling)

dismissed_at
string or null <date-time>
dollars_scheduled
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Scheduled procedure total from the source PMS; nullable when unknown

lab_case_id
string or null <uuid>

Link an existing lab case to this appointment. The case must belong to the same practice AND the same patient as the appointment; cross-tenant or cross-patient PKs are rejected with HTTP 400.

custom_data
any

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_hygienist": "cc1b609c-8966-4136-9bf1-9a022231718a",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "treatment_plan": "c4c01122-8b32-4bce-bbce-bb1bda9a1a32",
  • "date_time": "2019-08-24T14:15:22Z",
  • "duration_minutes": 2147483647,
  • "confirmed_status": "not_called",
  • "appointment_type": "string",
  • "is_hygiene": true,
  • "procedure_description": "string",
  • "note": "string",
  • "cancellation_reason": "string",
  • "reschedule_requested": true,
  • "arrived_at": "2019-08-24T14:15:22Z",
  • "seated_at": "2019-08-24T14:15:22Z",
  • "ready_for_doctor_at": "2019-08-24T14:15:22Z",
  • "ready_for_walkout_at": "2019-08-24T14:15:22Z",
  • "dismissed_at": "2019-08-24T14:15:22Z",
  • "dollars_scheduled": "string",
  • "lab_case_id": "89c336ec-0db7-4217-8d2c-a048f2e1ecfc",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_hygienist": "cc1b609c-8966-4136-9bf1-9a022231718a",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "treatment_plan": "c4c01122-8b32-4bce-bbce-bb1bda9a1a32",
  • "date_time": "2019-08-24T14:15:22Z",
  • "duration_minutes": 2147483647,
  • "status": "scheduled",
  • "confirmed_status": "not_called",
  • "appointment_type": "string",
  • "is_hygiene": true,
  • "procedure_description": "string",
  • "note": "string",
  • "cancellation_reason": "string",
  • "reschedule_requested": true,
  • "arrived_at": "2019-08-24T14:15:22Z",
  • "seated_at": "2019-08-24T14:15:22Z",
  • "ready_for_doctor_at": "2019-08-24T14:15:22Z",
  • "ready_for_walkout_at": "2019-08-24T14:15:22Z",
  • "dismissed_at": "2019-08-24T14:15:22Z",
  • "dollars_scheduled": "string",
  • "patient_name": "string",
  • "patient_noshow_risk_score": 0.1,
  • "provider_name": "string",
  • "provider_hygienist_name": "string",
  • "cancelled_by": "string",
  • "cancelled_by_name": "string",
  • "scheduled_procedures": [
    ],
  • "lab_warning": "string",
  • "lab_case": {
    },
  • "custom_data": null
}

practice_scheduling_appointment_status_list

Read-only list of appointment status metadata.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

practice_scheduling_appointment_status_retrieve

Read-only list of appointment status metadata.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
slug
required
string

A unique value identifying this appointment status.

Responses

Response samples

Content type
application/json
{
  • "slug": "string",
  • "label": "string",
  • "color": "string",
  • "is_visible": true,
  • "blocks_slot": true,
  • "sort_order": 0
}

practice_scheduling_appointment_confirm_create

Update appointment confirmation status (orthogonal to lifecycle status).

POST {"confirmed_status": "Confirmed"}

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
appointment_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
confirmed_status
required
string (ConfirmedStatusEnum)
Enum: "not_called" "left_message" "confirmed" "econfirmed"
  • not_called - Not Called
  • left_message - Left Message
  • confirmed - Confirmed
  • econfirmed - eConfirmed

Responses

Request samples

Content type

Confirmation is orthogonal to lifecycle status — an appointment can be scheduled and confirmed at the same time. Valid values: not_called, left_message, confirmed, econfirmed.

{
  • "confirmed_status": "confirmed"
}

Response samples

Content type
application/json

Response mirrors the appointment-detail shape.

{
  • "id": "55555555-5555-4555-8555-555555555555",
  • "patient": "11111111-1111-4111-8111-111111111111",
  • "provider": "22222222-2222-4222-8222-222222222222",
  • "provider_hygienist": "33333333-3333-4333-8333-333333333333",
  • "operatory": "44444444-4444-4444-8444-444444444444",
  • "treatment_plan": null,
  • "date_time": "2026-05-14T09:00:00-07:00",
  • "duration_minutes": 60,
  • "status": "scheduled",
  • "confirmed_status": "confirmed",
  • "appointment_type": "Crown Prep",
  • "is_hygiene": false,
  • "procedure_description": "D2740 Crown - porcelain/ceramic substrate",
  • "note": "Patient prefers morning appointments.",
  • "cancellation_reason": "",
  • "reschedule_requested": false,
  • "arrived_at": null,
  • "seated_at": null,
  • "ready_for_doctor_at": null,
  • "ready_for_walkout_at": null,
  • "dismissed_at": null,
  • "patient_name": "Example, Jane",
  • "provider_name": "Synthetic, Dr. Dana",
  • "provider_hygienist_name": "Synthetic, Hollis",
  • "scheduled_procedures": [
    ],
  • "custom_data": { }
}

practice_scheduling_appointment_history_list

Return the status transition history for an appointment.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
appointment_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json

One entry per transition, oldest first. changed_by is null for automated transitions (e.g. system auto-marking broken appointments overnight).

[
  • [
    ]
]

practice_scheduling_appointment_route_slip_retrieve

Aggregate endpoint for the front-desk route-slip print template (api#239).

GET /v1/practice/<uid>/scheduling/appointment/<appt_uid>/route-slip/

Returns every field the print template renders -- appointment, patient, procedures, primary insurance, provider, and operatory -- in a single JSON response. Designed for under ~50ms per call so check-in at the front desk stays snappy; the N+1 alternative (fetch the appointment, then patient, then insurance, then procedures) was measured as a noticeable stall while the patient stood at the counter.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
appointment_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "appointment": {
    },
  • "patient": {
    },
  • "procedures": [
    ],
  • "insurance": {
    },
  • "provider": {
    },
  • "operatory": {
    }
}

practice_scheduling_appointment_transition_create

Transition an appointment to a new status with validation and audit logging.

POST {"status": "complete", "note": "optional reason"}

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
appointment_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
status
required
string (AppointmentStatusEnum)
Enum: "scheduled" "arrived" "seated" "ready_for_doctor" "ready_for_walkout" "complete" "broken" "cancelled" "unscheduled" "planned" "other" "note" "self_booked_pending_review"
  • scheduled - Scheduled
  • arrived - Arrived
  • seated - Seated
  • ready_for_doctor - Ready for Doctor
  • ready_for_walkout - Ready for Walkout
  • complete - Complete
  • broken - Broken/No-Show
  • cancelled - Cancelled
  • unscheduled - Unscheduled
  • planned - Planned
  • other - Other
  • note - Note
  • self_booked_pending_review - Self-booked (pending review)
note
string
Default: ""

Responses

Request samples

Content type
Example

Call when the patient physically arrives. The API stamps arrived_at with the current server time (UTC).

{
  • "status": "arrived",
  • "note": "Checked in at front desk."
}

Response samples

Content type
application/json

Returns the full appointment resource with the new status and patient-flow timestamps.

{
  • "id": "55555555-5555-4555-8555-555555555555",
  • "patient": "11111111-1111-4111-8111-111111111111",
  • "provider": "22222222-2222-4222-8222-222222222222",
  • "provider_hygienist": "33333333-3333-4333-8333-333333333333",
  • "operatory": "44444444-4444-4444-8444-444444444444",
  • "treatment_plan": null,
  • "date_time": "2026-05-14T09:00:00-07:00",
  • "duration_minutes": 60,
  • "status": "arrived",
  • "confirmed_status": "not_called",
  • "appointment_type": "Crown Prep",
  • "is_hygiene": false,
  • "procedure_description": "D2740 Crown - porcelain/ceramic substrate",
  • "note": "Patient prefers morning appointments.",
  • "cancellation_reason": "",
  • "reschedule_requested": false,
  • "arrived_at": "2026-05-14T16:00:12Z",
  • "seated_at": null,
  • "ready_for_doctor_at": null,
  • "ready_for_walkout_at": null,
  • "dismissed_at": null,
  • "patient_name": "Example, Jane",
  • "provider_name": "Synthetic, Dr. Dana",
  • "provider_hygienist_name": "Synthetic, Hollis",
  • "scheduled_procedures": [
    ],
  • "custom_data": { }
}

practice_scheduling_available_slots_retrieve

Find available appointment slots for a given date.

Query params: date: Date in YYYY-MM-DD format (required). duration_minutes: Appointment length in minutes (required). provider: Optional provider ID. operatory: Optional operatory ID. interval: Slot interval in minutes (default 15).

Returns only slot times — does not leak why other times are unavailable.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
date
required
string <date>

Date (YYYY-MM-DD)

duration_minutes
required
integer

Required duration

interval
integer

Slot interval in minutes (default 15)

operatory
Array of integers

Filter by operatory. Repeat the param for a union: ?operatory=3&operatory=4.

provider
Array of integers

Filter by provider. Repeat the param for a union: ?provider=1&provider=2.

Responses

practice_scheduling_day_sheet_retrieve

Return the complete day-sheet for operatory-based schedule rendering.

Single request returning operatories, schedule blocks, and appointments.

Each entry in operatories[] carries an in_chair_patient field (GH-713) — None when the chair is empty, otherwise the authoritatively-resolved currently-seated patient:

{
    "patient_id": "<uuid>",
    "patient_name": "Last, First",
    "appointment_id": "<uuid> | null",
    "since": "<ISO 8601 UTC>",
}

Resolution rules (see :func:apps.scheduling.services._resolve_in_chair_patients):

  • Status is one of seated / ready_for_doctor / ready_for_walkout (the patient is in the chair across all three; arrived is lobby-only, complete sets dismissed_at).
  • dismissed_at IS NULL as a safety net for imported data.
  • On multiple "in chair" rows per operatory (back-to-back seatings without a dismiss — see GH-713 issue body), the most-recently-seated row wins.
  • Walk-ins: not exposed today (no walk-in-patient surface exists in the API yet — OperatoryPresence tracks staff occupancy, not patients). The appointment_id field is nullable so the shape is forward-compatible.

Query params: date: Date in YYYY-MM-DD format (required). include_hidden: "true" to include cancelled/unscheduled/planned appointments (default false).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
date
required
string <date>

Day sheet date (YYYY-MM-DD)

include_hidden
boolean

Include hidden appointments

Responses

Response samples

Content type
application/json
{
  • "date": "string",
  • "operatories": [
    ],
  • "blocks": [
    ],
  • "appointments": [
    ]
}

practice_scheduling_find_spot_retrieve

Multi-day slot search with patient scheduling constraints.

All constraint logic runs server-side. Clients send one request with constraints and get back matching slots across multiple days.

Query params: duration_minutes: Required appointment length in minutes. start_date: First date to search (default: today). YYYY-MM-DD. end_date: Last date to search (default: start_date + 30 days). YYYY-MM-DD. days_of_week: Legacy shorthand — comma-separated weekday ints (0=Mon..6=Sun). earliest_time: Legacy shorthand — earliest acceptable start time (HH:MM). latest_time: Legacy shorthand — latest acceptable start time (HH:MM). availability_windows: Repeatable <days>:<start>-<end> windows. Union semantics. Mutually exclusive with the legacy days_of_week / earliest_time / latest_time params — supply one form or the other. provider: Optional provider ID(s). Repeatable for union. operatory: Optional operatory ID(s). Repeatable for union. max_results: Max slots to return (default 500, max 500). When an explicit end_date is supplied the service spreads slots across the whole From->Through range rather than front-loading the first few days (GH-1061).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
availability_windows
Array of strings

Disjoint availability windows. Each value is <days>:<start>-<end> where <days> is a comma-separated list of weekday ints (0=Mon..6=Sun) and each time bound is HH:MM or blank. Repeat the param for a union. Example: ?availability_windows=4:15:00-&availability_windows=0,2,4:-10:00 means "Thursdays 3 PM onwards OR Mon/Wed/Fri before 10 AM". Mutually exclusive with the legacy days_of_week / earliest_time / latest_time trio.

days_of_week
string

Legacy single-window shorthand: comma-separated weekday ints (0=Mon..6=Sun). Mutually exclusive with availability_windows.

duration_minutes
required
integer

Required duration

earliest_time
string

Legacy single-window shorthand: earliest start time (HH:MM). Mutually exclusive with availability_windows.

end_date
string <date>

Last date to search (max 90 days)

latest_time
string

Legacy single-window shorthand: latest start time (HH:MM). Mutually exclusive with availability_windows.

max_results
integer

Max slots to return (default 500, max 500). Spread across the requested date range.

operatory
Array of integers

Filter by operatory. Repeat the param for a union: ?operatory=3&operatory=4.

provider
Array of integers

Filter by provider. Repeat the param for a union: ?provider=1&provider=2.

start_date
string <date>

First date to search (default: today)

Responses

practice_scheduling_month_summary_retrieve

Per-day appointment aggregate for the month-view calendar grid.

GET /v1/practice/<uid>/scheduling/month-summary/?from=YYYY-MM-DD&to=YYYY-MM-DD

Returns a sparse map of local-date strings to {appointment_count, production} in a single round-trip, replacing the auto-paginated /scheduling/appointment/ fetch loop used by the web month-view (useMonthData).

Business rules:

  • Days are bucketed in the practice's timezone, never server UTC nor the browser's timezone. An appointment at 11 PM local on 2026-04-01 stays on that date regardless of the server's wall clock.
  • appointment_count and production both exclude appointments whose status is cancelled or broken, matching the client-side filter the web app used to apply.
  • production sums AppointmentProcedure.fee for every scheduled procedure attached to an included appointment on the day.
  • The response is sparse: only days with at least one included appointment appear. Callers treat absent keys as empty days.
  • from / to are both inclusive. No server-side range cap is imposed (the caller bounds it to ~6 weeks for the month grid); the endpoint is a single GROUP BY query covered by (practice_id, date_time) so a reasonable window stays well under 50 ms even at 2000 appointments.
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
from
required
string <date>

Inclusive start date (YYYY-MM-DD), interpreted in practice timezone.

to
required
string <date>

Inclusive end date (YYYY-MM-DD), interpreted in practice timezone.

Responses

Response samples

Content type
application/json
{
  • "from": "2019-08-24",
  • "to": "2019-08-24",
  • "days": {
    }
}

practice_scheduling_open_close_retrieve

Return the practice's open/close times for a date from appointment data.

GET /v1/practice/<uid>/scheduling/open-close/?date=YYYY-MM-DD

"Open" is the earliest qualifying appointment's start; "close" is the latest qualifying appointment's end (start + duration). The endpoint is intentionally shaped for third-party integrations that simply need "when does the office open today?" without having to iterate the full schedule.

Business rules:

  • date is interpreted in the practice's timezone. An appointment whose local start time falls on that date counts, regardless of server UTC or the caller's wall clock.
  • Appointments with status cancelled or broken (the model's combined Broken / No-Show choice) are excluded -- a cancelled 8 AM slot does not make the office "open at 8:00".
  • open / close are returned as ISO-8601 datetimes with the practice's TZ offset baked in (e.g. 2026-04-22T08:15:00-04:00). The offset reflects the practice's timezone on that calendar date, so DST transitions produce the right offset on each side of the jump. Consumers that want bare wall-clock time can slice the string; consumers that need an unambiguous instant already have one.
  • No qualifying appointments yields {"date": ..., "open": null, "close": null} (HTTP 200) -- no data is a valid answer, not a 404.

Auth: any authenticated user with practice access. OAuth tokens must carry the scheduling:read scope; JWT / session callers pass through :class:SchedulingScope unchanged.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
date
required
string <date>
Examples:
  • date=2026-04-22 - Example date

Target date (YYYY-MM-DD) interpreted in the practice's local timezone. An appointment that starts at 8:15 AM local on that date yields an open timestamp anchored to 08:15 on that date with the practice's TZ offset.

Responses

Response samples

Content type
application/json
Example
{
  • "date": "2026-04-22",
  • "open": "2026-04-22T08:15:00-04:00",
  • "close": "2026-04-22T17:30:00-04:00"
}

practice_scheduling_operatory_walkin_create

Seat a patient as a walk-in in the given operatory (GH-715).

POST /api/v1/practice/<practice_uid>/scheduling/operatory/<operatory_id>/walkin/

Body: {"patient": "<patient_uid>"}

Creates an :class:OperatoryWalkIn row with seated_at=now() and surfaces the patient in the chair-grid's in_chair_patient field on the next day-sheet fetch (with appointment_id: null).

Refuses with HTTP 400 when an active walk-in already covers the same operatory -- a chair holds at most one patient at a time. Callers must dismiss the existing walk-in (or transition a scheduled appointment to seated, which auto-dismisses the walk-in) before seating a second one.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
operatory_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "seated_at": "2019-08-24T14:15:22Z",
  • "dismissed_at": "2019-08-24T14:15:22Z",
  • "seated_by": "b45d71b8-3393-4485-9ef5-232c57d50c44"
}

practice_scheduling_operatory_walkin_dismiss_create

Dismiss the active walk-in for the given operatory (GH-715).

POST /api/v1/practice/<practice_uid>/scheduling/operatory/<operatory_id>/walkin/dismiss/

Sets dismissed_at = now() on the active :class:OperatoryWalkIn row for the operatory, returning the closed row. Returns 404 when no active walk-in exists for that chair (also covers cross-tenant: operatories from another practice are filtered out before lookup).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
operatory_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "seated_at": "2019-08-24T14:15:22Z",
  • "dismissed_at": "2019-08-24T14:15:22Z",
  • "seated_by": "b45d71b8-3393-4485-9ef5-232c57d50c44"
}

practice_scheduling_recall_list

List and create recall / recare records for a practice.

Supports filtering by patient, recall_type, is_disabled, due-date range (due_before / due_after), and unscheduled status.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
due_after
string <date>
Examples:
  • due_after=2025-06-01 - Due from today

Inclusive lower bound on date_due (ISO 8601 date, YYYY-MM-DD).

due_before
string <date>
Examples:
  • due_before=2025-09-30 - Due this quarter

Inclusive upper bound on date_due (ISO 8601 date, YYYY-MM-DD).

is_disabled
string
Enum: "false" "true"

Filter by disabled status. Accepts true or false.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

patient
integer

Filter by patient integer PK.

recall_type
string
Examples:
  • recall_type=prophy -
  • recall_type=perio - Perio maintenance
  • recall_type=exam - Periodic exam

Filter by recall type slug. The field is free-form (CharField(max_length=100)) to accommodate PMS-specific categories during migrations; common values include prophy, perio, and exam.

unscheduled
string
Enum: "false" "true"

Filter to recalls whose date_scheduled is null (true) or non-null (false). Drives the operations-team 'unscheduled recalls' worklist.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_scheduling_recall_create

List and create recall / recare records for a practice.

Supports filtering by patient, recall_type, is_disabled, due-date range (due_before / due_after), and unscheduled status.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
patient
string <uuid>
recall_type
required
string [ 1 .. 100 ] characters
date_due
string or null <date>
date_previous
string or null <date>
date_scheduled
string or null <date>
is_disabled
boolean
custom_data
any

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "recall_type": "string",
  • "date_due": "2019-08-24",
  • "date_previous": "2019-08-24",
  • "date_scheduled": "2019-08-24",
  • "is_disabled": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "recall_type": "string",
  • "date_due": "2019-08-24",
  • "date_previous": "2019-08-24",
  • "date_scheduled": "2019-08-24",
  • "is_disabled": true,
  • "custom_data": null
}

practice_scheduling_recall_bulk_partial_update

Handle PATCH on the list endpoint for bulk updates.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
custom_data
any

Responses

Request samples

Content type
{
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "prefers_sms": true,
  • "prefers_email": true,
  • "recall_type": "string",
  • "date_due": "2019-08-24",
  • "date_previous": "2019-08-24",
  • "date_scheduled": "2019-08-24",
  • "last_visit_date": "2019-08-24",
  • "has_future_appointment": true,
  • "last_reached_at": "2019-08-24T14:15:22Z",
  • "is_disabled": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

List distinct recall types in use at a practice.

Reference-data endpoint that returns every distinct recall_type string currently in use on the practice's :class:Recall rows. The web Recall Due report uses this to populate its filter dropdown without having to harvest types from the visible page of results (which hides rare types the user has not scrolled to). Recall type is currently a free-form CharField on :class:apps.scheduling.models.Recall, so the source of truth is the existing rows -- there is no separate reference table.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "results": [
    ]
}

practice_scheduling_reports_cancellations_retrieve

Cancellation report with rebook annotations (api#155).

Returns every appointment whose status is cancelled and whose latest "to cancelled" status-log entry falls inside the requested window. Each row is annotated with rebook status and lead time so the front desk can tell at a glance whether the patient got back on the books and how much notice they gave.

Query params: cancelled_between YYYY-MM-DD,YYYY-MM-DD in practice TZ (preferred). When present, overrides from / to below. from, to Inclusive dates in practice TZ. Used when cancelled_between is not supplied.

Either the shortcut or explicit from/to must be provided.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
cancelled_between
string

Two ISO dates separated by a comma (YYYY-MM-DD,YYYY-MM-DD) interpreted in the practice's local timezone. Filters on the cancellation timestamp (latest status-log entry transitioning the row to cancelled). Either this parameter, or explicit from/to below, is required.

from
string <date>

Inclusive start date (YYYY-MM-DD, practice TZ). Ignored when cancelled_between is passed.

to
string <date>

Inclusive end date (YYYY-MM-DD, practice TZ). Ignored when cancelled_between is passed.

Responses

Response samples

Content type
application/json
{
  • "results": [
    ]
}

practice_scheduling_reports_provider_utilization_retrieve

Provider Utilization -- scheduled patient time / available working time.

Denominator rule (Aaron, api#156): blocked time (lunch, admin blocks, time-off overrides flagged non-patient) is subtracted from the denominator. A provider with 8h template time and a 1h lunch blockout shows a denominator of 7h, not 8h. Including blocked time would drag utilization down for reasons that are not actionable by the front desk.

Cancelled, broken (no-show), and unscheduled appointments do not count toward scheduled_hours -- they're treated as open time since the slot was released.

Query params: from Required. Inclusive start date (YYYY-MM-DD, practice TZ). to Required. Inclusive end date (YYYY-MM-DD, practice TZ). granularity Optional. day | week | month. provider Optional. Provider UID; repeat for multi-select.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
from
required
string <date>

Inclusive start date in the practice's local timezone (ISO 8601 YYYY-MM-DD).

granularity
string
Enum: "day" "month" "week"

Bucket size: day, week, or month. Defaults to day when the window is 14 days or less, week otherwise.

provider
Array of strings

Restrict the report to specific providers. Repeat the parameter for a multi-select filter, e.g. ?provider=<uuid-a>&provider=<uuid-b>. Omit to include every active, non-hidden provider in the practice.

to
required
string <date>

Inclusive end date in the practice's local timezone (ISO 8601 YYYY-MM-DD). The window must not exceed 12 months.

Responses

Response samples

Content type
application/json
{
  • "results": [
    ]
}

practice_scheduling_resolved_schedule_retrieve

Return the effective schedule for a date or date range.

Query params: date: Single date (YYYY-MM-DD). Returns blocks for that date. date_from / date_to: Date range. Returns blocks keyed by date. provider: Optional provider ID to filter to a single provider.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
date
string <date>

Single date (YYYY-MM-DD)

date_from
string <date>

Range start (YYYY-MM-DD)

date_to
string <date>

Range end (YYYY-MM-DD)

provider
integer

Filter by provider

Responses

Response samples

Content type
application/json
{
  • "date": "string",
  • "date_from": "string",
  • "date_to": "string",
  • "blocks": [
    ],
  • "schedule": {
    }
}

practice_scheduling_schedule_override_list

List and create date-specific schedule overrides.

Supports filtering by provider, date_from/date_to range, and schedule_type.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
date_from
string <date>
Examples:
  • date_from=2025-06-01 - Today forward

Inclusive lower bound on schedule_date (ISO 8601 date, YYYY-MM-DD).

date_to
string <date>
Examples:
  • date_to=2025-09-30 - Quarter end

Inclusive upper bound on schedule_date (ISO 8601 date, YYYY-MM-DD).

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

provider
integer

Filter to overrides owned by this provider (integer PK). Overrides with a null provider are practice-wide entries (holidays, closure days).

schedule_type
string
Enum: "blockout" "office_hours" "provider"

Filter by override kind. office_hours = one-off practice open/closed window, provider = one-off provider availability change, blockout = date-specific unavailable window.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_scheduling_schedule_override_create

List and create date-specific schedule overrides.

Supports filtering by provider, date_from/date_to range, and schedule_type.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
provider
string or null <uuid>
schedule_date
required
string <date>
start_time
required
string <time>
end_time
required
string <time>
schedule_type
required
string (ScheduleOverrideScheduleTypeEnum)
Enum: "office_hours" "provider" "blockout"
  • office_hours - Office Hours
  • provider - Provider Availability
  • blockout - Blockout
blockout_type
string <= 50 characters

e.g. lunch, meeting, holiday, time_off

operatory
string or null <uuid>
status
string (ScheduleOverrideStatusEnum)
Enum: "open" "closed" "holiday"
  • open - Open
  • closed - Closed
  • holiday - Holiday
note
string
custom_data
any

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "schedule_date": "2019-08-24",
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "schedule_type": "office_hours",
  • "blockout_type": "string",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "status": "open",
  • "note": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "schedule_date": "2019-08-24",
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "schedule_type": "office_hours",
  • "blockout_type": "string",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "status": "open",
  • "note": "string",
  • "custom_data": null
}

practice_scheduling_schedule_template_list

List and create recurring schedule templates.

Supports filtering by provider, day_of_week, and schedule_type.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
day_of_week
integer
Enum: 0 1 2 3 4 5 6

Filter by day of week. Integer 0-6 where 0=Sunday and 6=Saturday (Django Weekday convention).

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

provider
integer

Filter to templates owned by this provider (integer PK). Templates with a null provider are practice-wide blockout entries (e.g. a practice-wide lunch hour) and will not match a numeric provider filter.

schedule_type
string
Enum: "blockout" "provider"

Filter by template kind. provider = per-provider availability, blockout = recurring unavailable window (lunch, meetings). Practice-wide open hours moved off ScheduleTemplate in escape#308 -- see /api/v1/practice/<uid>/business-hours/ instead.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_scheduling_schedule_template_create

List and create recurring schedule templates.

Supports filtering by provider, day_of_week, and schedule_type.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
provider
string or null <uuid>
day_of_week
required
integer [ -2147483648 .. 2147483647 ]

0=Sunday, 1=Monday, ..., 6=Saturday

start_time
required
string <time>
end_time
required
string <time>
schedule_type
required
string (ScheduleTemplateScheduleTypeEnum)
Enum: "provider" "blockout"
  • provider - Provider Availability
  • blockout - Blockout
blockout_type
string <= 50 characters

e.g. lunch, meeting, admin

operatory
string or null <uuid>
is_active
boolean
custom_data
any

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "day_of_week": -2147483648,
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "schedule_type": "provider",
  • "blockout_type": "string",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "is_active": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "day_of_week": -2147483648,
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "schedule_type": "provider",
  • "blockout_type": "string",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "is_active": true,
  • "custom_data": null
}

practice_scheduling_stats_retrieve

Quick scheduling stats.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "total_appointments": 0,
  • "completed": 0,
  • "scheduled": 0,
  • "today": 0,
  • "this_week": 0
}

practice_scheduling_validate_appointment_create

Validate a proposed appointment against scheduling constraints.

POST { "operatory": 1, "date_time": "2026-03-19T09:00:00", "duration_minutes": 60, "provider": 1, // optional "exclude_appointment": 42 // optional, for rescheduling }

Returns {"issues": [...], "valid": true/false}

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
operatory
string or null <uuid>
date_time
required
string <date-time>

ISO 8601 with timezone offset.

duration_minutes
required
integer >= 1
provider
string or null <uuid>
exclude_appointment
string or null <uuid>

Responses

Request samples

Content type

Returns scheduling issues without persisting anything. Useful for drag-to-reschedule UX where the client wants to warn before the drop is committed. exclude_appointment ignores conflicts with the appointment being rescheduled.

{
  • "operatory": "44444444-4444-4444-8444-444444444444",
  • "date_time": "2026-05-14T09:00:00-07:00",
  • "duration_minutes": 60,
  • "provider": "22222222-2222-4222-8222-222222222222",
  • "exclude_appointment": "55555555-5555-4555-8555-555555555555"
}

Response samples

Content type
application/json
Example

Safe to book — no conflicts, no warnings.

{
  • "valid": true,
  • "issues": [ ]
}

Patients

Patient demographics and search

practice_intake_arrive_create

Single round-trip patient lookup + appointment arrival for kiosks.

POST /api/v1/practice/<uid>/intake/arrive/ Body: {"last_name": "Smith", "date_of_birth": "1980-04-22"}

Collapses the legacy three-call kiosk sequence (intake/lookup/scheduling/appointment/scheduling/.../transition/) into a single signed request so that a kiosk on a slow network can mark a patient arrived in one round-trip and so the kiosk OAuth token does not need IsStaffUser — only the write:patients scope.

Privacy contract

The 404 response is deliberately generic: the same status fires for "no patient match", "no eligible appointment today", and "multiple ambiguous patient matches". This prevents a public kiosk from being used as an enumeration oracle (whether a given last name + DOB exists in the practice, or whether that patient has an appointment).

Today is computed in the practice's local timezone, not the server's UTC clock — a remote staff member or a worker process in a different region must still see "today" from the office's perspective.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
last_name
required
string [ 1 .. 100 ] characters

Patient's last name (case-insensitive exact match).

date_of_birth
required
string <date>

Patient's date of birth (YYYY-MM-DD).

Responses

Request samples

Content type
{
  • "last_name": "string",
  • "date_of_birth": "2019-08-24"
}

Response samples

Content type
application/json
{
  • "patient": {
    },
  • "appointment": {
    }
}

practice_patient_list

List and create patients. Staff-only — patient users cannot access.

Supports the reporting filters for the New Patient report (api#153) and the Inactive Patient report (api#154). Both compute their "visit" date from the patient's completed appointments (complete / ready_for_walkout), bucketed in the practice's timezone, so a 23:30 appointment in Los Angeles doesn't spill into tomorrow because the server happens to speak UTC.

The first-visit and last-visit annotations are attached only when a corresponding filter is active or include=first_visit / include=last_visit is supplied -- they each add a correlated Subquery and we don't want every typeahead request paying for them.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
as_of
string <date>

Reference date for the is_still_active annotation (YYYY-MM-DD, practice TZ). Defaults to today in the practice timezone. Only meaningful when include=first_visit is set -- is_still_active is true when the patient has at least one completed appointment in the 90 days preceding as_of (inclusive).

first_visit_date_from
string <date>

Include only patients whose first completed visit (earliest complete or ready_for_walkout appointment, bucketed in practice TZ) is on or after this date (inclusive). Used by the New Patient report.

first_visit_date_to
string <date>

Include only patients whose first completed visit is on or before this date (inclusive). Combine with first_visit_date_from to form a closed range.

first_visit_production_gte
number <double>

Include only patients whose first-visit production is greater than or equal to this value. Requires the first-visit include group to be active (include=first_visit or first_visit_date_from/first_visit_date_to). Used by the New Patient report to exclude walk-in exams that never converted into real production.

has_future_appointment
boolean

When false, exclude patients with any scheduled future appointment (scheduled / arrived / seated / ready_for_doctor / ready_for_walkout with date_time in the future). When true, include only those patients. Default: no filtering on future appointments.

include
string

Comma-separated list of optional serializer field groups to include on every row. Supported values: first_visit (adds first_visit_date, first_visit_production, first_visit_provider_id, first_visit_provider_name, is_still_active), last_visit (adds last_visit_date). The first_visit_* fields are also returned automatically when first_visit_date_from / first_visit_date_to is set; last_visit_date is returned automatically when last_visit_before is set.

last_visit_before
string <date>

Include only patients whose most recent completed visit is on or before this date (inclusive). Used by the Inactive Patient report.

ordering
string

Ordering: first_visit_date / -first_visit_date, last_visit_date / -last_visit_date, recall_risk_score / -recall_risk_score. Nulls are sorted last in either direction so patients without any completed visits (or no recall-risk score) don't crowd the top of the list.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

phone
string

Filter to patients whose phone_mobile, phone_home, or phone_work matches the supplied phone number after E.164 normalisation on both sides. Accepts any phone-shaped input (+15551234567, 555-123-4567, (555) 123-4567); stored values are also re-normalised at match time, so a query for +15551234567 matches a stored (555) 123-4567 or 5551234567. Used by the call-pop screen to fetch a pre-filtered list instead of paging the full patient table. Unparseable input returns an empty list (200, not 400) — matches the spirit of the other forgiving query params on this endpoint.

provider
Array of strings <uuid> [ items <uuid > ]

Filter by provider UUID. May be repeated (?provider=<u1>&provider=<u2>) or comma-separated (?provider=<u1>,<u2>) to match any of several providers (union / OR). When the first-visit include group is active (include=first_visit or first_visit_date_from/first_visit_date_to is set), matches against the patient's first-visit provider -- i.e. who they saw on their earliest completed appointment. Otherwise matches against primary_provider.

recall_risk_score__gte
integer

Include only patients whose recall_risk_score is greater than or equal to this integer (0-100). Drives the 'high priority for outreach' filter -- pass 70 for the standard cutoff. Patients whose score is null (never scored, or not enrolled in any recall) are excluded by the filter. api#837.

search
string

Case-insensitive substring search. Single-token queries fan out across first_name, last_name, email, phone_home/phone_work/phone_mobile, date_of_birth, address, city, state, and zip_code. Multi-token queries (e.g. aaron de bruyn) are treated as name searches: every token must match first_name or last_name (AND across tokens, OR across the two name fields), which prevents accidental substring hits inside email/phone/address from returning unrelated patients. Also powers the patient-search typeahead; the TypeaheadPageNumberPagination cap (25/50) keeps autocomplete responses tight for UI clients.

status
string
Enum: "active" "archived" "deceased" "inactive" "prospective"

Filter by patient status.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_create

List and create patients. Staff-only — patient users cannot access.

Supports the reporting filters for the New Patient report (api#153) and the Inactive Patient report (api#154). Both compute their "visit" date from the patient's completed appointments (complete / ready_for_walkout), bucketed in the practice's timezone, so a 23:30 appointment in Los Angeles doesn't spill into tomorrow because the server happens to speak UTC.

The first-visit and last-visit annotations are attached only when a corresponding filter is active or include=first_visit / include=last_visit is supplied -- they each add a correlated Subquery and we don't want every typeahead request paying for them.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
header Parameters
Idempotency-Key
string [ 8 .. 128 ] characters ^[A-Za-z0-9._:-]{8,128}$

Optional client-generated key (8–128 chars, alphabet [A-Za-z0-9._:-]) that makes a POST idempotent for 24 hours. If the key has been seen before with the same request body, the original response is returned byte-for-byte with Idempotency-Status: replayed. If the key has been seen with a different body, the server returns 422. If a concurrent request using the same key is still in flight, the server returns 409 with retry_after_seconds. Absent the header, the request proceeds normally with no idempotency guarantee.

Request Body schema:
required
first_name
required
string [ 1 .. 100 ] characters
last_name
required
string [ 1 .. 100 ] characters
preferred_name
string <= 100 characters
email
string <email> <= 254 characters
date_of_birth
string or null <date>
gender
string (GenderEnum)
Enum: "male" "female" "prefer_not_to_say" "unknown"
  • male - Male
  • female - Female
  • prefer_not_to_say - Prefer not to say
  • unknown - Unknown
status
string (PatientStatusEnum)
Enum: "active" "inactive" "archived" "deceased" "prospective"
  • active - Active
  • inactive - Inactive
  • archived - Archived
  • deceased - Deceased
  • prospective - Prospective
phone_home
string or null
phone_work
string or null
phone_mobile
string or null
address
string <= 255 characters
address2
string <= 255 characters
city
string <= 100 characters
state
string <= 50 characters
zip_code
string <= 10 characters ^\d{5}(-\d{4})?$
primary_provider
string or null <uuid>
secondary_provider
string or null <uuid>
balance_current
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Current account balance, denormalized from the ledger for fast list rendering.

last_recall_date
string or null <date>

Most recent recall appointment date from the source PMS

next_recall_date
string or null <date>

Next scheduled recall appointment date from the source PMS

prefers_email
boolean

Patient opts in to email communications (per source PMS)

prefers_sms
boolean

Patient opts in to SMS/text communications (per source PMS)

hipaa_consent_signed
boolean

HIPAA treatment consent signed (per source PMS)

hipaa_consent_date
string or null <date>

Date HIPAA treatment consent was signed

hipaa_authorization_signed
boolean

HIPAA authorization (release of info) signed (per source PMS)

hipaa_authorization_date
string or null <date>

Date HIPAA authorization was signed

hipaa_privacy_practices_signed
boolean

HIPAA notice of privacy practices acknowledged (per source PMS)

hipaa_privacy_practices_date
string or null <date>

Date HIPAA notice of privacy practices was acknowledged

custom_data
any
ssn_full
string or null [ 1 .. 11 ] characters

Write-only. Sets the patient's SSN via the encrypted side table. Pass null to clear. Never returned on read -- the /ssn/full/ endpoint is the only path for audit-logged disclosure.

Responses

Request samples

Content type
{
  • "first_name": "string",
  • "last_name": "string",
  • "preferred_name": "string",
  • "email": "user@example.com",
  • "date_of_birth": "2019-08-24",
  • "gender": "male",
  • "status": "active",
  • "phone_home": "string",
  • "phone_work": "string",
  • "phone_mobile": "string",
  • "address": "string",
  • "address2": "string",
  • "city": "string",
  • "state": "string",
  • "zip_code": "string",
  • "primary_provider": "be2be9e9-c010-46fe-8c1e-a13cbc4f6d37",
  • "secondary_provider": "777f5dc9-f0f1-403f-9363-1023b8767d88",
  • "balance_current": "string",
  • "last_recall_date": "2019-08-24",
  • "next_recall_date": "2019-08-24",
  • "prefers_email": true,
  • "prefers_sms": true,
  • "hipaa_consent_signed": true,
  • "hipaa_consent_date": "2019-08-24",
  • "hipaa_authorization_signed": true,
  • "hipaa_authorization_date": "2019-08-24",
  • "hipaa_privacy_practices_signed": true,
  • "hipaa_privacy_practices_date": "2019-08-24",
  • "custom_data": null,
  • "ssn_full": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "first_name": "string",
  • "last_name": "string",
  • "preferred_name": "string",
  • "email": "user@example.com",
  • "date_of_birth": "2019-08-24",
  • "gender": "male",
  • "status": "active",
  • "phone_home": "string",
  • "phone_work": "string",
  • "phone_mobile": "string",
  • "address": "string",
  • "address2": "string",
  • "city": "string",
  • "state": "string",
  • "zip_code": "string",
  • "primary_provider": "be2be9e9-c010-46fe-8c1e-a13cbc4f6d37",
  • "secondary_provider": "777f5dc9-f0f1-403f-9363-1023b8767d88",
  • "last_medical_review": "2019-08-24",
  • "last_medical_review_by": "32e17085-58ec-492b-b21e-23eca3985cd7",
  • "last_medical_review_by_name": "string",
  • "balance_current": "string",
  • "last_recall_date": "2019-08-24",
  • "next_recall_date": "2019-08-24",
  • "recall_risk_score": 0,
  • "noshow_risk_score": 0.1,
  • "prefers_email": true,
  • "prefers_sms": true,
  • "hipaa_consent_signed": true,
  • "hipaa_consent_date": "2019-08-24",
  • "hipaa_authorization_signed": true,
  • "hipaa_authorization_date": "2019-08-24",
  • "hipaa_privacy_practices_signed": true,
  • "hipaa_privacy_practices_date": "2019-08-24",
  • "custom_data": null,
  • "referral_source": "string",
  • "ssn_last4_masked": "string",
  • "source_system": "string",
  • "source_id": "string"
}

practice_patient_bulk_partial_update

Handle PATCH on the list endpoint for bulk updates.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
first_name
string [ 1 .. 100 ] characters
last_name
string [ 1 .. 100 ] characters
preferred_name
string <= 100 characters
email
string <email> <= 254 characters
date_of_birth
string or null <date>
gender
string (GenderEnum)
Enum: "male" "female" "prefer_not_to_say" "unknown"
  • male - Male
  • female - Female
  • prefer_not_to_say - Prefer not to say
  • unknown - Unknown
status
string (PatientStatusEnum)
Enum: "active" "inactive" "archived" "deceased" "prospective"
  • active - Active
  • inactive - Inactive
  • archived - Archived
  • deceased - Deceased
  • prospective - Prospective
phone_home
string or null
phone_work
string or null
phone_mobile
string or null
address
string <= 255 characters
address2
string <= 255 characters
city
string <= 100 characters
state
string <= 50 characters
zip_code
string <= 10 characters ^\d{5}(-\d{4})?$
primary_provider
string or null <uuid>
secondary_provider
string or null <uuid>
balance_current
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Current account balance, denormalized from the ledger for fast list rendering.

last_recall_date
string or null <date>

Most recent recall appointment date from the source PMS

next_recall_date
string or null <date>

Next scheduled recall appointment date from the source PMS

prefers_email
boolean

Patient opts in to email communications (per source PMS)

prefers_sms
boolean

Patient opts in to SMS/text communications (per source PMS)

hipaa_consent_signed
boolean

HIPAA treatment consent signed (per source PMS)

hipaa_consent_date
string or null <date>

Date HIPAA treatment consent was signed

hipaa_authorization_signed
boolean

HIPAA authorization (release of info) signed (per source PMS)

hipaa_authorization_date
string or null <date>

Date HIPAA authorization was signed

hipaa_privacy_practices_signed
boolean

HIPAA notice of privacy practices acknowledged (per source PMS)

hipaa_privacy_practices_date
string or null <date>

Date HIPAA notice of privacy practices was acknowledged

custom_data
any
ssn_full
string or null [ 1 .. 11 ] characters

Write-only. Sets the patient's SSN via the encrypted side table. Pass null to clear. Never returned on read -- the /ssn/full/ endpoint is the only path for audit-logged disclosure.

Responses

Request samples

Content type
{
  • "first_name": "string",
  • "last_name": "string",
  • "preferred_name": "string",
  • "email": "user@example.com",
  • "date_of_birth": "2019-08-24",
  • "gender": "male",
  • "status": "active",
  • "phone_home": "string",
  • "phone_work": "string",
  • "phone_mobile": "string",
  • "address": "string",
  • "address2": "string",
  • "city": "string",
  • "state": "string",
  • "zip_code": "string",
  • "primary_provider": "be2be9e9-c010-46fe-8c1e-a13cbc4f6d37",
  • "secondary_provider": "777f5dc9-f0f1-403f-9363-1023b8767d88",
  • "balance_current": "string",
  • "last_recall_date": "2019-08-24",
  • "next_recall_date": "2019-08-24",
  • "prefers_email": true,
  • "prefers_sms": true,
  • "hipaa_consent_signed": true,
  • "hipaa_consent_date": "2019-08-24",
  • "hipaa_authorization_signed": true,
  • "hipaa_authorization_date": "2019-08-24",
  • "hipaa_privacy_practices_signed": true,
  • "hipaa_privacy_practices_date": "2019-08-24",
  • "custom_data": null,
  • "ssn_full": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "first_name": "string",
  • "last_name": "string",
  • "preferred_name": "string",
  • "email": "user@example.com",
  • "date_of_birth": "2019-08-24",
  • "gender": "male",
  • "status": "active",
  • "phone_home": "string",
  • "phone_work": "string",
  • "phone_mobile": "string",
  • "address": "string",
  • "address2": "string",
  • "city": "string",
  • "state": "string",
  • "zip_code": "string",
  • "primary_provider": "be2be9e9-c010-46fe-8c1e-a13cbc4f6d37",
  • "secondary_provider": "777f5dc9-f0f1-403f-9363-1023b8767d88",
  • "last_medical_review": "2019-08-24",
  • "last_medical_review_by": "32e17085-58ec-492b-b21e-23eca3985cd7",
  • "last_medical_review_by_name": "string",
  • "balance_current": "string",
  • "last_recall_date": "2019-08-24",
  • "next_recall_date": "2019-08-24",
  • "recall_risk_score": 0,
  • "noshow_risk_score": 0.1,
  • "prefers_email": true,
  • "prefers_sms": true,
  • "hipaa_consent_signed": true,
  • "hipaa_consent_date": "2019-08-24",
  • "hipaa_authorization_signed": true,
  • "hipaa_authorization_date": "2019-08-24",
  • "hipaa_privacy_practices_signed": true,
  • "hipaa_privacy_practices_date": "2019-08-24",
  • "custom_data": null,
  • "referral_source": "string",
  • "ssn_last4_masked": "string",
  • "source_system": "string",
  • "source_id": "string"
}

practice_patient_ssn_full_retrieve

Disclose the full SSN for a single patient.

Returns {"ssn": "<digits>"} on success. {"ssn": null} when the patient has no SSN on file (still 200 so callers can tell "no SSN" from "no patient" -- the latter is a 404).

Every successful decrypt writes an ssn.full_viewed audit event carrying the OAuth Application id (when present), the requesting user, IP, scope used, and timestamp. See :class:apps.patients.models.PatientSSNManager.reveal_full.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

practice_patient_ssn_last4_retrieve

Disclose the last-4 digits / PIN for a single patient.

Returns {"last4": "<digits>", "kind": "ssn"|"pin"} on success; {"last4": null, "kind": null} when the patient has no last-4 on file.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

practice_patient_referral_source_bulk_partial_update

Handle PATCH on the list endpoint for bulk updates.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
first_name
string <= 100 characters
last_name
string <= 100 characters
specialty
string <= 100 characters
phone
string <= 20 characters
email
string <email> <= 254 characters
npi
string <= 20 characters
is_doctor
boolean
custom_data
any

Responses

Request samples

Content type
{
  • "first_name": "string",
  • "last_name": "string",
  • "specialty": "string",
  • "phone": "string",
  • "email": "user@example.com",
  • "npi": "string",
  • "is_doctor": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "first_name": "string",
  • "last_name": "string",
  • "specialty": "string",
  • "phone": "string",
  • "email": "user@example.com",
  • "npi": "string",
  • "is_doctor": true,
  • "custom_data": null,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_patient_stats_retrieve

Quick stats for the practice's patient data. Staff-only.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

practice_patient_verify_create

Verify a patient's identity by name + DOB + last 4.

Body::

{
  "first_name": "Alice",
  "last_name": "Smith",
  "dob": "1990-04-12",
  "last_4": "1234"
}

Returns {"patient_id": "<uuid>"} on a single unambiguous match. Returns 404 (no body) on no-match OR when the (first_name, last_name, dob) triple matches multiple patients -- the endpoint refuses to disambiguate by returning a list, so a caller cannot enumerate patients within a practice via this surface.

Comparison is server-side. The candidate last-4 is decrypted out of pgcrypto and compared with hmac.compare_digest (constant time) -- the candidate is NEVER hashed-and-compared client-side.

A single ssn.verify_attempted event is emitted for every call regardless of outcome (outcome=success on match, outcome=failure on miss). The event metadata carries the (name, dob) tuple the caller supplied but NEVER the last-4 candidate.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
first_name
required
string [ 1 .. 100 ] characters
last_name
required
string [ 1 .. 100 ] characters
dob
required
string <date>
last_4
required
string = 4 characters ^\d{4}$

Responses

Request samples

Content type
{
  • "first_name": "string",
  • "last_name": "string",
  • "dob": "2019-08-24",
  • "last_4": "stri"
}

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

Clinical

Notes, procedures, treatment plans, perio, vitals, conditions, medications, allergies

practice_clinical_alerts_retrieve

Batch medical alert summaries for multiple patients.

GET /practice//clinical/alerts/?patient_ids=1,2,3

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

List chairside auto-note macros for a practice.

Returns the practice's catalog of operator-built chairside macros (#periomax -> a perio-eval template) for the chart-note editor's autocomplete surface. Paginated with :class:config.pagination.DefaultPageNumberPagination (stable ordering via pk tiebreaker).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

search
string

Case-insensitive substring search across name and body.

Responses

Response samples

Content type
application/json
{}

Create or upsert an auto-note macro.

Creates a new auto-note macro, or updates the existing row when (practice, name) already exists. This is the idempotent landing path for the Eaglesoft / OpenDental converters (escape-tools#205, escape-tools#206): re-running an import will refresh the body / prompts instead of returning HTTP 400 from the unique constraint.

Returns 201 Created for new rows and 200 OK for updates.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 128 ] characters

Operator-visible macro label, e.g. 'Perio Max'.

body
required
string non-empty

Template body with single-braced {key} placeholders matched against prompts[].key.

category
string <= 64 characters

Free-form grouping (e.g. 'Hygiene', 'Endo'). PMS-supplied; not enumerated.

Array of objects

Operator-fill widget specs. See AutoNote model docs for shape.

custom_data
any

Responses

Request samples

Content type
{
  • "name": "string",
  • "body": "string",
  • "category": "string",
  • "prompts": [
    ],
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "body": "string",
  • "category": "string",
  • "prompts": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_clinical_auto_note_retrieve

Retrieve, update, or delete a single :class:AutoNote.

Hard delete is correct here -- auto-notes are authoring aids, not patient data, so HIPAA immutability does not apply.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
auto_note_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "body": "string",
  • "category": "string",
  • "prompts": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_clinical_auto_notes_update

Retrieve, update, or delete a single :class:AutoNote.

Hard delete is correct here -- auto-notes are authoring aids, not patient data, so HIPAA immutability does not apply.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
auto_note_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 128 ] characters

Operator-visible macro label, e.g. 'Perio Max'.

body
required
string non-empty

Template body with single-braced {key} placeholders matched against prompts[].key.

category
string <= 64 characters

Free-form grouping (e.g. 'Hygiene', 'Endo'). PMS-supplied; not enumerated.

Array of objects

Operator-fill widget specs. See AutoNote model docs for shape.

custom_data
any

Responses

Request samples

Content type
{
  • "name": "string",
  • "body": "string",
  • "category": "string",
  • "prompts": [
    ],
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "body": "string",
  • "category": "string",
  • "prompts": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_clinical_auto_note_partial_update

Retrieve, update, or delete a single :class:AutoNote.

Hard delete is correct here -- auto-notes are authoring aids, not patient data, so HIPAA immutability does not apply.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
auto_note_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
name
string [ 1 .. 128 ] characters

Operator-visible macro label, e.g. 'Perio Max'.

body
string non-empty

Template body with single-braced {key} placeholders matched against prompts[].key.

category
string <= 64 characters

Free-form grouping (e.g. 'Hygiene', 'Endo'). PMS-supplied; not enumerated.

Array of objects

Operator-fill widget specs. See AutoNote model docs for shape.

custom_data
any

Responses

Request samples

Content type
{
  • "name": "string",
  • "body": "string",
  • "category": "string",
  • "prompts": [
    ],
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "body": "string",
  • "category": "string",
  • "prompts": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_clinical_auto_note_destroy

Retrieve, update, or delete a single :class:AutoNote.

Hard delete is correct here -- auto-notes are authoring aids, not patient data, so HIPAA immutability does not apply.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
auto_note_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_clinical_note_template_list

List and create clinical note templates for a practice.

Supports filtering by category and active status.

Uses :class:ReferenceDataPagination (100/2000) instead of the default 20/100 cap because the web UI loads the full note-template catalog once for typeahead / dropdown rendering inside the chart. A mature practice accumulates hundreds of templates across categories -- paginating 20 at a time would thrash the chart UI. See api#194.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
active
string
Enum: "false" "true"

Filter by active status. Accepts true or false.

category
string
Enum: "endo" "exam" "general" "hygiene" "oral_surgery"

Filter by template category.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{}

practice_clinical_note_template_create

List and create clinical note templates for a practice.

Supports filtering by category and active status.

Uses :class:ReferenceDataPagination (100/2000) instead of the default 20/100 cap because the web UI loads the full note-template catalog once for typeahead / dropdown rendering inside the chart. A mature practice accumulates hundreds of templates across categories -- paginating 20 at a time would thrash the chart UI. See api#194.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 255 ] characters
CategoryEnum (string) or BlankEnum (any)
content
required
string non-empty

Template body. Supports placeholder tokens like {{tooth}}, {{provider}}.

is_active
boolean
sort_order
integer [ 0 .. 2147483647 ]
custom_data
any

Responses

Request samples

Content type
{
  • "name": "string",
  • "category": "exam",
  • "content": "string",
  • "is_active": true,
  • "sort_order": 2147483647,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "category": "exam",
  • "content": "string",
  • "is_active": true,
  • "sort_order": 2147483647,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_clinical_note_template_render_create

Resolve a note template's {{token}} placeholders (GH-1020).

POST /practice/<uid>/clinical/note-template/render/

Body: {"content": "...", "patient_id"?, "provider_id"?, "tooth"?}.

Returns {"content": "<rendered>"}. Known catalog tokens are substituted with real values; unknown tokens are left verbatim. This is the path that fixes the literal-token bug -- the web note-form (web#818) calls it when applying a template so the chart note gets resolved values instead of raw {{provider}} text.

Mirrors the reactivation template render action (api#867): pure preview/transform, no note is created. Each referenced UUID is validated against the URL-mounted practice, so a cross-tenant UID 404s before any data is read.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
content
required
string non-empty

Template body containing {{token}} placeholders to resolve.

patient_id
string or null <uuid>

Patient to resolve patient_* tokens against.

provider_id
string or null <uuid>

Provider to resolve provider tokens against.

tooth
string <= 10 characters

Tooth number from the active chart context, resolves {{tooth}}.

Responses

Request samples

Content type
{
  • "content": "string",
  • "patient_id": "3854866a-5476-48be-8313-77029ccdd7a7",
  • "provider_id": "fe3d49af-4061-436b-ae60-f7044f252a44",
  • "tooth": "string"
}

Response samples

Content type
application/json
{
  • "content": "string"
}

practice_clinical_note_template_variables_list

Canonical catalog of note-template placeholders (GH-1020).

GET /practice/<uid>/clinical/note-template/variables/

Returns every {{token}} the note renderer can resolve, with a human description and the data field it comes from. The web variable picker (web#818) consumes this instead of hard-coding a guessed list, so the picker and the renderer can never drift apart.

The catalog is static (no per-practice data), but the endpoint stays practice-scoped and staff-gated for consistency with the rest of the clinical surface and so its shape can later vary per practice without a URL change.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

practice_clinical_procedure_list

Practice-wide procedure list and bulk create.

GET returns all procedures for the practice (paginated, filterable). POST accepts a JSON array for bulk import (up to 5000 records).

Used by escape-opendental, escape-eaglesoft, and escape-backup tools.

Uses PageNumberPagination instead of the default CursorPagination because bulk-imported procedures may have NULL created timestamps, which causes CursorPagination to crash with a 500.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
date_from
string <date>

Inclusive lower bound on proc_date (ISO 8601 date).

date_to
string <date>

Inclusive upper bound on proc_date (ISO 8601 date).

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

patient
string <uuid>

Filter to procedures for a single patient UUID.

provider
string <uuid>

Filter by provider UUID.

status
string
Enum: "complete" "existing_current" "existing_other"

Filter by procedure status. Common values are complete, existing_current, and existing_other; free-text is accepted for legacy PMS imports.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_clinical_procedure_create

Practice-wide procedure list and bulk create.

GET returns all procedures for the practice (paginated, filterable). POST accepts a JSON array for bulk import (up to 5000 records).

Used by escape-opendental, escape-eaglesoft, and escape-backup tools.

Uses PageNumberPagination instead of the default CursorPagination because bulk-imported procedures may have NULL created timestamps, which causes CursorPagination to crash with a 500.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>
provider
string or null <uuid>
appointment
string or null <uuid>
procedure_code
string or null <uuid>
proc_code
string <= 20 characters
description
string <= 255 characters
proc_date
string or null <date>
date_complete
string or null <date>
proc_fee
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
status
string <= 30 characters

complete, existing_current, existing_other

tooth_num
string <= 10 characters
surface
string <= 20 characters
discount
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
unit_qty
integer [ 0 .. 2147483647 ]
custom_data
any

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "proc_code": "string",
  • "description": "string",
  • "proc_date": "2019-08-24",
  • "date_complete": "2019-08-24",
  • "proc_fee": "string",
  • "status": "string",
  • "tooth_num": "string",
  • "surface": "string",
  • "discount": "string",
  • "unit_qty": 2147483647,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "proc_code": "string",
  • "description": "string",
  • "proc_date": "2019-08-24",
  • "date_complete": "2019-08-24",
  • "proc_fee": "string",
  • "status": "string",
  • "tooth_num": "string",
  • "surface": "string",
  • "discount": "string",
  • "unit_qty": 2147483647,
  • "custom_data": null
}

practice_clinical_procedure_code_list

List and create procedure codes for a practice. Searchable by code/description.

Uses :class:ReferenceDataPagination (100/2000) instead of the default 20/100 cap because the web UI loads the full catalog once for local typeahead and service-type filtering across dropdowns. A typical practice catalog is 1K-4K ADA codes -- paginating 20 at a time would require dozens of round-trips and break the Service Codes screen / checkout dialog procedure search.

Conflict guard (api#926)

When Client.enforce_service_codes is True for the practice's owning Client, creating a custom code whose code value (case-insensitively) matches an existing client-managed row is rejected with HTTP 403. This is a server-side guard; the web UI should prevent the attempt, but enforcement must live here so bypass attempts are caught.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
active
string
Enum: "false" "true"

Filter by active status. Accepts true or false.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

search
string

Case-insensitive substring search across code, description, and abbreviation.

service_type
string
Enum: "adjunctive" "basic" "diagnostic" "endodontics" "major" "oral_surgery" "orthodontics" "other" "periodontics" "preventive" "prosthodontics"

Filter by ADA service type classification.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_clinical_procedure_code_create

List and create procedure codes for a practice. Searchable by code/description.

Uses :class:ReferenceDataPagination (100/2000) instead of the default 20/100 cap because the web UI loads the full catalog once for local typeahead and service-type filtering across dropdowns. A typical practice catalog is 1K-4K ADA codes -- paginating 20 at a time would require dozens of round-trips and break the Service Codes screen / checkout dialog procedure search.

Conflict guard (api#926)

When Client.enforce_service_codes is True for the practice's owning Client, creating a custom code whose code value (case-insensitively) matches an existing client-managed row is rejected with HTTP 403. This is a server-side guard; the web UI should prevent the attempt, but enforcement must live here so bypass attempts are caught.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
code
required
string [ 1 .. 20 ] characters
description
string <= 255 characters
abbreviation
string <= 100 characters
ServiceTypeEnum (string) or BlankEnum (any)
default_fee
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Practice UCR fee

default_duration_minutes
integer [ 0 .. 2147483647 ]

Default appointment block size

generate_recall
boolean

Triggers recall scheduling when completed

is_active
boolean
ada_code
string <= 20 characters

ADA/CDT code reference (insurance module)

custom_data
any

Responses

Request samples

Content type
{
  • "code": "string",
  • "description": "string",
  • "abbreviation": "string",
  • "service_type": "diagnostic",
  • "default_fee": "string",
  • "default_duration_minutes": 2147483647,
  • "generate_recall": true,
  • "is_active": true,
  • "ada_code": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "code": "string",
  • "description": "string",
  • "abbreviation": "string",
  • "service_type": "diagnostic",
  • "default_fee": "string",
  • "default_duration_minutes": 2147483647,
  • "generate_recall": true,
  • "is_active": true,
  • "ada_code": "string",
  • "is_client_managed": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_clinical_procedure_code_bulk_partial_update

Handle PATCH on the list endpoint for bulk updates.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
code
string [ 1 .. 20 ] characters
description
string <= 255 characters
abbreviation
string <= 100 characters
ServiceTypeEnum (string) or BlankEnum (any)
default_fee
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Practice UCR fee

default_duration_minutes
integer [ 0 .. 2147483647 ]

Default appointment block size

generate_recall
boolean

Triggers recall scheduling when completed

is_active
boolean
ada_code
string <= 20 characters

ADA/CDT code reference (insurance module)

custom_data
any

Responses

Request samples

Content type
{
  • "code": "string",
  • "description": "string",
  • "abbreviation": "string",
  • "service_type": "diagnostic",
  • "default_fee": "string",
  • "default_duration_minutes": 2147483647,
  • "generate_recall": true,
  • "is_active": true,
  • "ada_code": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "code": "string",
  • "description": "string",
  • "abbreviation": "string",
  • "service_type": "diagnostic",
  • "default_fee": "string",
  • "default_duration_minutes": 2147483647,
  • "generate_recall": true,
  • "is_active": true,
  • "ada_code": "string",
  • "is_client_managed": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_clinical_procedure_code_suggest_retrieve

Suggest an appropriate CDT code based on patient clinical history.

GET /practice//clinical/procedure-code/suggest/?patient_id=

Checks if the patient has any completed D4341/D4342 (SRP) procedures. If yes, suggests D4910 (perio maintenance) instead of D1110 (prophylaxis).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
query
string

Search query for procedure code suggestions

Responses

practice_patient_clinical_alerts_retrieve

Single-patient medical alert summary.

GET /practice//patient//clinical/alerts/

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

practice_patient_clinical_anesthesia_list

List and create anesthesia records for a patient.

Supports filtering by appointment and date range.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
appointment
string <uuid>

Filter records to a single appointment UUID.

date_from
string <date>

Inclusive lower bound on administered_at (ISO 8601 date). Interpreted in the practice's local timezone.

date_to
string <date>

Inclusive upper bound on administered_at (ISO 8601 date). Interpreted in the practice's local timezone.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_clinical_anesthesia_create

List and create anesthesia records for a patient.

Supports filtering by appointment and date range.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
appointment
string or null <uuid>
provider
string or null <uuid>
agent
required
string (AgentEnum)
Enum: "lidocaine_epi" "lidocaine" "articaine_epi" "articaine_epi_200" "mepivacaine_epi" "mepivacaine" "bupivacaine_epi" "prilocaine_epi" "prilocaine" "topical_benzocaine" "topical_lidocaine" "nitrous" "other"
  • lidocaine_epi - Lidocaine 2% with Epinephrine 1:100,000
  • lidocaine - Lidocaine 2% (plain)
  • articaine_epi - Articaine 4% with Epinephrine 1:100,000
  • articaine_epi_200 - Articaine 4% with Epinephrine 1:200,000
  • mepivacaine_epi - Mepivacaine 2% with Levonordefrin 1:20,000
  • mepivacaine - Mepivacaine 3% (plain)
  • bupivacaine_epi - Bupivacaine 0.5% with Epinephrine 1:200,000
  • prilocaine_epi - Prilocaine 4% with Epinephrine 1:200,000
  • prilocaine - Prilocaine 4% (plain)
  • topical_benzocaine - Topical Benzocaine 20%
  • topical_lidocaine - Topical Lidocaine 5%
  • nitrous - Nitrous Oxide / Oxygen
  • other - Other
agent_other
string <= 100 characters

If agent=other, specify here

route
string (RouteEnum)
Enum: "infiltration" "block" "topical" "inhalation"
  • infiltration - Infiltration
  • block - Block
  • topical - Topical
  • inhalation - Inhalation
site
string <= 100 characters

e.g. #14 buccal infiltration, right IAN block

carpules
string <decimal> ^-?\d{0,2}(?:\.\d{0,1})?$

Number of carpules administered

lot_number
string <= 50 characters
expiration_date
string or null <date>
administered_at
required
string <date-time>

When the anesthesia was administered

note
string

Complications, reactions, or additional notes

custom_data
any

Responses

Request samples

Content type
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "agent": "lidocaine_epi",
  • "agent_other": "string",
  • "route": "infiltration",
  • "site": "string",
  • "carpules": "string",
  • "lot_number": "string",
  • "expiration_date": "2019-08-24",
  • "administered_at": "2019-08-24T14:15:22Z",
  • "note": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "agent": "lidocaine_epi",
  • "agent_other": "string",
  • "route": "infiltration",
  • "site": "string",
  • "carpules": "string",
  • "lot_number": "string",
  • "expiration_date": "2019-08-24",
  • "administered_at": "2019-08-24T14:15:22Z",
  • "note": "string",
  • "custom_data": null
}

practice_patient_clinical_confirm_medical_review_create

Confirm that a patient's medical history has been reviewed.

POST sets patient.last_medical_review to today and patient.last_medical_review_by to the authenticated user.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_clinical_education_list

List and create patient education records for a patient.

Supports filtering by appointment, topic, and date range.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
appointment
string <uuid>

Filter records to a single appointment UUID.

date_from
string <date>

Inclusive lower bound on education_date (ISO 8601 date).

date_to
string <date>

Inclusive upper bound on education_date (ISO 8601 date).

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

topic
string
Enum: "brushing" "bruxism" "caries_risk" "diet_counseling" "dry_mouth" "electric_toothbrush" "flossing" "fluoride" "implant_care" "interproximal" "oral_hygiene" "ortho_care" "other" "perio_disease" "post_op" "pre_med" "sensitivity" "tobacco_cessation" "whitening"

Filter by education topic.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_clinical_education_create

List and create patient education records for a patient.

Supports filtering by appointment, topic, and date range.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
appointment
string or null <uuid>
provider
string or null <uuid>
topic
required
string (TopicEnum)
Enum: "oral_hygiene" "brushing" "flossing" "interproximal" "electric_toothbrush" "fluoride" "diet_counseling" "tobacco_cessation" "perio_disease" "caries_risk" "dry_mouth" "bruxism" "sensitivity" "whitening" "ortho_care" "implant_care" "post_op" "pre_med" "other"
  • oral_hygiene - Oral Hygiene Instructions
  • brushing - Brushing Technique
  • flossing - Flossing Technique
  • interproximal - Interproximal Cleaning
  • electric_toothbrush - Electric Toothbrush
  • fluoride - Fluoride Use
  • diet_counseling - Diet Counseling
  • tobacco_cessation - Tobacco Cessation
  • perio_disease - Periodontal Disease
  • caries_risk - Caries Risk
  • dry_mouth - Dry Mouth / Xerostomia
  • bruxism - Bruxism / Night Guard
  • sensitivity - Sensitivity
  • whitening - Whitening Options
  • ortho_care - Orthodontic Care
  • implant_care - Implant Care
  • post_op - Post-Operative Instructions
  • pre_med - Premedication Reminder
  • other - Other
detail
string

Specific instructions or notes about what was discussed

products_recommended
string <= 255 characters

e.g. Sonicare, Waterpik, MI Paste

education_date
required
string <date>
compliance_note
string

Patient response, compliance observations

send_to_portal
boolean

Make available in patient portal

custom_data
any

Responses

Request samples

Content type
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "topic": "oral_hygiene",
  • "detail": "string",
  • "products_recommended": "string",
  • "education_date": "2019-08-24",
  • "compliance_note": "string",
  • "send_to_portal": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "topic": "oral_hygiene",
  • "detail": "string",
  • "products_recommended": "string",
  • "education_date": "2019-08-24",
  • "compliance_note": "string",
  • "send_to_portal": true,
  • "custom_data": null
}

practice_patient_clinical_note_list

List and create clinical notes for a patient.

Supports filtering by note_type, provider, date range, and free-text search.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
date_from
string <date>

Inclusive lower bound on note_date (ISO 8601 date, e.g. 2025-01-15).

date_to
string <date>

Inclusive upper bound on note_date (ISO 8601 date).

note_type
string
Enum: "clinical" "consult" "exam" "hygiene" "lab" "other" "phone"

Filter by note type.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

provider
string <uuid>

Filter by provider UUID.

search
string

Case-insensitive substring search across subject and content.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_clinical_note_create

List and create clinical notes for a patient.

Supports filtering by note_type, provider, date range, and free-text search.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
appointment
string or null <uuid>
provider
string or null <uuid>
template
string or null <uuid>

Template used to create this note (reference only, content is copied)

note_type
string (NoteTypeEnum)
Enum: "clinical" "exam" "hygiene" "consult" "phone" "lab" "internal" "other"
  • clinical - Clinical Note
  • exam - Exam Note
  • hygiene - Hygiene Note
  • consult - Consult Note
  • phone - Phone Note
  • lab - Lab Note
  • internal - Internal Note
  • other - Other
subject
string <= 200 characters
content
string

Plain text or structured note content

note_date
string or null <date>
is_addendum
boolean

Addendum to a previous note

parent_note
string or null <uuid>

If is_addendum=True, the original note this amends

custom_data
any

Responses

Request samples

Content type
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "note_type": "clinical",
  • "subject": "string",
  • "content": "string",
  • "note_date": "2019-08-24",
  • "is_addendum": true,
  • "parent_note": "47e0a283-e822-462a-a025-efa34db2b778",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "note_type": "clinical",
  • "subject": "string",
  • "content": "string",
  • "note_date": "2019-08-24",
  • "is_addendum": true,
  • "parent_note": "47e0a283-e822-462a-a025-efa34db2b778",
  • "custom_data": null
}

practice_patient_clinical_note_sign_create

Sign a clinical note (irreversible HIPAA action).

POST signs the note, setting is_signed=True, signed_by, and signed_at. Once signed, the note content becomes immutable.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
note_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_clinical_perio_readings_update

Bulk upsert perio readings for an exam.

PUT accepts an array of reading objects keyed by tooth_num. Uses update_or_create per tooth within the exam. Returns the full exam with nested readings after save.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
perio_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_clinical_perio_compare_retrieve

Compare two perio exams side by side.

GET /...perio/compare/?exam1=&exam2= Validates both exams belong to the same practice and patient.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
exam1
required
string <uuid>

First perio exam UUID to compare.

exam2
required
string <uuid>

Second perio exam UUID to compare.

Responses

practice_patient_clinical_procedure_list

List and create procedures for a patient.

Supports filtering by provider, date range, status, and free-text search.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
date_from
string <date>

Inclusive lower bound on proc_date (ISO 8601 date).

date_to
string <date>

Inclusive upper bound on proc_date (ISO 8601 date).

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

provider
string <uuid>

Filter by provider UUID.

search
string

Case-insensitive substring search across proc_code and description.

status
string
Enum: "complete" "existing_current" "existing_other"

Filter by procedure status. Common values are complete, existing_current, and existing_other; free-text is accepted for legacy PMS imports.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_clinical_procedure_create

List and create procedures for a patient.

Supports filtering by provider, date range, status, and free-text search.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
provider
string or null <uuid>
appointment
string or null <uuid>
procedure_code
string or null <uuid>
proc_code
string <= 20 characters
description
string <= 255 characters
proc_date
string or null <date>
proc_fee
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
status
string <= 30 characters

complete, existing_current, existing_other

tooth_num
string <= 10 characters
surface
string <= 20 characters
discount
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
unit_qty
integer [ 0 .. 2147483647 ]
custom_data
any

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "proc_code": "string",
  • "description": "string",
  • "proc_date": "2019-08-24",
  • "proc_fee": "string",
  • "status": "string",
  • "tooth_num": "string",
  • "surface": "string",
  • "discount": "string",
  • "unit_qty": 2147483647,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "proc_code": "string",
  • "description": "string",
  • "proc_date": "2019-08-24",
  • "proc_fee": "string",
  • "status": "string",
  • "tooth_num": "string",
  • "surface": "string",
  • "discount": "string",
  • "unit_qty": 2147483647,
  • "custom_data": null
}

practice_patient_clinical_procedure_bulk_partial_update

Handle PATCH on the list endpoint for bulk updates.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
custom_data
any

Responses

Request samples

Content type
{
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "procedure_code": {
    },
  • "proc_code": "string",
  • "description": "string",
  • "proc_date": "2019-08-24",
  • "date_complete": "2019-08-24",
  • "proc_fee": "string",
  • "status": "string",
  • "tooth_num": "string",
  • "surface": "string",
  • "discount": "string",
  • "unit_qty": 0,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_timeline_retrieve

Unified chronological feed for a patient.

Combines procedures, clinical notes, perio exams, treatment plans, imaging exams, communication logs, and appointments into a single sorted timeline. Paginated, newest first.

Accepts an optional event_type query parameter (comma-separated) to filter to specific event types.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
event_type
string

Comma-separated list of event types to include. Valid values: procedure, note, perio_exam, treatment_plan, imaging, communication, appointment. Omit to include all types.

page
integer

Page number (1-indexed)

page_size
integer

Number of events per page (default 50, max 200)

Responses

practice_patient_clinical_tooth_list

List and create tooth conditions for a patient.

Defaults to current conditions only (is_current=True). Supports filtering by tooth_num and overriding is_current.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
is_current
string
Enum: "all" "false"

Filter by current status. Defaults to current-only. Accepts false to return non-current conditions, or all to return every condition.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

tooth_num
string

Filter by tooth number (Universal Numbering System, e.g. 14).

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_clinical_tooth_create

List and create tooth conditions for a patient.

Defaults to current conditions only (is_current=True). Supports filtering by tooth_num and overriding is_current.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
tooth_num
required
string [ 1 .. 5 ] characters

Universal numbering: 1-32 (permanent), A-T (primary)

condition
required
string (ConditionEnum)
Enum: "missing" "implant" "crown" "bridge_abutment" "bridge_pontic" "veneer" "root_canal" "extraction_planned" "impacted" "unerupted" "supernumerary" "deciduous" "denture" "partial_denture" "caries" "filling" "sealant" "fracture" "watch"
  • missing - Missing
  • implant - Implant
  • crown - Crown
  • bridge_abutment - Bridge Abutment
  • bridge_pontic - Bridge Pontic
  • veneer - Veneer
  • root_canal - Root Canal
  • extraction_planned - Extraction Planned
  • impacted - Impacted
  • unerupted - Unerupted
  • supernumerary - Supernumerary
  • deciduous - Deciduous / Primary
  • denture - Denture
  • partial_denture - Partial Denture
  • caries - Caries
  • filling - Filling
  • sealant - Sealant
  • fracture - Fracture
  • watch - Watch
dentition
string (DentitionEnum)
Enum: "permanent" "primary"
  • permanent - Permanent
  • primary - Primary
surfaces
string <= 10 characters

Affected surfaces: M, O, D, B/F, L, I (e.g. 'MOD')

material
string <= 50 characters

e.g. PFM, zirconia, amalgam, composite

note
string
date_identified
string or null <date>
is_current
boolean

False = historical condition superseded by a newer one

custom_data
any

Responses

Request samples

Content type
{
  • "tooth_num": "strin",
  • "condition": "missing",
  • "dentition": "permanent",
  • "surfaces": "string",
  • "material": "string",
  • "note": "string",
  • "date_identified": "2019-08-24",
  • "is_current": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "tooth_num": "strin",
  • "condition": "missing",
  • "dentition": "permanent",
  • "surfaces": "string",
  • "material": "string",
  • "note": "string",
  • "date_identified": "2019-08-24",
  • "is_current": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_tooth_summary_retrieve

Aggregated tooth chart for the odontogram.

Returns all current conditions grouped by tooth number. Response: {"teeth": {"1": [conditions...], "14": [conditions...]}}

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

practice_patient_clinical_treatment_plan_list

List and create treatment plans for a patient.

Supports filtering by status.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

status
string
Enum: "accepted" "active" "archived" "completed" "declined"

Filter by treatment plan status.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_clinical_treatment_plan_create

List and create treatment plans for a patient.

Supports filtering by status.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
provider
string or null <uuid>
name
required
string [ 1 .. 200 ] characters
note
string
status
string (TreatmentPlanStatusEnum)
Enum: "active" "accepted" "declined" "completed" "archived"
  • active - Active
  • accepted - Accepted
  • declined - Declined
  • completed - Completed
  • archived - Archived
date_accepted
string or null <date>
custom_data
any
Array of objects (TreatmentPlanItemWriteRequest)

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "name": "string",
  • "note": "string",
  • "status": "active",
  • "date_accepted": "2019-08-24",
  • "custom_data": null,
  • "items": [
    ]
}

Response samples

Content type
application/json
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "name": "string",
  • "note": "string",
  • "status": "active",
  • "date_accepted": "2019-08-24",
  • "custom_data": null,
  • "items": [
    ]
}

practice_patient_clinical_treatment_plan_accept_create

Accept a treatment plan. Sets status=accepted and date_accepted=today.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_clinical_treatment_plan_decline_create

Decline a treatment plan. Sets status=declined.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_clinical_treatment_plan_estimate_create

Estimate insurance benefits for all items in a treatment plan.

Calls the insurance estimation service with all plan items as a batch so deductible and annual max accumulate correctly across lines. Persists the results back to each TreatmentPlanItem and returns the updated plan.

POST /patient/{patient_id}/clinical/treatment-plan/{pk}/estimate/ Optional body: {"explain": true} for step-by-step calculation details.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_clinical_treatment_plan_schedule_create

Create an appointment from treatment plan items.

POST accepts: provider, operatory, date_time, duration_minutes, item_ids (optional). If item_ids is omitted, all plan items are scheduled.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_clinical_vital_sign_list

List and create vital sign readings for a patient.

Supports filtering by appointment and date range. Ordered by most recent reading first.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
appointment
string <uuid>

Filter readings to a single appointment UUID.

date_from
string <date>

Inclusive lower bound on reading_date (ISO 8601 date). Interpreted in the practice's local timezone.

date_to
string <date>

Inclusive upper bound on reading_date (ISO 8601 date). Interpreted in the practice's local timezone.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_clinical_vital_sign_create

List and create vital sign readings for a patient.

Supports filtering by appointment and date range. Ordered by most recent reading first.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
appointment
string or null <uuid>
provider
string or null <uuid>
reading_date
required
string <date-time>

When the vitals were taken

bp_systolic
integer or null [ 0 .. 32767 ]

Systolic blood pressure (mmHg)

bp_diastolic
integer or null [ 0 .. 32767 ]

Diastolic blood pressure (mmHg)

pulse
integer or null [ 0 .. 32767 ]

Pulse rate (bpm)

respiration
integer or null [ 0 .. 32767 ]

Respiration rate (breaths/min)

o2_saturation
integer or null [ 0 .. 32767 ]

Oxygen saturation (%)

temperature
string or null <decimal> ^-?\d{0,3}(?:\.\d{0,1})?$

Temperature (F)

note
string
custom_data
any

Responses

Request samples

Content type
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "reading_date": "2019-08-24T14:15:22Z",
  • "bp_systolic": 32767,
  • "bp_diastolic": 32767,
  • "pulse": 32767,
  • "respiration": 32767,
  • "o2_saturation": 32767,
  • "temperature": "string",
  • "note": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "reading_date": "2019-08-24T14:15:22Z",
  • "bp_systolic": 32767,
  • "bp_diastolic": 32767,
  • "pulse": 32767,
  • "respiration": 32767,
  • "o2_saturation": 32767,
  • "temperature": "string",
  • "note": "string",
  • "custom_data": null
}

practice_patient_tooth_history_retrieve

Chronological clinical timeline for a single tooth.

Materialized from :class:Procedure, :class:ToothCondition, and :class:TreatmentPlanItem -- never the audit log. Aaron's escape#269 answer explicitly ruled out the audit log as an unreliable source for clinical history; this endpoint queries the canonical clinical tables instead.

Returns a flat list (no pagination -- a tooth's lifetime history is bounded and fits comfortably in a single response). Newest events first; events without a date column populated sink to the end.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
tooth_number
required
string

Universal Numbering System tooth identifier. Permanent: 1-32. Primary: A-T.

Responses

Import service codes from a library (global or client) into this practice.

Copies a subset (or the whole) of the selected library into this practice's :class:apps.clinical.models.ProcedureCode table. Idempotent: codes already present are skipped, never overwritten -- the practice owns its own UCR fees and active/inactive flags once a row is copied.

Set source to "global" (default) to import from the Escape global CDT library, or "client" to import from the parent Client's curated list.

When source=client and the practice has no parent Client, {copied: 0, skipped: 0, errors: []} is returned (not an error).

code_ids accepts either a list of source-row UUIDs or the literal string "all" to import the entire library.

Access is gated on practice membership of <practice_uid>; members of a different practice receive 403. A member of practice A targeting practice B's UID cannot write into practice B.

Returns {copied, skipped, errors} counters.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
source
string
Default: "global"
Enum: "global" "client"

"global" imports from the Escape CDT library; "client" imports from the parent Client's curated list.

  • global - global
  • client - client
code_ids
required
any

List of source-row UUIDs to import, or the literal string "all" to import the entire library into this practice.

Responses

Request samples

Content type
{
  • "source": "global",
  • "code_ids": null
}

Response samples

Content type
application/json
{
  • "copied": 0,
  • "skipped": 0,
  • "errors": [
    ]
}

Browse a service-code library (global or client).

Read-only paginated list of a service-code library. Use ?source=global (default) to preview the Escape global CDT starter library, or ?source=client to preview the parent Client's curated list.

When source=client and the practice has no parent Client, an empty paginated response is returned (not an error).

Filter by category (case-insensitive exact match) and free-text search across code and description.

Access is gated on practice membership of <practice_uid>; members of a different practice receive 403.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
category
string

Filter to a single category (case-insensitive exact match, e.g. Diagnostic).

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

search
string

Case-insensitive substring match across code and description.

source
string
Enum: "client" "global"

"global" (default) returns the Escape CDT starter library; "client" returns the parent Client's curated list.

Responses

Response samples

Content type
application/json
{}

Insurance

Carriers, plans, benefits, fee schedules, claims, estimation

practice_insurance_carrier_list

List and create insurance carriers for a practice.

Uses :class:ReferenceDataPagination (100/2000) instead of the default 20/100 cap because the web UI loads the full carrier catalog once for local typeahead on plan / fee-schedule / claim forms. A group practice with years of imported history can easily carry hundreds of (mostly inactive) carriers. See api#194.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
active
string
Value: "true"

Filter by active status. Only true is honored -- when supplied, inactive carriers are hidden. Omit to return every carrier regardless of status.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

search
string

Case-insensitive substring search on name.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_insurance_carrier_create

List and create insurance carriers for a practice.

Uses :class:ReferenceDataPagination (100/2000) instead of the default 20/100 cap because the web UI loads the full carrier catalog once for local typeahead on plan / fee-schedule / claim forms. A group practice with years of imported history can easily carry hundreds of (mostly inactive) carriers. See api#194.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 255 ] characters
phone
string <= 20 characters
website
string <uri> <= 200 characters
address_line1
string <= 255 characters
address_line2
string <= 255 characters
city
string <= 100 characters
state
string <= 2 characters
zip_code
string <= 10 characters
payer_id
string <= 50 characters

EDI payer ID for clearinghouse submission

claim_office_id
string <= 50 characters

Separate claim submission office ID

hpid
string <= 50 characters

Health Plan Identifier

payment_source
string <= 50 characters

check, eft, virtual_card

notes
string
is_active
boolean
custom_data
any

Responses

Request samples

Content type
{
  • "name": "string",
  • "phone": "string",
  • "website": "http://example.com",
  • "address_line1": "string",
  • "address_line2": "string",
  • "city": "string",
  • "state": "st",
  • "zip_code": "string",
  • "payer_id": "string",
  • "claim_office_id": "string",
  • "hpid": "string",
  • "payment_source": "string",
  • "notes": "string",
  • "is_active": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "phone": "string",
  • "website": "http://example.com",
  • "address_line1": "string",
  • "address_line2": "string",
  • "city": "string",
  • "state": "st",
  • "zip_code": "string",
  • "payer_id": "string",
  • "claim_office_id": "string",
  • "hpid": "string",
  • "payment_source": "string",
  • "notes": "string",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_insurance_claim_list

Practice-wide claims list with filtering. For the claims management page.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
date_from
string <date>

Inclusive lower bound on date_service (ISO 8601 date, e.g. 2025-01-15).

date_to
string <date>

Inclusive upper bound on date_service (ISO 8601 date).

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

provider
string <uuid>

Filter claims by the rendering provider UUID.

search
string

Case-insensitive substring search across the patient's first_name and last_name.

status
string
Enum: "accepted" "appealed" "denied" "draft" "imported" "paid" "partial" "rejected" "resubmitted" "submitted" "void"

Filter claims by their current state-machine status.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_insurance_claims_summary_retrieve

Aggregate claims counts and dollar amounts grouped by status.

Returns per-status breakdowns (count, total_fee, total_paid) and practice-wide totals including outstanding balance.

GET /practice//insurance/claims/summary/

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

practice_insurance_fee_schedule_list

List and create fee schedules for a practice.

Uses :class:ReferenceDataPagination (100/2000) instead of the default 20/100 cap because the web UI loads the full fee-schedule catalog once for local dropdown rendering on insurance / plan admin screens. See api#194.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
carrier
string <uuid>

Filter fee schedules by the associated insurance carrier UUID.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

search
string

Case-insensitive substring search across name, carrier__name, and notes.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_insurance_fee_schedule_create

List and create fee schedules for a practice.

Uses :class:ReferenceDataPagination (100/2000) instead of the default 20/100 cap because the web UI loads the full fee-schedule catalog once for local dropdown rendering on insurance / plan admin screens. See api#194.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
carrier
string or null <uuid>
name
required
string [ 1 .. 255 ] characters
effective_date
string or null <date>
expiration_date
string or null <date>
notes
string
custom_data
any

Responses

Request samples

Content type
{
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "name": "string",
  • "effective_date": "2019-08-24",
  • "expiration_date": "2019-08-24",
  • "notes": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "carrier_name": "string",
  • "name": "string",
  • "effective_date": "2019-08-24",
  • "expiration_date": "2019-08-24",
  • "notes": "string",
  • "entry_count": 0,
  • "entries": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_insurance_fee_schedule_entry_bulk_create

Bulk create/update fee schedule entries. Accepts a list of {proc_code, allowed_amount, description?}.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
fee_schedule_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
proc_code
required
string [ 1 .. 20 ] characters
allowed_amount
required
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
description
string <= 255 characters

Override description, falls back to ProcedureCode

custom_data
any

Responses

Request samples

Content type
{
  • "proc_code": "string",
  • "allowed_amount": "string",
  • "description": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "proc_code": "string",
  • "allowed_amount": "string",
  • "description": "string",
  • "custom_data": null
}

practice_insurance_patient_insurance_list

Practice-wide patient-insurance list and bulk create.

GET returns all PatientInsurance records for the practice (paginated, filterable by patient, carrier, ordinal). POST accepts a JSON array for bulk import (up to 5000 records). Each record must include patient since the endpoint is not patient-scoped. PATCH accepts a JSON array of {id, ...} objects for bulk update.

Carrier resolution: if a POSTed record includes carrier_name but no carrier FK, the serializer resolves-or-creates an :class:InsuranceCarrier row in the current practice (case-insensitive match on name) and links the enrollment to it. This replaces the previous behavior where sync tools had to pre-create carriers themselves.

Used by escape-eaglesoft and escape-opendental sync tools to avoid the per-patient loop against patient/<uid>/insurance/plan/.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
carrier
string <uuid>

Filter enrollments by the associated insurance carrier UUID.

ordinal
integer

Filter by coverage ordinal. 1 = primary coverage, 2 = secondary coverage. Higher values are accepted for practices that track tertiary+ coverage.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

patient
string <uuid>

Filter enrollments down to a single patient by patient UUID.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_insurance_patient_insurance_create

Practice-wide patient-insurance list and bulk create.

GET returns all PatientInsurance records for the practice (paginated, filterable by patient, carrier, ordinal). POST accepts a JSON array for bulk import (up to 5000 records). Each record must include patient since the endpoint is not patient-scoped. PATCH accepts a JSON array of {id, ...} objects for bulk update.

Carrier resolution: if a POSTed record includes carrier_name but no carrier FK, the serializer resolves-or-creates an :class:InsuranceCarrier row in the current practice (case-insensitive match on name) and links the enrollment to it. This replaces the previous behavior where sync tools had to pre-create carriers themselves.

Used by escape-eaglesoft and escape-opendental sync tools to avoid the per-patient loop against patient/<uid>/insurance/plan/.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>
insurance_plan
string or null <uuid>
carrier_name
required
string [ 1 .. 255 ] characters
carrier
string or null <uuid>
fee_schedule
string or null <uuid>

Fee schedule used for benefit estimation under this plan

group_number
string <= 100 characters
subscriber_id
string <= 100 characters
subscriber_name
string <= 255 characters

Policy holder name if different from patient

ordinal
integer [ 0 .. 32767 ]

1=primary, 2=secondary

RelationshipToSubscriberEnum (string) or BlankEnum (any)
effective_date
string or null <date>
termination_date
string or null <date>
custom_data
any

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "carrier_name": "string",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5",
  • "group_number": "string",
  • "subscriber_id": "string",
  • "subscriber_name": "string",
  • "ordinal": 32767,
  • "relationship_to_subscriber": "self",
  • "effective_date": "2019-08-24",
  • "termination_date": "2019-08-24",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "carrier_name": "string",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5",
  • "group_number": "string",
  • "subscriber_id": "string",
  • "subscriber_name": "string",
  • "ordinal": 32767,
  • "relationship_to_subscriber": "self",
  • "effective_date": "2019-08-24",
  • "termination_date": "2019-08-24",
  • "custom_data": null
}

practice_insurance_plan_list

List and create insurance plans for a practice. Supports bulk create (POST array) and bulk update (PATCH array).

Uses :class:ReferenceDataPagination (100/2000) instead of the default 20/100 cap because the web UI loads the full plan catalog once for local typeahead on patient-insurance, verification, and claim forms. Practices routinely accumulate thousands of employer/plan combinations over the lifetime of the office. See api#194.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
active
string
Value: "true"

Filter by active status. Only true is honored -- when supplied, inactive plans are hidden. Omit to return every plan regardless of status.

carrier
string <uuid>

Filter plans by the associated insurance carrier UUID.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

search
string

Case-insensitive substring search across plan_name, group_name, employer_name, and group_number.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_insurance_plan_create

List and create insurance plans for a practice. Supports bulk create (POST array) and bulk update (PATCH array).

Uses :class:ReferenceDataPagination (100/2000) instead of the default 20/100 cap because the web UI loads the full plan catalog once for local typeahead on patient-insurance, verification, and claim forms. Practices routinely accumulate thousands of employer/plan combinations over the lifetime of the office. See api#194.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
carrier
string or null <uuid>
plan_name
string <= 255 characters
group_name
string <= 255 characters
group_number
string <= 100 characters
employer_name
string <= 255 characters
PlanTypeEnum (string) or BlankEnum (any)
annual_maximum
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
individual_deductible
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
family_deductible
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
plan_year_begin_month
integer or null [ 0 .. 32767 ]

Month (1-12) when the plan year resets

fee_schedule
string or null <uuid>

Carrier-specific fee schedule (allowed amounts) for this plan

notes
string
is_active
boolean
Array of objects (InsuranceBenefitWriteRequest)
custom_data
any

Responses

Request samples

Content type
{
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "plan_name": "string",
  • "group_name": "string",
  • "group_number": "string",
  • "employer_name": "string",
  • "plan_type": "ppo",
  • "annual_maximum": "string",
  • "individual_deductible": "string",
  • "family_deductible": "string",
  • "plan_year_begin_month": 32767,
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5",
  • "notes": "string",
  • "is_active": true,
  • "benefits": [
    ],
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "carrier_name": "string",
  • "plan_name": "string",
  • "group_name": "string",
  • "group_number": "string",
  • "employer_name": "string",
  • "plan_type": "ppo",
  • "annual_maximum": "string",
  • "individual_deductible": "string",
  • "family_deductible": "string",
  • "plan_year_begin_month": 32767,
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5",
  • "notes": "string",
  • "is_active": true,
  • "benefits": [
    ],
  • "enrollment_count": 0,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_insurance_plan_bulk_partial_update

Handle PATCH on the list endpoint for bulk updates.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
carrier
string or null <uuid>
plan_name
string <= 255 characters
group_name
string <= 255 characters
group_number
string <= 100 characters
employer_name
string <= 255 characters
PlanTypeEnum (string) or BlankEnum (any)
annual_maximum
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
individual_deductible
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
family_deductible
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
plan_year_begin_month
integer or null [ 0 .. 32767 ]

Month (1-12) when the plan year resets

fee_schedule
string or null <uuid>

Carrier-specific fee schedule (allowed amounts) for this plan

notes
string
is_active
boolean
Array of objects (InsuranceBenefitWriteRequest)
custom_data
any

Responses

Request samples

Content type
{
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "plan_name": "string",
  • "group_name": "string",
  • "group_number": "string",
  • "employer_name": "string",
  • "plan_type": "ppo",
  • "annual_maximum": "string",
  • "individual_deductible": "string",
  • "family_deductible": "string",
  • "plan_year_begin_month": 32767,
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5",
  • "notes": "string",
  • "is_active": true,
  • "benefits": [
    ],
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "carrier_name": "string",
  • "plan_name": "string",
  • "group_name": "string",
  • "group_number": "string",
  • "employer_name": "string",
  • "plan_type": "ppo",
  • "annual_maximum": "string",
  • "individual_deductible": "string",
  • "family_deductible": "string",
  • "plan_year_begin_month": 32767,
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5",
  • "notes": "string",
  • "is_active": true,
  • "benefits": [
    ],
  • "enrollment_count": 0,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_insurance_plan_benefit_list

List benefits attached to a specific insurance plan. Scope is fixed by the plan_id path parameter; the filter set is intentionally empty -- narrow the result set by choosing a different plan rather than by query string. Standard page / page_size pagination applies.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
plan_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_insurance_plan_benefit_create

List and create benefits for an insurance plan.

Uses :class:ReferenceDataPagination (100/2000) instead of the default 20/100 cap because the web UI fetches every benefit for a plan in one request to render the full coverage grid (per-category + per-procedure overrides). Imported plans from legacy PMS can carry hundreds of benefit rows per plan. See api#194.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
plan_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
insurance_plan
string or null <uuid>
BenefitTypeEnum (string) or BlankEnum (any)
CoverageCategoryEnum (string) or BlankEnum (any)
percent
string <decimal> ^-?\d{0,3}(?:\.\d{0,2})?$
monetary_amt
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
TimePeriodEnum (string) or BlankEnum (any)
proc_code
string <= 20 characters

Benefit tied to a specific procedure code

procedure_code
string or null <uuid>
min_age
integer or null [ 0 .. 32767 ]

Minimum patient age (inclusive) for this benefit to apply

max_age
integer or null [ 0 .. 32767 ]

Maximum patient age (inclusive) for this benefit to apply

waiting_period_months
integer or null [ 0 .. 32767 ]

Months from effective date before this benefit is available

custom_data
any

Responses

Request samples

Content type
{
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "benefit_type": "percentage",
  • "coverage_category": "diagnostic",
  • "percent": "string",
  • "monetary_amt": "string",
  • "time_period": "calendar_year",
  • "proc_code": "string",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "min_age": 32767,
  • "max_age": 32767,
  • "waiting_period_months": 32767,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "benefit_type": "percentage",
  • "coverage_category": "diagnostic",
  • "percent": "string",
  • "monetary_amt": "string",
  • "time_period": "calendar_year",
  • "proc_code": "string",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "min_age": 32767,
  • "max_age": 32767,
  • "waiting_period_months": 32767,
  • "custom_data": null
}

practice_insurance_verification_list

List and create insurance verifications for a practice.

Filters (all optional, combinable):

  • patient -- UUID
  • insurance_plan -- UUID
  • verified_between -- from,to ISO 8601 datetimes (inclusive)

Emits insurance.verification_viewed on GET and insurance.verification_created on POST.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
insurance_plan
string <uuid>

Filter verifications by the associated insurance plan UUID.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

patient
string <uuid>

Filter verifications down to a single patient by patient UUID.

verified_between
string

Restrict results to verifications whose verified_at falls inside a comma-separated ISO 8601 datetime range, e.g. 2026-04-01T00:00:00Z,2026-04-23T23:59:59Z. Both bounds are inclusive; omit this filter to retrieve every verification.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_insurance_verification_create

Record a new insurance verification. Verifications are append-only: this endpoint has no PUT/PATCH/DELETE counterpart. Re-verifying coverage creates a new row so the audit trail of what the payer said, and when, is preserved.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>
insurance_plan
required
string <uuid>
verified_at
required
string <date-time>

When the verification was obtained from the payer / portal.

source
required
string (InsuranceVerificationSourceEnum)
Enum: "phone" "portal" "clearinghouse"
  • phone - Phone
  • portal - Portal
  • clearinghouse - Clearinghouse
raw_response
any

Raw payer/clearinghouse/portal blob (270/271, screen scrape, etc).

annual_max
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Annual maximum benefit in dollars, if quoted. NULL = not provided.

deductible_total
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Total deductible for the plan year, if quoted. NULL = not provided.

deductible_met
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Portion of the deductible already met, if quoted. NULL = not provided.

waiting_period_notes
string

Free-text notes on waiting periods (e.g. 'major services 6mo WP remaining').

frequency_limits
any

Structured frequency limitations, e.g. {'D1110': '2 per calendar year'}. Defaults to empty dict so callers can merge without None-checks.

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "verified_at": "2019-08-24T14:15:22Z",
  • "source": "phone",
  • "raw_response": null,
  • "annual_max": "string",
  • "deductible_total": "string",
  • "deductible_met": "string",
  • "waiting_period_notes": "string",
  • "frequency_limits": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "verified_by": "8c493be0-efe2-4a3e-bdbd-7af0eab50aa2",
  • "verified_at": "2019-08-24T14:15:22Z",
  • "source": "phone",
  • "raw_response": null,
  • "annual_max": "string",
  • "deductible_total": "string",
  • "deductible_met": "string",
  • "waiting_period_notes": "string",
  • "frequency_limits": null,
  • "plan": {
    },
  • "patient_summary": {
    },
  • "verified_by_summary": {
    },
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_patient_insurance_claim_list

Insurance claims for a patient. POST to create a new claim in draft status.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

status
string
Enum: "accepted" "appealed" "denied" "draft" "imported" "paid" "partial" "rejected" "resubmitted" "submitted" "void"

Filter claims by their current state-machine status.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_insurance_claim_create

Insurance claims for a patient. POST to create a new claim in draft status.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
header Parameters
Idempotency-Key
string [ 8 .. 128 ] characters ^[A-Za-z0-9._:-]{8,128}$

Optional client-generated key (8–128 chars, alphabet [A-Za-z0-9._:-]) that makes a POST idempotent for 24 hours. If the key has been seen before with the same request body, the original response is returned byte-for-byte with Idempotency-Status: replayed. If the key has been seen with a different body, the server returns 422. If a concurrent request using the same key is still in flight, the server returns 409 with retry_after_seconds. Absent the header, the request proceeds normally with no idempotency guarantee.

Request Body schema:
provider
string or null <uuid>
patient_insurance
string or null <uuid>
date_service
string or null <date>
date_sent
string or null <date>
claim_fee
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
ins_pay_est
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
ins_pay_amt
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
ded_applied
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
write_off
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
Array of objects (ClaimProcedureWriteRequest)
custom_data
any

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "patient_insurance": "e396a8de-c249-4467-871f-c8b5f28219f1",
  • "date_service": "2019-08-24",
  • "date_sent": "2019-08-24",
  • "claim_fee": "string",
  • "ins_pay_est": "string",
  • "ins_pay_amt": "string",
  • "ded_applied": "string",
  • "write_off": "string",
  • "procedures": [
    ],
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "patient_insurance": "e396a8de-c249-4467-871f-c8b5f28219f1",
  • "date_service": "2019-08-24",
  • "date_sent": "2019-08-24",
  • "claim_fee": "string",
  • "ins_pay_est": "string",
  • "ins_pay_amt": "string",
  • "ded_applied": "string",
  • "write_off": "string",
  • "procedures": [
    ],
  • "custom_data": null
}

practice_patient_insurance_claim_transition_create

Transition a claim's status through the state machine.

POST /practice//patient//insurance/claim//transition/ Body: {"new_status": "submitted", "note": "Sent to Delta Dental"}

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
claim_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
new_status
required
string (ClaimStatusEnum)
Enum: "draft" "submitted" "accepted" "rejected" "resubmitted" "paid" "partial" "denied" "appealed" "void" "imported"
  • draft - Draft
  • submitted - Submitted
  • accepted - Accepted
  • rejected - Rejected
  • resubmitted - Resubmitted
  • paid - Paid
  • partial - Partially Paid
  • denied - Denied
  • appealed - Appealed
  • void - Void
  • imported - Imported
note
string
Default: ""

Responses

Request samples

Content type
{
  • "new_status": "draft",
  • "note": ""
}

Response samples

Content type
application/json
{
  • "new_status": "draft",
  • "note": ""
}

practice_patient_insurance_estimate_create

Estimate insurance coverage for proposed procedures.

POST /practice/{uid}/patient/{patient_id}/insurance/estimate/ Body: { "procedures": [{ "proc_code": "D2391", "fee": "450.00" }] }

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_insurance_estimate_explain_create

Verbose step-by-step insurance estimation with explanation.

POST /practice/{uid}/patient/{patient_id}/insurance/estimate-explain/ Body: { "procedures": [{ "proc_code": "D2391", "fee": "450.00" }] }

Returns the same structure as the standard estimate endpoint, plus an 'explanation' key containing global and per-line calculation steps.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_insurance_plan_list

List a patient's insurance enrollments (PatientInsurance rows). Scope is fixed by the patient_id path parameter; the filter set is intentionally empty -- use the practice-wide endpoint (/insurance/patient-insurance/) if cross-patient filtering is required. Standard page / page_size pagination applies.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_insurance_plan_create

List and create insurance plans for a patient.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
insurance_plan
string or null <uuid>
carrier_name
required
string [ 1 .. 255 ] characters
carrier
string or null <uuid>
fee_schedule
string or null <uuid>

Fee schedule used for benefit estimation under this plan

group_number
string <= 100 characters
subscriber_id
string <= 100 characters
subscriber_name
string <= 255 characters

Policy holder name if different from patient

ordinal
integer [ 0 .. 32767 ]

1=primary, 2=secondary

RelationshipToSubscriberEnum (string) or BlankEnum (any)
effective_date
string or null <date>
termination_date
string or null <date>
custom_data
any

Responses

Request samples

Content type
{
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "carrier_name": "string",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5",
  • "group_number": "string",
  • "subscriber_id": "string",
  • "subscriber_name": "string",
  • "ordinal": 32767,
  • "relationship_to_subscriber": "self",
  • "effective_date": "2019-08-24",
  • "termination_date": "2019-08-24",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "carrier_name": "string",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5",
  • "group_number": "string",
  • "subscriber_id": "string",
  • "subscriber_name": "string",
  • "ordinal": 32767,
  • "relationship_to_subscriber": "self",
  • "effective_date": "2019-08-24",
  • "termination_date": "2019-08-24",
  • "custom_data": null
}

practice_patient_insurance_plan_benefit_list

List benefits attached to a patient's insurance enrollment. Scope is fixed by the patient_id and plan_id path parameters; the filter set is intentionally empty -- all relevant narrowing is already expressed by the URL. Standard page / page_size pagination applies.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
plan_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_insurance_plan_benefit_create

List and create benefits for a patient insurance plan.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
plan_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
insurance_plan
string or null <uuid>
BenefitTypeEnum (string) or BlankEnum (any)
CoverageCategoryEnum (string) or BlankEnum (any)
percent
string <decimal> ^-?\d{0,3}(?:\.\d{0,2})?$
monetary_amt
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
TimePeriodEnum (string) or BlankEnum (any)
proc_code
string <= 20 characters

Benefit tied to a specific procedure code

procedure_code
string or null <uuid>
min_age
integer or null [ 0 .. 32767 ]

Minimum patient age (inclusive) for this benefit to apply

max_age
integer or null [ 0 .. 32767 ]

Maximum patient age (inclusive) for this benefit to apply

waiting_period_months
integer or null [ 0 .. 32767 ]

Months from effective date before this benefit is available

custom_data
any

Responses

Request samples

Content type
{
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "benefit_type": "percentage",
  • "coverage_category": "diagnostic",
  • "percent": "string",
  • "monetary_amt": "string",
  • "time_period": "calendar_year",
  • "proc_code": "string",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "min_age": 32767,
  • "max_age": 32767,
  • "waiting_period_months": 32767,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "benefit_type": "percentage",
  • "coverage_category": "diagnostic",
  • "percent": "string",
  • "monetary_amt": "string",
  • "time_period": "calendar_year",
  • "proc_code": "string",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "min_age": 32767,
  • "max_age": 32767,
  • "waiting_period_months": 32767,
  • "custom_data": null
}

Billing

Balances, payments, adjustments, checkout, production reports

client_billing_portal_session_create

Mint a Stripe-hosted billing portal session for the caller's Client.

POST /api/v1/client//billing/portal-session/

The Stripe billing portal lets customers update their payment method, download past invoices, and cancel / resume their subscription. Letting Stripe host the surface is the standard self-service pattern and keeps PCI scope at SAQ-A.

Permissions: the caller must hold a membership on the target Client (direct ClientMembership or via a PracticeMembership on one of the Client's practices). Cross-tenant UID guesses get a 404 so we never leak Client existence.

No PHI is sent to Stripe (the existing ensure_customer helper only ships the business name + client_uid metadata). The signed portal URL is not audit-logged because it carries a single-use token; we record the create event with the Client + return_url only.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
Request Body schema:
return_url
string <uri> non-empty

Responses

Request samples

Content type
{}

Response samples

Content type
application/json

practice_billing_adjustment_list

Practice-wide adjustment list (api#185).

Backs the Adjustments report (web#154). Supports date_from / date_to (inclusive, practice TZ), repeated provider and adj_type params, and an optional single patient filter. POST creates an adjustment with patient provided in the request body (the URL is not patient-scoped).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
adj_type
Array of strings

Filter by the free-text adj_type string. Repeat the parameter to include multiple types (?adj_type=discount&adj_type=writeoff).

date_from
string <date>

Inclusive lower bound on adj_date (YYYY-MM-DD, practice TZ). Omit to return adjustments with any date.

date_to
string <date>

Inclusive upper bound on adj_date (YYYY-MM-DD, practice TZ). Omit to return adjustments with any date.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

patient
string <uuid>

Filter adjustments to a single patient by patient UUID. Omit to return every adjustment across the practice.

provider
Array of strings <uuid> [ items <uuid > ]

Filter by provider UUID. Repeat the parameter to include multiple providers (?provider=<uid>&provider=<uid>).

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_billing_adjustment_create

Practice-wide adjustment list (api#185).

Backs the Adjustments report (web#154). Supports date_from / date_to (inclusive, practice TZ), repeated provider and adj_type params, and an optional single patient filter. POST creates an adjustment with patient provided in the request body (the URL is not patient-scoped).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>
adj_date
string or null <date>
adj_amount
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
adj_type
string <= 100 characters
adj_note
string
provider
string or null <uuid>
custom_data
any

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "adj_date": "2019-08-24",
  • "adj_amount": "string",
  • "adj_type": "string",
  • "adj_note": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "adj_date": "2019-08-24",
  • "adj_amount": "string",
  • "adj_type": "string",
  • "adj_note": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "custom_data": null
}

practice_billing_payment_list

Practice-wide payment list. GET all payments, POST to create (patient in body).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
date_from
string <date>

Earliest pay_date to include (inclusive, YYYY-MM-DD).

date_to
string <date>

Latest pay_date to include (inclusive, YYYY-MM-DD).

method
Array of strings

Filter by payment-method bucket. Repeatable. One of cash/check/card/insurance/other; the server maps the bucket to the set of raw PMS pay_type strings (visa, mc, carecredit etc.).

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

patient
string <uuid>

Filter payments to a single patient by patient UUID. Omit to return every payment across the practice.

provider
Array of strings <uuid> [ items <uuid > ]

Filter by provider UUID. Repeatable — e.g. ?provider=<a>&provider=<b> narrows to payments booked against either provider.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_billing_payment_create

Practice-wide payment list. GET all payments, POST to create (patient in body).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>
pay_date
string or null <date>
pay_amount
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
pay_type
string <= 100 characters
pay_note
string
provider
string or null <uuid>
custom_data
any
Array of objects (PaymentSplitWriteRequest)

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "pay_date": "2019-08-24",
  • "pay_amount": "string",
  • "pay_type": "string",
  • "pay_note": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "custom_data": null,
  • "splits": [
    ]
}

Response samples

Content type
application/json
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "pay_date": "2019-08-24",
  • "pay_amount": "string",
  • "pay_type": "string",
  • "pay_note": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "custom_data": null,
  • "splits": [
    ]
}

practice_billing_reports_aging_retrieve

A/R aging report — practice-wide summary, top 25 balances, plus by_provider and by_insurance breakdowns (api#303). Per-row bucket totals in the breakdowns reconcile with the summary because both reuse the same FIFO-allocated per-patient numbers.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
as_of_date
string <date>

Reference date for age calculation (YYYY-MM-DD, practice-local). Defaults to today. as_of is accepted as an alias.

include_archived
boolean

When true, include inactive patients in the aggregation. Defaults to false (active only).

Responses

Response samples

Content type
application/json
{
  • "summary": {
    },
  • "top_balances": [
    ],
  • "by_provider": [
    ],
  • "by_insurance": [
    ]
}

practice_billing_reports_aging_jobs_retrieve

Poll for an async aging report result.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

practice_billing_reports_aging_jobs_create

Kick off an async aging report computation.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_billing_reports_aging_jobs_retrieve_2

Poll for an async aging report result.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
as_of_date
required
string
practice_uid
required
string <uuid>

Responses

practice_billing_reports_aging_jobs_create_2

Kick off an async aging report computation.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
as_of_date
required
string
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_billing_reports_patient_balance_retrieve

GET practice-wide patient-balance report with aging buckets (api#152).

Backs the Patient Balance report UI (web#128). Returns one paginated row per patient with a non-trivial balance, each row carrying the four aging-bucket amounts (0-30 / 31-60 / 61-90 / over-90), the computed balance_total, last-payment metadata, and enough patient info for the table to render without a second round-trip.

Aging buckets are computed from live Procedure / PaymentRecord / Adjustment / InsuranceClaim data (not the stored :class:PatientBalance snapshot) so the as_of parameter is honored. Buckets start as gross completed charges in each age range and are then reduced oldest-first by the net of payments, adjustments, and insurance-paid amounts so the summed buckets always reconcile with balance_total — the convention every PMS aging report uses.

Query params: as_of (YYYY-MM-DD, default today) — reference date for ages bucket (0_30 | 31_60 | 61_90 | over_90) — post-allocation filter min_balance (decimal, default 0.01) — drops zero / credit balances provider (UUID) — restrict to patients with this primary provider carrier (UUID) — restrict to patients whose primary insurance PatientInsurance (ordinal=1) points at this carrier; malformed UUIDs return 400. Backs the A/R aging drill-down (web#327) for scoping by carrier. status (active | inactive | any, default active)

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
as_of
string <date>

Reference date for age calculation (YYYY-MM-DD, practice TZ). Defaults to today.

bucket
string

Filter to a single aging bucket after allocation. One of 0_30 / 31_60 / 61_90 / over_90. Returns only patients with a positive net balance in the named bucket.

carrier
string <uuid>

Restrict to patients whose primary insurance (PatientInsurance.ordinal=1) points at this InsuranceCarrier UUID. Malformed UUID returns 400. Backs the A/R aging drill-down (web#327).

min_balance
number <double>

Exclude rows whose balance_total is below this threshold. Defaults to 0.01.

provider
string <uuid>

Restrict to patients whose primary_provider matches this UUID.

status
string

Patient status filter: active (default) / inactive / any.

Responses

Response samples

Content type
application/json
{
  • "count": 0,
  • "next": "string",
  • "previous": "string",
  • "results": [
    ],
  • "summary": {
    }
}

practice_billing_reports_production_retrieve

GET production report aggregated across a date range.

Practice-scoped (not patient-scoped). Returns total production, collections, adjustments, net production, and procedure count — both as a summary and broken down by provider. Also exposes a per-procedure rollup (by_procedure) and splits scheduled_production vs completed_production on each by_provider row so the Production Report UI (web#151) can surface pipeline work alongside collected work.

Procedures tied to cancelled appointments are pulled out of every bucket — the same rule as the trending report in :mod:apps.billing.reports.

Query params: date_from (YYYY-MM-DD) — defaults to 30 days ago date_to (YYYY-MM-DD) — defaults to today provider (UUID, repeatable) — narrows the summary totals and the by_provider / by_procedure breakdowns; null-provider rows are excluded when the filter is active.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
date_from
required
string <date>

Start date (YYYY-MM-DD)

date_to
required
string <date>

End date (YYYY-MM-DD)

provider
Array of strings <uuid> [ items <uuid > ]

Filter to these providers only. Repeatable (?provider=<a>&provider=<b>). Narrows the summary totals and the by_provider / by_procedure breakdowns.

Responses

Response samples

Content type
application/json
{
  • "date_from": "string",
  • "date_to": "string",
  • "summary": {
    },
  • "by_provider": [
    ],
  • "by_procedure": [
    ]
}

practice_patient_billing_adjustment_list

Paginated adjustment history for a patient. Scope is fixed by the patient_id path parameter; the filter set is intentionally empty. Standard page / page_size pagination applies.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_billing_adjustment_create

Paginated adjustment history for a patient. POST to create a new adjustment.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
adj_date
string or null <date>
adj_amount
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
adj_type
string <= 100 characters
adj_note
string
provider
string or null <uuid>
custom_data
any

Responses

Request samples

Content type
{
  • "adj_date": "2019-08-24",
  • "adj_amount": "string",
  • "adj_type": "string",
  • "adj_note": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "adj_date": "2019-08-24",
  • "adj_amount": "string",
  • "adj_type": "string",
  • "adj_note": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "custom_data": null
}

practice_patient_billing_balance_summary_retrieve

GET computed balance from actual ledger data (not stored snapshot).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "total_charges": "string",
  • "total_payments": "string",
  • "total_adjustments": "string",
  • "insurance_paid": "string",
  • "insurance_estimate": "string",
  • "balance": "string"
}

practice_patient_billing_checkout_create

POST checkout/walkout — complete an appointment with procedures, payment, and optional claim.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
appointment_id
required
string <uuid>
required
Array of objects (CheckoutProcedureRequest)
object or null

Optional payment collected at checkout.

create_claim
boolean
Default: true

Responses

Request samples

Content type
{
  • "appointment_id": "21634f0d-2156-4d4b-a142-2e7c783a9212",
  • "procedures": [
    ],
  • "payment": {
    },
  • "create_claim": true
}

Response samples

Content type
application/json
{
  • "procedures_count": 0,
  • "payment_amount": "string",
  • "claim_id": "string",
  • "balance_summary": {
    }
}

practice_patient_billing_ledger_list

GET the unified patient ledger (api#1051 / escape#416, Phase 1).

Aggregates the same four sources the balance summary nets together -- completed :class:Procedure charges, :class:PaymentRecord payments, :class:Adjustment rows, and :class:InsuranceClaim events -- but returns them as date-sorted transaction lines with a running true balance plus a parallel estimated_patient_portion figure.

The running balance is accumulated oldest-first (so it's meaningful) and its final value equals this patient's /billing/balance-summary/ balance -- the consistency guarantee enforced by the service and asserted in tests. Rows are returned most-recent-first for display, then paginated.

Insurance contributes two events per (non-void) claim: an estimate at submission (parallel figure only, never the true balance) and an actual insurance payment when ins_pay_amt has posted on a non-void/draft claim (which does move the true balance).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

practice_patient_billing_payment_list

Paginated payment history for a patient. Scope is fixed by the patient_id path parameter; the filter set is intentionally empty -- use the practice-wide endpoint (/billing/payment/) when cross-patient filtering is required. Standard page / page_size pagination applies.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_billing_payment_create

Paginated payment history for a patient. POST to create a new payment.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
header Parameters
Idempotency-Key
string [ 8 .. 128 ] characters ^[A-Za-z0-9._:-]{8,128}$

Optional client-generated key (8–128 chars, alphabet [A-Za-z0-9._:-]) that makes a POST idempotent for 24 hours. If the key has been seen before with the same request body, the original response is returned byte-for-byte with Idempotency-Status: replayed. If the key has been seen with a different body, the server returns 422. If a concurrent request using the same key is still in flight, the server returns 409 with retry_after_seconds. Absent the header, the request proceeds normally with no idempotency guarantee.

Request Body schema:
pay_date
string or null <date>
pay_amount
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
pay_type
string <= 100 characters
pay_note
string
provider
string or null <uuid>
custom_data
any
Array of objects (PaymentSplitWriteRequest)

Responses

Request samples

Content type
{
  • "pay_date": "2019-08-24",
  • "pay_amount": "string",
  • "pay_type": "string",
  • "pay_note": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "custom_data": null,
  • "splits": [
    ]
}

Response samples

Content type
application/json
{
  • "pay_date": "2019-08-24",
  • "pay_amount": "string",
  • "pay_type": "string",
  • "pay_note": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "custom_data": null,
  • "splits": [
    ]
}

practice_patient_billing_payment_plan_list

Payment plans for a patient. Scope is fixed by the patient_id path parameter; the filter set is intentionally empty. Standard page / page_size pagination applies.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_billing_payment_plan_create

Payment plans for a patient. Unpaginated. POST to create a new plan.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
guarantor
string or null <uuid>
plan_date
string or null <date>
apr
string <decimal> ^-?\d{0,3}(?:\.\d{0,2})?$
completed_amt
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
is_closed
boolean
Array of objects (PaymentPlanChargeWriteRequest)
custom_data
any

Responses

Request samples

Content type
{
  • "guarantor": "2dc581b4-936d-4ab3-8a7d-1fc8f857bc6f",
  • "plan_date": "2019-08-24",
  • "apr": "string",
  • "completed_amt": "string",
  • "is_closed": true,
  • "charges": [
    ],
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "guarantor": "2dc581b4-936d-4ab3-8a7d-1fc8f857bc6f",
  • "plan_date": "2019-08-24",
  • "apr": "string",
  • "completed_amt": "string",
  • "is_closed": true,
  • "charges": [
    ],
  • "custom_data": null
}

Imaging

Sources, exam templates, exams, images, x-ray capture

escape-imaging update check.

Return the highest release this machine is eligible for, or 204.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
arch
required
string

Workstation architecture: x86 or x64.

current_version
string

Installed escape-imaging version; enables the server-side no-downgrade guard.

machine_salt
required
string

Stable per-machine salt (Windows MachineGuid); used only for cohort hashing.

scope
required
string

Install scope: per_user or per_machine.

Responses

Response samples

Content type
application/json
{
  • "version": "string",
  • "architecture": "x86",
  • "installer_scope": "per_user",
  • "msi_url": "http://example.com",
  • "sha256": "string",
  • "release_notes": "string",
  • "allow_rollback": true
}

practice_imaging_capture_token_create

Create a capture session and return a one-time token.

Called by the web app when staff clicks "Capture X-Rays". The token is passed to the desktop app via escape-imaging://capture?token=....

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

Current escape-imaging installers for the download prompt.

Newest published (rollout > 0) installer per architecture x scope (up to 4 rows). Powers the staff web 'escape-imaging not detected' download prompt (escape#478). No PHI.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

xrays_sessions_complete_create

Mark a capture session as complete.

Called by the desktop app when the user clicks "Complete". Sets ImageExam.is_complete = True (api#834 -- the legacy :class:Exam model has been retired).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
session_uid
required
string <uuid>

Responses

xrays_token_exchange_create

Exchange a one-time capture token for an OAuth2 access token.

Called by the desktop app after receiving the escape-imaging:// URL. No prior authentication is required — the token IS the auth.

Authorizations:
jwtAuthbearerAuthoauth2None

Responses

Documents

Document center, inbox, scan-to-email

desktop_documents_sessions_complete_create

Mark a desktop capture session as complete.

Called by the desktop app when the user clicks "Done".

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
session_uid
required
string <uuid>

Responses

desktop_documents_sessions_upload_create

Upload a document to a desktop capture session.

Called by the desktop app for each scanned/selected file. Files are stored as InboxItem rows on the session's practice with source=API and source_application pointing at the OAuth2 app that minted the upload token.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
session_uid
required
string <uuid>

Responses

desktop_documents_token_exchange_create

Exchange a one-time capture token for an OAuth2 access token.

Called by the desktop app after receiving the escape-documents:// URL. No prior authentication is required — the token IS the auth.

A token may only be exchanged once. Replay or expired tokens return 410 Gone and are audited via doccenter.upload_session_rejected.

Authorizations:
jwtAuthbearerAuthoauth2None

Responses

practice_doccenter_capture_token_create

Create a document capture session and return a one-time token.

Called by the web app when staff clicks "Scan Documents". The token is passed to the desktop app via escape-documents://capture?token=....

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_doccenter_document_list

List practice-level documents (no patient). Filter by ?category=.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
category
string <uuid>

Filter by document category UID. Categories are returned by GET /api/v1/practice/{practice_uid}/doccenter/category/ and include both system (practice is null) and practice-custom entries.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_doccenter_document_delete_destroy

Soft-delete a document (HIPAA retention).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
doc_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

Search documents by full-text content with highlights

Full-text search across document titles, descriptions, filenames, and OCR-extracted body text within a practice. Results are ranked by Elasticsearch relevance score and include highlighted snippets around matched terms.

HIPAA scoping — results are always restricted to the practice in the URL. Cross-practice leakage is a critical bug; the practice filter is enforced at the Elasticsearch query layer and cannot be bypassed via query parameters.

Pass patient_id to scope to a single patient (patient docs tab), or omit it for practice-wide search. Pass category (slug) to narrow to one document category.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
category
string

Optional category slug (e.g. insurance, referrals). Resolved against system + practice-custom categories.

page
integer

1-based page number for pagination.

page_size
integer

Page size (max 100, default 20).

patient_id
string <uuid>

Optional patient UID — narrows to one patient's documents.

q
required
string

Search query. Required. Must be at least 2 characters.

Responses

Response samples

Content type
application/json
{
  • "count": 0,
  • "next": "string",
  • "previous": "string",
  • "results": [
    ]
}

practice_doccenter_document_upload_create

Upload a practice-level document.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_doccenter_inbox_accept_create

Convert an inbox item to a permanent Document.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
inbox_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_doccenter_inbox_reject_destroy

Hard-delete an inbox item and its S3 file.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
inbox_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_doccenter_inbox_upload_create

Upload a file to the inbox.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_doccenter_scan_to_email_retrieve

GET: return config. POST: enable scan-to-email. DELETE: disable.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

practice_doccenter_scan_to_email_create

GET: return config. POST: enable scan-to-email. DELETE: disable.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_doccenter_scan_to_email_destroy

GET: return config. POST: enable scan-to-email. DELETE: disable.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

Voicemail inbox — un-linked voicemails with patient suggestions

Returns voicemail recordings (Document rows under the system voicemail category) for the practice, ranked with caller-ID patient suggestions. Default scope is unlinked — voicemails with patient is None. Operators confirm a suggestion via PATCH /doccenter/document/<doc_id>/ setting patient (the existing audit-emitting Document update endpoint).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

status
string
Enum: "all" "linked" "unlinked"

Filter by link state: unlinked (default — no patient yet), linked (already linked to a patient), or all.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

File a voicemail against the practice (resolve without a patient)

Marks the voicemail Document as resolved against the practice — it drops out of GET /doccenter/voicemail-inbox/ (default status=unlinked) without being deleted. Idempotent: re-posting on an already-resolved row refreshes the actor + timestamp. Reversible via DELETE.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
doc_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "category": "86d23d13-9dbb-46f3-82d0-25253c7750c3",
  • "referral": "0ff1dce1-5a61-425e-b768-f89c7726a65e",
  • "title": "string",
  • "description": "string",
  • "original_filename": "string",
  • "mime_type": "string",
  • "file_size": 0,
  • "page_count": 0,
  • "uploaded_by": "e134ce2c-a199-4e99-9c11-627b70a7ff28",
  • "source_application": 0,
  • "is_deleted": true,
  • "deleted_at": "2019-08-24T14:15:22Z",
  • "deleted_by": "d7d7cfa2-327b-4733-8887-d09252b40b06",
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "resolved_by": "d0d57369-b08b-4db8-8952-8cdeedd9aebc",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "download_url": "string",
  • "patient_name": "string",
  • "category_label": "string",
  • "uploaded_by_name": "string",
  • "caller_id": "string",
  • "processing_state": "pending",
  • "processing_error": "string",
  • "processing_updated_at": "2019-08-24T14:15:22Z",
  • "transcript": "string",
  • "transcript_confidence": "string",
  • "av_status": "pending",
  • "av_scanned_at": "2019-08-24T14:15:22Z",
  • "av_scanner": "string",
  • "av_threat_name": "string",
  • "suggested_patient_ids": [
    ],
  • "custom_data": null
}

Un-resolve a voicemail filed against the practice

Clears the resolved_at flag, returning the voicemail to the default unlinked queue. Used by the triage UI's undo affordance.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
doc_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "category": "86d23d13-9dbb-46f3-82d0-25253c7750c3",
  • "referral": "0ff1dce1-5a61-425e-b768-f89c7726a65e",
  • "title": "string",
  • "description": "string",
  • "original_filename": "string",
  • "mime_type": "string",
  • "file_size": 0,
  • "page_count": 0,
  • "uploaded_by": "e134ce2c-a199-4e99-9c11-627b70a7ff28",
  • "source_application": 0,
  • "is_deleted": true,
  • "deleted_at": "2019-08-24T14:15:22Z",
  • "deleted_by": "d7d7cfa2-327b-4733-8887-d09252b40b06",
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "resolved_by": "d0d57369-b08b-4db8-8952-8cdeedd9aebc",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "download_url": "string",
  • "patient_name": "string",
  • "category_label": "string",
  • "uploaded_by_name": "string",
  • "caller_id": "string",
  • "processing_state": "pending",
  • "processing_error": "string",
  • "processing_updated_at": "2019-08-24T14:15:22Z",
  • "transcript": "string",
  • "transcript_confidence": "string",
  • "av_status": "pending",
  • "av_scanned_at": "2019-08-24T14:15:22Z",
  • "av_scanner": "string",
  • "av_threat_name": "string",
  • "suggested_patient_ids": [
    ],
  • "custom_data": null
}

practice_patient_doccenter_list

List documents for a specific patient. Filter by ?category= and/or ?referral=.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
category
string <uuid>

Filter patient documents by category UID. Categories are returned by GET /api/v1/practice/{practice_uid}/doccenter/category/.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

referral
string <uuid>

Filter patient documents by the referral they were filed against (api#1002) — used by the referral-scoped document view to show only the reports returned for this consult. The id is matched within the patient's own practice/patient scope first, so a referral id from another practice or patient yields an empty list rather than leaking rows. Omit the parameter to list every document for the patient.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_doccenter_delete_destroy

Soft-delete a document (HIPAA retention).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
doc_id
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_doccenter_upload_create

Upload a document associated with a patient.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

Providers

Providers and operatories

practice_provider_list

List and create providers for a practice.

The list endpoint currently returns every provider for the practice without server-side filtering; clients (e.g. the staff web app) filter in-memory by is_active / is_hidden for dropdown rendering. If server-side filtering becomes a hot path, add explicit OpenApiParameter entries here so the schema stays honest.

Uses :class:ReferenceDataPagination (100/2000) instead of the default 20/100 cap because every staff surface (schedule, checkout, claim, chart) needs the full provider roster for local filtering. Historical imports can push a DSO's combined roster past the 100-row default. See api#194.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_provider_create

List and create providers for a practice.

The list endpoint currently returns every provider for the practice without server-side filtering; clients (e.g. the staff web app) filter in-memory by is_active / is_hidden for dropdown rendering. If server-side filtering becomes a hot path, add explicit OpenApiParameter entries here so the schema stays honest.

Uses :class:ReferenceDataPagination (100/2000) instead of the default 20/100 cap because every staff surface (schedule, checkout, claim, chart) needs the full provider roster for local filtering. Historical imports can push a DSO's combined roster past the 100-row default. See api#194.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
first_name
required
string [ 1 .. 100 ] characters
last_name
required
string [ 1 .. 100 ] characters
abbreviation
string <= 20 characters
specialty
string <= 100 characters
provider_type
string (ProviderTypeEnum)
Enum: "dentist" "hygienist" "assistant" "other"
  • dentist - Dentist
  • hygienist - Hygienist
  • assistant - Assistant
  • other - Other
color
string <= 7 characters

Hex color for calendar rendering, e.g. #3B82F6

npi
string <= 10 characters

National Provider Identifier

dea_number
string <= 9 characters

DEA registration number (2 letters + 7 digits, e.g. AB1234567). Required on paper controlled-substance prescriptions. Not required for non-controlled prescriptions. Added as part of the prescriptions module (escape#136 / api#482).

is_hidden
boolean

Hidden from dropdowns but visible on historical records

is_secondary
boolean

Legacy import field — use provider_type instead

is_active
boolean

Currently employed at this practice

is_web_sched
boolean

Available for patient online scheduling.

custom_data
any

Responses

Request samples

Content type
{
  • "first_name": "string",
  • "last_name": "string",
  • "abbreviation": "string",
  • "specialty": "string",
  • "provider_type": "dentist",
  • "color": "string",
  • "npi": "string",
  • "dea_number": "string",
  • "is_hidden": true,
  • "is_secondary": true,
  • "is_active": true,
  • "is_web_sched": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "first_name": "string",
  • "last_name": "string",
  • "abbreviation": "string",
  • "specialty": "string",
  • "provider_type": "dentist",
  • "color": "string",
  • "npi": "string",
  • "dea_number": "string",
  • "can_prescribe": true,
  • "can_prescribe_controlled": true,
  • "is_hidden": true,
  • "is_secondary": true,
  • "is_active": true,
  • "is_web_sched": true,
  • "custom_data": null
}

practice_provider_bulk_partial_update

Handle PATCH on the list endpoint for bulk updates.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
first_name
string [ 1 .. 100 ] characters
last_name
string [ 1 .. 100 ] characters
abbreviation
string <= 20 characters
specialty
string <= 100 characters
provider_type
string (ProviderTypeEnum)
Enum: "dentist" "hygienist" "assistant" "other"
  • dentist - Dentist
  • hygienist - Hygienist
  • assistant - Assistant
  • other - Other
color
string <= 7 characters

Hex color for calendar rendering, e.g. #3B82F6

npi
string <= 10 characters

National Provider Identifier

dea_number
string <= 9 characters

DEA registration number (2 letters + 7 digits, e.g. AB1234567). Required on paper controlled-substance prescriptions. Not required for non-controlled prescriptions. Added as part of the prescriptions module (escape#136 / api#482).

is_hidden
boolean

Hidden from dropdowns but visible on historical records

is_secondary
boolean

Legacy import field — use provider_type instead

is_active
boolean

Currently employed at this practice

is_web_sched
boolean

Available for patient online scheduling.

custom_data
any

Responses

Request samples

Content type
{
  • "first_name": "string",
  • "last_name": "string",
  • "abbreviation": "string",
  • "specialty": "string",
  • "provider_type": "dentist",
  • "color": "string",
  • "npi": "string",
  • "dea_number": "string",
  • "is_hidden": true,
  • "is_secondary": true,
  • "is_active": true,
  • "is_web_sched": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "first_name": "string",
  • "last_name": "string",
  • "abbreviation": "string",
  • "specialty": "string",
  • "provider_type": "dentist",
  • "color": "string",
  • "npi": "string",
  • "dea_number": "string",
  • "can_prescribe": true,
  • "can_prescribe_controlled": true,
  • "is_hidden": true,
  • "is_secondary": true,
  • "is_active": true,
  • "is_web_sched": true,
  • "custom_data": null
}

practice_provider_operatory_list

List and create operatories for a practice.

Returns every operatory for the practice; clients filter client-side for schedule rendering (is_hygiene, is_hidden, is_web_sched). Add OpenApiParameter entries here if server-side filters are introduced.

Uses :class:ReferenceDataPagination (100/2000) instead of the default 20/100 cap because the schedule grid needs every operatory (including hidden / legacy ones for historical appointment context) in one request. See api#194.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_provider_operatory_create

List and create operatories for a practice.

Returns every operatory for the practice; clients filter client-side for schedule rendering (is_hygiene, is_hidden, is_web_sched). Add OpenApiParameter entries here if server-side filters are introduced.

Uses :class:ReferenceDataPagination (100/2000) instead of the default 20/100 cap because the schedule grid needs every operatory (including hidden / legacy ones for historical appointment context) in one request. See api#194.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 100 ] characters
abbreviation
string <= 20 characters
provider_dentist
string or null <uuid>

Default dentist assigned to this chair

provider_hygienist
string or null <uuid>

Default hygienist assigned to this chair

is_hygiene
boolean
is_hidden
boolean
is_bookable
boolean

Operatories where is_bookable=False are skipped by the slot-finder. Used for PMS 'overflow' or 'notes-only' pseudo-chairs that host free-text annotations but aren't real rooms.

sort_order
integer [ 0 .. 2147483647 ]

Display ordering in schedule views

is_web_sched
boolean

Available for patient online scheduling

accepts_self_booking
boolean

Expose this operatory to the public patient self-booking surface (api#823). Off by default -- opt-in only; distinct from is_web_sched which gates the staff-side online scheduler.

custom_data
any

Responses

Request samples

Content type
{
  • "name": "string",
  • "abbreviation": "string",
  • "provider_dentist": "e47c6d02-29ee-4cef-ae75-7c7efebcc8cb",
  • "provider_hygienist": "cc1b609c-8966-4136-9bf1-9a022231718a",
  • "is_hygiene": true,
  • "is_hidden": true,
  • "is_bookable": true,
  • "sort_order": 2147483647,
  • "is_web_sched": true,
  • "accepts_self_booking": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "abbreviation": "string",
  • "provider_dentist": "e47c6d02-29ee-4cef-ae75-7c7efebcc8cb",
  • "provider_dentist_name": "string",
  • "provider_hygienist": "cc1b609c-8966-4136-9bf1-9a022231718a",
  • "provider_hygienist_name": "string",
  • "is_hygiene": true,
  • "is_hidden": true,
  • "is_bookable": true,
  • "sort_order": 2147483647,
  • "is_web_sched": true,
  • "accepts_self_booking": true,
  • "custom_data": null
}

practice_provider_operatory_bulk_partial_update

Handle PATCH on the list endpoint for bulk updates.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
name
string [ 1 .. 100 ] characters
abbreviation
string <= 20 characters
provider_dentist
string or null <uuid>

Default dentist assigned to this chair

provider_hygienist
string or null <uuid>

Default hygienist assigned to this chair

is_hygiene
boolean
is_hidden
boolean
is_bookable
boolean

Operatories where is_bookable=False are skipped by the slot-finder. Used for PMS 'overflow' or 'notes-only' pseudo-chairs that host free-text annotations but aren't real rooms.

sort_order
integer [ 0 .. 2147483647 ]

Display ordering in schedule views

is_web_sched
boolean

Available for patient online scheduling

accepts_self_booking
boolean

Expose this operatory to the public patient self-booking surface (api#823). Off by default -- opt-in only; distinct from is_web_sched which gates the staff-side online scheduler.

custom_data
any

Responses

Request samples

Content type
{
  • "name": "string",
  • "abbreviation": "string",
  • "provider_dentist": "e47c6d02-29ee-4cef-ae75-7c7efebcc8cb",
  • "provider_hygienist": "cc1b609c-8966-4136-9bf1-9a022231718a",
  • "is_hygiene": true,
  • "is_hidden": true,
  • "is_bookable": true,
  • "sort_order": 2147483647,
  • "is_web_sched": true,
  • "accepts_self_booking": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "abbreviation": "string",
  • "provider_dentist": "e47c6d02-29ee-4cef-ae75-7c7efebcc8cb",
  • "provider_dentist_name": "string",
  • "provider_hygienist": "cc1b609c-8966-4136-9bf1-9a022231718a",
  • "provider_hygienist_name": "string",
  • "is_hygiene": true,
  • "is_hidden": true,
  • "is_bookable": true,
  • "sort_order": 2147483647,
  • "is_web_sched": true,
  • "accepts_self_booking": true,
  • "custom_data": null
}

Staff

Practice members, invitations, roles

practice_staff_invitations_list

List or create practice invitations.

Returns every PracticeInvitation attached to the practice -- the staff UI filters by status (PENDING / ACCEPTED / REVOKED / EXPIRED) client- side. pagination_class = None keeps the response a flat array.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

practice_staff_invitations_create

List or create practice invitations.

Returns every PracticeInvitation attached to the practice -- the staff UI filters by status (PENDING / ACCEPTED / REVOKED / EXPIRED) client- side. pagination_class = None keeps the response a flat array.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
email
required
string <email> non-empty
role
required
string non-empty

Responses

Request samples

Content type
{
  • "email": "user@example.com",
  • "role": "string"
}

Response samples

Content type
application/json
{
  • "email": "user@example.com",
  • "role": "string"
}

practice_staff_invitations_revoke_create

Revoke a pending practice invitation.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
invitation_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_staff_members_list

List everyone with access to a practice.

Returns the union of:

  • every :class:PracticeMembership for the practice (direct members, active and deactivated alike), serialized with via_practice=True;
  • every :class:ClientMembership of the practice's parent client (organization-level admins -- OWNER / BILLING / TECHNICAL), serialized with via_client=True so the UI can tag the row with an "Inherited from organization" badge.

The two tables don't share a common id space, so the union happens at the serializer-output level rather than as a SQL UNION. The response stays a flat JSON array (pagination_class = None) so the staff UI can render the members table in one pass and the web usePracticeMembers hook can keep typing it as T[].

Dedup (api#570): when a user holds BOTH a PracticeMembership for this practice AND a ClientMembership for its parent client, only one row is emitted. The direct PracticeMembership row wins (its per- practice role is concrete and primary) and via_client=True is set on that row so the UI can still surface the "also has client-level access" signal. This prevents the duplicate row Aaron screenshotted in escapedental/escape#169.

Practice members are emitted first (sorted by display name), client-only members second (also sorted by display name). Display name is the user's full name with the email as a fallback, so ordering stays deterministic even before the user has filled in their profile.

Read access is open to any authenticated staff user with effective access to the practice -- including users whose only membership is at the client level (api#557). Mutating endpoints continue to gate on practice admin roles via :class:PracticeMemberDetailView.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

List per-practice user grants

Returns every :class:PracticeUserGrant row attached to the practice. Optional ?user=<uuid> and ?grant_type=<perm> filters narrow the result set; when both are supplied they are AND-ed. grant_type accepts the canonical permission string (e.g. patient.can_share, reports.production).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create a per-practice user grant

Adds a new grant for the given user + permission pair. The view sets practice from the URL and granted_by from the requesting user, so the body only carries the target user, the permission, an optional granted boolean (defaults True), and an optional free-text note. Returns the full grant on success.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
user
required
string <uuid>
permission
required
string (PermissionEnum)
Enum: "patient.can_share" "reports.all" "reports.production" "reports.ar" "reports.patients" "reports.operations" "reports.compliance"
  • patient.can_share - Patient: Can Share
  • reports.all - Reports: All Categories
  • reports.production - Reports: Production
  • reports.ar - Reports: A/R
  • reports.patients - Reports: Patients
  • reports.operations - Reports: Operations
  • reports.compliance - Reports: Compliance
granted
boolean
Default: true

True forces the permission ON; False forces it OFF.

note
string

Optional reason for the grant (e.g. 'covering for OM on leave').

Responses

Request samples

Content type
{
  • "user": "76f62a58-5404-486d-9afc-07bded328704",
  • "permission": "patient.can_share",
  • "granted": true,
  • "note": "string"
}

Response samples

Content type
application/json
{
  • "user": "76f62a58-5404-486d-9afc-07bded328704",
  • "permission": "patient.can_share",
  • "granted": true,
  • "note": "string"
}

Revoke a per-practice user grant

Permanently removes the grant row. The resolution helper in :mod:apps.sharing.permissions falls back to the role default once the row is gone, so a deleted grant returns the user to the role-default permission state.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
grant_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

Account

User profile, passkeys, preferences

account_invite_codes_list

List or mint invite codes.

GET Returns the codes attributed to the caller's accessible clients. Staff users may pass ?client=<uid> to scope to one specific Client; without the filter, staff see codes for every client they can access (and superusers see them all).

Paginated with the project default :class:`StandardPageNumberPagination`
(20 per page, ``?page_size=`` capped at 100, ``?page=N`` to walk
further pages).  The response is the standard DRF envelope:
``{count, next, previous, results}``.  See GH-463 — bulk staff-minted
codes will eventually outgrow a single page and the project rule is
"never remove backend pagination."

POST Staff-only. Body {"client": "<uid>"|null} -- a null/missing client mints a staff-bulk code that any sign-up can redeem.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

account_invite_codes_create

List or mint invite codes.

GET Returns the codes attributed to the caller's accessible clients. Staff users may pass ?client=<uid> to scope to one specific Client; without the filter, staff see codes for every client they can access (and superusers see them all).

Paginated with the project default :class:`StandardPageNumberPagination`
(20 per page, ``?page_size=`` capped at 100, ``?page=N`` to walk
further pages).  The response is the standard DRF envelope:
``{count, next, previous, results}``.  See GH-463 — bulk staff-minted
codes will eventually outgrow a single page and the project rule is
"never remove backend pagination."

POST Staff-only. Body {"client": "<uid>"|null} -- a null/missing client mints a staff-bulk code that any sign-up can redeem.

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
client
string or null <uuid>

Responses

Request samples

Content type
{
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8"
}

Response samples

Content type
application/json
{
  • "code": "string",
  • "expires_at": "2019-08-24T14:15:22Z",
  • "created_at": "2019-08-24T14:15:22Z"
}

account_invite_codes_revoke_create

Revoke an invite code.

Members of the issuer Client (or staff) may revoke a code. Returns 409 if the code is already revoked or already redeemed. Codes are looked up case-insensitively to match the redeem flow.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
code
required
string

Responses

account_invite_codes_validate_retrieve

Public invite-code validation -- no auth required.

Used by the sign-up form's pre-submit check (escape#127 / api#440). The response shape is intentionally minimal -- we never leak the issuer Client, the creator user, or the expiration date, just a boolean and a coarse error code so the form can render the right message.

Authorizations:
bearerAuthoauth2None

Responses

Response samples

Content type
application/json
{
  • "valid": true,
  • "error": "string"
}

account_me_retrieve

Return the authenticated user's own profile.

The new scope taxonomy (api#124) does not yet name a per-user "profile" scope, so this view continues to honour the legacy profile:read (or umbrella read) catalog entries via :class:HasScope's any_scope=True mode. Session / JWT auth bypasses the scope check; third-party OAuth tokens carrying neither scope receive 403 — which is the contract callers from before GH-387 were already coded against.

Authorizations:
jwtAuthbearerAuthoauth2

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "email": "user@example.com",
  • "first_name": "string",
  • "last_name": "string",
  • "is_patient": true,
  • "is_staff": true,
  • "is_superuser": true,
  • "is_support_staff": true,
  • "is_active": true,
  • "date_joined": "2019-08-24T14:15:22Z",
  • "last_login": "2019-08-24T14:15:22Z",
  • "last_seen_at": "2019-08-24T14:15:22Z",
  • "first_run_tour_completed_at": "2019-08-24T14:15:22Z",
  • "preference_data": "string",
  • "memberships": [
    ],
  • "client_memberships": [
    ],
  • "current_practice_id": "edf1be34-8ae4-41f5-bad6-133af3513eac",
  • "practice_timezone": "string"
}

account_me_first_run_tour_complete_create

Mark the in-app first-run guided tour as completed for the caller.

POST /api/v1/account/me/first-run-tour/complete/ (GH-661).

Stamps :attr:User.first_run_tour_completed_at to now() the first time it's called for an account. Subsequent calls return 200 with the existing timestamp so the client can retry safely across flaky networks or two browser tabs racing the completion callback -- the column is a monotonic latch and never gets re-armed by this endpoint.

Scoped implicitly to request.user: there is no path parameter and the queryset is never widened, so a session for user A cannot flip the latch on user B's account.

Audits user.first_run_tour_completed (category auth) with metadata.already_completed set so operators can distinguish a genuine first-time completion from a redundant retry without pulling the row.

Authorizations:
jwtAuthbearerAuthoauth2

Responses

Response samples

Content type
application/json
{
  • "first_run_tour_completed_at": "2019-08-24T14:15:22Z",
  • "already_completed": true
}

account_me_preferences_retrieve

Read or write the authenticated user's preferences for the current OAuth2 application (the one the access token was issued to). The data blob is opaque to the API -- callers own its schema. For cross-application preferences such as theme, use /me/preferences/global/ instead.

Authorizations:
jwtAuthbearerAuthoauth2

Responses

Response samples

Content type
application/json

Per-OAuth2-application preferences are an opaque JSON blob from the API's perspective. Schema and key conventions are owned by the calling application; theme lives on the global row, not here.

{
  • "id": "11111111-1111-4111-8111-111111111111",
  • "data": {
    },
  • "created": "2026-04-25T14:30:00Z",
  • "modified": "2026-04-25T14:30:00Z"
}

account_me_preferences_update

Read or write the authenticated user's preferences for the current OAuth2 application (the one the access token was issued to). The data blob is opaque to the API -- callers own its schema. For cross-application preferences such as theme, use /me/preferences/global/ instead.

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
data
any

Responses

Request samples

Content type

PUT replaces the entire data object for the current OAuth2 application.

{
  • "data": {
    }
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "data": null,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

account_me_preferences_partial_update

Read or write the authenticated user's preferences for the current OAuth2 application (the one the access token was issued to). The data blob is opaque to the API -- callers own its schema. For cross-application preferences such as theme, use /me/preferences/global/ instead.

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
data
any

Responses

Request samples

Content type
{
  • "data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "data": null,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

account_me_preferences_destroy

Read or write the authenticated user's preferences for the current OAuth2 application (the one the access token was issued to). The data blob is opaque to the API -- callers own its schema. For cross-application preferences such as theme, use /me/preferences/global/ instead.

Authorizations:
jwtAuthbearerAuthoauth2

Responses

account_me_preferences_global_retrieve

Read or write the authenticated user's global preferences row (application=NULL). This row holds cross-application preferences such as the user's theme.

Documented keys on data:

  • theme -- one of light, dark, or system. Any other value (including missing) is treated as system when the value is read back, so the OS-level prefers-color-scheme setting wins. The web app and the Security Nexus both read and write this same key so a single user-facing toggle controls both surfaces.

Additional keys may be added by first-party clients over time and are preserved verbatim by PATCH; PUT replaces the object wholesale.

Authorizations:
jwtAuthbearerAuthoauth2

Responses

Response samples

Content type
application/json

Typical response for a user who has selected a non-default theme. The web app and the Security Nexus both read this row to render in the requested mode.

{
  • "id": "11111111-1111-4111-8111-111111111111",
  • "data": {
    },
  • "created": "2026-04-25T14:30:00Z",
  • "modified": "2026-04-25T14:30:00Z"
}

account_me_preferences_global_update

Read or write the authenticated user's global preferences row (application=NULL). This row holds cross-application preferences such as the user's theme.

Documented keys on data:

  • theme -- one of light, dark, or system. Any other value (including missing) is treated as system when the value is read back, so the OS-level prefers-color-scheme setting wins. The web app and the Security Nexus both read and write this same key so a single user-facing toggle controls both surfaces.

Additional keys may be added by first-party clients over time and are preserved verbatim by PATCH; PUT replaces the object wholesale.

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
data
any

Responses

Request samples

Content type

PUT replaces the entire data object. Allowed values for theme are light, dark, and system; any other value is treated as system when the theme is read back by the Nexus or the web app.

{
  • "data": {
    }
}

Response samples

Content type
application/json

Returned after a successful PUT or PATCH that updated the theme.

{
  • "id": "11111111-1111-4111-8111-111111111111",
  • "data": {
    },
  • "created": "2026-04-25T14:30:00Z",
  • "modified": "2026-04-25T14:31:12Z"
}

account_me_preferences_global_partial_update

Read or write the authenticated user's global preferences row (application=NULL). This row holds cross-application preferences such as the user's theme.

Documented keys on data:

  • theme -- one of light, dark, or system. Any other value (including missing) is treated as system when the value is read back, so the OS-level prefers-color-scheme setting wins. The web app and the Security Nexus both read and write this same key so a single user-facing toggle controls both surfaces.

Additional keys may be added by first-party clients over time and are preserved verbatim by PATCH; PUT replaces the object wholesale.

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
data
any

Responses

Request samples

Content type

PATCH shallow-merges into the existing data object, so other keys (locale, timezone, ...) on the global row are preserved. Allowed values for theme are light, dark, and system.

{
  • "data": {
    }
}

Response samples

Content type
application/json

Returned after a successful PUT or PATCH that updated the theme.

{
  • "id": "11111111-1111-4111-8111-111111111111",
  • "data": {
    },
  • "created": "2026-04-25T14:30:00Z",
  • "modified": "2026-04-25T14:31:12Z"
}

account_signup_create

Public self-service signup with optional invite-code gating (GH-440).

POST /api/v1/account/signup/ Body::

{
    "email": "owner@newpractice.test",
    "first_name": "Pat",
    "last_name": "Ient",
    "client_name": "New Practice DSO",
    "invite_code": "ABCDEFGH2345"   // optional unless flag is on
}

Behaviour

  • Always :class:AllowAny -- this is the entry point into the product for new tenants. Throttled by the project-wide anon scope so it can't be turned into a Client-creation cannon.

  • When the invited_signup_required Waffle flag is off for the request, invite_code is ignored -- a missing or invalid code does not block signup. This is the day-one default.

  • When the flag is on, invite_code is required and is atomically redeemed inside the same transaction that creates the User, Client, and ClientMembership. The redemption uses select_for_update (see :meth:InviteCode.redeem) so two simultaneous signups racing for the same code can't both win -- one gets the new account, the other gets a 400.

Atomic boundary

Everything happens inside a single transaction.atomic block:

  1. Create the new :class:apps.practices.models.Client.
  2. Create the new :class:User (passwordless -- the next step in the signup wizard is magic-link → passkey enrolment).
  3. Create the :class:ClientMembership with role OWNER.
  4. (When the flag is on) atomically redeem the invite code.

If step 4 raises -- e.g. someone revoked the code between pre-flight validation and the POST landing -- the whole transaction rolls back: no orphan Client, no orphan User, no leaked email collision.

Authorizations:
bearerAuthoauth2None
Request Body schema:
required
email
required
string <email> non-empty
first_name
required
string [ 1 .. 150 ] characters
last_name
required
string [ 1 .. 150 ] characters
client_name
required
string [ 1 .. 255 ] characters

Display name for the new business entity (DSO or solo practitioner).

invite_code
string

Required only when the invited_signup_required Waffle flag is on. Single-use; consumed atomically on successful signup.

npi
string^\d{10}$

10-digit National Provider Identifier. Required when the npi_verification_required Waffle flag is on.

state
string <= 2 characters

Two-letter US state code where the practice operates. Required when the npi_verification_required Waffle flag is on; matched case-insensitively against the NPI Registry's address rows.

Responses

Request samples

Content type
{
  • "email": "user@example.com",
  • "first_name": "string",
  • "last_name": "string",
  • "client_name": "string",
  • "invite_code": "string",
  • "npi": "string",
  • "state": "st"
}

Response samples

Content type
application/json
{
  • "user_id": "a169451c-8525-4352-b8ca-070dd449a1a5",
  • "email": "user@example.com",
  • "client_id": "5b3fa7ba-57d3-4017-a65b-d57dcd2db643"
}

account_token_logout_create

Revoke tokens and flush all Django sessions for the user.

Accepts a refresh token from any of:

  • The HttpOnly escape_refresh_token cookie (preferred — set by the API on login, cleared on logout, never visible to JS).
  • A SimpleJWT refresh token in the body ({"refresh": "..."}) for backward compatibility with clients that have not yet switched to the cookie flow.
  • An OAuth2 access token via the Authorization header — the staff web app's path since GH-1081: the 10-hour access token IS the session, so sign-out must kill it here rather than letting it ride out its remaining lifetime.

In every case, all Django sessions for the identified user are flushed so the Nexus session cookie is invalidated, the presenting OAuth2 access token (and its sibling refresh token, if any) is revoked, and the refresh-token cookie is unset on the response.

Authorizations:
jwtAuthbearerAuthoauth2None

Responses

account_token_refresh_create

Cookie-aware wrapper around SimpleJWT's :class:TokenRefreshView.

Behavioural differences from the base class:

  • If the request body has no refresh field, the view falls back to reading the escape_refresh_token HttpOnly cookie and forwards it to the serializer. This is the common path for the web SPA after GH-293.
  • On a successful 200 response, the rotated refresh token is written to the cookie and stripped from the response body so no JS-readable copy is ever returned to the browser. The access token stays in the body where the SPA can stash it in memory (or component state) for the short access-token TTL.
  • Body-based callers (curl, integration tests, legacy clients) that POST a refresh field still see the rotated refresh token in the response so they keep working during the rollout window.
  • The serializer is overridden to :class:apps.accounts.jwt_tokens.ChainCappedTokenRefreshSerializer (GH-564) so the rotation chain inherits an absolute lifetime cap. An active polling client can no longer keep refreshing forever just by exchanging tokens within the per-token lifetime — the chain dies once the configured absolute window elapses, anchored to the original login.
Authorizations:
bearerAuthoauth2
Request Body schema:
required
refresh
required
string non-empty

Responses

Request samples

Content type
{
  • "refresh": "string"
}

Response samples

Content type
application/json
{
  • "refresh": "string",
  • "access": "string"
}

client_invite_codes_list

List or mint invite codes scoped to a single Client (GH-649).

GET /api/v1/client//invite-codes/ Returns the codes attributed to client_uid. Same shape as the legacy GET /api/v1/account/invite-codes/ endpoint but always pre-filtered to the URL Client so the frontend doesn't have to know whether the caller is staff (and would otherwise see codes for every Client they can access).

Visible to any user who can read the Client's data -- the
existing :func:`_user_can_see_client_codes` rule applies (staff
OR an active ``ClientMembership`` at this Client).  Cross-tenant
UID guesses get a 404 indistinguishable from a non-existent
Client.

POST /api/v1/client//invite-codes/ Mints a fresh code attributed to client_uid with created_by set to the caller. Gated by :func:_user_can_mint_for_client (staff / OWNER / admin / OM / dentist) and rate-limited per Client to :data:CLIENT_INVITE_CODE_MONTHLY_LIMIT codes per calendar month. Hit the cap and the response is 429 with body {"detail": "...", "limit": <int>, "period_start": "<iso>"}.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

client_invite_codes_create

List or mint invite codes scoped to a single Client (GH-649).

GET /api/v1/client//invite-codes/ Returns the codes attributed to client_uid. Same shape as the legacy GET /api/v1/account/invite-codes/ endpoint but always pre-filtered to the URL Client so the frontend doesn't have to know whether the caller is staff (and would otherwise see codes for every Client they can access).

Visible to any user who can read the Client's data -- the
existing :func:`_user_can_see_client_codes` rule applies (staff
OR an active ``ClientMembership`` at this Client).  Cross-tenant
UID guesses get a 404 indistinguishable from a non-existent
Client.

POST /api/v1/client//invite-codes/ Mints a fresh code attributed to client_uid with created_by set to the caller. Gated by :func:_user_can_mint_for_client (staff / OWNER / admin / OM / dentist) and rate-limited per Client to :data:CLIENT_INVITE_CODE_MONTHLY_LIMIT codes per calendar month. Hit the cap and the response is 429 with body {"detail": "...", "limit": <int>, "period_start": "<iso>"}.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "code": "string",
  • "expires_at": "2019-08-24T14:15:22Z",
  • "created_at": "2019-08-24T14:15:22Z"
}

Practices

Practice management and logo upload

client_create

Create a new organization (Client) for the authenticated staff user.

Creates the :class:Client row, then mints an OWNER :class:~apps.accounts.models.ClientMembership so the user immediately has full control. New clients are automatically assigned the free plan by :meth:Client.save.

Returns HTTP 201 with the new client payload on success. Returns HTTP 409 if the user already belongs to at least one active client — the getting-started wizard guards against this case on the frontend, but the API enforces it so the endpoint can't be used as an org-creation cannon.

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema: application/json
name
required
string

Organization name

Responses

Request samples

Content type
application/json
{
  • "name": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "logo_url": "string",
  • "accent_color": "string",
  • "email_login_enabled": true,
  • "enforce_service_codes": true,
  • "is_active": true,
  • "baa_signed": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null,
  • "active_banners": "string"
}

practice_retrieve

Retrieve or update a specific practice by its UUID.

Addressed by /api/v1/practice/<practice_uid>/ (the non-scoped root). Access is restricted to authenticated staff users whose accessible practices include the target UID. Cross-tenant UID guesses receive a 404 so the endpoint does not leak the existence of other tenants' practices.

PATCH-writable fields include the practice's name, address, phone, timezone, settings, and the three production-goal fields. Every update emits a practice.updated audit event mirroring PracticeDetailView.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "client_name": "string",
  • "name": "string",
  • "address_line1": "string",
  • "address_line2": "string",
  • "city": "string",
  • "state": "st",
  • "zip_code": "string",
  • "phone": "string",
  • "timezone": "string",
  • "settings": null,
  • "production_goal_daily": "string",
  • "production_goal_weekly": "string",
  • "production_goal_monthly": "string",
  • "is_active": true,
  • "logo_url": "string",
  • "client_logo_url": "string",
  • "effective_logo_url": "string",
  • "client_accent_color": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null,
  • "active_banners": "string",
  • "inbound_document_email": "string",
  • "email_login_enabled": true,
  • "effective_email_login_enabled": true,
  • "auto_rescan_enabled": true
}

practice_update

Retrieve or update a specific practice by its UUID.

Addressed by /api/v1/practice/<practice_uid>/ (the non-scoped root). Access is restricted to authenticated staff users whose accessible practices include the target UID. Cross-tenant UID guesses receive a 404 so the endpoint does not leak the existence of other tenants' practices.

PATCH-writable fields include the practice's name, address, phone, timezone, settings, and the three production-goal fields. Every update emits a practice.updated audit event mirroring PracticeDetailView.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
client
string or null <uuid>
name
required
string [ 1 .. 255 ] characters
address_line1
string <= 255 characters
address_line2
string <= 255 characters
city
string <= 100 characters
state
string <= 2 characters
zip_code
string <= 10 characters ^\d{5}(-\d{4})?$
phone
string <= 128 characters
timezone
string [ 1 .. 50 ] characters
settings
any

Practice-specific configuration.

production_goal_daily
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Daily production goal in USD. Null = no goal set.

production_goal_weekly
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Weekly production goal in USD. Null = no goal set.

production_goal_monthly
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Monthly production goal in USD. Null = no goal set.

is_active
boolean
custom_data
any
email_login_enabled
boolean

Allow staff at this practice to sign in via email magic link. Off by default; the owning Client must ALSO have email_login_enabled=True for the feature to be live here.

auto_rescan_enabled
boolean

Include this practice in the nightly AV re-scan sweep. On by default; turn off to skip the recurring scan. Upload-time scans always run regardless of this flag.

Responses

Request samples

Content type
{
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "address_line1": "string",
  • "address_line2": "string",
  • "city": "string",
  • "state": "st",
  • "zip_code": "string",
  • "phone": "string",
  • "timezone": "string",
  • "settings": null,
  • "production_goal_daily": "string",
  • "production_goal_weekly": "string",
  • "production_goal_monthly": "string",
  • "is_active": true,
  • "custom_data": null,
  • "email_login_enabled": true,
  • "auto_rescan_enabled": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "client_name": "string",
  • "name": "string",
  • "address_line1": "string",
  • "address_line2": "string",
  • "city": "string",
  • "state": "st",
  • "zip_code": "string",
  • "phone": "string",
  • "timezone": "string",
  • "settings": null,
  • "production_goal_daily": "string",
  • "production_goal_weekly": "string",
  • "production_goal_monthly": "string",
  • "is_active": true,
  • "logo_url": "string",
  • "client_logo_url": "string",
  • "effective_logo_url": "string",
  • "client_accent_color": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null,
  • "active_banners": "string",
  • "inbound_document_email": "string",
  • "email_login_enabled": true,
  • "effective_email_login_enabled": true,
  • "auto_rescan_enabled": true
}

practice_partial_update

Retrieve or update a specific practice by its UUID.

Addressed by /api/v1/practice/<practice_uid>/ (the non-scoped root). Access is restricted to authenticated staff users whose accessible practices include the target UID. Cross-tenant UID guesses receive a 404 so the endpoint does not leak the existence of other tenants' practices.

PATCH-writable fields include the practice's name, address, phone, timezone, settings, and the three production-goal fields. Every update emits a practice.updated audit event mirroring PracticeDetailView.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
client
string or null <uuid>
name
string [ 1 .. 255 ] characters
address_line1
string <= 255 characters
address_line2
string <= 255 characters
city
string <= 100 characters
state
string <= 2 characters
zip_code
string <= 10 characters ^\d{5}(-\d{4})?$
phone
string <= 128 characters
timezone
string [ 1 .. 50 ] characters
settings
any

Practice-specific configuration.

production_goal_daily
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Daily production goal in USD. Null = no goal set.

production_goal_weekly
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Weekly production goal in USD. Null = no goal set.

production_goal_monthly
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Monthly production goal in USD. Null = no goal set.

is_active
boolean
custom_data
any
email_login_enabled
boolean

Allow staff at this practice to sign in via email magic link. Off by default; the owning Client must ALSO have email_login_enabled=True for the feature to be live here.

auto_rescan_enabled
boolean

Include this practice in the nightly AV re-scan sweep. On by default; turn off to skip the recurring scan. Upload-time scans always run regardless of this flag.

Responses

Request samples

Content type
{
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "address_line1": "string",
  • "address_line2": "string",
  • "city": "string",
  • "state": "st",
  • "zip_code": "string",
  • "phone": "string",
  • "timezone": "string",
  • "settings": null,
  • "production_goal_daily": "string",
  • "production_goal_weekly": "string",
  • "production_goal_monthly": "string",
  • "is_active": true,
  • "custom_data": null,
  • "email_login_enabled": true,
  • "auto_rescan_enabled": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "client_name": "string",
  • "name": "string",
  • "address_line1": "string",
  • "address_line2": "string",
  • "city": "string",
  • "state": "st",
  • "zip_code": "string",
  • "phone": "string",
  • "timezone": "string",
  • "settings": null,
  • "production_goal_daily": "string",
  • "production_goal_weekly": "string",
  • "production_goal_monthly": "string",
  • "is_active": true,
  • "logo_url": "string",
  • "client_logo_url": "string",
  • "effective_logo_url": "string",
  • "client_accent_color": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null,
  • "active_banners": "string",
  • "inbound_document_email": "string",
  • "email_login_enabled": true,
  • "effective_email_login_enabled": true,
  • "auto_rescan_enabled": true
}

practice_business_hours_list

List or create practice-wide business hours rows.

Staff-only. All rows belong to the URL practice -- the practice FK is set automatically on create.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{}

practice_business_hours_create

List or create practice-wide business hours rows.

Staff-only. All rows belong to the URL practice -- the practice FK is set automatically on create.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
day_of_week
required
integer [ -2147483648 .. 2147483647 ]

0=Sunday, 1=Monday, ..., 6=Saturday

start_time
required
string <time>

Open time (practice-local).

end_time
required
string <time>

Close time (practice-local).

is_active
boolean

Inactive rows are ignored by the slot finder; soft-disable lets staff preserve historical hours without deleting the row.

Responses

Request samples

Content type
{
  • "day_of_week": -2147483648,
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "day_of_week": -2147483648,
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_logo_create

Upload or delete the logo for a practice.

POST /api/v1/practice/{uid}/logo/ -- upload a new logo image DELETE /api/v1/practice/{uid}/logo/ -- remove the current logo

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema: multipart/form-data
required
file
required
string <binary>

Responses

Response samples

Content type
application/json
{}

practice_logo_destroy

Upload or delete the logo for a practice.

POST /api/v1/practice/{uid}/logo/ -- upload a new logo image DELETE /api/v1/practice/{uid}/logo/ -- remove the current logo

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_logo_client_create

Upload or delete the logo for the client that owns a practice.

POST /api/v1/practice/{uid}/logo/client/ -- upload a new client logo DELETE /api/v1/practice/{uid}/logo/client/ -- remove the current client logo

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema: multipart/form-data
required
file
required
string <binary>

Responses

Response samples

Content type
application/json
{}

practice_logo_client_destroy

Upload or delete the logo for the client that owns a practice.

POST /api/v1/practice/{uid}/logo/client/ -- upload a new client logo DELETE /api/v1/practice/{uid}/logo/client/ -- remove the current client logo

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

Read the per-practice messaging inbox owners.

GET / PATCH the named messaging inbox owners for a practice.

See module docstring for the auth / validation / audit contract.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "inbox_owner_user_ids": [
    ],
  • "inbox_owner_users": [
    ]
}

Replace the per-practice messaging inbox owners.

GET / PATCH the named messaging inbox owners for a practice.

See module docstring for the auth / validation / audit contract.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
inbox_owner_user_ids
Array of strings <uuid> [ items <uuid > ]

Users to route new patient-portal threads to. Empty list restores the default ADMIN / OFFICE_MANAGER / FRONT_DESK fan-out.

Responses

Request samples

Content type
{
  • "inbox_owner_user_ids": [
    ]
}

Response samples

Content type
application/json
{
  • "inbox_owner_user_ids": [
    ],
  • "inbox_owner_users": [
    ]
}

practice_privacy_config_retrieve

Return the privacy configuration for the practice's state.

Looks up the StatePrivacyConfig for the practice's state and returns the full config object. If the state has no privacy law on file, returns an empty config dict.

Staff-auth required; practice-scoped via PracticeScopedMixin.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "state": "string",
  • "state_name": "string",
  • "config": null,
  • "is_active": true
}

practice_create_create

Create a new practice during import onboarding.

If the authenticated user does not yet have a Client, one is created automatically using the practice name. The new practice is then associated with the user's client.

The import:write scope (legacy catalog entry, still issued to the first-party migration tools — escape-importer / escape-backup / escape-restore) gates this endpoint. The new-taxonomy sync:* scopes are reserved for a future tightening; until any first-party tool actually ships with a sync:patients token, requiring it here would lock the importer out of practice onboarding.

Authorizations:
jwtAuthbearerAuthoauth2

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "client_name": "string",
  • "name": "string",
  • "address_line1": "string",
  • "address_line2": "string",
  • "city": "string",
  • "state": "st",
  • "zip_code": "string",
  • "phone": "string",
  • "timezone": "string",
  • "settings": null,
  • "production_goal_daily": "string",
  • "production_goal_weekly": "string",
  • "production_goal_monthly": "string",
  • "is_active": true,
  • "logo_url": "string",
  • "client_logo_url": "string",
  • "effective_logo_url": "string",
  • "client_accent_color": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null,
  • "active_banners": "string",
  • "inbound_document_email": "string",
  • "email_login_enabled": true,
  • "effective_email_login_enabled": true,
  • "auto_rescan_enabled": true
}

Import

Data migration sessions and batches

practice_sync_export_retrieve

Stream all practice data as a JSON download.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

practice_sync_export_counts_retrieve

Return entity counts for a practice (lightweight preview).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "practice_name": "string",
  • "counts": {
    },
  • "total_records": 0
}

practice_sync_import_create

Receive a batch of records for a given entity type.

Records are bulk-created with ignore_conflicts=True so re-running a migration is safe.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
entity_type
required
string
practice_uid
required
string <uuid>
Request Body schema:
required
session_id
required
string <uuid>
entity_type
required
string (EntityTypeEnum)
Enum: "definitions" "providers" "operatories" "patients" "recalls" "appointments" "balances" "payments" "insurance" "commlogs" "procedure_codes" "schedules" "planned_services" "eod" "procedures" "adjustments" "claims" "treatment_plans" "benefits" "referrals" "medical_history" "payment_plans" "patient_notes" "carriers" "appointment_procedures" "treatment_plan_items" "conditions" "allergies" "medications" "vital_signs" "tooth_conditions" "perio_exams" "perio_readings" "clinical_notes" "note_templates" "patient_education" "anesthesia_records" "payment_records" "payment_splits" "payment_plan_charges" "insurance_carriers" "insurance_plans" "fee_schedules" "fee_schedule_entries" "patient_insurance" "insurance_claims" "claim_procedures" "insurance_benefits" "comm_logs" "schedule_templates" "schedule_overrides" "referral_sources" "patient_referrals" "portal_messages" "imaging_exams" "imaging_exam_images"
  • definitions - definitions
  • providers - providers
  • operatories - operatories
  • patients - patients
  • recalls - recalls
  • appointments - appointments
  • balances - balances
  • payments - payments
  • insurance - insurance
  • commlogs - commlogs
  • procedure_codes - procedure_codes
  • schedules - schedules
  • planned_services - planned_services
  • eod - eod
  • procedures - procedures
  • adjustments - adjustments
  • claims - claims
  • treatment_plans - treatment_plans
  • benefits - benefits
  • referrals - referrals
  • medical_history - medical_history
  • payment_plans - payment_plans
  • patient_notes - patient_notes
  • carriers - carriers
  • appointment_procedures - appointment_procedures
  • treatment_plan_items - treatment_plan_items
  • conditions - conditions
  • allergies - allergies
  • medications - medications
  • vital_signs - vital_signs
  • tooth_conditions - tooth_conditions
  • perio_exams - perio_exams
  • perio_readings - perio_readings
  • clinical_notes - clinical_notes
  • note_templates - note_templates
  • patient_education - patient_education
  • anesthesia_records - anesthesia_records
  • payment_records - payment_records
  • payment_splits - payment_splits
  • payment_plan_charges - payment_plan_charges
  • insurance_carriers - insurance_carriers
  • insurance_plans - insurance_plans
  • fee_schedules - fee_schedules
  • fee_schedule_entries - fee_schedule_entries
  • patient_insurance - patient_insurance
  • insurance_claims - insurance_claims
  • claim_procedures - claim_procedures
  • insurance_benefits - insurance_benefits
  • comm_logs - comm_logs
  • schedule_templates - schedule_templates
  • schedule_overrides - schedule_overrides
  • referral_sources - referral_sources
  • patient_referrals - patient_referrals
  • portal_messages - portal_messages
  • imaging_exams - imaging_exams
  • imaging_exam_images - imaging_exam_images
required
Array of objects

Responses

Request samples

Content type
{
  • "session_id": "1ffd059c-17ea-40a8-8aef-70fd0307db82",
  • "entity_type": "definitions",
  • "records": [
    ]
}

Response samples

Content type
application/json
{
  • "created": 0,
  • "skipped": 0,
  • "errors": 0,
  • "error_messages": [
    ]
}

practice_sync_import_session_list

List import sessions (GET) or create a new one (POST).

GET is open to any authenticated caller — listing one's own import sessions is non-sensitive metadata. POST is restricted to sync tools via the sync:patients gate (first-party bypass keeps the migration tools working; third-party apps cannot request sync:* scopes).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

practice_sync_import_session_create

List import sessions (GET) or create a new one (POST).

GET is open to any authenticated caller — listing one's own import sessions is non-sensitive metadata. POST is restricted to sync tools via the sync:patients gate (first-party bypass keeps the migration tools working; third-party apps cannot request sync:* scopes).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
source
required
string (ImportSessionCreateSourceEnum)
Enum: "opendental" "eaglesoft" "dentrix" "restore" "faker"
  • opendental - OpenDental
  • eaglesoft - Eaglesoft
  • dentrix - Dentrix
  • restore - Backup Restore
  • faker - Demo Data

Responses

Request samples

Content type
{
  • "source": "opendental"
}

Response samples

Content type
application/json
{
  • "session_id": "string",
  • "practice_id": 0,
  • "practice_name": "string"
}

practice_sync_import_session_retrieve

Retrieve session detail with conversion progress (GET) or delete (DELETE).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
session_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "string",
  • "source": "string",
  • "status": "string",
  • "started_at": "string",
  • "completed_at": "string",
  • "created_by": "user@example.com",
  • "record_counts": {
    },
  • "total_records": 0,
  • "conversion_error_count": 0,
  • "import_report": {
    },
  • "import_error_details": [
    ],
  • "has_schema": true,
  • "conversion": {
    }
}

practice_sync_import_session_destroy

Retrieve session detail with conversion progress (GET) or delete (DELETE).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
session_id
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_sync_import_session_accept_create

Accept conversion results (even with errors) and mark session as converted.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
session_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "detail": "string",
  • "session_id": "string"
}

practice_sync_import_session_complete_create

Mark an import session as completed.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
session_id
required
string <uuid>
Request Body schema:
session_id
string <uuid>
Array of objects
object

Responses

Request samples

Content type
{
  • "session_id": "1ffd059c-17ea-40a8-8aef-70fd0307db82",
  • "results": [
    ],
  • "report": {
    }
}

Response samples

Content type
application/json
{
  • "session_id": "string",
  • "status": "string",
  • "completed_at": "string",
  • "record_counts": {
    }
}

practice_sync_import_session_convert_create

Trigger conversion of a completed import session to live data.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
session_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "detail": "string",
  • "session_id": "string"
}

practice_sync_import_session_error_report_retrieve

Download a conversion error report as JSON or CSV.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
session_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "records": [
    ]
}

practice_sync_import_session_rollback_create

Delete all normalized data for this session and reset to uploaded status.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
session_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "detail": "string"
}

practice_sync_import_session_schema_create

Upload a source PMS schema dump for an import session.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
session_id
required
string <uuid>
Request Body schema:
required
schema_text
required
string non-empty
source_type
required
string [ 1 .. 20 ] characters
object

Responses

Request samples

Content type
{
  • "schema_text": "string",
  • "source_type": "string",
  • "metadata": {
    }
}

Response samples

Content type
application/json
{
  • "detail": "string"
}

practice_sync_ping_retrieve

Simple authentication check.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "status": "string"
}

practice_sync_status_list

List all sync status records for a practice.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

practice_sync_status_retrieve

Get or update a sync status record for a specific entity type.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
entity_type
required
string
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "entity_type": "string",
  • "last_synced_at": "string",
  • "last_record_count": 0,
  • "is_running": true,
  • "error_message": "string"
}

practice_sync_status_create

Get or update a sync status record for a specific entity type.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
entity_type
required
string
practice_uid
required
string <uuid>
Request Body schema:
last_synced_at
string or null <date-time>
last_record_count
integer
Default: 0
is_running
boolean
Default: false
error_message
string
Default: ""

Responses

Request samples

Content type
{
  • "last_synced_at": "2019-08-24T14:15:22Z",
  • "last_record_count": 0,
  • "is_running": false,
  • "error_message": ""
}

Response samples

Content type
application/json
{
  • "entity_type": "string",
  • "last_synced_at": "string",
  • "last_record_count": 0,
  • "is_running": true,
  • "error_message": "string"
}

Webhooks

Webhook subscriptions and delivery

webhooks_events_retrieve

Public endpoint returning all registered webhook events grouped by category.

No authentication required — this is a discovery endpoint for developers building integrations against the Escape Dental API.

Authorizations:
jwtAuthbearerAuthoauth2None

Responses

webhooks_subscriptions_test_create

Send a test ping delivery to a subscription's target URL.

Creates a WebhookDelivery with event type 'test.ping' and enqueues it for immediate delivery via Celery.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
subscription_uid
required
string <uuid>

Responses

webhooks_subscriptions_verify_create

Trigger URL ownership verification for a subscription.

Enqueues a Celery task that sends a challenge request to the target URL. The subscription's is_verified flag is set to True only after the endpoint echoes the challenge back correctly.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
subscription_uid
required
string <uuid>

Responses

OAuth2

Authorization and token management

account

account_passkey_retrieve

List the authenticated user's registered passkeys.

GET /api/v1/account/passkey/

Authorizations:
jwtAuthbearerAuthoauth2

Responses

account_passkey_destroy

Delete a registered passkey.

DELETE /api/v1/account/passkey//

Returns 400 if this is the user's only passkey (last-passkey protection).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
passkey_uid
required
string <uuid>

Responses

account_passkey_rename_partial_update

Rename a registered passkey.

PATCH /api/v1/account/passkey//rename/ Body: { "name": "New Name" }

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
passkey_uid
required
string <uuid>

Responses

account_passkey_auth_begin_create

Begin passkey authentication ceremony.

POST /api/v1/account/passkey/auth/begin/ Body: { "email": "user@example.com" } (optional)

If email is provided, returns allowCredentials scoped to that user. If email is omitted, returns empty allowCredentials for discoverable credential / conditional UI flow.

Authorizations:
jwtAuthbearerAuthoauth2None

Responses

account_passkey_auth_complete_create

Complete passkey authentication ceremony.

POST /api/v1/account/passkey/auth/complete/ Body: { "assertion": {...}, "challenge_key": "..." }

On success, returns JWT access + refresh tokens.

Authorizations:
jwtAuthbearerAuthoauth2None

Responses

account_passkey_register_begin_create

Begin passkey registration ceremony.

POST /api/v1/account/passkey/register/begin/ Auth: Bearer token (setup or full session)

Authorizations:
jwtAuthbearerAuthoauth2

Responses

account_passkey_register_complete_create

Complete passkey registration ceremony.

POST /api/v1/account/passkey/register/complete/ Auth: Bearer token (setup or full session) Body: { "credential": {...}, "name": "My Passkey" }

On success during setup session: auto-upgrades to full session.

Authorizations:
jwtAuthbearerAuthoauth2

Responses

account_token_verify_create

Takes a token and indicates if it is valid. This view provides no information about a token's fitness for a particular use.

Authorizations:
bearerAuthoauth2
Request Body schema:
required
token
required
string non-empty

Responses

Request samples

Content type
{
  • "token": "string"
}

account_user_list

List users visible to the authenticated user (scoped by practice membership).

Staff (is_staff=True) and superusers (is_superuser=True) get the unscoped queryset -- the support tool runs under one of those roles and needs cross-tenant visibility to find users by email, name, or UUID regardless of which Client they belong to. This mirrors the pattern used by PracticeListView and the Client procedure-code endpoint (see _get_client_or_404).

Optional boolean filters (?is_staff=true|false and ?is_superuser=true|false) let callers narrow the result to the staff / superuser populations (or exclude them). Both filters accept the strings "true" and "false" (case-insensitive); any other value is ignored so unknown params never surface as a 500.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
cursor
string

The pagination cursor value.

Responses

Response samples

Content type
application/json
{
  • "results": [
    ]
}

account_user_retrieve

Retrieve or update a user by ID (scoped to client).

Reads are allowed for any authenticated user within the same client. Writes are restricted: users can update their own profile, but only admins can update other users' profiles.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
user_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "email": "user@example.com",
  • "first_name": "string",
  • "last_name": "string",
  • "is_patient": true,
  • "is_staff": true,
  • "is_superuser": true,
  • "is_support_staff": true,
  • "is_active": true,
  • "date_joined": "2019-08-24T14:15:22Z",
  • "last_login": "2019-08-24T14:15:22Z",
  • "last_seen_at": "2019-08-24T14:15:22Z",
  • "first_run_tour_completed_at": "2019-08-24T14:15:22Z",
  • "preference_data": "string",
  • "memberships": [
    ],
  • "client_memberships": [
    ],
  • "current_practice_id": "edf1be34-8ae4-41f5-bad6-133af3513eac",
  • "practice_timezone": "string"
}

account_user_update

Retrieve or update a user by ID (scoped to client).

Reads are allowed for any authenticated user within the same client. Writes are restricted: users can update their own profile, but only admins can update other users' profiles.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
user_uid
required
string <uuid>
Request Body schema:
required
first_name
required
string [ 1 .. 150 ] characters
last_name
required
string [ 1 .. 150 ] characters

Responses

Request samples

Content type
{
  • "first_name": "string",
  • "last_name": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "email": "user@example.com",
  • "first_name": "string",
  • "last_name": "string",
  • "is_patient": true,
  • "is_staff": true,
  • "is_superuser": true,
  • "is_support_staff": true,
  • "is_active": true,
  • "date_joined": "2019-08-24T14:15:22Z",
  • "last_login": "2019-08-24T14:15:22Z",
  • "last_seen_at": "2019-08-24T14:15:22Z",
  • "first_run_tour_completed_at": "2019-08-24T14:15:22Z",
  • "preference_data": "string",
  • "memberships": [
    ],
  • "client_memberships": [
    ],
  • "current_practice_id": "edf1be34-8ae4-41f5-bad6-133af3513eac",
  • "practice_timezone": "string"
}

account_user_partial_update

Retrieve or update a user by ID (scoped to client).

Reads are allowed for any authenticated user within the same client. Writes are restricted: users can update their own profile, but only admins can update other users' profiles.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
user_uid
required
string <uuid>
Request Body schema:
first_name
string [ 1 .. 150 ] characters
last_name
string [ 1 .. 150 ] characters

Responses

Request samples

Content type
{
  • "first_name": "string",
  • "last_name": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "email": "user@example.com",
  • "first_name": "string",
  • "last_name": "string",
  • "is_patient": true,
  • "is_staff": true,
  • "is_superuser": true,
  • "is_support_staff": true,
  • "is_active": true,
  • "date_joined": "2019-08-24T14:15:22Z",
  • "last_login": "2019-08-24T14:15:22Z",
  • "last_seen_at": "2019-08-24T14:15:22Z",
  • "first_run_tour_completed_at": "2019-08-24T14:15:22Z",
  • "preference_data": "string",
  • "memberships": [
    ],
  • "client_memberships": [
    ],
  • "current_practice_id": "edf1be34-8ae4-41f5-bad6-133af3513eac",
  • "practice_timezone": "string"
}

Admin

Read OAuth API usage rollups

Aggregate the OAuthAppUsageMetric rollup table by scope, method, and window. Staff-only. Powers the support-tool API stats dashboard.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
from
string <date>

Inclusive lower bound on bucket_start (UTC date, YYYY-MM-DD).

group_by
string
Enum: "app" "client" "practice" "user"

Aggregate into one row per entity in this scope dimension instead of time-windowed rows. Rows carry {scope_id, display_name, total, reads, writes} sorted by total descending; the paginated body gains a summary object computed over the full filtered set.

method
string
Enum: "DELETE" "GET" "HEAD" "OPTIONS" "PATCH" "POST" "PUT" "READ" "WRITE"

HTTP method or bucket. GET/HEAD/OPTIONS map to the READ bucket; POST/PUT/PATCH/DELETE map to the WRITE bucket; READ/WRITE select a bucket directly.

page
integer

1-indexed page number.

page_size
integer

Page size, default 20, max 100.

scope
string
Enum: "app" "client" "practice" "user"

Scope dimension to filter on.

scope_id
string

Denormalized scope identifier. UUID for client/practice/user, OAuth client_id for app. Requires scope to be set.

to
string <date>

Inclusive upper bound on bucket_start (UTC date, YYYY-MM-DD).

window
string
Enum: "day" "hour" "month" "week"

Bucket size. Defaults to hour.

Responses

Response samples

Content type
application/json
{}

List audit events

Paginated, filterable read of the audit-events-* Elasticsearch index. Staff-only. Powers the support-tool audit-log panel. Filters are AND-combined; missing filters are open-ended. Page size defaults to 50, max 100.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
actor_email
string

Exact-match actor email; matched against the keyword field actor.email.

event_type
string

Dotted-name event type (e.g. patient.viewed).

page
integer

1-indexed page number. Defaults to 1.

page_size
integer

Page size, default 50, max 100 (clamped).

practice
string <uuid>

Practice UUID — only events tagged with this practice_id are returned.

since
string <date-time>

ISO8601 lower bound (inclusive) on timestamp.

until
string <date-time>

ISO8601 upper bound (inclusive) on timestamp.

Responses

Response samples

Content type
application/json
[
  • {
    }
]

admin_client_partial_update

Toggle is_active on a Client.

Support-staff-only (is_support_staff=True). Sets the is_active flag on the Client model. Deactivating a client effectively disables all practices under it.

Disabling delegates to :meth:Client.disable, which atomically flips the flag AND revokes every outstanding OAuth access/refresh token and SimpleJWT refresh token issued to the Client's users. This is the escape#310 fix -- before the delegation existed, disabling left active sessions intact and users could keep reading PHI right up until the next token rotation.

Idempotent: re-submitting the current state is a no-op that still writes an audit entry (with no_op=True) so the attempt itself is recorded.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>
Request Body schema:
is_active
boolean

Set to true to enable, false to disable.

reason
string [ 5 .. 1024 ] characters

Free-text justification recorded in the audit log (min 5 chars).

Responses

Request samples

Content type
{
  • "is_active": true,
  • "reason": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "is_active": true
}

List the canonical MCP tool catalog

Read-only list of every key registered in apps.mcp.tools.registry.REGISTRY. Staff-only. Returns name, description, required_scopes, and pass_context. Used by the support UI to render every gating row even when no PracticeToolGate exists yet for the practice in view.

Authorizations:
jwtAuthbearerAuthoauth2

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Get OAuth application detail

Return the public payload for a single OAuth application.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_id
required
string

Responses

Response samples

Content type
application/json
{
  • "client_id": "string",
  • "name": "string",
  • "throttle_mode": "string",
  • "is_first_party": true,
  • "approval_status": "string",
  • "request_count_24h": 0,
  • "audit_throttle_hits_24h": 0,
  • "enforce_throttle_hits_24h": 0,
  • "slots": [
    ],
  • "url_template": "",
  • "approved_at": "2019-08-24T14:15:22Z",
  • "approved_by_email": "string"
}

Update OAuth application throttle mode and / or slot manifest

Either flips the per-app throttle override (throttle_mode + reason body) or updates the slot manifest (slots / url_template body) — or both in a single request. At least one set of fields must be present. Staff-only.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_id
required
string
Request Body schema:
throttle_mode
string
Enum: "default" "audit" "enforce"

Target throttle mode. default clears any per-app override and inherits the global setting.

  • default - Default (inherit global)
  • audit - Audit
  • enforce - Enforce
reason
string [ 5 .. 1024 ] characters

Free-text justification recorded in the audit log (min 5 chars).

Responses

Request samples

Content type
{
  • "throttle_mode": "default",
  • "reason": "string"
}

Response samples

Content type
application/json
{
  • "client_id": "string",
  • "name": "string",
  • "throttle_mode": "string",
  • "is_first_party": true,
  • "approval_status": "string",
  • "request_count_24h": 0,
  • "audit_throttle_hits_24h": 0,
  • "enforce_throttle_hits_24h": 0,
  • "slots": [
    ],
  • "url_template": "",
  • "approved_at": "2019-08-24T14:15:22Z",
  • "approved_by_email": "string"
}

admin_practice_partial_update

Toggle is_active on a Practice.

Support-staff-only (is_support_staff=True). Sets the is_active flag on the Practice model.

Idempotent: re-submitting the current state is a no-op that still writes an audit entry (with no_op=True).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>
Request Body schema:
is_active
boolean

Set to true to enable, false to disable.

reason
string [ 5 .. 1024 ] characters

Free-text justification recorded in the audit log (min 5 chars).

Responses

Request samples

Content type
{
  • "is_active": true,
  • "reason": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "is_active": true
}

admin_practice_ocr_backfill_create

Queue OCR + Elasticsearch indexing for documents in the given practice that pre-date the OCR pipeline. Idempotent: skips documents that already have a DocumentOcrResult row unless force is true. Requires reason, which is recorded in the audit log.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>
Request Body schema:
required
reason
required
string [ 5 .. 1024 ] characters

Free-text justification recorded in the audit log (min 5 chars).

limit
integer or null [ 1 .. 100000 ]

Cap the number of OCR tasks dispatched. Defaults to no cap.

mime
Array of strings or null[ items [ 1 .. 100 ] characters ]

Override the default mime allow-list. Defaults to ['application/pdf', 'image/jpeg', 'image/png', 'image/tiff', 'image/webp'].

force
boolean
Default: false

Re-OCR documents that already have a DocumentOcrResult row.

dry_run
boolean
Default: false

Compute the would-be queued count without dispatching tasks.

Responses

Request samples

Content type
{
  • "reason": "string",
  • "limit": 1,
  • "mime": [
    ],
  • "force": false,
  • "dry_run": false
}

Response samples

Content type
application/json
{
  • "queued": 0,
  • "errored": 0,
  • "total_matched": 0,
  • "dry_run": true
}

admin_practice_ocr_status_retrieve

Return {documents_total, ocr_results_total, pending} for the practice. Lets the support UI render OCR progress without paginating either list.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "documents_total": 0,
  • "ocr_results_total": 0,
  • "pending": 0
}

Upsert an MCP tool gate for a practice

Create or update a PracticeToolGate row. Fires the model's post_save signal so connected MCP SSE clients receive a notifications/tools/list_changed frame.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_id
required
string <uuid>
tool_key
required
string
Request Body schema:
required
enabled
required
boolean

True to allow the tool, False to hide it from the practice's catalog.

note
string <= 4096 characters
Default: ""

Optional free-text reason surfaced in the support UI.

Responses

Request samples

Content type
{
  • "enabled": true,
  • "note": ""
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "tool_key": "string",
  • "enabled": true,
  • "note": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "created_by_email": "string",
  • "modified_by_email": "string"
}

Remove an MCP tool gate for a practice

Delete the PracticeToolGate row, reverting the tool to its default-enabled state. Fires the model's post_delete signal so connected MCP SSE clients receive a notifications/tools/list_changed frame. Idempotent -- deleting a non-existent gate returns 404.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_id
required
string <uuid>
tool_key
required
string

Responses

admin_user_partial_update

Toggle is_active on a User.

Support-staff-only (is_support_staff=True). Sets the is_active flag on the User model.

Only superusers may disable a superuser -- a non-superuser staff member attempting this gets a 403. The support tool enforces the same rule client-side; the server check is the authoritative guard (belt + suspenders against a broken or misbehaving client).

Idempotent: re-submitting the current state is a no-op that still writes an audit entry (with no_op=True).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>
Request Body schema:
is_active
boolean

Set to true to enable, false to disable.

reason
string [ 5 .. 1024 ] characters

Free-text justification recorded in the audit log (min 5 chars).

Responses

Request samples

Content type
{
  • "is_active": true,
  • "reason": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "email": "user@example.com",
  • "first_name": "string",
  • "last_name": "string",
  • "is_active": true
}

admin

admin_oauth_app_list

Paginated list of OAuth applications for the support tool.

Cross-tenant — staff operates above the practice-scoping layer, so every Application row is returned. Ordered by name for a stable, human-friendly default; the support UI may later re-sort client-side.

Query parameters (api#408):

  • q — case-insensitive substring match against name OR client_id. Empty/missing means "no filter". Translates to Q(name__icontains=q) | Q(client_id__icontains=q) so the index planner picks the cheaper side.
  • throttle_mode — exact match against :class:OAuthAppProfile.throttle_mode (default / audit / enforce). Apps with NO profile row are treated as default so ?throttle_mode=default returns them too — implemented with a LEFT JOIN + Coalesce annotation rather than a Python-side filter so pagination metadata (count/next/previous) reflects the filtered set.

Both filters AND-combine. An unknown throttle_mode value returns HTTP 400 with a clear error — picked over silently ignoring because a typo on the support tool's side should fail loudly rather than serve up the unfiltered list and look like a pagination bug.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

admin_oauth_app_approve_create

Approve, reject, or suspend a third-party OAuth application.

POST /api/v1/admin/oauth-app/<client_id>/approve/ POST /api/v1/admin/oauth-app/<client_id>/reject/ POST /api/v1/admin/oauth-app/<client_id>/suspend/

The action kwarg is set by the URL dispatcher (see admin_api/urls.py).

Approve: Sets approval_status=APPROVED, stamps approved_at and approved_by. reason is optional (but logged if supplied). Returns 200 with the updated serializer payload.

Reject / Suspend: Sets the corresponding status. reason is required (≥5 chars) so there is always a human-readable explanation in the audit log. approved_at / approved_by are cleared on reject/suspend so the record accurately reflects the current state.

First-party apps: Always returns 400 — they bypass the approval workflow by design and must not be touched via this endpoint.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_id
required
string

Responses

admin_oauth_app_reject_create

Approve, reject, or suspend a third-party OAuth application.

POST /api/v1/admin/oauth-app/<client_id>/approve/ POST /api/v1/admin/oauth-app/<client_id>/reject/ POST /api/v1/admin/oauth-app/<client_id>/suspend/

The action kwarg is set by the URL dispatcher (see admin_api/urls.py).

Approve: Sets approval_status=APPROVED, stamps approved_at and approved_by. reason is optional (but logged if supplied). Returns 200 with the updated serializer payload.

Reject / Suspend: Sets the corresponding status. reason is required (≥5 chars) so there is always a human-readable explanation in the audit log. approved_at / approved_by are cleared on reject/suspend so the record accurately reflects the current state.

First-party apps: Always returns 400 — they bypass the approval workflow by design and must not be touched via this endpoint.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_id
required
string

Responses

admin_oauth_app_suspend_create

Approve, reject, or suspend a third-party OAuth application.

POST /api/v1/admin/oauth-app/<client_id>/approve/ POST /api/v1/admin/oauth-app/<client_id>/reject/ POST /api/v1/admin/oauth-app/<client_id>/suspend/

The action kwarg is set by the URL dispatcher (see admin_api/urls.py).

Approve: Sets approval_status=APPROVED, stamps approved_at and approved_by. reason is optional (but logged if supplied). Returns 200 with the updated serializer payload.

Reject / Suspend: Sets the corresponding status. reason is required (≥5 chars) so there is always a human-readable explanation in the audit log. approved_at / approved_by are cleared on reject/suspend so the record accurately reflects the current state.

First-party apps: Always returns 400 — they bypass the approval workflow by design and must not be touched via this endpoint.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_id
required
string

Responses

admin_practice_mcp_gates_list

List existing :class:PracticeToolGate rows for one practice.

Empty list means "no overrides -- every tool is default-enabled". Returns the rows in tool_key order so the support UI's rendering is stable across requests.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_id
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

admin_support_patients_list

Cross-practice, PHI-free patient search for the support tool.

Support-staff-only (is_support_staff=True). Accepts a ?q=<query> parameter:

  • If q is UUID-shaped, does an exact match on Patient.id.
  • Otherwise, performs a case-insensitive prefix match against first_name OR last_name.

The PHI fields are searched server-side -- a tech needs to type a name to find a record -- but the response never contains them. The query string itself is NOT recorded in the audit log, because it may itself be PHI (e.g. a patient's surname).

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

admin_support_patients_retrieve

PHI-free patient detail view for the support tool.

Support-staff-only (is_support_staff=True). Exposes the same allow-listed fields as the list view (see :class:SupportPatientSerializer). Emits a support.patient.viewed audit event on every access.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "initials": "string",
  • "practice": {
    },
  • "status": "active",
  • "last_appointment_at": "string",
  • "balance_outstanding": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Banners

banner_list

CRUD for sign-in / pop-up banners attached to a Client or a Practice.

Permissions (deny-by-default):

  • All requests require an authenticated, non-patient staff user.
  • Read (list/retrieve): any user with an active membership in the banner's owning Client (for client-scoped banners) or Practice (for practice-scoped banners). By default the list returns only currently-active banners; pass ?include_expired=true to include expired and not-yet-started banners (admin role required).
  • Write (create/update/destroy):
    • Banners targeting a Client require an active ClientMembership on that Client with role OWNER or TECHNICAL.
    • Banners targeting a Practice require either:
      • an active PracticeMembership on that Practice with role ADMIN or OFFICE_MANAGER, or
      • an active ClientMembership on the Practice's Client with role OWNER (Owners can manage banners on any of their practices).
    • Crucially, a Practice admin cannot create Client-level banners — that requires explicit Client admin rights.

Cross-tenant safety: get_queryset always restricts to the user's accessible clients and practices, so a user in tenant A cannot see, list, or PATCH a banner in tenant B even by guessing UUIDs.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

banner_create

CRUD for sign-in / pop-up banners attached to a Client or a Practice.

Permissions (deny-by-default):

  • All requests require an authenticated, non-patient staff user.
  • Read (list/retrieve): any user with an active membership in the banner's owning Client (for client-scoped banners) or Practice (for practice-scoped banners). By default the list returns only currently-active banners; pass ?include_expired=true to include expired and not-yet-started banners (admin role required).
  • Write (create/update/destroy):
    • Banners targeting a Client require an active ClientMembership on that Client with role OWNER or TECHNICAL.
    • Banners targeting a Practice require either:
      • an active PracticeMembership on that Practice with role ADMIN or OFFICE_MANAGER, or
      • an active ClientMembership on the Practice's Client with role OWNER (Owners can manage banners on any of their practices).
    • Crucially, a Practice admin cannot create Client-level banners — that requires explicit Client admin rights.

Cross-tenant safety: get_queryset always restricts to the user's accessible clients and practices, so a user in tenant A cannot see, list, or PATCH a banner in tenant B even by guessing UUIDs.

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
required
title
string <= 120 characters

Optional short heading shown above the message.

message
required
string non-empty

Plain-text banner body. HTML is not rendered by the client.

severity
string
Enum: "info" "warning" "urgent"

Visual treatment hint for the frontend (info/warning/urgent).

  • info - Info
  • warning - Warning
  • urgent - Urgent
starts_at
string <date-time>

UTC datetime the banner becomes active. Defaults to now.

expires_at
required
string <date-time>

UTC datetime after which the banner is no longer active.

client
string or null <uuid>

Client this banner targets. Mutually exclusive with practice.

practice
string or null <uuid>

Practice this banner targets. Mutually exclusive with client.

Responses

Request samples

Content type
{
  • "title": "string",
  • "message": "string",
  • "severity": "info",
  • "starts_at": "2019-08-24T14:15:22Z",
  • "expires_at": "2019-08-24T14:15:22Z",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "title": "string",
  • "message": "string",
  • "severity": "info",
  • "starts_at": "2019-08-24T14:15:22Z",
  • "expires_at": "2019-08-24T14:15:22Z",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

banner_retrieve

CRUD for sign-in / pop-up banners attached to a Client or a Practice.

Permissions (deny-by-default):

  • All requests require an authenticated, non-patient staff user.
  • Read (list/retrieve): any user with an active membership in the banner's owning Client (for client-scoped banners) or Practice (for practice-scoped banners). By default the list returns only currently-active banners; pass ?include_expired=true to include expired and not-yet-started banners (admin role required).
  • Write (create/update/destroy):
    • Banners targeting a Client require an active ClientMembership on that Client with role OWNER or TECHNICAL.
    • Banners targeting a Practice require either:
      • an active PracticeMembership on that Practice with role ADMIN or OFFICE_MANAGER, or
      • an active ClientMembership on the Practice's Client with role OWNER (Owners can manage banners on any of their practices).
    • Crucially, a Practice admin cannot create Client-level banners — that requires explicit Client admin rights.

Cross-tenant safety: get_queryset always restricts to the user's accessible clients and practices, so a user in tenant A cannot see, list, or PATCH a banner in tenant B even by guessing UUIDs.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>

A UUID string identifying this banner.

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "title": "string",
  • "message": "string",
  • "severity": "info",
  • "starts_at": "2019-08-24T14:15:22Z",
  • "expires_at": "2019-08-24T14:15:22Z",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

banner_update

CRUD for sign-in / pop-up banners attached to a Client or a Practice.

Permissions (deny-by-default):

  • All requests require an authenticated, non-patient staff user.
  • Read (list/retrieve): any user with an active membership in the banner's owning Client (for client-scoped banners) or Practice (for practice-scoped banners). By default the list returns only currently-active banners; pass ?include_expired=true to include expired and not-yet-started banners (admin role required).
  • Write (create/update/destroy):
    • Banners targeting a Client require an active ClientMembership on that Client with role OWNER or TECHNICAL.
    • Banners targeting a Practice require either:
      • an active PracticeMembership on that Practice with role ADMIN or OFFICE_MANAGER, or
      • an active ClientMembership on the Practice's Client with role OWNER (Owners can manage banners on any of their practices).
    • Crucially, a Practice admin cannot create Client-level banners — that requires explicit Client admin rights.

Cross-tenant safety: get_queryset always restricts to the user's accessible clients and practices, so a user in tenant A cannot see, list, or PATCH a banner in tenant B even by guessing UUIDs.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>

A UUID string identifying this banner.

Request Body schema:
required
title
string <= 120 characters

Optional short heading shown above the message.

message
required
string non-empty

Plain-text banner body. HTML is not rendered by the client.

severity
string
Enum: "info" "warning" "urgent"

Visual treatment hint for the frontend (info/warning/urgent).

  • info - Info
  • warning - Warning
  • urgent - Urgent
starts_at
string <date-time>

UTC datetime the banner becomes active. Defaults to now.

expires_at
required
string <date-time>

UTC datetime after which the banner is no longer active.

client
string or null <uuid>

Client this banner targets. Mutually exclusive with practice.

practice
string or null <uuid>

Practice this banner targets. Mutually exclusive with client.

Responses

Request samples

Content type
{
  • "title": "string",
  • "message": "string",
  • "severity": "info",
  • "starts_at": "2019-08-24T14:15:22Z",
  • "expires_at": "2019-08-24T14:15:22Z",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "title": "string",
  • "message": "string",
  • "severity": "info",
  • "starts_at": "2019-08-24T14:15:22Z",
  • "expires_at": "2019-08-24T14:15:22Z",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

banner_partial_update

CRUD for sign-in / pop-up banners attached to a Client or a Practice.

Permissions (deny-by-default):

  • All requests require an authenticated, non-patient staff user.
  • Read (list/retrieve): any user with an active membership in the banner's owning Client (for client-scoped banners) or Practice (for practice-scoped banners). By default the list returns only currently-active banners; pass ?include_expired=true to include expired and not-yet-started banners (admin role required).
  • Write (create/update/destroy):
    • Banners targeting a Client require an active ClientMembership on that Client with role OWNER or TECHNICAL.
    • Banners targeting a Practice require either:
      • an active PracticeMembership on that Practice with role ADMIN or OFFICE_MANAGER, or
      • an active ClientMembership on the Practice's Client with role OWNER (Owners can manage banners on any of their practices).
    • Crucially, a Practice admin cannot create Client-level banners — that requires explicit Client admin rights.

Cross-tenant safety: get_queryset always restricts to the user's accessible clients and practices, so a user in tenant A cannot see, list, or PATCH a banner in tenant B even by guessing UUIDs.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>

A UUID string identifying this banner.

Request Body schema:
title
string <= 120 characters

Optional short heading shown above the message.

message
string non-empty

Plain-text banner body. HTML is not rendered by the client.

severity
string
Enum: "info" "warning" "urgent"

Visual treatment hint for the frontend (info/warning/urgent).

  • info - Info
  • warning - Warning
  • urgent - Urgent
starts_at
string <date-time>

UTC datetime the banner becomes active. Defaults to now.

expires_at
string <date-time>

UTC datetime after which the banner is no longer active.

client
string or null <uuid>

Client this banner targets. Mutually exclusive with practice.

practice
string or null <uuid>

Practice this banner targets. Mutually exclusive with client.

Responses

Request samples

Content type
{
  • "title": "string",
  • "message": "string",
  • "severity": "info",
  • "starts_at": "2019-08-24T14:15:22Z",
  • "expires_at": "2019-08-24T14:15:22Z",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "title": "string",
  • "message": "string",
  • "severity": "info",
  • "starts_at": "2019-08-24T14:15:22Z",
  • "expires_at": "2019-08-24T14:15:22Z",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

banner_destroy

CRUD for sign-in / pop-up banners attached to a Client or a Practice.

Permissions (deny-by-default):

  • All requests require an authenticated, non-patient staff user.
  • Read (list/retrieve): any user with an active membership in the banner's owning Client (for client-scoped banners) or Practice (for practice-scoped banners). By default the list returns only currently-active banners; pass ?include_expired=true to include expired and not-yet-started banners (admin role required).
  • Write (create/update/destroy):
    • Banners targeting a Client require an active ClientMembership on that Client with role OWNER or TECHNICAL.
    • Banners targeting a Practice require either:
      • an active PracticeMembership on that Practice with role ADMIN or OFFICE_MANAGER, or
      • an active ClientMembership on the Practice's Client with role OWNER (Owners can manage banners on any of their practices).
    • Crucially, a Practice admin cannot create Client-level banners — that requires explicit Client admin rights.

Cross-tenant safety: get_queryset always restricts to the user's accessible clients and practices, so a user in tenant A cannot see, list, or PATCH a banner in tenant B even by guessing UUIDs.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>

A UUID string identifying this banner.

Responses

client

client_list

List and create client (organization) records for the current user.

GET /api/v1/client/ -- list the caller's accessible organizations (unchanged behaviour).

POST /api/v1/client/ -- create a new organization for the caller (api#469). Used by the first-run /getting-started wizard when the user has no existing clients. See :meth:post for the full contract.

Authorizations:
jwtAuthbearerAuthoauth2

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Exploding Codes

List client-scope exploding codes.

GET/POST /api/v1/client/<client_uid>/exploding-codes/.

Client-level authoring surface -- only scope=CLIENT rows are in scope here. Mutation requires the client OWNER role or Escape support staff (is_support_staff, for Security-Nexus management on the org's behalf -- GH-1029); any user with Client access may read.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

Author a client-scope exploding code.

GET/POST /api/v1/client/<client_uid>/exploding-codes/.

Client-level authoring surface -- only scope=CLIENT rows are in scope here. Mutation requires the client OWNER role or Escape support staff (is_support_staff, for Security-Nexus management on the org's behalf -- GH-1029); any user with Client access may read.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 20 ] characters ^[A-Za-z0-9_-]{1,20}$

Shorthand alias (1-20 chars, A-Z / 0-9 / - / _). Normalized to uppercase; case-insensitive lookup.

description
string <= 255 characters

Optional human-readable label shown in the type-ahead UI.

leaves
Array of strings <uuid> [ items <uuid > ]
leaf_codes
Array of strings[ items [ 1 .. 20 ] characters ]

Responses

Request samples

Content type
{
  • "name": "string",
  • "description": "string",
  • "leaves": [
    ],
  • "leaf_codes": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "description": "string",
  • "scope": "global",
  • "scope_source": "string",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "leaves": [
    ],
  • "leaf_codes": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

client_exploding_codes_retrieve

Retrieve / update / delete a single client-scope exploding code.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
code_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "description": "string",
  • "scope": "global",
  • "scope_source": "string",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "leaves": [
    ],
  • "leaf_codes": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

client_exploding_codes_update

Retrieve / update / delete a single client-scope exploding code.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
code_id
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 20 ] characters ^[A-Za-z0-9_-]{1,20}$

Shorthand alias (1-20 chars, A-Z / 0-9 / - / _). Normalized to uppercase; case-insensitive lookup.

description
string <= 255 characters

Optional human-readable label shown in the type-ahead UI.

leaves
Array of strings <uuid> [ items <uuid > ]
leaf_codes
Array of strings[ items [ 1 .. 20 ] characters ]

Responses

Request samples

Content type
{
  • "name": "string",
  • "description": "string",
  • "leaves": [
    ],
  • "leaf_codes": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "description": "string",
  • "scope": "global",
  • "scope_source": "string",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "leaves": [
    ],
  • "leaf_codes": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

client_exploding_codes_partial_update

Retrieve / update / delete a single client-scope exploding code.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
code_id
required
string <uuid>
Request Body schema:
name
string [ 1 .. 20 ] characters ^[A-Za-z0-9_-]{1,20}$

Shorthand alias (1-20 chars, A-Z / 0-9 / - / _). Normalized to uppercase; case-insensitive lookup.

description
string <= 255 characters

Optional human-readable label shown in the type-ahead UI.

leaves
Array of strings <uuid> [ items <uuid > ]
leaf_codes
Array of strings[ items [ 1 .. 20 ] characters ]

Responses

Request samples

Content type
{
  • "name": "string",
  • "description": "string",
  • "leaves": [
    ],
  • "leaf_codes": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "description": "string",
  • "scope": "global",
  • "scope_source": "string",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "leaves": [
    ],
  • "leaf_codes": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

client_exploding_codes_destroy

Retrieve / update / delete a single client-scope exploding code.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
code_id
required
string <uuid>

Responses

List effective exploding codes for a practice.

Returns the effective set of exploding codes for the URL's practice with three-layer scoping applied: practice override > client override > global library. More-specific layers win on name collision -- a practice override for NEW hides the client and global versions.

This is a read of the resolved view; the underlying rows live in three storage tiers (practice / client / global) and are authored through separate endpoints. Use the per-practice POST on this same URL to author a per-practice override.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

Create a per-practice exploding code.

Author a practice-scope override. scope and practice are server-set from the URL -- a body that tries to set them to a different value is ignored. Office Manager role or above is required.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 20 ] characters ^[A-Za-z0-9_-]{1,20}$

Shorthand alias (1-20 chars, A-Z / 0-9 / - / _). Normalized to uppercase; case-insensitive lookup.

description
string <= 255 characters

Optional human-readable label shown in the type-ahead UI.

leaves
Array of strings <uuid> [ items <uuid > ]
leaf_codes
Array of strings[ items [ 1 .. 20 ] characters ]

Responses

Request samples

Content type
{
  • "name": "string",
  • "description": "string",
  • "leaves": [
    ],
  • "leaf_codes": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "description": "string",
  • "scope": "global",
  • "scope_source": "string",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "leaves": [
    ],
  • "leaf_codes": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_exploding_codes_retrieve

Retrieve / update / delete a single per-practice exploding code.

Only operates on rows whose scope=PRACTICE and practice=<URL practice>. Editing a client or global row from the practice URL is intentionally not supported -- mutate those from their authoring surface instead. Trying to do so returns 404 (the row is not in this surface's queryset), which matches the access boundary the URL itself implies.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
code_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "description": "string",
  • "scope": "global",
  • "scope_source": "string",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "leaves": [
    ],
  • "leaf_codes": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_exploding_codes_update

Retrieve / update / delete a single per-practice exploding code.

Only operates on rows whose scope=PRACTICE and practice=<URL practice>. Editing a client or global row from the practice URL is intentionally not supported -- mutate those from their authoring surface instead. Trying to do so returns 404 (the row is not in this surface's queryset), which matches the access boundary the URL itself implies.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
code_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 20 ] characters ^[A-Za-z0-9_-]{1,20}$

Shorthand alias (1-20 chars, A-Z / 0-9 / - / _). Normalized to uppercase; case-insensitive lookup.

description
string <= 255 characters

Optional human-readable label shown in the type-ahead UI.

leaves
Array of strings <uuid> [ items <uuid > ]
leaf_codes
Array of strings[ items [ 1 .. 20 ] characters ]

Responses

Request samples

Content type
{
  • "name": "string",
  • "description": "string",
  • "leaves": [
    ],
  • "leaf_codes": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "description": "string",
  • "scope": "global",
  • "scope_source": "string",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "leaves": [
    ],
  • "leaf_codes": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_exploding_codes_partial_update

Retrieve / update / delete a single per-practice exploding code.

Only operates on rows whose scope=PRACTICE and practice=<URL practice>. Editing a client or global row from the practice URL is intentionally not supported -- mutate those from their authoring surface instead. Trying to do so returns 404 (the row is not in this surface's queryset), which matches the access boundary the URL itself implies.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
code_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
name
string [ 1 .. 20 ] characters ^[A-Za-z0-9_-]{1,20}$

Shorthand alias (1-20 chars, A-Z / 0-9 / - / _). Normalized to uppercase; case-insensitive lookup.

description
string <= 255 characters

Optional human-readable label shown in the type-ahead UI.

leaves
Array of strings <uuid> [ items <uuid > ]
leaf_codes
Array of strings[ items [ 1 .. 20 ] characters ]

Responses

Request samples

Content type
{
  • "name": "string",
  • "description": "string",
  • "leaves": [
    ],
  • "leaf_codes": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "description": "string",
  • "scope": "global",
  • "scope_source": "string",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "leaves": [
    ],
  • "leaf_codes": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_exploding_codes_destroy

Retrieve / update / delete a single per-practice exploding code.

Only operates on rows whose scope=PRACTICE and practice=<URL practice>. Editing a client or global row from the practice URL is intentionally not supported -- mutate those from their authoring surface instead. Trying to do so returns 404 (the row is not in this surface's queryset), which matches the access boundary the URL itself implies.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
code_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

Expand an exploding code by name against the practice.

Looks up code (case-insensitive) using the same three-layer scoping as the list endpoint, then returns the expanded leaves with per-leaf missing flags plus a rolled-up warnings list. Leaves whose CDT code is not on the practice's active ProcedureCode table are returned with missing=true and fee=null (per Aaron's call in escape#315: skip + warn, do not block the rest).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
code
required
string

Shorthand name (case-insensitive, 1-20 chars).

practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "name": "string",
  • "description": "string",
  • "scope": "global",
  • "leaves": [
    ],
  • "warnings": [
    ]
}

Client Service Codes

List client-level service codes.

Returns the curated service-code list for the URL's Client. Filterable by ?category=<name> (case-insensitive exact match) and ?search=<query> (case-insensitive substring on code and description).

Open to any authenticated user with access to the Client. Writes (POST) require OWNER role.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{}

Add a service code to the client list.

Creates a new :class:~apps.clinical.models.ClientServiceCode row on the URL's Client. code uniqueness is enforced case-insensitively per client -- D0150 and d0150 are the same code. OWNER role required.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
Request Body schema:
required
code
required
string [ 1 .. 16 ] characters

CDT / service code identifier, e.g. D0150. Case-insensitive unique per client.

description
required
string non-empty

Plain-English description of the service code.

category
string <= 32 characters

Free-text grouping label (e.g. 'Diagnostic', 'Preventive', 'Restorative').

default_fee
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Suggested UCR fee. Practices may override on import; NULL means no suggestion.

Responses

Request samples

Content type
{
  • "code": "string",
  • "description": "string",
  • "category": "string",
  • "default_fee": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "code": "string",
  • "description": "string",
  • "category": "string",
  • "default_fee": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Retrieve a client service code.

GET/PATCH/PUT/DELETE /api/v1/client/<client_uid>/service-codes/<code_id>/.

Object-level IDOR safety: the queryset is filtered to the resolved client, so a valid UUID for a different client's code returns 404 rather than 403.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
code_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "code": "string",
  • "description": "string",
  • "category": "string",
  • "default_fee": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Replace a client service code.

Full-replace update. OWNER role required.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
code_id
required
string <uuid>
Request Body schema:
required
code
required
string [ 1 .. 16 ] characters

CDT / service code identifier, e.g. D0150. Case-insensitive unique per client.

description
required
string non-empty

Plain-English description of the service code.

category
string <= 32 characters

Free-text grouping label (e.g. 'Diagnostic', 'Preventive', 'Restorative').

default_fee
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Suggested UCR fee. Practices may override on import; NULL means no suggestion.

Responses

Request samples

Content type
{
  • "code": "string",
  • "description": "string",
  • "category": "string",
  • "default_fee": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "code": "string",
  • "description": "string",
  • "category": "string",
  • "default_fee": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Partially update a client service code.

Update one or more fields. OWNER role required.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
code_id
required
string <uuid>
Request Body schema:
code
string [ 1 .. 16 ] characters

CDT / service code identifier, e.g. D0150. Case-insensitive unique per client.

description
string non-empty

Plain-English description of the service code.

category
string <= 32 characters

Free-text grouping label (e.g. 'Diagnostic', 'Preventive', 'Restorative').

default_fee
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Suggested UCR fee. Practices may override on import; NULL means no suggestion.

Responses

Request samples

Content type
{
  • "code": "string",
  • "description": "string",
  • "category": "string",
  • "default_fee": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "code": "string",
  • "description": "string",
  • "category": "string",
  • "default_fee": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Delete a client service code.

Removes the code from the client's curated list. OWNER role required.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
code_id
required
string <uuid>

Responses

Copy global service codes into the client's list.

Materialises a subset (or the entire) global service-code library into the URL's Client's :class:~apps.clinical.models.ClientServiceCode table. Existing rows (matched case-insensitively on code) are skipped, never overwritten -- once a client owns a row, its fee and description are the client's to edit freely.

Idempotent: re-running with the same input is safe. Returns {copied, skipped, errors} counters so the onboarding UI can render a useful summary.

code_ids accepts a list of UUIDs or the literal string "all" for "everything in the library".

OWNER role required.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
Request Body schema:
required
code_ids
required
any

List of GlobalServiceCode UUIDs to copy, or the literal string "all" to copy everything.

Responses

Request samples

Content type
{
  • "code_ids": null
}

Response samples

Content type
application/json
{
  • "copied": 0,
  • "skipped": 0,
  • "errors": [
    ]
}

Enable service-code enforcement and trigger propagation.

Sets Client.enforce_service_codes = True and queues a Celery task that upserts the Client's service-code list into every practice as locked :class:~apps.clinical.models.ProcedureCode rows. Idempotent: calling this when enforcement is already active re-queues the propagation task (useful after bulk-editing the client list). OWNER role required.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "enforce_service_codes": true,
  • "task_queued": true
}

Client Website Registration

List registered websites for a Client.

Returns all website registrations for the URL's Client, including verification status and DNS TXT record values. Any authenticated user with access to the Client may read.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{}

Register a new website/domain for a Client.

Creates a new ClientWebsite row. The domain must be unique across all Clients. The dns_txt_record_value in the response is the exact TXT record value the Client must publish to verify domain ownership. OWNER role required.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
Request Body schema:
required
domain
required
string [ 1 .. 253 ] characters

Registered domain (lower-cased, no scheme, no trailing slash). Examples: acme-dental.com, www.acme.com, booking.acme.com.

is_active
boolean

Soft-delete. Inactive domains are ignored by the resolver.

Responses

Request samples

Content type
{
  • "domain": "string",
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "domain": "string",
  • "verified": true,
  • "verified_at": "2019-08-24T14:15:22Z",
  • "dns_txt_record_value": "string",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Retrieve a registered website.

GET/PATCH/PUT/DELETE /api/v1/client/<client_uid>/websites/<website_id>/.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
website_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "domain": "string",
  • "verified": true,
  • "verified_at": "2019-08-24T14:15:22Z",
  • "dns_txt_record_value": "string",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Replace a registered website.

Full-replace update. OWNER role required.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
website_id
required
string <uuid>
Request Body schema:
required
domain
required
string [ 1 .. 253 ] characters

Registered domain (lower-cased, no scheme, no trailing slash). Examples: acme-dental.com, www.acme.com, booking.acme.com.

is_active
boolean

Soft-delete. Inactive domains are ignored by the resolver.

Responses

Request samples

Content type
{
  • "domain": "string",
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "domain": "string",
  • "verified": true,
  • "verified_at": "2019-08-24T14:15:22Z",
  • "dns_txt_record_value": "string",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Partially update a registered website.

Only is_active may be changed after creation. OWNER role required.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
website_id
required
string <uuid>
Request Body schema:
domain
string [ 1 .. 253 ] characters

Registered domain (lower-cased, no scheme, no trailing slash). Examples: acme-dental.com, www.acme.com, booking.acme.com.

is_active
boolean

Soft-delete. Inactive domains are ignored by the resolver.

Responses

Request samples

Content type
{
  • "domain": "string",
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "domain": "string",
  • "verified": true,
  • "verified_at": "2019-08-24T14:15:22Z",
  • "dns_txt_record_value": "string",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Delete a registered website.

Deletes the registration and all associated routes. OWNER role required. Consider setting is_active=false instead if you may want to re-verify later.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
website_id
required
string <uuid>

Responses

Verify domain ownership via DNS TXT record.

Checks the domain's DNS TXT records for escape-site-verify=<token>. On success, marks the registration as verified so the public booking resolver will route traffic from this domain. Idempotent for already-verified domains. OWNER role required.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
website_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "verified": true,
  • "domain": "string",
  • "detail": "string"
}

Client Website Routes

List routes for a registered website.

GET/POST /api/v1/client/<client_uid>/websites/<website_id>/routes/.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
website_id
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{}

Add a path-prefix → practice route.

Maps a URL path prefix on the registered website to a specific practice. The practice must belong to the same Client as the website. Path prefixes are deduplicated per website. OWNER role required.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
website_id
required
string <uuid>
Request Body schema:
required
path_prefix
required
string [ 1 .. 500 ] characters

URL path prefix that triggers this route. Must start and end with '/'. E.g. '/north/', '/downtown/', '/'. Matched longest-prefix first.

practice_id
required
string <uuid>

UUID of the Practice this path prefix should route to.

Responses

Request samples

Content type
{
  • "path_prefix": "string",
  • "practice_id": "ab8b92c6-fdd4-4c27-ab69-c61896d976bd"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "path_prefix": "string",
  • "practice_id": "ab8b92c6-fdd4-4c27-ab69-c61896d976bd",
  • "practice_name": "string",
  • "practice_booking_slug": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Retrieve a website route.

GET/PATCH/PUT/DELETE /api/v1/client/<client_uid>/websites/<website_id>/routes/<route_id>/.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
route_id
required
string <uuid>
website_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "path_prefix": "string",
  • "practice_id": "ab8b92c6-fdd4-4c27-ab69-c61896d976bd",
  • "practice_name": "string",
  • "practice_booking_slug": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Replace a website route. OWNER role required.

GET/PATCH/PUT/DELETE /api/v1/client/<client_uid>/websites/<website_id>/routes/<route_id>/.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
route_id
required
string <uuid>
website_id
required
string <uuid>
Request Body schema:
required
path_prefix
required
string [ 1 .. 500 ] characters

URL path prefix that triggers this route. Must start and end with '/'. E.g. '/north/', '/downtown/', '/'. Matched longest-prefix first.

practice_id
required
string <uuid>

UUID of the Practice this path prefix should route to.

Responses

Request samples

Content type
{
  • "path_prefix": "string",
  • "practice_id": "ab8b92c6-fdd4-4c27-ab69-c61896d976bd"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "path_prefix": "string",
  • "practice_id": "ab8b92c6-fdd4-4c27-ab69-c61896d976bd",
  • "practice_name": "string",
  • "practice_booking_slug": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Partially update a website route.

Update path prefix or target practice. OWNER role required.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
route_id
required
string <uuid>
website_id
required
string <uuid>
Request Body schema:
path_prefix
string [ 1 .. 500 ] characters

URL path prefix that triggers this route. Must start and end with '/'. E.g. '/north/', '/downtown/', '/'. Matched longest-prefix first.

practice_id
string <uuid>

UUID of the Practice this path prefix should route to.

Responses

Request samples

Content type
{
  • "path_prefix": "string",
  • "practice_id": "ab8b92c6-fdd4-4c27-ab69-c61896d976bd"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "path_prefix": "string",
  • "practice_id": "ab8b92c6-fdd4-4c27-ab69-c61896d976bd",
  • "practice_name": "string",
  • "practice_booking_slug": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Delete a website route. OWNER role required.

GET/PATCH/PUT/DELETE /api/v1/client/<client_uid>/websites/<website_id>/routes/<route_id>/.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
route_id
required
string <uuid>
website_id
required
string <uuid>

Responses

Compliance

Download the executed BAA PDF.

Returns an HTTP 302 redirect to a short-lived signed URL for the most recent BAAExecution PDF. Available to any authenticated user with access to the Client; the OWNER gate is the WRITE-side enforcement and downloads are intentionally broader so non-OWNER staff can produce the document for compliance reviews.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>

Responses

Execute the BAA (OWNER only).

Captures the Client OWNER's signature, auto-stamps the Escape Dental countersignature from the configured singleton, renders the executed PDF onto object storage, and flips Client.baa_signed to True so converter writes are unblocked. Returns the new BAAExecution row with a presigned URL for the executed PDF.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
Request Body schema:
required
signature_image_base64
required
string non-empty

Rendered signature PNG from the pad widget, base64-encoded (without the data: URI prefix).

typed_name
required
string [ 1 .. 255 ] characters

Full name the OWNER typed alongside the signature pad.

Responses

Request samples

Content type
{
  • "signature_image_base64": "string",
  • "typed_name": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "template_version": "598f3bca-4191-44bf-99c4-1e544f9e0e52",
  • "template_version_str": "string",
  • "client_signed_name_typed": "string",
  • "signed_at": "2019-08-24T14:15:22Z",
  • "countersigned_at": "2019-08-24T14:15:22Z",
  • "executed_pdf_url": "string",
  • "requesting_ip": "string",
  • "signing_user": "c1b1476a-3b94-4527-a075-f7e6c0844938",
  • "signing_user_email": "user@example.com",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Fetch the active BAA template for review.

Returns the active :class:BAATemplateVersion with its full Markdown body plus a flag indicating whether the Client has already executed a BAA. Any authenticated user with access to the Client may read the template (so non-OWNER staff members can review the document before asking an owner to sign); the sign endpoint enforces the OWNER role separately.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "version": "string",
  • "body_markdown": "string",
  • "active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "already_signed": true,
  • "current_execution_id": "17a764a2-4898-4251-bc8d-26aeb226c316"
}

Recall

clients_reactivation_sequences_list

Client-scoped CRUD for :class:ReactivationSequence (api#838).

Same access shape as :class:RecallProtocolViewSet: reads are open to any authenticated user with Client access, writes require the OWNER role. Reactivation sequences encode multi-practice outreach policy (and downstream financial exposure on the messaging provider bill); restricting writes to OWNER keeps a single FRONT_DESK account from setting policy that affects siblings.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{}

clients_reactivation_sequences_create

Client-scoped CRUD for :class:ReactivationSequence (api#838).

Same access shape as :class:RecallProtocolViewSet: reads are open to any authenticated user with Client access, writes require the OWNER role. Reactivation sequences encode multi-practice outreach policy (and downstream financial exposure on the messaging provider bill); restricting writes to OWNER keeps a single FRONT_DESK account from setting policy that affects siblings.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 120 ] characters

Human-readable name shown to staff (e.g. '12-month reactivation').

trigger_overdue_days
integer [ 0 .. 2147483647 ]

How long a :class:PatientRecall must have been overdue (i.e. days since next_due_date) before step 0 fires. Aaron's spec uses 365 (12 months) as the canonical default.

steps
any

Ordered list of touchpoint dicts. Each step is a {"channel": "email"|"sms", "offset_days": int, "template_id": str | null} triple. Step 0 fires when the patient is first picked up; subsequent steps fire offset_days days after the previous attempt.

is_active
boolean

Disable the sequence without deleting it (preserves the attempt history). An inactive sequence will not pick up new patients but will not abandon patients mid-flight either; in-flight attempts continue until the final step drops them, then no new sweeps will pick them up again.

Responses

Request samples

Content type
{
  • "name": "string",
  • "trigger_overdue_days": 2147483647,
  • "steps": null,
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "trigger_overdue_days": 2147483647,
  • "steps": null,
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

clients_reactivation_sequences_retrieve

Client-scoped CRUD for :class:ReactivationSequence (api#838).

Same access shape as :class:RecallProtocolViewSet: reads are open to any authenticated user with Client access, writes require the OWNER role. Reactivation sequences encode multi-practice outreach policy (and downstream financial exposure on the messaging provider bill); restricting writes to OWNER keeps a single FRONT_DESK account from setting policy that affects siblings.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
sequence_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "trigger_overdue_days": 2147483647,
  • "steps": null,
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

clients_reactivation_sequences_update

Client-scoped CRUD for :class:ReactivationSequence (api#838).

Same access shape as :class:RecallProtocolViewSet: reads are open to any authenticated user with Client access, writes require the OWNER role. Reactivation sequences encode multi-practice outreach policy (and downstream financial exposure on the messaging provider bill); restricting writes to OWNER keeps a single FRONT_DESK account from setting policy that affects siblings.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
sequence_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 120 ] characters

Human-readable name shown to staff (e.g. '12-month reactivation').

trigger_overdue_days
integer [ 0 .. 2147483647 ]

How long a :class:PatientRecall must have been overdue (i.e. days since next_due_date) before step 0 fires. Aaron's spec uses 365 (12 months) as the canonical default.

steps
any

Ordered list of touchpoint dicts. Each step is a {"channel": "email"|"sms", "offset_days": int, "template_id": str | null} triple. Step 0 fires when the patient is first picked up; subsequent steps fire offset_days days after the previous attempt.

is_active
boolean

Disable the sequence without deleting it (preserves the attempt history). An inactive sequence will not pick up new patients but will not abandon patients mid-flight either; in-flight attempts continue until the final step drops them, then no new sweeps will pick them up again.

Responses

Request samples

Content type
{
  • "name": "string",
  • "trigger_overdue_days": 2147483647,
  • "steps": null,
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "trigger_overdue_days": 2147483647,
  • "steps": null,
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

clients_reactivation_sequences_partial_update

Client-scoped CRUD for :class:ReactivationSequence (api#838).

Same access shape as :class:RecallProtocolViewSet: reads are open to any authenticated user with Client access, writes require the OWNER role. Reactivation sequences encode multi-practice outreach policy (and downstream financial exposure on the messaging provider bill); restricting writes to OWNER keeps a single FRONT_DESK account from setting policy that affects siblings.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
sequence_uid
required
string <uuid>
Request Body schema:
name
string [ 1 .. 120 ] characters

Human-readable name shown to staff (e.g. '12-month reactivation').

trigger_overdue_days
integer [ 0 .. 2147483647 ]

How long a :class:PatientRecall must have been overdue (i.e. days since next_due_date) before step 0 fires. Aaron's spec uses 365 (12 months) as the canonical default.

steps
any

Ordered list of touchpoint dicts. Each step is a {"channel": "email"|"sms", "offset_days": int, "template_id": str | null} triple. Step 0 fires when the patient is first picked up; subsequent steps fire offset_days days after the previous attempt.

is_active
boolean

Disable the sequence without deleting it (preserves the attempt history). An inactive sequence will not pick up new patients but will not abandon patients mid-flight either; in-flight attempts continue until the final step drops them, then no new sweeps will pick them up again.

Responses

Request samples

Content type
{
  • "name": "string",
  • "trigger_overdue_days": 2147483647,
  • "steps": null,
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "trigger_overdue_days": 2147483647,
  • "steps": null,
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

clients_reactivation_sequences_destroy

Client-scoped CRUD for :class:ReactivationSequence (api#838).

Same access shape as :class:RecallProtocolViewSet: reads are open to any authenticated user with Client access, writes require the OWNER role. Reactivation sequences encode multi-practice outreach policy (and downstream financial exposure on the messaging provider bill); restricting writes to OWNER keeps a single FRONT_DESK account from setting policy that affects siblings.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
sequence_uid
required
string <uuid>

Responses

clients_recall_protocols_list

Client-scoped full CRUD for :class:RecallProtocol.

Reads are open to any authenticated user with access to the Client; writes (create / update / destroy) require the OWNER role on the Client. The client FK is set server-side from the URL -- a request body that tries to override it is ignored by the serializer's read_only_fields.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{}

clients_recall_protocols_create

Client-scoped full CRUD for :class:RecallProtocol.

Reads are open to any authenticated user with access to the Client; writes (create / update / destroy) require the OWNER role on the Client. The client FK is set server-side from the URL -- a request body that tries to override it is ignored by the serializer's read_only_fields.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 120 ] characters

Human-readable name shown to staff (e.g. 'Standard 6-month recall').

recall_type
string
Enum: "prophy_6mo" "prophy_4mo" "perio_maintenance" "other"

Recall cadence; controls the interval used when bumping next_due_date.

  • prophy_6mo - Prophylaxis (6 months)
  • prophy_4mo - Prophylaxis (4 months)
  • perio_maintenance - Perio Maintenance (3 months)
  • other - Other
channels
string [ 1 .. 64 ] characters

Comma-separated outreach channels in preference order (e.g. 'email,sms'). Allowed values: email, sms.

timing_offsets_days
any

List of integer offsets (in days) relative to next_due_date; negative = before due, positive = after. Example: [-14, -7, -3, -1] for 14/7/3/1 days before due.

Responses

Request samples

Content type
{
  • "name": "string",
  • "recall_type": "prophy_6mo",
  • "channels": "string",
  • "timing_offsets_days": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "recall_type": "prophy_6mo",
  • "channels": "string",
  • "timing_offsets_days": null,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

clients_recall_protocols_retrieve

Client-scoped full CRUD for :class:RecallProtocol.

Reads are open to any authenticated user with access to the Client; writes (create / update / destroy) require the OWNER role on the Client. The client FK is set server-side from the URL -- a request body that tries to override it is ignored by the serializer's read_only_fields.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
protocol_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "recall_type": "prophy_6mo",
  • "channels": "string",
  • "timing_offsets_days": null,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

clients_recall_protocols_update

Client-scoped full CRUD for :class:RecallProtocol.

Reads are open to any authenticated user with access to the Client; writes (create / update / destroy) require the OWNER role on the Client. The client FK is set server-side from the URL -- a request body that tries to override it is ignored by the serializer's read_only_fields.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
protocol_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 120 ] characters

Human-readable name shown to staff (e.g. 'Standard 6-month recall').

recall_type
string
Enum: "prophy_6mo" "prophy_4mo" "perio_maintenance" "other"

Recall cadence; controls the interval used when bumping next_due_date.

  • prophy_6mo - Prophylaxis (6 months)
  • prophy_4mo - Prophylaxis (4 months)
  • perio_maintenance - Perio Maintenance (3 months)
  • other - Other
channels
string [ 1 .. 64 ] characters

Comma-separated outreach channels in preference order (e.g. 'email,sms'). Allowed values: email, sms.

timing_offsets_days
any

List of integer offsets (in days) relative to next_due_date; negative = before due, positive = after. Example: [-14, -7, -3, -1] for 14/7/3/1 days before due.

Responses

Request samples

Content type
{
  • "name": "string",
  • "recall_type": "prophy_6mo",
  • "channels": "string",
  • "timing_offsets_days": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "recall_type": "prophy_6mo",
  • "channels": "string",
  • "timing_offsets_days": null,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

clients_recall_protocols_partial_update

Client-scoped full CRUD for :class:RecallProtocol.

Reads are open to any authenticated user with access to the Client; writes (create / update / destroy) require the OWNER role on the Client. The client FK is set server-side from the URL -- a request body that tries to override it is ignored by the serializer's read_only_fields.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
protocol_uid
required
string <uuid>
Request Body schema:
name
string [ 1 .. 120 ] characters

Human-readable name shown to staff (e.g. 'Standard 6-month recall').

recall_type
string
Enum: "prophy_6mo" "prophy_4mo" "perio_maintenance" "other"

Recall cadence; controls the interval used when bumping next_due_date.

  • prophy_6mo - Prophylaxis (6 months)
  • prophy_4mo - Prophylaxis (4 months)
  • perio_maintenance - Perio Maintenance (3 months)
  • other - Other
channels
string [ 1 .. 64 ] characters

Comma-separated outreach channels in preference order (e.g. 'email,sms'). Allowed values: email, sms.

timing_offsets_days
any

List of integer offsets (in days) relative to next_due_date; negative = before due, positive = after. Example: [-14, -7, -3, -1] for 14/7/3/1 days before due.

Responses

Request samples

Content type
{
  • "name": "string",
  • "recall_type": "prophy_6mo",
  • "channels": "string",
  • "timing_offsets_days": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "recall_type": "prophy_6mo",
  • "channels": "string",
  • "timing_offsets_days": null,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

clients_recall_protocols_destroy

Client-scoped full CRUD for :class:RecallProtocol.

Reads are open to any authenticated user with access to the Client; writes (create / update / destroy) require the OWNER role on the Client. The client FK is set server-side from the URL -- a request body that tries to override it is ignored by the serializer's read_only_fields.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
protocol_uid
required
string <uuid>

Responses

practice_recall_patient_recalls_list

Practice-scoped CRUD on per-patient recall state rows.

The queryset is filtered to patient__practice=<practice from URL> so a UID-guess that lands on another tenant's row 404s. The serializer accepts the patient and protocol as FKs; the view validates the patient belongs to the URL-mounted practice and the protocol belongs to that practice's Client before saving.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_recall_patient_recalls_create

Practice-scoped CRUD on per-patient recall state rows.

The queryset is filtered to patient__practice=<practice from URL> so a UID-guess that lands on another tenant's row 404s. The serializer accepts the patient and protocol as FKs; the view validates the patient belongs to the URL-mounted practice and the protocol belongs to that practice's Client before saving.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>
protocol
required
string <uuid>

Protected so you cannot orphan patient state by deleting a protocol with active enrolments. Drop the patient first, then the protocol.

next_due_date
required
string <date>

The date the patient is next due for this recall.

last_completed_date
string or null <date>

The most recent completed visit date that satisfied this recall.

last_contact_attempt_at
string or null <date-time>

Timestamp of the most recent outreach attempt recorded by staff (e.g. the 'No answer' outcome button on the recall outreach list). Distinct from last_completed_date which tracks the actual completed hygiene visit; this field lets the next outreach sweep de-prioritize rows we already tried to reach so the queue does not churn on the same patient repeatedly within the same day.

status
string (PatientRecallStatusEnum)
Enum: "active" "overdue" "dropped"
  • active - Active
  • overdue - Overdue
  • dropped - Dropped

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "protocol": "d65b4798-1950-44c0-b67e-95ece94e3247",
  • "next_due_date": "2019-08-24",
  • "last_completed_date": "2019-08-24",
  • "last_contact_attempt_at": "2019-08-24T14:15:22Z",
  • "status": "active"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "protocol": "d65b4798-1950-44c0-b67e-95ece94e3247",
  • "protocol_name": "string",
  • "protocol_recall_type": "string",
  • "next_due_date": "2019-08-24",
  • "last_completed_date": "2019-08-24",
  • "last_contact_attempt_at": "2019-08-24T14:15:22Z",
  • "status": "active",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_recall_patient_recalls_retrieve

Practice-scoped CRUD on per-patient recall state rows.

The queryset is filtered to patient__practice=<practice from URL> so a UID-guess that lands on another tenant's row 404s. The serializer accepts the patient and protocol as FKs; the view validates the patient belongs to the URL-mounted practice and the protocol belongs to that practice's Client before saving.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_recall_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "protocol": "d65b4798-1950-44c0-b67e-95ece94e3247",
  • "protocol_name": "string",
  • "protocol_recall_type": "string",
  • "next_due_date": "2019-08-24",
  • "last_completed_date": "2019-08-24",
  • "last_contact_attempt_at": "2019-08-24T14:15:22Z",
  • "status": "active",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_recall_patient_recalls_update

Practice-scoped CRUD on per-patient recall state rows.

The queryset is filtered to patient__practice=<practice from URL> so a UID-guess that lands on another tenant's row 404s. The serializer accepts the patient and protocol as FKs; the view validates the patient belongs to the URL-mounted practice and the protocol belongs to that practice's Client before saving.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_recall_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>
protocol
required
string <uuid>

Protected so you cannot orphan patient state by deleting a protocol with active enrolments. Drop the patient first, then the protocol.

next_due_date
required
string <date>

The date the patient is next due for this recall.

last_completed_date
string or null <date>

The most recent completed visit date that satisfied this recall.

last_contact_attempt_at
string or null <date-time>

Timestamp of the most recent outreach attempt recorded by staff (e.g. the 'No answer' outcome button on the recall outreach list). Distinct from last_completed_date which tracks the actual completed hygiene visit; this field lets the next outreach sweep de-prioritize rows we already tried to reach so the queue does not churn on the same patient repeatedly within the same day.

status
string (PatientRecallStatusEnum)
Enum: "active" "overdue" "dropped"
  • active - Active
  • overdue - Overdue
  • dropped - Dropped

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "protocol": "d65b4798-1950-44c0-b67e-95ece94e3247",
  • "next_due_date": "2019-08-24",
  • "last_completed_date": "2019-08-24",
  • "last_contact_attempt_at": "2019-08-24T14:15:22Z",
  • "status": "active"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "protocol": "d65b4798-1950-44c0-b67e-95ece94e3247",
  • "protocol_name": "string",
  • "protocol_recall_type": "string",
  • "next_due_date": "2019-08-24",
  • "last_completed_date": "2019-08-24",
  • "last_contact_attempt_at": "2019-08-24T14:15:22Z",
  • "status": "active",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_recall_patient_recalls_partial_update

Practice-scoped CRUD on per-patient recall state rows.

The queryset is filtered to patient__practice=<practice from URL> so a UID-guess that lands on another tenant's row 404s. The serializer accepts the patient and protocol as FKs; the view validates the patient belongs to the URL-mounted practice and the protocol belongs to that practice's Client before saving.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_recall_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
patient
string <uuid>
protocol
string <uuid>

Protected so you cannot orphan patient state by deleting a protocol with active enrolments. Drop the patient first, then the protocol.

next_due_date
string <date>

The date the patient is next due for this recall.

last_completed_date
string or null <date>

The most recent completed visit date that satisfied this recall.

last_contact_attempt_at
string or null <date-time>

Timestamp of the most recent outreach attempt recorded by staff (e.g. the 'No answer' outcome button on the recall outreach list). Distinct from last_completed_date which tracks the actual completed hygiene visit; this field lets the next outreach sweep de-prioritize rows we already tried to reach so the queue does not churn on the same patient repeatedly within the same day.

status
string (PatientRecallStatusEnum)
Enum: "active" "overdue" "dropped"
  • active - Active
  • overdue - Overdue
  • dropped - Dropped

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "protocol": "d65b4798-1950-44c0-b67e-95ece94e3247",
  • "next_due_date": "2019-08-24",
  • "last_completed_date": "2019-08-24",
  • "last_contact_attempt_at": "2019-08-24T14:15:22Z",
  • "status": "active"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "protocol": "d65b4798-1950-44c0-b67e-95ece94e3247",
  • "protocol_name": "string",
  • "protocol_recall_type": "string",
  • "next_due_date": "2019-08-24",
  • "last_completed_date": "2019-08-24",
  • "last_contact_attempt_at": "2019-08-24T14:15:22Z",
  • "status": "active",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_recall_patient_recalls_destroy

Practice-scoped CRUD on per-patient recall state rows.

The queryset is filtered to patient__practice=<practice from URL> so a UID-guess that lands on another tenant's row 404s. The serializer accepts the patient and protocol as FKs; the view validates the patient belongs to the URL-mounted practice and the protocol belongs to that practice's Client before saving.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_recall_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_recall_patient_recalls_record_attempt_create

Stamp last_contact_attempt_at to timezone.now() (api#850).

Used by the recall outreach UI's "No answer" outcome button so the next outreach sweep can de-prioritize already-attempted rows. Idempotent -- every call sets the field to the current UTC instant; calling twice in a row simply records the latest attempt time. An audit event is emitted so the contact cadence per patient is reconstructible from the audit trail independently of the in-row column.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_recall_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>
protocol
required
string <uuid>

Protected so you cannot orphan patient state by deleting a protocol with active enrolments. Drop the patient first, then the protocol.

next_due_date
required
string <date>

The date the patient is next due for this recall.

last_completed_date
string or null <date>

The most recent completed visit date that satisfied this recall.

last_contact_attempt_at
string or null <date-time>

Timestamp of the most recent outreach attempt recorded by staff (e.g. the 'No answer' outcome button on the recall outreach list). Distinct from last_completed_date which tracks the actual completed hygiene visit; this field lets the next outreach sweep de-prioritize rows we already tried to reach so the queue does not churn on the same patient repeatedly within the same day.

status
string (PatientRecallStatusEnum)
Enum: "active" "overdue" "dropped"
  • active - Active
  • overdue - Overdue
  • dropped - Dropped

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "protocol": "d65b4798-1950-44c0-b67e-95ece94e3247",
  • "next_due_date": "2019-08-24",
  • "last_completed_date": "2019-08-24",
  • "last_contact_attempt_at": "2019-08-24T14:15:22Z",
  • "status": "active"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "protocol": "d65b4798-1950-44c0-b67e-95ece94e3247",
  • "protocol_name": "string",
  • "protocol_recall_type": "string",
  • "next_due_date": "2019-08-24",
  • "last_completed_date": "2019-08-24",
  • "last_contact_attempt_at": "2019-08-24T14:15:22Z",
  • "status": "active",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_recall_protocols_list

Read the recall protocols inherited from the Practice's Client.

Mounted at /api/v1/practice/<practice_uid>/recall/protocols/. The web app uses this to render the policy on the practice's dashboard without needing to know the Client UID; the Client-level CRUD endpoint is the authoring surface.

Returns an empty list when the Practice has no Client (legacy rows pre-Client) rather than 404, so the UI degrades gracefully.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{}

practice_recall_reactivation_attempts_list

Practice-scoped read-only view onto :class:ReactivationAttempt rows.

Attempt rows are authored by the Celery sweep, not by API callers, so this viewset is intentionally list + retrieve only. Mounted at /api/v1/practice/<practice_uid>/recall/reactivation-attempts/; supports ?patient=<uuid> for the per-patient outreach history panel.

Cross-tenant safety: the queryset filters on patient_recall__patient__practice so a UID-guess that lands on another tenant's row 404s before serialization.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_recall_reactivation_attempts_retrieve

Practice-scoped read-only view onto :class:ReactivationAttempt rows.

Attempt rows are authored by the Celery sweep, not by API callers, so this viewset is intentionally list + retrieve only. Mounted at /api/v1/practice/<practice_uid>/recall/reactivation-attempts/; supports ?patient=<uuid> for the per-patient outreach history panel.

Cross-tenant safety: the queryset filters on patient_recall__patient__practice so a UID-guess that lands on another tenant's row 404s before serialization.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
attempt_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient_recall": "b3938d2e-cd17-40d0-b3e3-a3974325f5d9",
  • "sequence": "02d7e86a-44ba-4ff5-9ec4-96b49020b598",
  • "sequence_name": "string",
  • "step_index": 0,
  • "channel": "email",
  • "sent_at": "2019-08-24T14:15:22Z",
  • "outcome": "sent",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_recall_template_list

Practice-scoped CRUD for :class:ReactivationTemplate (api#867).

Mounted at /api/v1/practice/<uid>/recall/template/ per the ticket spec; the practice URL drives access enforcement, but the rows themselves live at the Client level so a DSO with multiple practices authors a single set and every practice under the Client sees the same library. The queryset is filtered to the practice's Client (read shares across siblings; write requires OWNER on the Client, same gate :class:ReactivationSequenceViewSet uses).

Render preview

POST /<id>/render/ accepts {"patient_id": "<uuid>"} and returns the rendered subject + body for the staff preview UI. The patient must belong to the URL-mounted practice -- a cross-tenant UID 404s before render so a UID-guess attack cannot use the preview endpoint as an exfiltration channel for another tenant's patient names.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_recall_template_create

Practice-scoped CRUD for :class:ReactivationTemplate (api#867).

Mounted at /api/v1/practice/<uid>/recall/template/ per the ticket spec; the practice URL drives access enforcement, but the rows themselves live at the Client level so a DSO with multiple practices authors a single set and every practice under the Client sees the same library. The queryset is filtered to the practice's Client (read shares across siblings; write requires OWNER on the Client, same gate :class:ReactivationSequenceViewSet uses).

Render preview

POST /<id>/render/ accepts {"patient_id": "<uuid>"} and returns the rendered subject + body for the staff preview UI. The patient must belong to the URL-mounted practice -- a cross-tenant UID 404s before render so a UID-guess attack cannot use the preview endpoint as an exfiltration channel for another tenant's patient names.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 120 ] characters

Human-readable name shown to staff and used as the step reference (e.g. 'Reactivation step 0 - email').

channel
required
string
Enum: "email" "sms"

Which delivery channel this template targets. Email templates require a non-blank subject; SMS templates ignore subject and body_html.

  • email - Email
  • sms - SMS
subject
string <= 255 characters

Email subject line (Django template syntax allowed). Required for channel='email'; ignored for SMS.

body_text
required
string non-empty

Plain-text body. For SMS this is the message body sent verbatim (subject to the 160-char SMS limit -- the sender fragments longer messages). For email this is the text/plain part of the multipart/alternative payload.

body_html
string

Optional HTML body for email templates (text/html part of the multipart payload). Ignored for SMS; leave blank when you want a plain-text-only email.

variables_doc
string

Markdown documentation shown to the staff member editing the template -- lists the variables they can use (e.g. {{ patient.first_name }}). Free-form; does not affect rendering, just helps the author.

Responses

Request samples

Content type
{
  • "name": "string",
  • "channel": "email",
  • "subject": "string",
  • "body_text": "string",
  • "body_html": "string",
  • "variables_doc": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "channel": "email",
  • "subject": "string",
  • "body_text": "string",
  • "body_html": "string",
  • "variables_doc": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_recall_template_retrieve

Practice-scoped CRUD for :class:ReactivationTemplate (api#867).

Mounted at /api/v1/practice/<uid>/recall/template/ per the ticket spec; the practice URL drives access enforcement, but the rows themselves live at the Client level so a DSO with multiple practices authors a single set and every practice under the Client sees the same library. The queryset is filtered to the practice's Client (read shares across siblings; write requires OWNER on the Client, same gate :class:ReactivationSequenceViewSet uses).

Render preview

POST /<id>/render/ accepts {"patient_id": "<uuid>"} and returns the rendered subject + body for the staff preview UI. The patient must belong to the URL-mounted practice -- a cross-tenant UID 404s before render so a UID-guess attack cannot use the preview endpoint as an exfiltration channel for another tenant's patient names.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "channel": "email",
  • "subject": "string",
  • "body_text": "string",
  • "body_html": "string",
  • "variables_doc": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_recall_template_update

Practice-scoped CRUD for :class:ReactivationTemplate (api#867).

Mounted at /api/v1/practice/<uid>/recall/template/ per the ticket spec; the practice URL drives access enforcement, but the rows themselves live at the Client level so a DSO with multiple practices authors a single set and every practice under the Client sees the same library. The queryset is filtered to the practice's Client (read shares across siblings; write requires OWNER on the Client, same gate :class:ReactivationSequenceViewSet uses).

Render preview

POST /<id>/render/ accepts {"patient_id": "<uuid>"} and returns the rendered subject + body for the staff preview UI. The patient must belong to the URL-mounted practice -- a cross-tenant UID 404s before render so a UID-guess attack cannot use the preview endpoint as an exfiltration channel for another tenant's patient names.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 120 ] characters

Human-readable name shown to staff and used as the step reference (e.g. 'Reactivation step 0 - email').

channel
required
string
Enum: "email" "sms"

Which delivery channel this template targets. Email templates require a non-blank subject; SMS templates ignore subject and body_html.

  • email - Email
  • sms - SMS
subject
string <= 255 characters

Email subject line (Django template syntax allowed). Required for channel='email'; ignored for SMS.

body_text
required
string non-empty

Plain-text body. For SMS this is the message body sent verbatim (subject to the 160-char SMS limit -- the sender fragments longer messages). For email this is the text/plain part of the multipart/alternative payload.

body_html
string

Optional HTML body for email templates (text/html part of the multipart payload). Ignored for SMS; leave blank when you want a plain-text-only email.

variables_doc
string

Markdown documentation shown to the staff member editing the template -- lists the variables they can use (e.g. {{ patient.first_name }}). Free-form; does not affect rendering, just helps the author.

Responses

Request samples

Content type
{
  • "name": "string",
  • "channel": "email",
  • "subject": "string",
  • "body_text": "string",
  • "body_html": "string",
  • "variables_doc": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "channel": "email",
  • "subject": "string",
  • "body_text": "string",
  • "body_html": "string",
  • "variables_doc": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_recall_template_partial_update

Practice-scoped CRUD for :class:ReactivationTemplate (api#867).

Mounted at /api/v1/practice/<uid>/recall/template/ per the ticket spec; the practice URL drives access enforcement, but the rows themselves live at the Client level so a DSO with multiple practices authors a single set and every practice under the Client sees the same library. The queryset is filtered to the practice's Client (read shares across siblings; write requires OWNER on the Client, same gate :class:ReactivationSequenceViewSet uses).

Render preview

POST /<id>/render/ accepts {"patient_id": "<uuid>"} and returns the rendered subject + body for the staff preview UI. The patient must belong to the URL-mounted practice -- a cross-tenant UID 404s before render so a UID-guess attack cannot use the preview endpoint as an exfiltration channel for another tenant's patient names.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_uid
required
string <uuid>
Request Body schema:
name
string [ 1 .. 120 ] characters

Human-readable name shown to staff and used as the step reference (e.g. 'Reactivation step 0 - email').

channel
string
Enum: "email" "sms"

Which delivery channel this template targets. Email templates require a non-blank subject; SMS templates ignore subject and body_html.

  • email - Email
  • sms - SMS
subject
string <= 255 characters

Email subject line (Django template syntax allowed). Required for channel='email'; ignored for SMS.

body_text
string non-empty

Plain-text body. For SMS this is the message body sent verbatim (subject to the 160-char SMS limit -- the sender fragments longer messages). For email this is the text/plain part of the multipart/alternative payload.

body_html
string

Optional HTML body for email templates (text/html part of the multipart payload). Ignored for SMS; leave blank when you want a plain-text-only email.

variables_doc
string

Markdown documentation shown to the staff member editing the template -- lists the variables they can use (e.g. {{ patient.first_name }}). Free-form; does not affect rendering, just helps the author.

Responses

Request samples

Content type
{
  • "name": "string",
  • "channel": "email",
  • "subject": "string",
  • "body_text": "string",
  • "body_html": "string",
  • "variables_doc": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "channel": "email",
  • "subject": "string",
  • "body_text": "string",
  • "body_html": "string",
  • "variables_doc": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_recall_template_destroy

Practice-scoped CRUD for :class:ReactivationTemplate (api#867).

Mounted at /api/v1/practice/<uid>/recall/template/ per the ticket spec; the practice URL drives access enforcement, but the rows themselves live at the Client level so a DSO with multiple practices authors a single set and every practice under the Client sees the same library. The queryset is filtered to the practice's Client (read shares across siblings; write requires OWNER on the Client, same gate :class:ReactivationSequenceViewSet uses).

Render preview

POST /<id>/render/ accepts {"patient_id": "<uuid>"} and returns the rendered subject + body for the staff preview UI. The patient must belong to the URL-mounted practice -- a cross-tenant UID 404s before render so a UID-guess attack cannot use the preview endpoint as an exfiltration channel for another tenant's patient names.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_recall_template_render_create

Render the template against a patient + return the result.

Body: {"patient_id": "<uuid>"}. The patient must belong to the URL-mounted practice (cross-tenant 404s). Returns::

{
    "subject": "...",   # blank for SMS
    "body_text": "...",
    "body_html": "...", # blank for SMS / plain-text emails
    "channel": "email" | "sms",
}

Pure preview -- no message is sent, no attempt row is created. Used by the staff template editor's live-preview pane.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_uid
required
string <uuid>
Request Body schema:
required
patient_id
required
string <uuid>

UUID of the patient to render the template against.

Responses

Request samples

Content type
{
  • "patient_id": "3854866a-5476-48be-8313-77029ccdd7a7"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "channel": "email",
  • "subject": "string",
  • "body_text": "string",
  • "body_html": "string",
  • "variables_doc": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

DSO Reports

clients_reports_adjustments_retrieve

Per-practice adjustments breakdown by adj_type.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
query Parameters
end_date
string <date>

Inclusive end date (YYYY-MM-DD). Defaults to today.

start_date
string <date>

Inclusive start date (YYYY-MM-DD). Defaults to 30 days before end_date.

Responses

Response samples

Content type
application/json
{
  • "date_from": "string",
  • "date_to": "string",
  • "grand_total": "string",
  • "practices": [
    ]
}

clients_reports_ar_aging_retrieve

Four-bucket AR aging totals + per-practice breakdown.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
query Parameters
as_of
string <date>

Reference date for point-in-time aggregates (YYYY-MM-DD). Defaults to today.

Responses

Response samples

Content type
application/json
{
  • "as_of": "string",
  • "totals": {
    },
  • "practices": [
    ]
}

clients_reports_case_acceptance_retrieve

Per-practice case-acceptance rate with cross-practice rollup.

api#506 adds two pieces on top of the original contract:

  • Per-practice same_visit_accepted_pct and delayed_accepted_pct -- both expressed as a percentage of the presented amount so a stacked bar can read them directly.
  • ?procedure_category= -- comma-separated set of :class:apps.clinical.models.ServiceType codes (e.g. major,endodontics) that narrows the queryset to plan items whose linked :class:ProcedureCode.service_type is in the set. Items with no linked code are excluded once a filter is supplied.
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
query Parameters
end_date
string <date>

Inclusive end date (YYYY-MM-DD). Defaults to today.

procedure_category
string

Comma-separated list of ServiceType codes (diagnostic, preventive, basic, major, endodontics, periodontics, oral_surgery, orthodontics, prosthodontics, adjunctive, other). Narrows the queryset to plan items whose linked ProcedureCode.service_type falls in the supplied set.

start_date
string <date>

Inclusive start date (YYYY-MM-DD). Defaults to 30 days before end_date.

Responses

Response samples

Content type
application/json
{
  • "date_from": "string",
  • "date_to": "string",
  • "totals": {
    },
  • "practices": [
    ]
}

clients_reports_hygiene_recare_retrieve

Per-practice hygiene-recare compliance counts and rate.

api#507 adds two pieces:

  • avg_days_late_among_non_compliant per practice -- the mean number of days past date_due across the practice's overdue patients. Surfaces "narrowly missed" vs "long lost".
  • ?include_without_active_recare=true -- widens the denominator to include active patients with no recall row at all. Returned as a separate without_active_recare_count bucket so consumers can show "of every active patient, what fraction are actually on a recare track".
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
query Parameters
as_of
string <date>

Reference date for point-in-time aggregates (YYYY-MM-DD). Defaults to today.

include_without_active_recare
boolean

When true, widens the denominator to include active patients with no active recall row. These patients show up in a separate without_active_recare_count bucket and depress the compliance rate accordingly. Default false preserves the legacy denominator (active recall rows only).

Responses

Response samples

Content type
application/json
{
  • "as_of": "string",
  • "totals": {
    },
  • "practices": [
    ]
}

clients_reports_overview_retrieve

KPI tiles for the DSO landing page.

Returns four numbers per practice -- today's production, the trailing-week production, current AR total, and the 30-day no-show rate -- plus an org-wide totals block that sums the dollar values and computes a weighted no-show rate so the rollup tile isn't dominated by an outlier practice.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
query Parameters
as_of
string <date>

Reference date for point-in-time aggregates (YYYY-MM-DD). Defaults to today.

Responses

Response samples

Content type
application/json
{
  • "as_of": "string",
  • "totals": {
    },
  • "practices": [
    ]
}

clients_reports_payer_mix_retrieve

Per-practice payer mix derived from each patient's primary insurance.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "practices": [
    ]
}

clients_reports_production_by_provider_retrieve

Per-practice / per-provider production with production-per-hour.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
query Parameters
end_date
string <date>

Inclusive end date (YYYY-MM-DD). Defaults to today.

start_date
string <date>

Inclusive start date (YYYY-MM-DD). Defaults to 30 days before end_date.

Responses

Response samples

Content type
application/json
{
  • "date_from": "string",
  • "date_to": "string",
  • "practices": [
    ]
}

clients_reports_production_vs_collections_retrieve

Per-practice production / collections / adjustments table.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_uid
required
string <uuid>
query Parameters
end_date
string <date>

Inclusive end date (YYYY-MM-DD). Defaults to today.

start_date
string <date>

Inclusive start date (YYYY-MM-DD). Defaults to 30 days before end_date.

Responses

Response samples

Content type
application/json
{
  • "date_from": "string",
  • "date_to": "string",
  • "totals": {
    },
  • "practices": [
    ]
}

desktop

desktop_documents_sessions_retrieve

Get capture session status for crash recovery.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
session_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "status": "pending",
  • "workstation_name": "string",
  • "item_count": "string",
  • "created": "2019-08-24T14:15:22Z"
}

feedback

List feedback submissions (internal staff only).

Filters: ?status= (new / triaged / resolved), ?user= (submitter UUID), ?practice= (practice UUID), ?client= (client UUID), ?occurred_from= / ?occurred_to= (calendar-day range on created, UTC, inclusive of both endpoints, YYYY-MM-DD). Ordered by -created (newest first). Returns the compact list shape; open the detail view to read the full submission including the signed screenshot URL.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
client
string <uuid>

Filter by client UUID.

occurred_from
string <date>

Filter rows whose created timestamp (UTC) falls on or after this calendar date (YYYY-MM-DD). Invalid date format returns 400.

occurred_to
string <date>

Filter rows whose created timestamp (UTC) falls on or before this calendar date (YYYY-MM-DD); the endpoint is inclusive of the entire day. Invalid date format returns 400.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

practice
string <uuid>

Filter by practice UUID.

status
string

Filter by triage status: new / triaged / resolved.

user
string <uuid>

Filter by submitter user UUID.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

Submit in-app feedback (any authenticated staff user).

Accepts a feedback submission from the staff feedback widget. Body may be either application/json (no screenshot) or multipart/form-data (screenshot attached as the screenshot field). The submitting user is set server-side from request.user -- a client-supplied user value is ignored. The row is treated as PHI on the read side.

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
required
practice
string or null <uuid>

Practice context at submission time, when known.

title
required
string [ 1 .. 80 ] characters

One-line summary the submitter typed into the feedback widget.

details
required
string non-empty

Long-form description of the issue.

screenshot
string <binary>

Optional screenshot of the page the bug was observed on (private bucket).

url
string <= 2000 characters

Page URL the feedback was submitted from.

viewport
any

Browser viewport metadata (width / height / devicePixelRatio).

user_agent
string <= 1024 characters

User-Agent string at submission time.

js_errors
any

Recent JS console errors with timestamps (widget-owned shape).

Responses

Request samples

Content type
{
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "title": "string",
  • "details": "string",
  • "screenshot": "string",
  • "url": "string",
  • "viewport": null,
  • "user_agent": "string",
  • "js_errors": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "user": "76f62a58-5404-486d-9afc-07bded328704",
  • "submitter_email": "user@example.com",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "title": "string",
  • "details": "string",
  • "screenshot_url": "string",
  • "url": "string",
  • "viewport": null,
  • "user_agent": "string",
  • "js_errors": null,
  • "status": "new",
  • "triaged_by": "918c35b9-bedc-437d-84b5-ebe932e91c8b",
  • "triaged_by_email": "user@example.com",
  • "triaged_at": "2019-08-24T14:15:22Z",
  • "resolved_by": "d0d57369-b08b-4db8-8952-8cdeedd9aebc",
  • "resolved_by_email": "user@example.com",
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "resolution_note": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Read a single feedback submission (internal staff only).

Returns the full row, including a short-lived signed URL for the screenshot when one was attached. Every read fires a feedback.viewed audit event because the row may carry incidentally captured PHI.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
feedback_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "user": "76f62a58-5404-486d-9afc-07bded328704",
  • "submitter_email": "user@example.com",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "title": "string",
  • "details": "string",
  • "screenshot_url": "string",
  • "url": "string",
  • "viewport": null,
  • "user_agent": "string",
  • "js_errors": null,
  • "status": "new",
  • "triaged_by": "918c35b9-bedc-437d-84b5-ebe932e91c8b",
  • "triaged_by_email": "user@example.com",
  • "triaged_at": "2019-08-24T14:15:22Z",
  • "resolved_by": "d0d57369-b08b-4db8-8952-8cdeedd9aebc",
  • "resolved_by_email": "user@example.com",
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "resolution_note": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Transition a feedback row's status (internal staff only).

Valid target statuses: new / triaged / resolved. Side effects: moving out of new for the first time stamps triaged_by / triaged_at; moving to resolved stamps resolved_by / resolved_at; bouncing back to new or triaged clears the resolved-stamp pair so the field always reflects the current state.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
feedback_uid
required
string <uuid>
Request Body schema:
required
status
required
string (FeedbackStatusEnum)
Enum: "new" "triaged" "resolved"
  • new - New
  • triaged - Triaged
  • resolved - Resolved
resolution_note
string
Default: ""

Responses

Request samples

Content type
{
  • "status": "new",
  • "resolution_note": ""
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "user": "76f62a58-5404-486d-9afc-07bded328704",
  • "submitter_email": "user@example.com",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "title": "string",
  • "details": "string",
  • "screenshot_url": "string",
  • "url": "string",
  • "viewport": null,
  • "user_agent": "string",
  • "js_errors": null,
  • "status": "new",
  • "triaged_by": "918c35b9-bedc-437d-84b5-ebe932e91c8b",
  • "triaged_by_email": "user@example.com",
  • "triaged_at": "2019-08-24T14:15:22Z",
  • "resolved_by": "d0d57369-b08b-4db8-8952-8cdeedd9aebc",
  • "resolved_by_email": "user@example.com",
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "resolution_note": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

FHIR Bulk Data

Kick off a FHIR Bulk Data ($export) job.

System-level FHIR Bulk Data Access $export. Returns 202 with a Content-Location header pointing at the poll URL. The job runs asynchronously and writes one NDJSON file per requested resource type to private object storage.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
_since
string <date-time>

Only emit resources modified at or after this ISO-8601 datetime (must be tz-aware).

_type
string

Comma-separated FHIR resource types to export. Defaults to all supported types.

header Parameters
X-Practice-UID
string <uuid>

Practice UUID; required when the token grants access to multiple practices.

Responses

Response samples

Content type
application/json
{
  • "property1": null,
  • "property2": null
}

Poll a FHIR Bulk Data ($export) job.

Returns 202 + X-Progress header while the job is running; 200 with the IG-defined manifest when complete; 200 with an empty output when the job was cancelled or failed.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
job_uid
required
string <uuid>
header Parameters
X-Practice-UID
string <uuid>

Practice UUID; required when the token grants access to multiple practices.

Responses

Response samples

Content type
application/json
{
  • "property1": null,
  • "property2": null
}

Cancel a FHIR Bulk Data ($export) job.

Marks the job as cancelled. The Celery worker checks the row's status between resource types and exits cleanly.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
job_uid
required
string <uuid>
header Parameters
X-Practice-UID
string <uuid>

Practice UUID; required when the token grants access to multiple practices.

Responses

Response samples

Content type
application/json
{
  • "property1": null,
  • "property2": null
}

Forms

forms_kiosk_retrieve

GET /api/v1/forms/kiosk/<token>/

Token-scoped read. Returns the kiosk session state, the currently- loaded sendout (if any), and the templates the device should render. A request against an ended / idled-out session returns 410 Gone.

The state read DOES bump last_activity_at — a tablet that polls every few seconds keeps the session alive, which is the intended UX: idle timeout only fires when the patient walks away.

Authorizations:
bearerAuthoauth2
path Parameters
token
required
string

Responses

forms_kiosk_submit_create

POST /api/v1/forms/kiosk/<token>/submit/

Body shape mirrors :class:PublicSubmitView{ "submissions": [...] }. Differences from the patient-portal public submit:

  • The session must be active; an expired session returns 410 Gone.
  • A loaded :class:FormSendOut is required; submitting against a session with current_sendout=None is a 400 (the kiosk shouldn't be rendering a form yet anyway).
  • Submissions are tagged submitted_via='kiosk'; the submitted_via field in the payload is ignored if present.
  • The sendout's status is NOT flipped to submitted: staff may want to load another form on the same kiosk for the same patient, so closing the sendout here would force the staff client to mint a fresh sendout for every form. Staff close out the sendout from their UI when the visit ends.
  • Every accepted submission stamps last_activity_at on the kiosk session so a fast-filling patient keeps the deadline pushed out.

Note: the chart-attach + mapping-proposal signals fire on every :class:FormSubmission regardless of channel, so kiosk submissions get the same downstream pipeline (PDF in the chart, staged patient- record writes) as portal / signed-link submissions.

Authorizations:
bearerAuthoauth2
path Parameters
token
required
string

Responses

forms_public_retrieve

GET /api/v1/forms/public// — render template + in-progress state.

No auth. Open access is intentional: the token IS the credential. The token is single-use only in the sense that status=submitted rejects further submissions; reads (this endpoint) stay available so the patient can review what they sent.

Authorizations:
bearerAuthoauth2
path Parameters
token
required
string

Responses

forms_public_submit_create

POST /api/v1/forms/public//submit/

Body shape: { "submissions": [ { "template_id": "<uuid>", "submitted_via": "link|portal|kiosk", "responses": [ { "field_id": "<uuid>", "value": "..." } ] } ] }

The endpoint pins each submission to the exact :class:FormTemplate row served by the public GET endpoint, so a staff edit landing mid-fill does not retroactively rewrite the patient's responses.

Authorizations:
bearerAuthoauth2
path Parameters
token
required
string

Responses

practice_forms_bundles_list

List or create form bundles.

GET is open to any authenticated staff (no role check). POST is gated to manager-or-above via :class:IsManagerOrAbove — same write-side guardrail the spec for api#769 requires. The IsManagerOrAbove permission allows safe methods through unconditionally, so a single permission_classes list covers both cases without a per-method override.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_forms_bundles_create

List or create form bundles.

GET is open to any authenticated staff (no role check). POST is gated to manager-or-above via :class:IsManagerOrAbove — same write-side guardrail the spec for api#769 requires. The IsManagerOrAbove permission allows safe methods through unconditionally, so a single permission_classes list covers both cases without a per-method override.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 200 ] characters
description
string
is_default_new_patient
boolean

When true, this bundle is the practice's default new-patient intake packet (api#769). Setting this true on a row clears the flag on any sibling bundle in the same practice — at most one default per practice. False on any number of rows is fine.

template_ids
Array of strings <uuid> [ items <uuid > ]

Ordered list of FormTemplate UUIDs to include.

Responses

Request samples

Content type
{
  • "name": "string",
  • "description": "string",
  • "is_default_new_patient": true,
  • "template_ids": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "description": "string",
  • "is_default_new_patient": true,
  • "items": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_forms_bundles_retrieve

Retrieve, update, or delete a form bundle.

Update + delete are gated to manager-or-above (api#769); retrieve stays open to any authenticated staff thanks to :class:IsManagerOrAbove letting safe methods through.

Delete cascades to :class:FormBundleItem rows (the FK is CASCADE) but PROTECTs against orphaning a :class:FormSendOut that still references the bundle — staff must archive the sendout first. The PROTECT raises :class:django.db.models.ProtectedError, which DRF's default exception handler maps to 409 Conflict.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
bundle_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "description": "string",
  • "is_default_new_patient": true,
  • "items": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_forms_bundles_partial_update

Retrieve, update, or delete a form bundle.

Update + delete are gated to manager-or-above (api#769); retrieve stays open to any authenticated staff thanks to :class:IsManagerOrAbove letting safe methods through.

Delete cascades to :class:FormBundleItem rows (the FK is CASCADE) but PROTECTs against orphaning a :class:FormSendOut that still references the bundle — staff must archive the sendout first. The PROTECT raises :class:django.db.models.ProtectedError, which DRF's default exception handler maps to 409 Conflict.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
bundle_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
name
string [ 1 .. 200 ] characters
description
string
is_default_new_patient
boolean

When true, this bundle is the practice's default new-patient intake packet (api#769). Setting this true on a row clears the flag on any sibling bundle in the same practice — at most one default per practice. False on any number of rows is fine.

template_ids
Array of strings <uuid> [ items <uuid > ]

Ordered list of FormTemplate UUIDs to include.

Responses

Request samples

Content type
{
  • "name": "string",
  • "description": "string",
  • "is_default_new_patient": true,
  • "template_ids": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "description": "string",
  • "is_default_new_patient": true,
  • "items": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_forms_bundles_destroy

Retrieve, update, or delete a form bundle.

Update + delete are gated to manager-or-above (api#769); retrieve stays open to any authenticated staff thanks to :class:IsManagerOrAbove letting safe methods through.

Delete cascades to :class:FormBundleItem rows (the FK is CASCADE) but PROTECTs against orphaning a :class:FormSendOut that still references the bundle — staff must archive the sendout first. The PROTECT raises :class:django.db.models.ProtectedError, which DRF's default exception handler maps to 409 Conflict.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
bundle_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_forms_bundles_default_new_patient_retrieve

Return the practice's default new-patient bundle (api#769).

Convenience endpoint for the staff web's "Send new patient forms" entry point — saves a list-then-filter round-trip. Returns 404 if no bundle on this practice has is_default_new_patient=True.

Read access is open to any authenticated staff; there is no write surface on this URL — flipping the flag goes through :class:FormBundleDetailView PATCH.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "description": "string",
  • "is_default_new_patient": true,
  • "items": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_forms_kiosk_draft_submit_create

POST one walk-up bundle form, bound to a new_patient_draft.

The companion to :class:apps.intake.views.NewPatientDraftSubmitView (escape-kiosk#38). After the kiosk stages a draft and gets back its uid, it walks the practice's default new-patient bundle and posts one request per form here -- every request carrying the same draft uid and the same session_id so the submissions correlate into one draft for staff review.

Auth mirrors NewPatientDraftSubmitView: the calling tablet's OAuth bearer is the auth (TabletOAuth2Authentication attaches request.tablet); a staff session is rejected with 401 because this surface is exclusively for in-office tablets running the kiosk wizard.

Security (IDOR prevention)

  • The tablet must be paired with the URL practice (403 otherwise).
  • The new_patient_draft must belong to that practice and still be open for submissions (404 otherwise -- a generic not-found, never a cross-practice leak).
  • The template must be a member of the practice's default new-patient bundle (400 otherwise -- arbitrary / cross-practice templates are rejected).

Idempotency

The model carries a partial unique index on (session_id, template) (forms_submission_session_template_unique). A flaky-network retry of the same (session_id, template) returns the existing row with 201 instead of creating a duplicate -- get_or_create plus an IntegrityError fallback covers the race.

Privacy: no PHI in logs -- the audit metadata and log lines carry only identifiers (draft id, template id, session id, submission id).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
template
required
string <uuid>

Template UUID; must belong to the default new-patient bundle.

new_patient_draft
required
string <uuid>

Draft uid returned by the intake-draft submit endpoint.

session_id
required
string <uuid>

Shared correlation UUID for the whole bundle walk.

responses
required
any

Field-name -> value map captured by the tablet renderer.

Responses

Request samples

Content type
{
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "new_patient_draft": "e42c62b1-48c4-4e26-8c4f-c79c300f4d95",
  • "session_id": "1ffd059c-17ea-40a8-8aef-70fd0307db82",
  • "responses": null
}

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_forms_kiosk_sessions_list

GET / POST /api/v1/practice/<uid>/forms/kiosk-sessions/

GET lists kiosk sessions for the practice (most-recent first). POST mints a fresh device-bound session — body accepts device_label and idle_timeout_seconds (both optional); token and kiosk_url come back in the response so the staff client can immediately point a tablet at the URL.

Only one server-side endpoint creates kiosk rows; the public token path never produces them. This keeps the create path firmly behind staff auth + the practice scope check.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_forms_kiosk_sessions_create

GET / POST /api/v1/practice/<uid>/forms/kiosk-sessions/

GET lists kiosk sessions for the practice (most-recent first). POST mints a fresh device-bound session — body accepts device_label and idle_timeout_seconds (both optional); token and kiosk_url come back in the response so the staff client can immediately point a tablet at the URL.

Only one server-side endpoint creates kiosk rows; the public token path never produces them. This keeps the create path firmly behind staff auth + the practice scope check.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
device_label
string <= 120 characters

Optional human-readable label, e.g. 'Front desk tablet 1'.

idle_timeout_seconds
integer [ 0 .. 2147483647 ]

Seconds of inactivity after which the session is considered expired (default 10 minutes).

Responses

Request samples

Content type
{
  • "device_label": "string",
  • "idle_timeout_seconds": 2147483647
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "device_label": "string",
  • "idle_timeout_seconds": 2147483647,
  • "token": "b5507016-7da2-4777-a161-1e8042a6a377",
  • "started_at": "2019-08-24T14:15:22Z",
  • "last_activity_at": "2019-08-24T14:15:22Z",
  • "ended_at": "2019-08-24T14:15:22Z",
  • "current_sendout": "5fd310e5-0160-4f65-852a-6661765cf842",
  • "kiosk_url": "string"
}

practice_forms_kiosk_sessions_retrieve

GET /api/v1/practice/<uid>/forms/kiosk-sessions/<id>/

Staff-facing retrieve. Mutations live on dedicated action endpoints (/load-sendout/ and /end/) so each verb carries its own audit event and validation rules.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
session_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "device_label": "string",
  • "idle_timeout_seconds": 0,
  • "token": "b5507016-7da2-4777-a161-1e8042a6a377",
  • "started_at": "2019-08-24T14:15:22Z",
  • "last_activity_at": "2019-08-24T14:15:22Z",
  • "ended_at": "2019-08-24T14:15:22Z",
  • "is_active": true,
  • "current_sendout": "5fd310e5-0160-4f65-852a-6661765cf842",
  • "kiosk_url": "string"
}

practice_forms_kiosk_sessions_end_create

POST /api/v1/practice/<uid>/forms/kiosk-sessions/<id>/end/

Explicitly terminates a kiosk session. Idempotent — re-ending a session that already ended is a 200 with the existing row, not a 409 or 410 (the staff client may double-click the End button).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
session_id
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_forms_kiosk_sessions_load_sendout_create

POST /api/v1/practice/<uid>/forms/kiosk-sessions/<id>/load-sendout/

Assigns a :class:FormSendOut to the kiosk session so the device can pull it on the next public state read. The sendout must belong to the same practice as the kiosk and must not already be submitted or expired — those would render an empty form.

Loading a new sendout on a session that already had one is allowed (and intentional: the kiosk flow is "patient finishes form, staff walks over and taps Load Next Form" — the same session can host a series of submissions for one patient).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
session_id
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_forms_mapping_proposals_list

GET /api/v1/practice/<uid>/forms/mapping-proposals/

Filterable by ?submission=<uuid>, ?status=<pending|approved|rejected>, and ?patient=<uuid>. Returns the same shape the detail endpoint serves, paginated by the project default.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_forms_mapping_proposals_retrieve

GET /api/v1/practice/<uid>/forms/mapping-proposals/<id>/

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
proposal_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "submission": "1b93aee1-8240-405b-a875-ba2e84126725",
  • "submission_template": "0e3de4ce-1a0e-4d8c-a5c3-c059c0cf2f70",
  • "field_response": "0909d828-03ff-42b0-9055-4ddb448a6b02",
  • "field_label": "string",
  • "field_type": "string",
  • "target_patient_field": "string",
  • "proposed_value": "string",
  • "current_patient_value_snapshot": "string",
  • "status": "pending",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "reviewed_by_email": "user@example.com",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "review_notes": "string",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_forms_mapping_proposals_approve_create

POST /api/v1/practice/<uid>/forms/mapping-proposals/<id>/approve/

Body: {"notes": "optional"}.

Idempotent — re-approving an already-approved proposal is a no-op that returns 200 with the existing row. Approving a previously rejected proposal is rejected with 409 (Conflict): the staff member should file a new submission / sendout cycle if they want to revisit.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
proposal_id
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_forms_mapping_proposals_reject_create

POST /api/v1/practice/<uid>/forms/mapping-proposals/<id>/reject/

Body: {"notes": "required"}.

A non-blank notes is required so the audit trail explains why the proposed change did not land. Re-rejecting an already-rejected proposal is idempotent. Rejecting a previously approved proposal is a 409 — once the patient record changed, it's the staff member's job to walk it back via the appropriate patient-edit endpoint.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
proposal_id
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_forms_mapping_proposals_bulk_approve_create

POST /api/v1/practice/<uid>/forms/mapping-proposals/bulk-approve/

Body: {"ids": [<uuid>, ...], "notes": "optional"}.

All-or-nothing: a single validation failure (unknown target field, bad date format, etc.) rolls back the entire batch. Already-approved proposals are no-ops inside the batch; already-rejected proposals abort the batch with 409 — matching the single-row endpoint's semantics.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_forms_sendouts_list

List or create sendouts.

Creating a sendout mints a fresh signed link the staff can hand to the patient; reads return the list filtered by ?status= and ?patient=.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_forms_sendouts_create

List or create sendouts.

Creating a sendout mints a fresh signed link the staff can hand to the patient; reads return the list filtered by ?status= and ?patient=.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>
bundle
string or null <uuid>
template
string or null <uuid>

Set when sending exactly one template without a bundle.

channel
string
Enum: "email" "sms" "kiosk"

Delivery channel for the patient-facing link (api#748). Email and SMS dispatch a Celery notification at create + resend; kiosk is a no-op (staff loads the sendout from the kiosk control panel).

  • email - Email
  • sms - SMS
  • kiosk - In-office kiosk
expires_at
string <date-time>

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "bundle": "6350974e-b7e0-4bb6-8ec3-333ab03ecfbf",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "channel": "email",
  • "expires_at": "2019-08-24T14:15:22Z"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "bundle": "6350974e-b7e0-4bb6-8ec3-333ab03ecfbf",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "channel": "email",
  • "token": "string",
  • "status": "pending",
  • "expires_at": "2019-08-24T14:15:22Z",
  • "public_url": "string",
  • "created": "2019-08-24T14:15:22Z"
}

practice_forms_sendouts_retrieve

GET /api/v1/practice/<uid>/forms/sendouts/<id>/ (api#654).

Practice-scoped retrieve. Closes the gap that forced the web detail page (web#532 / web#535) to walk the paginated list endpoint to render a single row. Cross-tenant access returns 404 -- the sendout's existence is not leaked to a foreign practice.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
sendout_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "bundle": "6350974e-b7e0-4bb6-8ec3-333ab03ecfbf",
  • "bundle_name": "string",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "template_name": "string",
  • "channel": "email",
  • "token": "string",
  • "status": "pending",
  • "expires_at": "2019-08-24T14:15:22Z",
  • "opened_at": "2019-08-24T14:15:22Z",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "last_resent_at": "2019-08-24T14:15:22Z",
  • "created": "2019-08-24T14:15:22Z"
}

practice_forms_sendouts_cancel_create

POST /api/v1/practice/<uid>/forms/sendouts/<id>/cancel/ (api#654).

Flip status to :attr:SendOutStatus.ARCHIVED so the sendout no longer blocks template archive and the patient-side endpoint stops accepting submissions against the token.

Status semantics

* ``pending`` / ``in_progress`` -> ``archived`` + audit event.
* ``archived`` / ``expired`` -> 200 idempotent re-cancel; audit
  event still fires so the trail captures the intent regardless
  of state (mirrors the template-archive contract).
* ``submitted`` -> 409.  A completed sendout is history; the
  patient already filled the form and the chart already carries
  the submission.  Cancelling here would lie to the audit trail
  about what really happened.

The transition is a single-column UPDATE so a racing transition
on the same row (e.g. the patient submitting between our
``select_for_update`` and the write) can't trample the
``modified`` timestamp on either side; we re-check the row
inside the same transaction to keep the contract honest.
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
sendout_id
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_forms_sendouts_resend_create

POST /api/v1/practice/<uid>/forms/sendouts/<id>/resend/ (api#655).

Re-broadcast the patient-facing notification for sendout_id using the SAME token (no new credential is minted -- staff explicitly asked for "send the same link again"). Throttled to at most one delivery per :data:RESEND_THROTTLE window per sendout so a button-mash does not spam the patient.

Lifecycle gating

* ``pending`` / ``in_progress`` -- allowed.
* ``submitted`` / ``expired`` / ``archived`` -- rejected with 409.
  A submitted form has nothing to remind about; an expired or
  cancelled token would land the patient on a 410 the moment they
  tap the link.

Throttle contract

Returns 429 with {"detail": "...", "next_resend_at": "<iso>"} when the previous resend landed inside the window. The web client uses next_resend_at to gray out the button until the deadline elapses without polling.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
sendout_id
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_forms_sendouts_submissions_list

GET /api/v1/practice/<uid>/forms/sendouts/<id>/submissions/ (api#656).

List :class:FormSubmission rows attached to sendout_id, newest first. Single-template sendouts return a 0-or-1 row list; bundle sendouts return one row per template the patient completed.

Scoping

The parent sendout is resolved against the practice queryset before
we list, so a foreign practice's submissions are unreachable even
when the staff user guesses the bundle's child IDs.  Returns the
same paginated envelope as every other list endpoint.
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
sendout_id
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_forms_sendouts_submissions_latest_retrieve

GET /api/v1/practice/<uid>/forms/sendouts/<id>/submissions/latest/ (api#656).

Convenience endpoint that returns the single most-recent :class:FormSubmission for sendout_id -- the row a staff member is most likely to want when clicking "View submission" on the detail page. Returns 404 when the sendout has no submissions yet (patient hasn't filled the form), so the web client can treat the absence as a non-error "nothing to show" state without parsing a list envelope.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
sendout_id
required
string <uuid>

Responses

practice_forms_submissions_pdf_retrieve

GET /api/v1/practice//forms/submissions//pdf/

Render a completed :class:FormSubmission as a human-readable PDF and stream it to the caller with Content-Type: application/pdf.

The same renderer powers the Celery task that auto-attaches the PDF to the patient's chart on submit (api#620 / escape#156); this endpoint exists so staff can re-download the snapshot on demand without having to dig through the doccenter.

Scoping

Practice-scoped — the submission must belong to a sendout owned by the URL-supplied practice. Cross-tenant access produces a 404 rather than a 403 so the existence of a foreign submission isn't leaked.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
submission_id
required
string <uuid>

Responses

practice_forms_templates_list

List or create form templates for a practice.

GET /v1/practice//forms/templates/?active=true|false|all POST /v1/practice//forms/templates/

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_forms_templates_create

List or create form templates for a practice.

GET /v1/practice//forms/templates/?active=true|false|all POST /v1/practice//forms/templates/

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 200 ] characters
description
string
Array of objects (FormFieldRequest)
prefill_map
any

Map of FormField.label (or template field name) -> dotted attribute path on the Patient row that should pre-populate that field on the kiosk / portal renderer (api#772). Shape: {field_name: 'patient.attribute_dotted_path'}. Example: {'First name': 'first_name', 'Insurance member ID': 'insurance_enrollments.first.subscriber_id'}. Resolution is best-effort and read-only -- absent attributes / null values are omitted from the response so the renderer treats them as 'user must fill in'. See :func:apps.forms.prefill.resolve_prefill for traversal rules.

Responses

Request samples

Content type
{
  • "name": "string",
  • "description": "string",
  • "fields": [
    ],
  • "prefill_map": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "version_group": "270269c2-f759-4e54-adee-ae78012a3e32",
  • "version": 1,
  • "name": "string",
  • "description": "string",
  • "is_active": true,
  • "fields": [
    ],
  • "prefill_map": null,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_forms_templates_retrieve

Retrieve or update a form template.

GET /v1/practice//forms/templates// PATCH /v1/practice//forms/templates//

PATCH semantics: * Editing a template that has zero submissions updates in place. * Editing a template that has any submissions archives the row (is_active=False) and returns a fresh version=N+1 row with the edits applied. Past submissions stay pinned to the archived row.

PUT is intentionally unsupported — full-replace edits over a versioned document are confusing semantically.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "version_group": "270269c2-f759-4e54-adee-ae78012a3e32",
  • "version": 1,
  • "name": "string",
  • "description": "string",
  • "is_active": true,
  • "fields": [
    ],
  • "prefill_map": null,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_forms_templates_partial_update

Retrieve or update a form template.

GET /v1/practice//forms/templates// PATCH /v1/practice//forms/templates//

PATCH semantics: * Editing a template that has zero submissions updates in place. * Editing a template that has any submissions archives the row (is_active=False) and returns a fresh version=N+1 row with the edits applied. Past submissions stay pinned to the archived row.

PUT is intentionally unsupported — full-replace edits over a versioned document are confusing semantically.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_id
required
string <uuid>
Request Body schema:
name
string [ 1 .. 200 ] characters
description
string
Array of objects (FormFieldRequest)
prefill_map
any

Map of FormField.label (or template field name) -> dotted attribute path on the Patient row that should pre-populate that field on the kiosk / portal renderer (api#772). Shape: {field_name: 'patient.attribute_dotted_path'}. Example: {'First name': 'first_name', 'Insurance member ID': 'insurance_enrollments.first.subscriber_id'}. Resolution is best-effort and read-only -- absent attributes / null values are omitted from the response so the renderer treats them as 'user must fill in'. See :func:apps.forms.prefill.resolve_prefill for traversal rules.

Responses

Request samples

Content type
{
  • "name": "string",
  • "description": "string",
  • "fields": [
    ],
  • "prefill_map": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "version_group": "270269c2-f759-4e54-adee-ae78012a3e32",
  • "version": 1,
  • "name": "string",
  • "description": "string",
  • "is_active": true,
  • "fields": [
    ],
  • "prefill_map": null,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_forms_templates_archive_create

POST /api/v1/practice/<uid>/forms/templates/<id>/archive/

Flip is_active=False on the template so it disappears from the active-templates list staff hand out. Historical sendouts and submissions remain pinned to the archived row — versioning is immutable — so existing chart entries stay defensible.

Idempotent: re-archiving an already-archived template is a 200 with the current serialized row. Both archive and re-archive emit the form_template.archived audit event so the trail captures the intent regardless of state.

Conflict

Returns ``409 Conflict`` with ``open_sendout_ids`` when at least one
:class:`FormSendOut` referencing this template is still in a non-
resolved status (``pending`` or ``in_progress``).  The web client
surfaces this as "close N outstanding sendouts first" so staff don't
accidentally orphan an in-flight patient packet.
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_id
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_forms_templates_unarchive_create

POST /api/v1/practice/<uid>/forms/templates/<id>/unarchive/

Flip is_active=True on the template so it reappears in the active-templates list. Idempotent: re-unarchiving an already-active template is a 200 with the current serialized row.

Note that the versioning invariant says only one row per version_group can be active at a time, but the model does NOT currently enforce that with a partial unique index. Unarchive does not auto-archive a competing active version — staff are expected to use the archive endpoint first if they want to swap which version is live, and the API surfaces both endpoints as independent verbs. A future hardening pass can add a deferred-unique constraint if the competing-versions case becomes a real footgun.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_id
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_forms_prefill_retrieve

GET /api/v1/practice/<uid>/patient/<patient_id>/forms/<template_id>/prefill/

Resolve a form template's :attr:FormTemplate.prefill_map against a specific patient and return the values the kiosk / portal should pre-populate (api#772).

Auth

**Staff session only** -- gated to manager-or-above through
:class:`IsManagerOrAbove`.  Same convention as the bundle
endpoints: pre-fill data is PHI (patient demographics + insurance
identifiers) so front-desk-only roles don't get it.

(The former paired-tablet caller path was removed with the
send-to-tablet push surface in escape#439 -- the kiosk no longer
receives a server-pushed patient-bound session to validate the
pre-fill request against.)

Response shape

.. code:: json

{
  "template_id": "...",
  "values": {
    "First name": "Jane",
    "Date of birth": "1985-05-22"
  }
}

Empty prefill_map, missing patient attributes, and null values all surface as an empty / shorter values dict -- the renderer treats absent keys as "user must fill in" so the resolver is permissively quiet.

Errors

* 404 when the template or patient doesn't exist in this practice.
* 403 when a staff caller is below manager rank.
* 401 when no authentication credentials are supplied at all.
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
template_id
required
string <uuid>

Responses

help-events

Submit a batch of help-panel telemetry events.

Records open / dwell / empty-state events from the staff web app's in-app help panel (web#653). The request body is a batch -- the web client buffers events for a session and flushes them in one POST to keep network chatter low. Up to 100 events per batch; oversized batches and unknown event types are rejected with 400.

Attribution is server-side: user is set from request.user and practice is set from the batch-level practice UID after verifying the user has access to that practice. A client-supplied user is ignored; a client-supplied practice that the caller has no membership to is rejected with 400.

The :class:apps.help_events.models.HelpEvent table is non-PHI-bearing by construction; the URL field is stripped of query string and fragment server-side.

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
required
practice
string or null <uuid>
required
Array of objects (HelpEventInRequest)

Responses

Request samples

Content type
{
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "events": [
    ]
}

Internal - Staff Only

List clients (staff-side).

Lists every :class:Client in the system, including disabled tenants. Filter to a single activity bucket with ?is_active=true / ?is_active=false; omit the parameter to see both. Free-text search across name is supported via ?search=<query>.

Staff-only. The support tool consumes this endpoint to render its client list -- before GH-883 the support tool was reading the user-facing /api/v1/client/ endpoint with an ad-hoc include_disabled flag, which conflated user and staff permission surfaces. This endpoint is the dedicated staff replacement.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
is_active
boolean

Filter to active (true) or disabled (false) clients. Omit for both.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

search
string

Case-insensitive substring match against Client.name.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

Retrieve a single client (staff-side).

Returns the staff-side projection of a single :class:Client, including disabled tenants. Support-staff-only -- the URL-level IsSupportStaff gate makes the endpoint invisible to regular users.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "logo_url": "string",
  • "accent_color": "string",
  • "email_login_enabled": true,
  • "enforce_service_codes": true,
  • "is_active": true,
  • "baa_signed": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null,
  • "active_banners": "string",
  • "plan_slug": "string",
  • "practice_count": 0,
  • "practice_count_active": 0,
  • "primary_owner_email": "string"
}

List a client's organization-level memberships (staff-side).

Returns every :class:ClientMembership on the client -- the organization-level roles (OWNER / BILLING / TECHNICAL) that grant access across all of the client's practices. Inactive memberships are included and flagged via is_active so a support agent can see revoked access while triaging. Support-staff-only; staff identity data only, no PHI. Disabled tenants are visible (this is the staff surface). Flat array -- client-level rosters are tiny, and the support UI (escape-support#129) renders the whole list in one pass.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Reactivate a disabled client.

Flips Client.is_active to True via :meth:Client.enable, which emits a client.enabled audit event carrying the actor + reason. Idempotent -- calling against an already-active client is a no-op that still returns 200.

Staff-only. The companion disable action lives at PATCH /api/v1/admin/client/<id>/ for now; both surfaces operate on the same underlying Client.enable / Client.disable helpers.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>
Request Body schema:
required
reason
required
string [ 5 .. 1024 ] characters

Free-text justification recorded in the audit log (min 5 chars).

Responses

Request samples

Content type
{
  • "reason": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "logo_url": "string",
  • "accent_color": "string",
  • "email_login_enabled": true,
  • "enforce_service_codes": true,
  • "is_active": true,
  • "baa_signed": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null,
  • "active_banners": "string",
  • "plan_slug": "string",
  • "practice_count": 0,
  • "practice_count_active": 0,
  • "primary_owner_email": "string"
}

List global exploding-code library (staff-only).

GET/POST /api/v1/internal/exploding-codes/.

Support-staff-only authoring of the global (staff-curated) library. Gated by IsSupportStaff -- platform reference data may only be mutated by Escape employees, never by practice-side is_staff administrators (GH-1007 / escape#388).

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

Author a global exploding code (staff-only).

GET/POST /api/v1/internal/exploding-codes/.

Support-staff-only authoring of the global (staff-curated) library. Gated by IsSupportStaff -- platform reference data may only be mutated by Escape employees, never by practice-side is_staff administrators (GH-1007 / escape#388).

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
required
name
required
string [ 1 .. 20 ] characters ^[A-Za-z0-9_-]{1,20}$

Shorthand alias (1-20 chars, A-Z / 0-9 / - / _). Normalized to uppercase; case-insensitive lookup.

description
string <= 255 characters

Optional human-readable label shown in the type-ahead UI.

leaves
Array of strings <uuid> [ items <uuid > ]
leaf_codes
Array of strings[ items [ 1 .. 20 ] characters ]

Responses

Request samples

Content type
{
  • "name": "string",
  • "description": "string",
  • "leaves": [
    ],
  • "leaf_codes": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "description": "string",
  • "scope": "global",
  • "scope_source": "string",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "leaves": [
    ],
  • "leaf_codes": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

internal_exploding_codes_retrieve

Retrieve / update / delete a single global-library exploding code.

Support-staff-only -- see :class:InternalExplodingCodeListCreateView for why the global library uses IsSupportStaff rather than IsAdminUser.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
code_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "description": "string",
  • "scope": "global",
  • "scope_source": "string",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "leaves": [
    ],
  • "leaf_codes": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

internal_exploding_codes_update

Retrieve / update / delete a single global-library exploding code.

Support-staff-only -- see :class:InternalExplodingCodeListCreateView for why the global library uses IsSupportStaff rather than IsAdminUser.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
code_id
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 20 ] characters ^[A-Za-z0-9_-]{1,20}$

Shorthand alias (1-20 chars, A-Z / 0-9 / - / _). Normalized to uppercase; case-insensitive lookup.

description
string <= 255 characters

Optional human-readable label shown in the type-ahead UI.

leaves
Array of strings <uuid> [ items <uuid > ]
leaf_codes
Array of strings[ items [ 1 .. 20 ] characters ]

Responses

Request samples

Content type
{
  • "name": "string",
  • "description": "string",
  • "leaves": [
    ],
  • "leaf_codes": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "description": "string",
  • "scope": "global",
  • "scope_source": "string",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "leaves": [
    ],
  • "leaf_codes": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

internal_exploding_codes_partial_update

Retrieve / update / delete a single global-library exploding code.

Support-staff-only -- see :class:InternalExplodingCodeListCreateView for why the global library uses IsSupportStaff rather than IsAdminUser.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
code_id
required
string <uuid>
Request Body schema:
name
string [ 1 .. 20 ] characters ^[A-Za-z0-9_-]{1,20}$

Shorthand alias (1-20 chars, A-Z / 0-9 / - / _). Normalized to uppercase; case-insensitive lookup.

description
string <= 255 characters

Optional human-readable label shown in the type-ahead UI.

leaves
Array of strings <uuid> [ items <uuid > ]
leaf_codes
Array of strings[ items [ 1 .. 20 ] characters ]

Responses

Request samples

Content type
{
  • "name": "string",
  • "description": "string",
  • "leaves": [
    ],
  • "leaf_codes": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "description": "string",
  • "scope": "global",
  • "scope_source": "string",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "leaves": [
    ],
  • "leaf_codes": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

internal_exploding_codes_destroy

Retrieve / update / delete a single global-library exploding code.

Support-staff-only -- see :class:InternalExplodingCodeListCreateView for why the global library uses IsSupportStaff rather than IsAdminUser.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
code_id
required
string <uuid>

Responses

Aggregated per-slug help-event counts (staff-side).

Returns per-slug open / dwell / empty-state counts on the :class:apps.help_events.models.HelpEvent table, plus the average dwell time (ms) and the most recent created timestamp per slug. Ordered by open_count DESC so the support tool's default view foregrounds the busiest articles; the consumer can re-sort client-side.

Optional date-range filter: ?since=YYYY-MM-DD / ?until=YYYY-MM-DD. Both endpoints are inclusive (a row whose created calendar date matches either bound is counted). Default is all-time.

Staff-only. The table itself is non-PHI-bearing by construction; this endpoint is the canonical read surface and individual rows are deliberately not exposed.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
since
string <date>

Include rows whose created calendar date (UTC) is on or after this value. Format YYYY-MM-DD.

until
string <date>

Include rows whose created calendar date (UTC) is on or before this value. Format YYYY-MM-DD.

Responses

Response samples

Content type
application/json
[
  • {
    }
]

escape-imaging check-in stats (staff-side).

Aggregate check-ins over the window and return the contract shape.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
days
integer

Rolling window size in days (default 7, max 30).

Responses

Response samples

Content type
application/json
{
  • "window_days": 0,
  • "rows": [
    ],
  • "total_checkins": 0,
  • "distinct_machines": 0
}

List escape-imaging releases (staff-side).

GET/POST /api/v1/internal/imaging-releases/.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
architecture
string

Filter by architecture (x86 / x64).

installer_scope
string

Filter by scope (per_user / per_machine).

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

Register a new escape-imaging release (starts at the given rollout, default 0%).

GET/POST /api/v1/internal/imaging-releases/.

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
required
version
required
string [ 1 .. 32 ] characters ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$

Strict semver core (MAJOR.MINOR.PATCH) of the escape-imaging build.

architecture
required
string (ArchitectureEnum)
Enum: "x86" "x64"
  • x86 - x86 (32-bit)
  • x64 - x64 (64-bit)
installer_scope
required
string (InstallerScopeEnum)
Enum: "per_user" "per_machine"
  • per_user - Per user
  • per_machine - Per machine
msi_url
required
string <uri> [ 1 .. 500 ] characters

HTTPS download URL for the MSI on an allow-listed artifact host.

sha256
required
string [ 1 .. 64 ] characters ^[0-9a-f]{64}$

Lowercase hex SHA-256 of the MSI; the updater refuses a mismatching download.

release_notes
string
rollout_percent
integer [ 0 .. 100 ]

Percentage of machines (by deterministic cohort bucket) eligible for this release.

allow_rollback
boolean

Permit machines on a NEWER version to downgrade to this release.

allowed_clients
Array of strings <uuid> [ items <uuid > ]

Clients eligible regardless of rollout percentage (early-access pin).

denied_clients
Array of strings <uuid> [ items <uuid > ]

Clients never eligible for this release, even at 100%.

Responses

Request samples

Content type
{
  • "version": "string",
  • "architecture": "x86",
  • "installer_scope": "per_user",
  • "msi_url": "http://example.com",
  • "sha256": "string",
  • "release_notes": "string",
  • "rollout_percent": 100,
  • "allow_rollback": true,
  • "allowed_clients": [
    ],
  • "denied_clients": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "version": "string",
  • "architecture": "x86",
  • "installer_scope": "per_user",
  • "msi_url": "http://example.com",
  • "sha256": "string",
  • "release_notes": "string",
  • "rollout_percent": 100,
  • "allow_rollback": true,
  • "allowed_clients": [
    ],
  • "denied_clients": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Retrieve a single escape-imaging release.

GET/PATCH /api/v1/internal/imaging-releases/<pk>/.

Read + partial update only. PUT is hidden (full-replace of an artifact row invites accidental hash/URL clears) and DELETE is not exposed: history of what we shipped is audit data -- halt a bad release by dialing rollout_percent to 0 instead.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "version": "string",
  • "architecture": "x86",
  • "installer_scope": "per_user",
  • "msi_url": "http://example.com",
  • "sha256": "string",
  • "release_notes": "string",
  • "rollout_percent": 100,
  • "allow_rollback": true,
  • "allowed_clients": [
    ],
  • "denied_clients": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Edit a release row.

Partial update of any writable field. For the routine rollout dial use the dedicated /set-rollout/ action so Nexus's percentage slider can't accidentally rewrite the artifact URL or hash in the same request.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>
Request Body schema:
version
string [ 1 .. 32 ] characters ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$

Strict semver core (MAJOR.MINOR.PATCH) of the escape-imaging build.

architecture
string (ArchitectureEnum)
Enum: "x86" "x64"
  • x86 - x86 (32-bit)
  • x64 - x64 (64-bit)
installer_scope
string (InstallerScopeEnum)
Enum: "per_user" "per_machine"
  • per_user - Per user
  • per_machine - Per machine
msi_url
string <uri> [ 1 .. 500 ] characters

HTTPS download URL for the MSI on an allow-listed artifact host.

sha256
string [ 1 .. 64 ] characters ^[0-9a-f]{64}$

Lowercase hex SHA-256 of the MSI; the updater refuses a mismatching download.

release_notes
string
rollout_percent
integer [ 0 .. 100 ]

Percentage of machines (by deterministic cohort bucket) eligible for this release.

allow_rollback
boolean

Permit machines on a NEWER version to downgrade to this release.

allowed_clients
Array of strings <uuid> [ items <uuid > ]

Clients eligible regardless of rollout percentage (early-access pin).

denied_clients
Array of strings <uuid> [ items <uuid > ]

Clients never eligible for this release, even at 100%.

Responses

Request samples

Content type
{
  • "version": "string",
  • "architecture": "x86",
  • "installer_scope": "per_user",
  • "msi_url": "http://example.com",
  • "sha256": "string",
  • "release_notes": "string",
  • "rollout_percent": 100,
  • "allow_rollback": true,
  • "allowed_clients": [
    ],
  • "denied_clients": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "version": "string",
  • "architecture": "x86",
  • "installer_scope": "per_user",
  • "msi_url": "http://example.com",
  • "sha256": "string",
  • "release_notes": "string",
  • "rollout_percent": 100,
  • "allow_rollback": true,
  • "allowed_clients": [
    ],
  • "denied_clients": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Set a release's rollout percentage.

Update rollout_percent and return the full row state.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>
Request Body schema:
required
rollout_percent
required
integer [ 0 .. 100 ]

Responses

Request samples

Content type
{
  • "rollout_percent": 100
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "version": "string",
  • "architecture": "x86",
  • "installer_scope": "per_user",
  • "msi_url": "http://example.com",
  • "sha256": "string",
  • "release_notes": "string",
  • "rollout_percent": 100,
  • "allow_rollback": true,
  • "allowed_clients": [
    ],
  • "denied_clients": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

List global service codes (staff-only).

Paginated list of :class:apps.clinical.models.GlobalServiceCode rows -- the cross-tenant CDT starter library curated by Escape staff. Filter by category with ?category=Diagnostic (exact match, case-insensitive). Free-text search across code and description is supported via ?search=<query>.

Staff-only. Practices consume the global library via the copy-to-practice action; they do not read this endpoint directly.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
category
string

Filter to a single category (case-insensitive exact match).

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

search
string

Case-insensitive substring match against code and description.

Responses

Response samples

Content type
application/json
{}

Create a global service code (staff-only).

GET/POST /api/v1/internal/service-codes/.

Support-staff-only authoring surface for the global CDT starter library. IsSupportStaff (not IsAdminUser) is the gate: the global library is platform reference data shared across every tenant, so only Escape employees -- not practice-side is_staff administrators -- may mutate it (GH-1007 / escape#388).

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
required
code
required
string [ 1 .. 16 ] characters

CDT / service code identifier, e.g. D0150. Case-insensitive unique.

description
required
string non-empty

Plain-English description, e.g. 'Comprehensive oral evaluation - new'.

category
string <= 32 characters

Free-text grouping label (e.g. 'Diagnostic', 'Preventive', 'Restorative').

default_fee
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Suggested UCR fee. Practices may override on import; NULL means no suggestion.

Responses

Request samples

Content type
{
  • "code": "string",
  • "description": "string",
  • "category": "string",
  • "default_fee": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "code": "string",
  • "description": "string",
  • "category": "string",
  • "default_fee": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Retrieve a global service code.

GET/PATCH/PUT/DELETE /api/v1/internal/service-codes/<id>/.

Support-staff-only -- see :class:InternalGlobalServiceCodeListCreateView for why platform reference data uses IsSupportStaff rather than IsAdminUser.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "code": "string",
  • "description": "string",
  • "category": "string",
  • "default_fee": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Replace a global service code.

GET/PATCH/PUT/DELETE /api/v1/internal/service-codes/<id>/.

Support-staff-only -- see :class:InternalGlobalServiceCodeListCreateView for why platform reference data uses IsSupportStaff rather than IsAdminUser.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>
Request Body schema:
required
code
required
string [ 1 .. 16 ] characters

CDT / service code identifier, e.g. D0150. Case-insensitive unique.

description
required
string non-empty

Plain-English description, e.g. 'Comprehensive oral evaluation - new'.

category
string <= 32 characters

Free-text grouping label (e.g. 'Diagnostic', 'Preventive', 'Restorative').

default_fee
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Suggested UCR fee. Practices may override on import; NULL means no suggestion.

Responses

Request samples

Content type
{
  • "code": "string",
  • "description": "string",
  • "category": "string",
  • "default_fee": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "code": "string",
  • "description": "string",
  • "category": "string",
  • "default_fee": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Update a global service code.

GET/PATCH/PUT/DELETE /api/v1/internal/service-codes/<id>/.

Support-staff-only -- see :class:InternalGlobalServiceCodeListCreateView for why platform reference data uses IsSupportStaff rather than IsAdminUser.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>
Request Body schema:
code
string [ 1 .. 16 ] characters

CDT / service code identifier, e.g. D0150. Case-insensitive unique.

description
string non-empty

Plain-English description, e.g. 'Comprehensive oral evaluation - new'.

category
string <= 32 characters

Free-text grouping label (e.g. 'Diagnostic', 'Preventive', 'Restorative').

default_fee
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Suggested UCR fee. Practices may override on import; NULL means no suggestion.

Responses

Request samples

Content type
{
  • "code": "string",
  • "description": "string",
  • "category": "string",
  • "default_fee": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "code": "string",
  • "description": "string",
  • "category": "string",
  • "default_fee": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Delete a global service code.

GET/PATCH/PUT/DELETE /api/v1/internal/service-codes/<id>/.

Support-staff-only -- see :class:InternalGlobalServiceCodeListCreateView for why platform reference data uses IsSupportStaff rather than IsAdminUser.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>

Responses

Copy global service codes into a practice's procedure-code table.

Materialises a subset (or the whole) of the global service-code library into the target practice's :class:apps.clinical.models.ProcedureCode table. Existing rows (matched case-insensitively on code) are skipped, never overwritten -- once a practice owns a row, its fees and active/inactive flags belong to the practice.

Idempotent: re-running with the same input is safe. Returns {copied, skipped, errors} counters so the onboarding UI can render a useful summary.

code_ids accepts either a list of UUIDs or the literal string "all" for "everything in the library".

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
required
practice
required
string <uuid>

Target practice UUID.

code_ids
required
any

List of GlobalServiceCode UUIDs to copy, or the literal string "all" to copy the entire library.

Responses

Request samples

Content type
{
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "code_ids": null
}

Response samples

Content type
application/json
{
  • "copied": 0,
  • "skipped": 0,
  • "errors": [
    ]
}

List status messages (staff-side).

Lists every :class:StatusMessage in the system, including already-resolved rows -- the user-facing /api/v1/status/ feed filters those out (escape#321). Filter to a single lifecycle bucket with ?resolved=true / ?resolved=false, and/or scope to a single severity tier with ?severity=down (legal values: down, disruption, informational, up). Newest-first.

Staff-only. The support tool consumes this endpoint to power its banner-management UI.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

resolved
boolean

Filter to resolved (true) or unresolved (false) rows. Omit for both.

severity
string

Filter to a single severity tier. Legal values: down, disruption, informational, up.

Responses

Response samples

Content type
application/json
{}

Author a new status message.

Creates a new :class:StatusMessage row. The row appears on the public feed immediately (assuming resolved=False, which is the default) and the post_save signal pushes a status.dirty WebSocket event so connected clients refetch /api/v1/status/ without waiting for their next poll cycle.

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
required
title
required
string [ 1 .. 120 ] characters

One-line headline shown in the menubar status indicator.

message
required
string non-empty

Long-form description shown in the status detail panel.

severity
required
string
Enum: "down" "disruption" "informational" "up"

Severity tier; drives the indicator colour.

  • down - Down
  • disruption - Disruption
  • informational - Informational
  • up - Up

Responses

Request samples

Content type
{
  • "title": "string",
  • "message": "string",
  • "severity": "down"
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "title": "string",
  • "message": "string",
  • "severity": "down",
  • "created_at": "2019-08-24T14:15:22Z",
  • "resolved": true,
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "resolved_by_email": "string"
}

Retrieve a single status message (staff-side).

GET/PATCH /api/v1/internal/status_messages/<pk>/.

Read + partial update only. PUT is hidden from the schema -- the full-replace shape would surprise callers who would expect to be able to set resolved from it; resolve flow has its own action. DELETE is hidden too: deletion is an admin-only operation (a banner posted in error) and intentionally not exposed to the support tool, which should resolve rather than delete to preserve history.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
integer

Responses

Response samples

Content type
application/json
{
  • "id": 0,
  • "title": "string",
  • "message": "string",
  • "severity": "down",
  • "created_at": "2019-08-24T14:15:22Z",
  • "resolved": true,
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "resolved_by_email": "string"
}

Edit a status message's title, body, or severity.

Updates one or more of title / message / severity on an existing :class:StatusMessage. resolved is deliberately read-only on this surface; use the dedicated /resolve/ action so the actor + timestamp get captured atomically. Save triggers a status.dirty WebSocket broadcast via the model's post_save signal.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
integer
Request Body schema:
title
string [ 1 .. 120 ] characters

One-line headline shown in the menubar status indicator.

message
string non-empty

Long-form description shown in the status detail panel.

severity
string
Enum: "down" "disruption" "informational" "up"

Severity tier; drives the indicator colour.

  • down - Down
  • disruption - Disruption
  • informational - Informational
  • up - Up

Responses

Request samples

Content type
{
  • "title": "string",
  • "message": "string",
  • "severity": "down"
}

Response samples

Content type
application/json
{
  • "id": 0,
  • "title": "string",
  • "message": "string",
  • "severity": "down",
  • "created_at": "2019-08-24T14:15:22Z",
  • "resolved": true,
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "resolved_by_email": "string"
}

Mark a status message resolved.

Flips resolved=True and captures resolved_at + resolved_by for the post-mortem record. Idempotent: re-resolving an already-resolved row is a no-op that preserves the original attribution. Fires the standard status.dirty WebSocket broadcast via the model's post_save signal.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
integer

Responses

Response samples

Content type
application/json
{
  • "id": 0,
  • "title": "string",
  • "message": "string",
  • "severity": "down",
  • "created_at": "2019-08-24T14:15:22Z",
  • "resolved": true,
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "resolved_by_email": "string"
}

OAuth

Mint a single-use launch JWT for a 3rd-party app

Mint a short-lived launch JWT bound to (user, application, practice).

The returned JWT carries aud=<client_id>, sub=user:<uid>, practice=<uid>, exp (now + 60 s), and a fresh jti. The jti is recorded in :class:LaunchTokenJTI before the response is returned so the exchange endpoint can detect replays.

Permission stack:

  1. IsAuthenticated -- session or bearer; practically staff sessions from the web nine-dots.
  2. IsStaffUser -- patient users cannot launch 3rd-party apps.
  3. Explicit check that the authenticated user has practice access.
  4. Explicit check that the user's active :class:OAuthPracticeGrant authorizes this app for this practice.
  5. Rate limit (see :class:LaunchTokenCreateThrottle).
Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
required
application
required
string non-empty

OAuth2 Application.client_id of the 3rd-party app to launch.

practice
required
string <uuid>

UUID of the practice the launch will be scoped to.

Responses

Request samples

Content type
{
  • "application": "string",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2"
}

Response samples

Content type
application/json
{
  • "launch_token": "string",
  • "expires_in": 0
}

Request an email magic-link login token

Public endpoint. Accepts an email address, applies a per-email AND per-IP rate limit (3 / hour each), and -- if the user exists and at least one of their practices has effective_email_login_enabled=True -- emails a single-use, 5-minute magic-link login token. Always returns HTTP 202 on accepted input to avoid leaking user existence or per-practice eligibility. Returns HTTP 429 only when the rate limit is exhausted.

Authorizations:
jwtAuthbearerAuthoauth2None
Request Body schema:
required
email
required
string <email> non-empty

Responses

Request samples

Content type
{
  • "email": "user@example.com"
}

Response samples

Content type
application/json
{
  • "ok": true
}

List the 3rd-party apps with delegated access to your account

Returns every OAuth application for which the caller holds at least one active act_on_behalf-scoped access token, enriched with first_granted_at from the backing grant and last_used_at from the usage-metric rollup. Powers the Connected Apps settings page. No practice filter -- delegated apps are scoped to the user, not to any single practice membership.

Authorizations:
jwtAuthbearerAuthoauth2

Responses

Response samples

Content type
application/json
{
  • "count": 0,
  • "results": [
    ]
}

Revoke a 3rd-party app's delegated access to your account

Invalidates every act_on_behalf-scoped grant and token held by the signing-in user for the target app. The app's practice-level authorization is not affected -- that is governed separately by the practice owner via the Security Nexus.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
app_id
required
string

Responses

Response samples

Content type
application/json
{
  • "grants_revoked": 0,
  • "tokens_revoked": 0
}

Companion Devices

oauth_companion_pair_create

Public pairing-exchange endpoint.

No authentication -- the unguessable single-use secret IS the auth. The endpoint hashes the presented secret, looks up the matching pending, unexpired, unrevoked :class:CompanionDevice, and atomically:

  1. Re-checks the row is still redeemable inside a select_for_update so two concurrent redemptions can't both win.
  2. Clears the pairing secret (single-use -- a replay now finds no matching live row and gets the same 401).
  3. Mints a provider-bound DOT AccessToken + RefreshToken pair against the escape-doc-companion public client.
  4. Stamps paired_at and binds the refresh token.

Returns the tokens + the provider/practice context so the device can immediately render and start making companion calls.

Authorizations:
bearerAuthoauth2None
Request Body schema:
required
pair_token
required
string [ 1 .. 512 ] characters

Single-use pairing secret issued by the doctor's pair-token endpoint.

Responses

Request samples

Content type
{
  • "pair_token": "string"
}

oauth_session_retrieve

Return the companion session's own context ("logged in as Dr X").

The only companion-management endpoint a companion token may reach (it is on the scope allowlist). Reads request.companion_device set by the authentication class. Refuses non-companion callers with 403 -- this endpoint is meaningless outside a companion session.

Authorizations:
jwtAuthbearerAuthoauth2

Responses

practice_companion_devices_list

List the active (non-revoked) companion devices at the practice.

Revoked rows are filtered out of the live "Linked Devices" list (escape#410): a doctor managing their linked devices wants to see what is currently linked, not a growing pile of retired entries. Auditability of unlinks is preserved by the companion.revoked audit event emitted on every revoke, so the audit log -- not a tombstone row in the live list -- answers "what was unlinked and by whom".

Optional ?provider=<uuid> narrows to one provider. The serializer still carries the is_revoked flag; it now reports False for every row the default list returns.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

practice_companion_devices_revoke_create

Soft-delete a companion device and revoke its OAuth tokens.

POST-only (a state transition, not a row DELETE). Idempotent: re-revoking returns the same 200 without re-stamping the timestamp. Manager-or-doctor isn't required beyond staff here -- any staff member managing the practice settings can unlink a lost device, and the audit event records who did it; the revoke is purely subtractive (it can only remove access).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
device_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "label": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "paired_at": "2019-08-24T14:15:22Z",
  • "last_seen_at": "2019-08-24T14:15:22Z",
  • "revoked_at": "2019-08-24T14:15:22Z",
  • "is_stale": true,
  • "is_revoked": true,
  • "is_paired": true,
  • "created_by_email": "string"
}

practice_companion_devices_pair_token_create

Mint a single-use companion-device pairing token.

Staff-authenticated; the caller must hold a DOCTOR (or ADMIN) role at the URL's practice. The endpoint:

  1. Validates the chosen provider belongs to this practice and is a prescribing dentist (can_prescribe) -- the companion surface is the doctor-Rx workflow, so a non-prescriber provider has no companion use and we refuse rather than mint an inert link.
  2. Creates a pending :class:CompanionDevice row carrying the hashed pairing secret + expiry.
  3. Returns the RAW pairing secret (shown once), the QR payload, and the expiry for the doctor-facing countdown.
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
label
required
string [ 1 .. 64 ] characters

Doctor-assigned label for the device (e.g. 'Dr Smith iPad').

provider
required
string <uuid>

Provider.id the companion session acts on behalf of (must be a prescribing dentist at the practice).

Responses

Request samples

Content type
{
  • "label": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9"
}

Response samples

Content type
application/json
{
  • "companion_device_id": "0dda6846-9ce2-4fc5-97cb-81677d7f1baa",
  • "pair_token": "string",
  • "qr_payload": "string",
  • "expires_at": "2019-08-24T14:15:22Z"
}

Companion Device

Curated clinical summary for the seated patient (doc app)

Presence-gated, read-only curated clinical summary for one patient.

GET /api/v1/oauth/companion/patients/<patient_id>/clinical-summary/

Reachable ONLY by a companion-device session (the URL name is on the :data:apps.companion_devices.scope.COMPANION_ALLOWED_VIEWS allowlist; every other caller is rejected by the scope gate before reaching this view, and a non-companion caller that somehow arrives is refused here too). The patient must be currently seated in front of the session's bound provider (see :func:resolve_seated_patient) or the response is an existence-non-leaking 404.

HTTP verbs: GET only. There is no write surface here by design.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "patient_id": "3854866a-5476-48be-8313-77029ccdd7a7",
  • "first_name": "string",
  • "last_name": "string",
  • "preferred_name": "string",
  • "date_of_birth": "2019-08-24",
  • "gender": "string",
  • "allergies": "string",
  • "alerts": "string",
  • "medications": "string",
  • "active_treatment_plan": "string",
  • "recent_chart_entries": "string"
}

Tablets

oauth_tablet_pair_create

Public pair-completion endpoint.

No authentication is required -- the unguessable pair_token IS the auth. The endpoint:

  1. Verifies the JWT signature + expiry.
  2. Confirms the named practice exists (404 cross-tenant guess protection -- a JWT for a since-deleted practice resolves to a clean 404 instead of a 500).
  3. Atomically: a. Inserts :class:PairTokenRedemption (Postgres unique constraint races a second redemption into 410). b. Creates the :class:Tablet row from the JWT claims + posted public key. c. Mints a DOT AccessToken + RefreshToken bound to the escape-kiosk-tablet Application and the new Tablet.
  4. Returns the access + refresh token values, the tablet id, the tablet name, and the practice id so the device can begin making authenticated calls immediately.
Authorizations:
bearerAuthoauth2None
Request Body schema:
required
pair_token
required
string [ 1 .. 4096 ] characters

Pair-token JWT issued by the staff-side pair-token endpoint.

public_key
required
string [ 1 .. 4096 ] characters

Base64-encoded ECDSA P-256 public key (DER SubjectPublicKeyInfo) the tablet just generated.

Responses

Request samples

Content type
{
  • "pair_token": "string",
  • "public_key": "string"
}

practice_kiosk_check_in_create

POST /api/v1/practice//kiosk/check-in/.

Tablet-authenticated. The DRF default auth chain includes :class:apps.tablets.authentication.TabletOAuth2Authentication, which attaches request.tablet when the bearer is a paired tablet's access token. Anything else (staff session, third-party OAuth app, no token at all) is rejected with 401 -- the kiosk check-in surface is exclusively for the in-office tablet, not a general write surface.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
last_name
required
string [ 1 .. 100 ] characters
dob
required
string <date>

Patient date of birth, ISO-8601 (YYYY-MM-DD).

Responses

Request samples

Content type
{
  • "last_name": "string",
  • "dob": "2019-08-24"
}

Response samples

Content type
application/json
{
  • "appointment_uid": "8f39db43-9e43-49ac-b3d9-d5d6ba2d63d8",
  • "scheduled_at": "2019-08-24T14:15:22Z",
  • "checked_in_at": "2019-08-24T14:15:22Z"
}

practice_tablets_list

Return the active (non-revoked) Tablets at the calling practice.

Revoked tablets are filtered out of the live list (escape#409): the Settings -> Tablets page is a fleet-management surface, and a retired device cluttering the list is noise an operator has to mentally filter past. Auditability of retirements is preserved elsewhere -- every revoke emits a tablet.revoked audit event, so "which tablets were retired and by whom" is answered by the audit log, not by carrying tombstone rows in the live list.

The serializer still exposes an is_revoked derived field; it now reports False for every row the default list returns, but stays on the contract so a future admin/audit caller can reuse the same serializer.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

practice_tablets_rename_create

Rename an existing tablet without re-pairing.

Staff manager+ surface. The new name must be unique across active tablets at the practice -- same rule the model's conditional unique constraint enforces, but checked at write time so the API returns a clean 400 instead of an opaque 500.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
tablet_id
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 64 ] characters

New staff-assigned label.

Responses

Request samples

Content type
{
  • "name": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "paired_at": "2019-08-24T14:15:22Z",
  • "last_seen_at": "2019-08-24T14:15:22Z",
  • "revoked_at": "2019-08-24T14:15:22Z",
  • "is_stale": true,
  • "is_revoked": true,
  • "paired_by_email": "string",
  • "revoked_by_email": "string"
}

practice_tablets_revoke_create

Soft-delete a tablet and revoke its OAuth tokens.

POST-only -- the action is a state transition (active -> revoked), not a DELETE of the row. Idempotent: re-revoking an already- revoked tablet returns the same 200 payload but does not double- stamp the timestamp.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
tablet_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "paired_at": "2019-08-24T14:15:22Z",
  • "last_seen_at": "2019-08-24T14:15:22Z",
  • "revoked_at": "2019-08-24T14:15:22Z",
  • "is_stale": true,
  • "is_revoked": true,
  • "paired_by_email": "string",
  • "revoked_by_email": "string"
}

practice_tablets_pair_token_create

Mint a short-lived single-use pair token for a new tablet.

Staff-authenticated; manager+ role (writes against practice settings). The response carries:

  • pair_token -- the raw JWT (only useful to a tablet capable of decoding it; included for non-QR flows like a future print-and-hand-off workflow).
  • qr_payload -- the absolute URL the tablet scans. Web renders this as a QR code.
  • expires_at -- ISO-8601 UTC timestamp of the pair token's expiry (5 minutes after mint). Used for the staff-facing countdown.
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 64 ] characters

Staff-assigned label for the tablet (e.g. 'Front Desk 1').

Responses

Request samples

Content type
{
  • "name": "string"
}

Response samples

Content type
application/json
{
  • "pair_token": "string",
  • "qr_payload": "http://example.com",
  • "expires_at": "2019-08-24T14:15:22Z"
}

patient-feedback

List patient-feedback submissions (internal staff only).

Filters: ?status= (new / triaged / resolved), ?user= (submitter UUID), ?patient= (patient UUID), ?practice= (practice UUID), ?client= (client UUID). Ordered by -created (newest first). Returns the compact list shape; open the detail view for the full row.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

Submit patient-portal feedback (patient users only).

Accepts a feedback submission from the patient portal. Body is application/json with {title, details, page_url}; viewport and user_agent are optional. The submitting user is set server-side from request.user -- a client-supplied user value is ignored. The matched per-practice Patient record is resolved automatically by case-insensitive email match. The row is treated as PHI on the read side. Throttled to 5 submissions per hour per portal user.

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
required
title
required
string [ 1 .. 80 ] characters

One-line summary the patient typed into the feedback dialog.

details
required
string non-empty

Long-form description of the issue.

page_url
string <= 2000 characters

Page URL the feedback was submitted from.

viewport
any

Browser viewport metadata (width / height / devicePixelRatio).

user_agent
string <= 1024 characters

User-Agent string at submission time.

Responses

Request samples

Content type
{
  • "title": "string",
  • "details": "string",
  • "page_url": "string",
  • "viewport": null,
  • "user_agent": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "user": "76f62a58-5404-486d-9afc-07bded328704",
  • "submitter_email": "user@example.com",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "title": "string",
  • "details": "string",
  • "page_url": "string",
  • "viewport": null,
  • "user_agent": "string",
  • "status": "new",
  • "triaged_by": "918c35b9-bedc-437d-84b5-ebe932e91c8b",
  • "triaged_by_email": "user@example.com",
  • "triaged_at": "2019-08-24T14:15:22Z",
  • "resolved_by": "d0d57369-b08b-4db8-8952-8cdeedd9aebc",
  • "resolved_by_email": "user@example.com",
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "resolution_note": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Read a single patient-feedback submission (internal staff only).

Returns the full row. Every read fires a patient_feedback.viewed audit event because the row may carry incidentally captured PHI.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_feedback_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "user": "76f62a58-5404-486d-9afc-07bded328704",
  • "submitter_email": "user@example.com",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "title": "string",
  • "details": "string",
  • "page_url": "string",
  • "viewport": null,
  • "user_agent": "string",
  • "status": "new",
  • "triaged_by": "918c35b9-bedc-437d-84b5-ebe932e91c8b",
  • "triaged_by_email": "user@example.com",
  • "triaged_at": "2019-08-24T14:15:22Z",
  • "resolved_by": "d0d57369-b08b-4db8-8952-8cdeedd9aebc",
  • "resolved_by_email": "user@example.com",
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "resolution_note": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Transition a patient-feedback row's status (internal staff only).

Valid target statuses: new / triaged / resolved. Side effects: moving out of new for the first time stamps triaged_by / triaged_at; moving to resolved stamps resolved_by / resolved_at; bouncing back to new or triaged clears the resolved-stamp pair so the field always reflects the current state.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_feedback_uid
required
string <uuid>
Request Body schema:
required
status
required
string (FeedbackStatusEnum)
Enum: "new" "triaged" "resolved"
  • new - New
  • triaged - Triaged
  • resolved - Resolved
resolution_note
string
Default: ""

Responses

Request samples

Content type
{
  • "status": "new",
  • "resolution_note": ""
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "user": "76f62a58-5404-486d-9afc-07bded328704",
  • "submitter_email": "user@example.com",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "title": "string",
  • "details": "string",
  • "page_url": "string",
  • "viewport": null,
  • "user_agent": "string",
  • "status": "new",
  • "triaged_by": "918c35b9-bedc-437d-84b5-ebe932e91c8b",
  • "triaged_by_email": "user@example.com",
  • "triaged_at": "2019-08-24T14:15:22Z",
  • "resolved_by": "d0d57369-b08b-4db8-8952-8cdeedd9aebc",
  • "resolved_by_email": "user@example.com",
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "resolution_note": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

payment

payment_list

List payment history for the authenticated patient.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{}

Payments

payment_create_create

Create a Stripe PaymentIntent and return the client secret.

POST /api/v1/payment/create/

The frontend takes client_secret and confirms the card via Stripe.js so raw PAN never touches our servers (SAQ-A scope). The matching PaymentIntent row is created in PENDING state and transitioned to SUCCEEDED / FAILED by the webhook handler when the confirmation lifecycle completes.

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
required
amount_cents
required
integer >= 50

Amount in cents (minimum $0.50).

description
string <= 255 characters
Default: ""
practice
string <uuid>

UUID of the practice the charge belongs to (used for metadata + audit trail).

save_for_future_use
boolean
Default: false

When true, attach the resulting card to the patient's Stripe Customer for reuse.

payment_method
string <= 64 characters
Default: ""

Optional Stripe PaymentMethod id (pm_...) for one-click pay.

Responses

Request samples

Content type
{
  • "amount_cents": 50,
  • "description": "",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "save_for_future_use": false,
  • "payment_method": ""
}

Response samples

Content type
application/json
{
  • "client_secret": "string",
  • "payment_intent_id": "string",
  • "audit_id": "78c04fa6-cfb4-46a0-9aa5-3681ba4f3897"
}

payment_webhook_stripe_create

Handle Stripe webhook events.

POST /api/v1/payment/webhook/stripe/

The Stripe SDK's Webhook.construct_event does signature + timestamp verification, so we delegate to it and treat any ValueError as a 400. Idempotency is enforced via the :class:WebhookDelivery table: the first time we see an event id we record it and run the handler, every subsequent delivery short-circuits to a 200 OK without side effects.

Authorizations:
bearerAuthoauth2

Responses

Response samples

Content type
application/json
{
  • "status": "string"
}

Portal

List the authenticated patient's appointments.

Returns appointments scoped to the authenticated patient -- resolved server-side from the access token's user. No patient_id query parameter is accepted (cross-patient access vector).

Response items carry the patient-portal-safe shape: uid, start_time (ISO 8601 UTC), duration_minutes, provider_name, procedure_description, and status. Clinical notes, treatment plan IDs, dollars_scheduled, and the long-tail status taxonomy are deliberately omitted.

Filters: ?from=YYYY-MM-DD / ?to=YYYY-MM-DD (inclusive both ends, practice timezone), ?status=scheduled,confirmed (comma-separated whitelist). Page size capped at 100 via StandardPageNumberPagination.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
from
string <date>

Earliest appointment date to include (YYYY-MM-DD, practice timezone).

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

status
string

Comma-separated whitelist of patient-facing statuses: scheduled, confirmed, arrived, completed, cancelled, no_show.

to
string <date>

Latest appointment date to include (YYYY-MM-DD, practice timezone, inclusive).

Responses

Response samples

Content type
application/json
{}

Batched badge counts for the patient-portal dashboard.

Returns a single envelope of integer counts the patient-portal home screen needs to render its card badges, replacing N full-list GETs the dashboard previously performed just to derive .length.

Counts are scoped to the authenticated patient -- resolved server-side from the access token's user via case-insensitive email match against the active Patient rows. No patient_id query parameter is honoured.

The response carries no PHI -- only integers -- so the endpoint is safe to cache for short windows in upstream caches. We set Cache-Control: private, max-age=15 to blunt thundering-herd from a tab the patient has left open; the SPA pairs this with TanStack Query's staleTime: 30_000 for defence-in-depth.

Future counts (unread messages, outstanding forms, uploaded-document approvals) will land here as new integer fields once the matching patient-facing surfaces exist server-side. Adding a field is backwards-compatible for the SPA.

Authorizations:
jwtAuthbearerAuthoauth2

Responses

Response samples

Content type
application/json
Example

Single-shot reply used to populate every count badge on the patient-portal home screen. The integer is a true COUNT(*) over the same filter the dashboard previously applied client-side after fetching the full list -- so the badge value is identical across the swap, just one network round-trip cheaper.

{
  • "upcoming_appointments": 2
}

List installed OAuth apps for the current user

Returns OAuth applications the current user has consented to that have declared the requested slot. The slot query parameter is required and must come from the canonical allowlist; unknown slots return 400.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
slot
required
string

Slot name to filter on. Allowed values: patient.detail.actions, patient.detail.tab, practice.bar.nine-dots, schedule.appointment.actions.

Responses

Response samples

Content type
application/json
[
  • {
    }
]

List the calling patient's conversations.

Returns the conversations the authenticated patient is an explicit participant of, newest activity first. Each row carries unread_count -- the count of messages created after the patient's last_read_at bookmark -- so the SPA dashboard's usePatientUnreadMessageCount can sum across rows for the badge without a second round-trip.

Cross-patient isolation: the queryset is filtered by ConversationParticipant.user = request.user. A patient with no participant rows sees an empty page; nobody can see another patient's threads. Same 401 / 403 / 404 contract as the sibling /portal/dashboard-counts/ and /portal/appointments/ endpoints.

Authorizations:
jwtAuthbearerAuthoauth2

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Start a new conversation with the calling patient's practice.

Creates a new direct Conversation rooted at the patient's resolved Practice, attaches the calling patient as a ConversationParticipant, attaches the practice's staff messaging recipients (active ADMIN / OFFICE_MANAGER / FRONT_DESK memberships) as additional participants, and persists the first message in a single transaction. Returns 201 with the conversation envelope (same shape as the detail GET).

Staff routing: if the practice has named messaging_inbox_owners configured (GH-695), only those active users are CC'd. Otherwise the fan-out is every active admin / office-manager / front-desk membership on the practice -- the simplest correct default for practices that haven't set an owner yet. A small admin pool can always triage and reassign; a single named owner that happens to be on vacation cannot, so the fallback also kicks in when every named owner has been deactivated.

Rate limited per portal user at portal_messaging_start_conversation (default 1 / 5 minutes) -- see apps.portal.throttles.

Audit: messaging.conversation_started_by_patient and messaging.message_sent_by_patient are both emitted with subject_user=request.user. Body and subject text are NEVER stored on the audit document -- only their lengths.

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
required
body
required
string [ 1 .. 5000 ] characters

First message in the new conversation. Non-empty after trim.

subject
string <= 255 characters
Default: ""

Optional thread title. Defaults to the first 80 characters of body when omitted or blank -- so the staff inbox always has a usable label.

Responses

Request samples

Content type
{
  • "body": "string",
  • "subject": ""
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "title": "string",
  • "conversation_type": "direct",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "participants": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Retrieve one of the calling patient's conversations.

Returns the conversation with the given id only if the authenticated patient is a participant. Returns 404 otherwise -- existence-leak ("this conversation exists, you just can't see it") is itself a PHI signal so we never distinguish 403 from 404 here.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
conversation_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "title": "string",
  • "conversation_type": "direct",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "participants": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

List messages in one of the calling patient's conversations.

Returns messages in the named conversation, chronological order (oldest first), paginated. Cross-patient isolation: the conversation must have the calling patient as an explicit participant or the endpoint returns 404 before issuing the message query.

Emits a single messaging.viewed_by_patient audit event per request (subject_user=request.user, resource_id=conversation_id). Message bodies are NOT included in audit metadata -- only the conversation id and the count of messages returned -- because the bodies are PHI and the audit document index isn't the right place for them.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
conversation_id
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Send a message in one of the calling patient's conversations.

Persists a new Message in the named conversation with sender=request.user. Returns 201 with the created message envelope (same shape the message-list endpoint returns) on success.

Cross-patient isolation: the conversation must have the calling patient as an explicit participant or the endpoint returns 404 (not 403). Same existence-leak rationale as the rest of the patient-portal messaging surface.

WebSocket broadcast: persistence triggers the existing message.new post-save signal in apps.messaging.signals so any staff window watching the conversation sees the new message in real time. No additional broadcast is needed in the view path.

Rate limited per portal user at portal_messaging_send (default 30/hour) -- see apps.portal.throttles.

Audit: messaging.message_sent_by_patient with subject_user=request.user. Body length is reported in metadata but the body itself is NEVER stored on the audit document -- the body is PHI.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
conversation_id
required
string <uuid>
Request Body schema:
required
body
required
string [ 1 .. 5000 ] characters

Message body. Must be non-empty after whitespace trim.

Responses

Request samples

Content type
{
  • "body": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "sender_id": "3194e023-c19f-4a42-9172-9e18d68e3a3a",
  • "sender_name": "string",
  • "body": "string",
  • "is_system": true,
  • "created": "2019-08-24T14:15:22Z"
}

Mark a conversation read for the calling patient.

Bumps ConversationParticipant.last_read_at for the calling patient on the named conversation to now(). Subsequent calls to the list endpoint will report unread_count: 0 for this row until a new message arrives.

Returns 404 if the calling patient is not an explicit participant -- the staff side's MarkConversationReadView auto-creates a participant row for operatory conversations, but the patient side never does: operatory threads are not patient-visible, so a missing participant row on the patient side always means the patient has no business in this thread.

Emits messaging.conversation_read_by_patient with subject_user=request.user.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
conversation_id
required
string <uuid>

Responses

Total unread message count for the calling patient.

Returns {"unread": N} -- the sum across the patient's conversations of messages created after each thread's last_read_at bookmark. Sibling helper to the /portal/dashboard-counts/ envelope (api#682); the patients-side dashboard hook today derives the badge by summing unread_count across the conversation list, but this single-integer endpoint exists so future callers (e.g. a header badge that doesn't need the full list) can ask for just the number.

The response carries no PHI -- a single integer -- so it is safe to cache briefly. Returns Cache-Control: private, max-age=15 matching /portal/dashboard-counts/.

Authorizations:
jwtAuthbearerAuthoauth2

Responses

List practices the current user can access

Returns active practices the authenticated user has access to via direct or client-level membership. Accepts first-party JWT/session auth, or OAuth2 bearer tokens carrying reports:read. Unpaginated; the per-user practice list is always small.

Authorizations:
jwtAuthbearerAuthoauth2

Responses

Response samples

Content type
application/json
[
  • {
    }
]

practice_portal_appointment_book_create

Book an appointment as an authenticated patient.

POST /api/v1/practice//portal/appointment/book/

Only patient users (is_patient=True) may access this endpoint. The patient is automatically resolved from the authenticated user's email. Provider and operatory are validated against the practice. Conflicts are checked before creating the appointment.

Returns 201 with the created appointment on success, or 409 with conflict details if the requested time slot is unavailable.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
provider
required
string <uuid>

Provider UUID

operatory
required
string <uuid>

Operatory UUID

start_time
required
string <date-time>

Appointment start (ISO 8601 with timezone)

duration_minutes
required
integer [ 5 .. 480 ]

Duration in minutes

procedures
Array of strings[ items [ 1 .. 20 ] characters ]

List of CDT procedure codes (e.g. ['D0120', 'D1110'])

notes
string <= 2000 characters
Default: ""

Responses

Request samples

Content type

Minimum payload to book an appointment from the patient portal. start_time MUST include a timezone offset -- naive datetimes are rejected with a 400. procedures is optional; if provided, CDT codes are matched against the practice's procedure table.

{
  • "provider": "22222222-2222-4222-8222-222222222222",
  • "operatory": "44444444-4444-4444-8444-444444444444",
  • "start_time": "2026-05-20T10:00:00-07:00",
  • "duration_minutes": 60,
  • "procedures": [
    ],
  • "notes": "First availability in the morning, please."
}

Response samples

Content type
application/json

Returned after the portal successfully books an appointment on the patient's behalf.

{
  • "id": "55555555-5555-4555-8555-555555555555",
  • "provider": "22222222-2222-4222-8222-222222222222",
  • "operatory": "44444444-4444-4444-8444-444444444444",
  • "date_time": "2026-05-20T10:00:00-07:00",
  • "duration_minutes": 60,
  • "status": "scheduled",
  • "note": "First availability in the morning, please.",
  • "provider_name": "Doe, Dr. John"
}

practice_portal_appointment_validate_create

Pre-flight conflict check for a proposed patient appointment.

POST /api/v1/practice//portal/appointment/validate/

Same payload as the booking endpoint but only checks for conflicts without creating anything. Returns 200 with {"available": true} or 409 with conflict details.

Only patient users (is_patient=True) may access this endpoint.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
provider
required
string <uuid>

Provider UUID

operatory
required
string <uuid>

Operatory UUID

start_time
required
string <date-time>

Appointment start (ISO 8601 with timezone)

duration_minutes
required
integer [ 5 .. 480 ]

Duration in minutes

procedures
Array of strings[ items [ 1 .. 20 ] characters ]

List of CDT procedure codes (e.g. ['D0120', 'D1110'])

notes
string <= 2000 characters
Default: ""

Responses

Request samples

Content type

Minimum payload to book an appointment from the patient portal. start_time MUST include a timezone offset -- naive datetimes are rejected with a 400. procedures is optional; if provided, CDT codes are matched against the practice's procedure table.

{
  • "provider": "22222222-2222-4222-8222-222222222222",
  • "operatory": "44444444-4444-4444-8444-444444444444",
  • "start_time": "2026-05-20T10:00:00-07:00",
  • "duration_minutes": 60,
  • "procedures": [
    ],
  • "notes": "First availability in the morning, please."
}

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_portal_appointments_cancel_create

Cancel an appointment as an authenticated patient.

POST /api/v1/practice//portal/appointments//cancel/

Only patient users (is_patient=True) may access this endpoint. The patient record is resolved from the authenticated user's email and must match the appointment's patient. Only appointments in a cancellable state (currently "scheduled") may be cancelled.

An audit-trail AppointmentStatusLog entry is created and an audit event is emitted for HIPAA compliance.

Returns 200 with the updated appointment on success.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
appointment_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
reason
string <= 2000 characters
Default: ""

Patient-supplied reason for cancellation.

reschedule_request
boolean
Default: false

If true, the front desk is notified to reschedule.

Responses

Request samples

Content type

Both fields are optional. reschedule_request=true notifies the front desk to follow up with the patient so the slot can be re-filled and the patient re-booked.

{
  • "reason": "Out of town for work that week.",
  • "reschedule_request": true
}

Response samples

Content type
application/json

Returns the updated appointment with status=cancelled. An AppointmentStatusLog entry is created server-side for the HIPAA audit trail.

{
  • "id": "55555555-5555-4555-8555-555555555555",
  • "provider": "22222222-2222-4222-8222-222222222222",
  • "operatory": "44444444-4444-4444-8444-444444444444",
  • "date_time": "2026-05-20T10:00:00-07:00",
  • "duration_minutes": 60,
  • "status": "cancelled",
  • "cancellation_reason": "Out of town for work that week.",
  • "reschedule_requested": true,
  • "provider_name": "Doe, Dr. John"
}

practice_portal_available_slots_retrieve

Single-day slot finder for the patient portal.

GET /api/v1/practice//portal/available-slots/

Returns slots on a single date, restricted to operatories flagged is_web_sched=True. The response omits operatory identifiers; the patient picks a time, and the booking endpoint chooses a concrete chair server-side.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
date
required
string <date>

Target date (YYYY-MM-DD).

duration_minutes
required
integer

Required appointment length in minutes.

provider
integer

Optional provider ID filter.

Responses

practice_portal_balance_retrieve

Compact balance summary for the patient portal landing page.

GET /api/v1/practice//portal/balance/

Returns:

  • total_balance -- net amount currently owed (positive) or held as credit (negative). Computed from the full ledger.
  • current_charges -- portion of the balance from charges dated within the last _PORTAL_OVERDUE_DAYS days.
  • overdue_charges -- portion of the balance from charges dated more than _PORTAL_OVERDUE_DAYS days ago. Capped at max(0, total_balance).
  • last_payment_date / last_payment_amount -- most recent patient-paid (non-insurance) payment, or null if none.
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json

total_balance is the net amount owed (positive) or held as credit (negative). The balance is split into current_charges (within the last 30 days) and overdue_charges (older than 30 days, never above total_balance). last_payment_* tracks only patient-paid payments -- insurance write-backs are excluded.

{
  • "total_balance": "1035.00",
  • "current_charges": "1035.00",
  • "overdue_charges": "0.00",
  • "last_payment_date": "2026-05-14",
  • "last_payment_amount": "150.00"
}

practice_portal_find_spot_retrieve

Multi-day slot finder for the patient portal.

GET /api/v1/practice//portal/find-spot/

Scans a date range and returns the first matching slots across all web-scheduling-eligible operatories. Search window is capped at 90 days and result count at 20 — both tighter than the staff endpoint.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
duration_minutes
required
integer

Required appointment length in minutes.

end_date
string <date>

Last date to search (default: start_date + 30 days). end_date - start_date must be <= 90 days.

max_results
integer

Maximum slots to return (default 20, max 20).

provider
integer

Optional provider ID filter.

start_date
string <date>

First date to search (default: today).

Responses

practice_portal_ledger_retrieve

Patient's ledger showing charges, payments, adjustments, and running balance.

GET /api/v1/practice//portal/ledger/

Returns a paginated, date-descending list of ledger entries. The running balance is computed across the full ledger (oldest-first) before paginating so each page's balance_after is correct regardless of which page is requested.

Only the authenticated patient's own data is returned.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

1-based page number (default 1).

page_size
integer

Rows per page (default 20, max 100).

Responses

Response samples

Content type
application/json

Ledger entries are sorted oldest-first so running_balance reads like a check register. balance at the envelope level is the net amount the patient currently owes (positive means the practice is owed money; negative means the patient has a credit).

{
  • "entries": [
    ],
  • "balance": "1035.00"
}

practice_portal_message_list

List or send messages for the authenticated patient.

Only patient users (is_patient=True) may access this endpoint. Messages are scoped to the practice in the URL and the authenticated user.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json

Typical response for a patient checking their inbox. Results are ordered newest-first by created and wrapped in the project-wide paginator envelope (count, next, previous, results).

{
  • "count": 123,
  • "results": [
    ]
}

practice_portal_message_create

List or send messages for the authenticated patient.

Only patient users (is_patient=True) may access this endpoint. Messages are scoped to the practice in the URL and the authenticated user.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
subject
required
string [ 1 .. 255 ] characters
body
required
string non-empty
is_read
boolean
custom_data
any

Responses

Request samples

Content type

Only subject and body are writable -- patient, practice and is_from_patient are server-set from the authenticated user and URL scope.

{
  • "subject": "Question about my upcoming cleaning",
  • "body": "Hi! Is it OK to drink coffee the morning of my cleaning appointment?"
}

Response samples

Content type
application/json

Full message record with server-assigned id, patient, practice, and timestamp.

{
  • "id": "cccccccc-cccc-4ccc-8ccc-cccccccccccc",
  • "patient": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
  • "practice": "99999999-9999-4999-8999-999999999999",
  • "subject": "Question about my upcoming cleaning",
  • "body": "Hi! Is it OK to drink coffee the morning of my cleaning appointment?",
  • "is_from_patient": true,
  • "is_read": false,
  • "created": "2026-05-10T14:22:08Z",
  • "custom_data": { }
}

practice_portal_message_retrieve

Retrieve a single portal message.

Practice-scoped and patient-scoped.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
message_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json

Same shape as the list entries. Fetching a message marks it viewed for audit purposes.

{
  • "id": "dddddddd-dddd-4ddd-8ddd-dddddddddddd",
  • "patient": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
  • "practice": "99999999-9999-4999-8999-999999999999",
  • "subject": "Re: Question about my upcoming cleaning",
  • "body": "Coffee is fine! Please just avoid eating within 30 minutes of your appointment.",
  • "is_from_patient": false,
  • "is_read": true,
  • "created": "2026-05-10T16:03:41Z",
  • "custom_data": { }
}

practice_portal_payment_methods_retrieve

List the patient's saved Stripe payment methods.

GET /api/v1/practice//portal/payment-methods/

Returns a sanitized shape — only brand / last4 / expiry are exposed to the frontend. When the patient has no Stripe Customer yet (never saved a card) we return an empty list rather than 404 so the UI can render its "no saved cards" empty state without special-casing.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "results": [
    ]
}

practice_portal_payment_methods_destroy

Detach a single saved payment method.

DELETE /api/v1/practice//portal/payment-methods//

Verifies the payment method belongs to the authenticated patient's Stripe Customer before detaching — without this check, a malicious portal user could detach another patient's card by guessing pm_xxx ids.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
pm_id
required
string
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_portal_payments_list

List patient-paid payment history for the authenticated patient.

Insurance-source payments (pay_type classified as insurance) are filtered out — patient-portal callers want their own out-of-pocket payments, not EOB write-backs. The ledger endpoint surfaces insurance payments separately.

Paginated via :class:StandardPageNumberPagination so a long history doesn't ship in a single response.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json

The patient sees only their own payments in this practice. pay_type is stable (online_patient_portal for portal-posted payments); Stripe processing is stubbed today and will land once the BAA is finalised.

[
  • [
    ]
]

practice_portal_payments_create

Record a patient payment from the portal — charge-then-persist.

The flow is:

  1. Validate the payload.
  2. If a Stripe payment_method token was supplied, create a confirmed off-session PaymentIntent server-side so the card is charged before we persist anything. A failure here returns 402 PAYMENT_REQUIRED with the sanitized Stripe error — no PaymentRecord is written.
  3. Only after a successful charge (or a non-Stripe payload — for e.g. the initial post-deploy window when STRIPE_SECRET_KEY is unset) do we persist the PaymentRecord.

503 SERVICE_UNAVAILABLE is returned when a payment_method is supplied but Stripe creds are missing — the frontend treats this as "payments not yet enabled in this environment" rather than a bug.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
amount
required
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Payment amount in dollars (e.g. 150.00).

payment_method
string <= 255 characters
Default: ""

Stripe payment method token (not processed yet).

notes
string <= 500 characters
Default: ""

Optional note for the payment (e.g. 'Co-pay for cleaning').

Responses

Request samples

Content type

amount is required and must be positive. payment_method is accepted today (Stripe PM token) but deferred until the BAA is finalised -- no card is charged yet, the PaymentRecord is written directly.

{
  • "amount": "150.00",
  • "payment_method": "pm_synthetic_placeholder",
  • "notes": "Co-pay for cleaning"
}

Response samples

Content type
application/json

Returns the freshly created PaymentRecord in the same shape used by the list endpoint.

{
  • "id": "cdcdcdcd-cdcd-4dcd-8dcd-cdcdcdcdcdcd",
  • "pay_date": "2026-05-14",
  • "pay_amount": "150.00",
  • "pay_type": "online_patient_portal",
  • "pay_note": "Co-pay for cleaning",
  • "created": "2026-05-14T18:02:19Z"
}

practice_portal_setup_intents_create

Create a Stripe SetupIntent so the patient can save a card.

POST /api/v1/practice//portal/setup-intents/

Returns client_secret for the frontend to call stripe.confirmSetup with. The Stripe Customer is created on demand so the row only exists once the patient actually saves a card.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "client_secret": "string",
  • "setup_intent_id": "string",
  • "customer_id": "string"
}

Patient Submissions (Public)

portal_submission_create

Submit patient intake data via a one-time invite token.

POST /api/v1/portal/submission//

No authentication required. The token must be valid, not expired, and not already used. Stores the submitted data and marks the submission as submitted.

Authorizations:
bearerAuthoauth2
path Parameters
token
required
string
Request Body schema:
required
submitted_data
required
any

Patient intake data (demographics, etc.).

Responses

Request samples

Content type

Public endpoint -- no authentication. The invite token in the URL authorises the write. submitted_data is an open JSON envelope; the practice's intake form decides its shape.

{
  • "submitted_data": {
    }
}

Response samples

Content type
application/json

The token is now marked used; replaying it returns 410 Gone.

{
  • "detail": "Submission received."
}

practice

practice_list

List practices (admin-only).

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_bulk_procedure_code_destroy

Bulk delete, skipping any client-managed rows.

Client-managed rows are excluded from the delete queryset before execution. The response reports both how many were deleted and how many were skipped so operators can audit enforcement coverage.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_business_hours_retrieve

Retrieve, update, or delete a single business-hours row.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
hours_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "day_of_week": -2147483648,
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_business_hours_update

Retrieve, update, or delete a single business-hours row.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
hours_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
day_of_week
required
integer [ -2147483648 .. 2147483647 ]

0=Sunday, 1=Monday, ..., 6=Saturday

start_time
required
string <time>

Open time (practice-local).

end_time
required
string <time>

Close time (practice-local).

is_active
boolean

Inactive rows are ignored by the slot finder; soft-disable lets staff preserve historical hours without deleting the row.

Responses

Request samples

Content type
{
  • "day_of_week": -2147483648,
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "day_of_week": -2147483648,
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_business_hours_partial_update

Retrieve, update, or delete a single business-hours row.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
hours_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
day_of_week
integer [ -2147483648 .. 2147483647 ]

0=Sunday, 1=Monday, ..., 6=Saturday

start_time
string <time>

Open time (practice-local).

end_time
string <time>

Close time (practice-local).

is_active
boolean

Inactive rows are ignored by the slot finder; soft-disable lets staff preserve historical hours without deleting the row.

Responses

Request samples

Content type
{
  • "day_of_week": -2147483648,
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "day_of_week": -2147483648,
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_business_hours_destroy

Retrieve, update, or delete a single business-hours row.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
hours_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_clinical_note_template_retrieve

Retrieve, update, or delete a clinical note template.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
note_template_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "category": "exam",
  • "content": "string",
  • "is_active": true,
  • "sort_order": 2147483647,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_clinical_note_template_update

Retrieve, update, or delete a clinical note template.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
note_template_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 255 ] characters
CategoryEnum (string) or BlankEnum (any)
content
required
string non-empty

Template body. Supports placeholder tokens like {{tooth}}, {{provider}}.

is_active
boolean
sort_order
integer [ 0 .. 2147483647 ]
custom_data
any

Responses

Request samples

Content type
{
  • "name": "string",
  • "category": "exam",
  • "content": "string",
  • "is_active": true,
  • "sort_order": 2147483647,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "category": "exam",
  • "content": "string",
  • "is_active": true,
  • "sort_order": 2147483647,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_clinical_note_template_partial_update

Retrieve, update, or delete a clinical note template.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
note_template_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
name
string [ 1 .. 255 ] characters
CategoryEnum (string) or BlankEnum (any)
content
string non-empty

Template body. Supports placeholder tokens like {{tooth}}, {{provider}}.

is_active
boolean
sort_order
integer [ 0 .. 2147483647 ]
custom_data
any

Responses

Request samples

Content type
{
  • "name": "string",
  • "category": "exam",
  • "content": "string",
  • "is_active": true,
  • "sort_order": 2147483647,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "category": "exam",
  • "content": "string",
  • "is_active": true,
  • "sort_order": 2147483647,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_clinical_note_template_destroy

Retrieve, update, or delete a clinical note template.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
note_template_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_clinical_procedure_partial_update

Handle PATCH on the list endpoint for bulk updates.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
custom_data
any

Responses

Request samples

Content type
{
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "procedure_code": {
    },
  • "proc_code": "string",
  • "description": "string",
  • "proc_date": "2019-08-24",
  • "date_complete": "2019-08-24",
  • "proc_fee": "string",
  • "status": "string",
  • "tooth_num": "string",
  • "surface": "string",
  • "discount": "string",
  • "unit_qty": 0,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_clinical_procedure_code_retrieve

Retrieve, update, or delete a procedure code.

Lock enforcement (api#926)

Rows where is_client_managed is True (i.e. client_service_code FK is non-NULL) are locked. Any PUT/PATCH or DELETE from the practice on a locked row is rejected with HTTP 403. Client-level OWNER users can still modify the originating :class:ClientServiceCode via the client service-code endpoint; changes propagate via the enforcement task.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
procedure_code_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "code": "string",
  • "description": "string",
  • "abbreviation": "string",
  • "service_type": "diagnostic",
  • "default_fee": "string",
  • "default_duration_minutes": 2147483647,
  • "generate_recall": true,
  • "is_active": true,
  • "ada_code": "string",
  • "is_client_managed": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_clinical_procedure_code_update

Retrieve, update, or delete a procedure code.

Lock enforcement (api#926)

Rows where is_client_managed is True (i.e. client_service_code FK is non-NULL) are locked. Any PUT/PATCH or DELETE from the practice on a locked row is rejected with HTTP 403. Client-level OWNER users can still modify the originating :class:ClientServiceCode via the client service-code endpoint; changes propagate via the enforcement task.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
procedure_code_uid
required
string <uuid>
Request Body schema:
required
code
required
string [ 1 .. 20 ] characters
description
string <= 255 characters
abbreviation
string <= 100 characters
ServiceTypeEnum (string) or BlankEnum (any)
default_fee
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Practice UCR fee

default_duration_minutes
integer [ 0 .. 2147483647 ]

Default appointment block size

generate_recall
boolean

Triggers recall scheduling when completed

is_active
boolean
ada_code
string <= 20 characters

ADA/CDT code reference (insurance module)

custom_data
any

Responses

Request samples

Content type
{
  • "code": "string",
  • "description": "string",
  • "abbreviation": "string",
  • "service_type": "diagnostic",
  • "default_fee": "string",
  • "default_duration_minutes": 2147483647,
  • "generate_recall": true,
  • "is_active": true,
  • "ada_code": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "code": "string",
  • "description": "string",
  • "abbreviation": "string",
  • "service_type": "diagnostic",
  • "default_fee": "string",
  • "default_duration_minutes": 2147483647,
  • "generate_recall": true,
  • "is_active": true,
  • "ada_code": "string",
  • "is_client_managed": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_clinical_procedure_code_partial_update

Retrieve, update, or delete a procedure code.

Lock enforcement (api#926)

Rows where is_client_managed is True (i.e. client_service_code FK is non-NULL) are locked. Any PUT/PATCH or DELETE from the practice on a locked row is rejected with HTTP 403. Client-level OWNER users can still modify the originating :class:ClientServiceCode via the client service-code endpoint; changes propagate via the enforcement task.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
procedure_code_uid
required
string <uuid>
Request Body schema:
code
string [ 1 .. 20 ] characters
description
string <= 255 characters
abbreviation
string <= 100 characters
ServiceTypeEnum (string) or BlankEnum (any)
default_fee
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Practice UCR fee

default_duration_minutes
integer [ 0 .. 2147483647 ]

Default appointment block size

generate_recall
boolean

Triggers recall scheduling when completed

is_active
boolean
ada_code
string <= 20 characters

ADA/CDT code reference (insurance module)

custom_data
any

Responses

Request samples

Content type
{
  • "code": "string",
  • "description": "string",
  • "abbreviation": "string",
  • "service_type": "diagnostic",
  • "default_fee": "string",
  • "default_duration_minutes": 2147483647,
  • "generate_recall": true,
  • "is_active": true,
  • "ada_code": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "code": "string",
  • "description": "string",
  • "abbreviation": "string",
  • "service_type": "diagnostic",
  • "default_fee": "string",
  • "default_duration_minutes": 2147483647,
  • "generate_recall": true,
  • "is_active": true,
  • "ada_code": "string",
  • "is_client_managed": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_clinical_procedure_code_destroy

Retrieve, update, or delete a procedure code.

Lock enforcement (api#926)

Rows where is_client_managed is True (i.e. client_service_code FK is non-NULL) are locked. Any PUT/PATCH or DELETE from the practice on a locked row is rejected with HTTP 403. Client-level OWNER users can still modify the originating :class:ClientServiceCode via the client service-code endpoint; changes propagate via the enforcement task.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
procedure_code_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_comms_commlog_partial_update

Handle PATCH on the list endpoint for bulk updates.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
patient
string or null <uuid>
date_time
string or null <date-time>
mode
string (ModeEnum)
Enum: "phone" "email" "text" "fax" "mail" "in_person" "web" "other"
  • phone - Phone
  • email - Email
  • text - Text
  • fax - Fax
  • mail - Mail
  • in_person - In Person
  • web - Web
  • other - Other
direction
string (Direction80cEnum)
Enum: "sent" "received" "neither"
  • sent - Sent
  • received - Received
  • neither - Neither
outcome
string
Enum: "success" "no_answer" "voicemail" "bounced" "bad_number" "other"

What happened on the contact attempt. Only success rows count toward the recall-list last_reached_at annotation.

  • success - Success
  • no_answer - No Answer
  • voicemail - Voicemail
  • bounced - Bounced
  • bad_number - Bad Number
  • other - Other
subject
string <= 255 characters

Short label, e.g. 'Recall reminder', 'Treatment plan follow-up'.

note
string
staff_user
string or null <uuid>

Staff member who logged the contact. Null for system-generated entries.

recall
string or null <uuid>

Optional link to the specific recall this contact addresses.

is_imported
boolean

True if this row was imported from a legacy PMS (escape-opendental, escape-eaglesoft, ...) rather than created natively in Escape. Imported rows may carry PHI in the note body that pre-dates the Escape BAA / no-PHI-in-comms policy (GH-575); clients must NOT expose 'resend' or 'use as template' affordances on imported rows, and any future send endpoint that takes a replicate_of_commlog_id MUST refuse imported sources.

custom_data
any

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "date_time": "2019-08-24T14:15:22Z",
  • "mode": "phone",
  • "direction": "sent",
  • "outcome": "success",
  • "subject": "string",
  • "note": "string",
  • "staff_user": "17986289-b0ef-402a-92d5-49bc6fa3367e",
  • "recall": "e7ef6ec4-8466-4387-af6a-2ed34de604a8",
  • "is_imported": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "date_time": "2019-08-24T14:15:22Z",
  • "mode": "phone",
  • "direction": "sent",
  • "outcome": "success",
  • "subject": "string",
  • "note": "string",
  • "staff_user": "17986289-b0ef-402a-92d5-49bc6fa3367e",
  • "recall": "e7ef6ec4-8466-4387-af6a-2ed34de604a8",
  • "is_imported": true,
  • "custom_data": null
}

practice_doccenter_category_list

List system + practice categories; POST creates a practice-custom category.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{}

practice_doccenter_category_create

List system + practice categories; POST creates a practice-custom category.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
slug
required
string [ 1 .. 50 ] characters ^[-a-zA-Z0-9_]+$
label
required
string [ 1 .. 100 ] characters
icon
string <= 50 characters

Lucide icon name

sort_order
integer [ 0 .. 32767 ]
custom_data
any

Responses

Request samples

Content type
{
  • "slug": "string",
  • "label": "string",
  • "icon": "string",
  • "sort_order": 32767,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "slug": "string",
  • "label": "string",
  • "icon": "string",
  • "sort_order": 32767,
  • "custom_data": null
}

practice_doccenter_category_retrieve

Update/delete practice-custom categories only.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
category_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "slug": "string",
  • "label": "string",
  • "icon": "string",
  • "sort_order": 32767,
  • "custom_data": null
}

practice_doccenter_category_update

Update/delete practice-custom categories only.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
category_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
slug
required
string [ 1 .. 50 ] characters ^[-a-zA-Z0-9_]+$
label
required
string [ 1 .. 100 ] characters
icon
string <= 50 characters

Lucide icon name

sort_order
integer [ 0 .. 32767 ]
custom_data
any

Responses

Request samples

Content type
{
  • "slug": "string",
  • "label": "string",
  • "icon": "string",
  • "sort_order": 32767,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "slug": "string",
  • "label": "string",
  • "icon": "string",
  • "sort_order": 32767,
  • "custom_data": null
}

practice_doccenter_category_partial_update

Update/delete practice-custom categories only.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
category_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
slug
string [ 1 .. 50 ] characters ^[-a-zA-Z0-9_]+$
label
string [ 1 .. 100 ] characters
icon
string <= 50 characters

Lucide icon name

sort_order
integer [ 0 .. 32767 ]
custom_data
any

Responses

Request samples

Content type
{
  • "slug": "string",
  • "label": "string",
  • "icon": "string",
  • "sort_order": 32767,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "slug": "string",
  • "label": "string",
  • "icon": "string",
  • "sort_order": 32767,
  • "custom_data": null
}

practice_doccenter_category_destroy

Update/delete practice-custom categories only.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
category_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_doccenter_document_retrieve

Retrieve or update document metadata.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
doc_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "category": "86d23d13-9dbb-46f3-82d0-25253c7750c3",
  • "referral": "0ff1dce1-5a61-425e-b768-f89c7726a65e",
  • "title": "string",
  • "description": "string",
  • "original_filename": "string",
  • "mime_type": "string",
  • "file_size": 0,
  • "page_count": 0,
  • "uploaded_by": "e134ce2c-a199-4e99-9c11-627b70a7ff28",
  • "source_application": 0,
  • "is_deleted": true,
  • "deleted_at": "2019-08-24T14:15:22Z",
  • "deleted_by": "d7d7cfa2-327b-4733-8887-d09252b40b06",
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "resolved_by": "d0d57369-b08b-4db8-8952-8cdeedd9aebc",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "download_url": "string",
  • "patient_name": "string",
  • "category_label": "string",
  • "uploaded_by_name": "string",
  • "caller_id": "string",
  • "processing_state": "pending",
  • "processing_error": "string",
  • "processing_updated_at": "2019-08-24T14:15:22Z",
  • "transcript": "string",
  • "transcript_confidence": "string",
  • "av_status": "pending",
  • "av_scanned_at": "2019-08-24T14:15:22Z",
  • "av_scanner": "string",
  • "av_threat_name": "string",
  • "suggested_patient_ids": [
    ],
  • "custom_data": null
}

practice_doccenter_document_update

Retrieve or update document metadata.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
doc_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
patient
string or null <uuid>
category
string or null <uuid>
referral
string or null <uuid>
title
required
string [ 1 .. 255 ] characters
description
string
caller_id
string <= 32 characters ^\+\d{1,15}$

E.164 caller-ID for voicemail recordings (e.g. +14155551234). Used by the patient-link suggestion engine downstream of the voicemail-to-text pipeline.

custom_data
any

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "category": "86d23d13-9dbb-46f3-82d0-25253c7750c3",
  • "referral": "0ff1dce1-5a61-425e-b768-f89c7726a65e",
  • "title": "string",
  • "description": "string",
  • "caller_id": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "category": "86d23d13-9dbb-46f3-82d0-25253c7750c3",
  • "referral": "0ff1dce1-5a61-425e-b768-f89c7726a65e",
  • "title": "string",
  • "description": "string",
  • "original_filename": "string",
  • "mime_type": "string",
  • "file_size": 0,
  • "page_count": 0,
  • "uploaded_by": "e134ce2c-a199-4e99-9c11-627b70a7ff28",
  • "source_application": 0,
  • "is_deleted": true,
  • "deleted_at": "2019-08-24T14:15:22Z",
  • "deleted_by": "d7d7cfa2-327b-4733-8887-d09252b40b06",
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "resolved_by": "d0d57369-b08b-4db8-8952-8cdeedd9aebc",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "download_url": "string",
  • "patient_name": "string",
  • "category_label": "string",
  • "uploaded_by_name": "string",
  • "caller_id": "string",
  • "processing_state": "pending",
  • "processing_error": "string",
  • "processing_updated_at": "2019-08-24T14:15:22Z",
  • "transcript": "string",
  • "transcript_confidence": "string",
  • "av_status": "pending",
  • "av_scanned_at": "2019-08-24T14:15:22Z",
  • "av_scanner": "string",
  • "av_threat_name": "string",
  • "suggested_patient_ids": [
    ],
  • "custom_data": null
}

practice_doccenter_document_partial_update

Retrieve or update document metadata.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
doc_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
patient
string or null <uuid>
category
string or null <uuid>
referral
string or null <uuid>
title
string [ 1 .. 255 ] characters
description
string
caller_id
string <= 32 characters ^\+\d{1,15}$

E.164 caller-ID for voicemail recordings (e.g. +14155551234). Used by the patient-link suggestion engine downstream of the voicemail-to-text pipeline.

custom_data
any

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "category": "86d23d13-9dbb-46f3-82d0-25253c7750c3",
  • "referral": "0ff1dce1-5a61-425e-b768-f89c7726a65e",
  • "title": "string",
  • "description": "string",
  • "caller_id": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "category": "86d23d13-9dbb-46f3-82d0-25253c7750c3",
  • "referral": "0ff1dce1-5a61-425e-b768-f89c7726a65e",
  • "title": "string",
  • "description": "string",
  • "original_filename": "string",
  • "mime_type": "string",
  • "file_size": 0,
  • "page_count": 0,
  • "uploaded_by": "e134ce2c-a199-4e99-9c11-627b70a7ff28",
  • "source_application": 0,
  • "is_deleted": true,
  • "deleted_at": "2019-08-24T14:15:22Z",
  • "deleted_by": "d7d7cfa2-327b-4733-8887-d09252b40b06",
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "resolved_by": "d0d57369-b08b-4db8-8952-8cdeedd9aebc",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "download_url": "string",
  • "patient_name": "string",
  • "category_label": "string",
  • "uploaded_by_name": "string",
  • "caller_id": "string",
  • "processing_state": "pending",
  • "processing_error": "string",
  • "processing_updated_at": "2019-08-24T14:15:22Z",
  • "transcript": "string",
  • "transcript_confidence": "string",
  • "av_status": "pending",
  • "av_scanned_at": "2019-08-24T14:15:22Z",
  • "av_scanner": "string",
  • "av_threat_name": "string",
  • "suggested_patient_ids": [
    ],
  • "custom_data": null
}

practice_doccenter_inbox_list

List inbox items for this practice.

Practice Inbox (escape#151) renders three tabs — Documents (emailed in), Voicemails, and Faxes — each backed by a single-source list query. The ?source= filter lets the web client pull just the rows it needs per tab without round-tripping every pending item and filtering client-side.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_doccenter_inbox_retrieve

View or update inbox item (title, notes).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
inbox_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "original_filename": "string",
  • "mime_type": "string",
  • "file_size": 0,
  • "title": "string",
  • "notes": "string",
  • "source": "web",
  • "inbound_email": "e4185790-fbc9-4897-be5d-ea0372f36408",
  • "uploaded_by": "e134ce2c-a199-4e99-9c11-627b70a7ff28",
  • "source_application": 0,
  • "expires_at": "2019-08-24T14:15:22Z",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "download_url": "string",
  • "uploaded_by_name": "string",
  • "source_application_name": "string",
  • "av_status": "pending",
  • "av_scanned_at": "2019-08-24T14:15:22Z",
  • "av_scanner": "string",
  • "av_threat_name": "string",
  • "custom_data": null
}

practice_doccenter_inbox_update

View or update inbox item (title, notes).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
inbox_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
title
string <= 255 characters
notes
string

Staff notes during triage

custom_data
any

Responses

Request samples

Content type
{
  • "title": "string",
  • "notes": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "original_filename": "string",
  • "mime_type": "string",
  • "file_size": 0,
  • "title": "string",
  • "notes": "string",
  • "source": "web",
  • "inbound_email": "e4185790-fbc9-4897-be5d-ea0372f36408",
  • "uploaded_by": "e134ce2c-a199-4e99-9c11-627b70a7ff28",
  • "source_application": 0,
  • "expires_at": "2019-08-24T14:15:22Z",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "download_url": "string",
  • "uploaded_by_name": "string",
  • "source_application_name": "string",
  • "av_status": "pending",
  • "av_scanned_at": "2019-08-24T14:15:22Z",
  • "av_scanner": "string",
  • "av_threat_name": "string",
  • "custom_data": null
}

practice_doccenter_inbox_partial_update

View or update inbox item (title, notes).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
inbox_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
title
string <= 255 characters
notes
string

Staff notes during triage

custom_data
any

Responses

Request samples

Content type
{
  • "title": "string",
  • "notes": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "original_filename": "string",
  • "mime_type": "string",
  • "file_size": 0,
  • "title": "string",
  • "notes": "string",
  • "source": "web",
  • "inbound_email": "e4185790-fbc9-4897-be5d-ea0372f36408",
  • "uploaded_by": "e134ce2c-a199-4e99-9c11-627b70a7ff28",
  • "source_application": 0,
  • "expires_at": "2019-08-24T14:15:22Z",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "download_url": "string",
  • "uploaded_by_name": "string",
  • "source_application_name": "string",
  • "av_status": "pending",
  • "av_scanned_at": "2019-08-24T14:15:22Z",
  • "av_scanner": "string",
  • "av_threat_name": "string",
  • "custom_data": null
}

practice_email_messages_retrieve

Retrieve a single email row.

Read-only -- there's no legitimate reason to PATCH a message row in place. Status changes flow through the (future) Anymail DLR webhook handler, not the user-facing API.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
message_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "direction": "inbound",
  • "from_address": "user@example.com",
  • "to_address": "user@example.com",
  • "subject": "string",
  • "body": "string",
  • "mailgun_message_id": "string",
  • "status": "queued",
  • "error_message": "string",
  • "phi_blocked": true,
  • "sent_at": "2019-08-24T14:15:22Z",
  • "delivered_at": "2019-08-24T14:15:22Z",
  • "received_at": "2019-08-24T14:15:22Z",
  • "sent_by": "40cc1a1c-5bda-4c73-bb08-df4a7613e4ee",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_faxes_retrieve

Retrieve a single fax row, including a signed download URL.

Read-only — there's no legitimate reason to PATCH a fax row in place. Status changes flow through the webhook handler, not the user-facing API.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
fax_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "direction": "inbound",
  • "from_number": "string",
  • "to_number": "string",
  • "page_count": 0,
  • "status": "queued",
  • "sinch_fax_id": "string",
  • "document_url": "string",
  • "error_message": "string",
  • "completed_at": "2019-08-24T14:15:22Z",
  • "sent_by": "40cc1a1c-5bda-4c73-bb08-df4a7613e4ee",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "practice_link": true,
  • "filed_at": "2019-08-24T14:15:22Z",
  • "filed_by": "011b59c1-1189-4a11-87df-fa9753db2861",
  • "discarded_at": "2019-08-24T14:15:22Z",
  • "discarded_by": "69474e1d-c497-4e9d-9f07-e93914ef0818",
  • "av_status": "pending",
  • "av_scanned_at": "2019-08-24T14:15:22Z",
  • "av_scanner": "string",
  • "av_threat_name": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_imaging_image_template_list

List + create per-Client :class:ImageTemplate rows (api#815).

Reads are open to any practice staff (the New Exam dialog lists templates); writes require OFFICE_MANAGER or above (web#927) -- :class:IsManagerOrAbove only enforces its role list on unsafe methods.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_imaging_image_template_create

List + create per-Client :class:ImageTemplate rows (api#815).

Reads are open to any practice staff (the New Exam dialog lists templates); writes require OFFICE_MANAGER or above (web#927) -- :class:IsManagerOrAbove only enforces its role list on unsafe methods.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 255 ] characters

Human-friendly name, e.g. 'FMX-18', 'BWX-4', 'PA-1', 'Pano-1'.

description
string
slot_count
required
integer [ 0 .. 32767 ]

Number of image slots in this template.

slot_positions
any

Slot rectangles in percent of the template canvas: a list of {"x": float, "y": float, "w": float, "h": float} objects where each value is 0-100. Each entry may carry an optional "label" string (max 32 chars) naming the slot, e.g. "UR PA Molar" or "BW R Molar". Length should equal slot_count; entries beyond slot_count are ignored.

is_active
boolean
custom_data
any

Responses

Request samples

Content type
{
  • "name": "string",
  • "description": "string",
  • "slot_count": 32767,
  • "slot_positions": null,
  • "is_active": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "description": "string",
  • "slot_count": 32767,
  • "slot_positions": null,
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_imaging_image_template_retrieve

Retrieve / update / delete a single :class:ImageTemplate (api#815).

Reads for any staff; writes require OFFICE_MANAGER or above (web#927).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "description": "string",
  • "slot_count": 32767,
  • "slot_positions": null,
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_imaging_image_template_update

Retrieve / update / delete a single :class:ImageTemplate (api#815).

Reads for any staff; writes require OFFICE_MANAGER or above (web#927).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 255 ] characters

Human-friendly name, e.g. 'FMX-18', 'BWX-4', 'PA-1', 'Pano-1'.

description
string
slot_count
required
integer [ 0 .. 32767 ]

Number of image slots in this template.

slot_positions
any

Slot rectangles in percent of the template canvas: a list of {"x": float, "y": float, "w": float, "h": float} objects where each value is 0-100. Each entry may carry an optional "label" string (max 32 chars) naming the slot, e.g. "UR PA Molar" or "BW R Molar". Length should equal slot_count; entries beyond slot_count are ignored.

is_active
boolean
custom_data
any

Responses

Request samples

Content type
{
  • "name": "string",
  • "description": "string",
  • "slot_count": 32767,
  • "slot_positions": null,
  • "is_active": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "description": "string",
  • "slot_count": 32767,
  • "slot_positions": null,
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_imaging_image_template_partial_update

Retrieve / update / delete a single :class:ImageTemplate (api#815).

Reads for any staff; writes require OFFICE_MANAGER or above (web#927).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_uid
required
string <uuid>
Request Body schema:
name
string [ 1 .. 255 ] characters

Human-friendly name, e.g. 'FMX-18', 'BWX-4', 'PA-1', 'Pano-1'.

description
string
slot_count
integer [ 0 .. 32767 ]

Number of image slots in this template.

slot_positions
any

Slot rectangles in percent of the template canvas: a list of {"x": float, "y": float, "w": float, "h": float} objects where each value is 0-100. Each entry may carry an optional "label" string (max 32 chars) naming the slot, e.g. "UR PA Molar" or "BW R Molar". Length should equal slot_count; entries beyond slot_count are ignored.

is_active
boolean
custom_data
any

Responses

Request samples

Content type
{
  • "name": "string",
  • "description": "string",
  • "slot_count": 32767,
  • "slot_positions": null,
  • "is_active": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "description": "string",
  • "slot_count": 32767,
  • "slot_positions": null,
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_imaging_image_template_destroy

Retrieve / update / delete a single :class:ImageTemplate (api#815).

Reads for any staff; writes require OFFICE_MANAGER or above (web#927).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_imaging_mount_list

List mounts in a practice and create new mounts from a template.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_imaging_mount_create

List mounts in a practice and create new mounts from a template.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>
exam
string or null <uuid>

Optional ImageExam the mount was initialised from (api#834).

template
required
string <uuid>
name
string <= 255 characters

Optional user-supplied label.

notes
string
custom_data
any

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "exam": "76d06126-4ce7-4fb4-98c2-d484d7e9ee38",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "name": "string",
  • "notes": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "exam": "76d06126-4ce7-4fb4-98c2-d484d7e9ee38",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "template_code": "string",
  • "template_name": "string",
  • "name": "string",
  • "notes": "string",
  • "slots": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_imaging_mount_template_list

List canonical mount templates (FMX-18, BW-4, Pano, etc.).

Templates are not practice-scoped (they're industry standards) but the endpoint is mounted under the practice URL so access control still runs through PracticeScopedMixin.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{}

practice_imaging_mount_retrieve

Retrieve, update metadata on, or delete a mount.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
mount_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "exam": "76d06126-4ce7-4fb4-98c2-d484d7e9ee38",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "template_code": "string",
  • "template_name": "string",
  • "name": "string",
  • "notes": "string",
  • "slots": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_imaging_mount_update

Retrieve, update metadata on, or delete a mount.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
mount_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>
exam
string or null <uuid>

Optional ImageExam the mount was initialised from (api#834).

template
required
string <uuid>
name
string <= 255 characters

Optional user-supplied label.

notes
string
custom_data
any

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "exam": "76d06126-4ce7-4fb4-98c2-d484d7e9ee38",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "name": "string",
  • "notes": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "exam": "76d06126-4ce7-4fb4-98c2-d484d7e9ee38",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "template_code": "string",
  • "template_name": "string",
  • "name": "string",
  • "notes": "string",
  • "slots": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_imaging_mount_partial_update

Retrieve, update metadata on, or delete a mount.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
mount_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
patient
string <uuid>
exam
string or null <uuid>

Optional ImageExam the mount was initialised from (api#834).

template
string <uuid>
name
string <= 255 characters

Optional user-supplied label.

notes
string
custom_data
any

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "exam": "76d06126-4ce7-4fb4-98c2-d484d7e9ee38",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "name": "string",
  • "notes": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "exam": "76d06126-4ce7-4fb4-98c2-d484d7e9ee38",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "template_code": "string",
  • "template_name": "string",
  • "name": "string",
  • "notes": "string",
  • "slots": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_imaging_mount_destroy

Retrieve, update metadata on, or delete a mount.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
mount_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_imaging_mount_slot_update

Update a single slot on a mount (assign/unassign image, rotate, flip).

Looked up by (mount_uid, slot_index). PATCH is the primary verb; PUT is supported for completeness but requires all updatable fields.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
mount_uid
required
string <uuid>
practice_uid
required
string <uuid>
slot_index
required
integer
Request Body schema:
image
string or null <uuid>
rotation
integer [ 0 .. 2147483647 ]

Display rotation in degrees: 0, 90, 180 or 270.

flipped
boolean

Horizontal flip.

label
string <= 255 characters
custom_data
any

Responses

Request samples

Content type
{
  • "image": "89f204d4-24d2-439a-b6e8-e97405cb1f8e",
  • "rotation": 2147483647,
  • "flipped": true,
  • "label": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "slot_index": 0,
  • "image": "89f204d4-24d2-439a-b6e8-e97405cb1f8e",
  • "rotation": 2147483647,
  • "flipped": true,
  • "label": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_imaging_mount_slot_partial_update

Update a single slot on a mount (assign/unassign image, rotate, flip).

Looked up by (mount_uid, slot_index). PATCH is the primary verb; PUT is supported for completeness but requires all updatable fields.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
mount_uid
required
string <uuid>
practice_uid
required
string <uuid>
slot_index
required
integer
Request Body schema:
image
string or null <uuid>
rotation
integer [ 0 .. 2147483647 ]

Display rotation in degrees: 0, 90, 180 or 270.

flipped
boolean

Horizontal flip.

label
string <= 255 characters
custom_data
any

Responses

Request samples

Content type
{
  • "image": "89f204d4-24d2-439a-b6e8-e97405cb1f8e",
  • "rotation": 2147483647,
  • "flipped": true,
  • "label": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "slot_index": 0,
  • "image": "89f204d4-24d2-439a-b6e8-e97405cb1f8e",
  • "rotation": 2147483647,
  • "flipped": true,
  • "label": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_insurance_carrier_retrieve

Retrieve, update, or deactivate an insurance carrier.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
carrier_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "phone": "string",
  • "website": "http://example.com",
  • "address_line1": "string",
  • "address_line2": "string",
  • "city": "string",
  • "state": "st",
  • "zip_code": "string",
  • "payer_id": "string",
  • "claim_office_id": "string",
  • "hpid": "string",
  • "payment_source": "string",
  • "notes": "string",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_insurance_carrier_update

Retrieve, update, or deactivate an insurance carrier.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
carrier_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 255 ] characters
phone
string <= 20 characters
website
string <uri> <= 200 characters
address_line1
string <= 255 characters
address_line2
string <= 255 characters
city
string <= 100 characters
state
string <= 2 characters
zip_code
string <= 10 characters
payer_id
string <= 50 characters

EDI payer ID for clearinghouse submission

claim_office_id
string <= 50 characters

Separate claim submission office ID

hpid
string <= 50 characters

Health Plan Identifier

payment_source
string <= 50 characters

check, eft, virtual_card

notes
string
is_active
boolean
custom_data
any

Responses

Request samples

Content type
{
  • "name": "string",
  • "phone": "string",
  • "website": "http://example.com",
  • "address_line1": "string",
  • "address_line2": "string",
  • "city": "string",
  • "state": "st",
  • "zip_code": "string",
  • "payer_id": "string",
  • "claim_office_id": "string",
  • "hpid": "string",
  • "payment_source": "string",
  • "notes": "string",
  • "is_active": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "phone": "string",
  • "website": "http://example.com",
  • "address_line1": "string",
  • "address_line2": "string",
  • "city": "string",
  • "state": "st",
  • "zip_code": "string",
  • "payer_id": "string",
  • "claim_office_id": "string",
  • "hpid": "string",
  • "payment_source": "string",
  • "notes": "string",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_insurance_carrier_partial_update

Retrieve, update, or deactivate an insurance carrier.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
carrier_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
name
string [ 1 .. 255 ] characters
phone
string <= 20 characters
website
string <uri> <= 200 characters
address_line1
string <= 255 characters
address_line2
string <= 255 characters
city
string <= 100 characters
state
string <= 2 characters
zip_code
string <= 10 characters
payer_id
string <= 50 characters

EDI payer ID for clearinghouse submission

claim_office_id
string <= 50 characters

Separate claim submission office ID

hpid
string <= 50 characters

Health Plan Identifier

payment_source
string <= 50 characters

check, eft, virtual_card

notes
string
is_active
boolean
custom_data
any

Responses

Request samples

Content type
{
  • "name": "string",
  • "phone": "string",
  • "website": "http://example.com",
  • "address_line1": "string",
  • "address_line2": "string",
  • "city": "string",
  • "state": "st",
  • "zip_code": "string",
  • "payer_id": "string",
  • "claim_office_id": "string",
  • "hpid": "string",
  • "payment_source": "string",
  • "notes": "string",
  • "is_active": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "phone": "string",
  • "website": "http://example.com",
  • "address_line1": "string",
  • "address_line2": "string",
  • "city": "string",
  • "state": "st",
  • "zip_code": "string",
  • "payer_id": "string",
  • "claim_office_id": "string",
  • "hpid": "string",
  • "payment_source": "string",
  • "notes": "string",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_insurance_carrier_destroy

Retrieve, update, or deactivate an insurance carrier.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
carrier_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_insurance_fee_schedule_entry_list

List entries for a fee schedule.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
fee_schedule_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{}

practice_insurance_fee_schedule_entry_destroy

Delete a single fee schedule entry.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
entry_uid
required
string <uuid>
fee_schedule_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_insurance_fee_schedule_retrieve

Retrieve, update, or delete a fee schedule.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
fee_schedule_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "carrier_name": "string",
  • "name": "string",
  • "effective_date": "2019-08-24",
  • "expiration_date": "2019-08-24",
  • "notes": "string",
  • "entry_count": 0,
  • "entries": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_insurance_fee_schedule_update

Retrieve, update, or delete a fee schedule.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
fee_schedule_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
carrier
string or null <uuid>
name
required
string [ 1 .. 255 ] characters
effective_date
string or null <date>
expiration_date
string or null <date>
notes
string
custom_data
any

Responses

Request samples

Content type
{
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "name": "string",
  • "effective_date": "2019-08-24",
  • "expiration_date": "2019-08-24",
  • "notes": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "carrier_name": "string",
  • "name": "string",
  • "effective_date": "2019-08-24",
  • "expiration_date": "2019-08-24",
  • "notes": "string",
  • "entry_count": 0,
  • "entries": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_insurance_fee_schedule_partial_update

Retrieve, update, or delete a fee schedule.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
fee_schedule_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
carrier
string or null <uuid>
name
string [ 1 .. 255 ] characters
effective_date
string or null <date>
expiration_date
string or null <date>
notes
string
custom_data
any

Responses

Request samples

Content type
{
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "name": "string",
  • "effective_date": "2019-08-24",
  • "expiration_date": "2019-08-24",
  • "notes": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "carrier_name": "string",
  • "name": "string",
  • "effective_date": "2019-08-24",
  • "expiration_date": "2019-08-24",
  • "notes": "string",
  • "entry_count": 0,
  • "entries": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_insurance_fee_schedule_destroy

Retrieve, update, or delete a fee schedule.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
fee_schedule_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_insurance_patient_insurance_partial_update

Handle PATCH on the list endpoint for bulk updates.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
patient
string <uuid>
insurance_plan
string or null <uuid>
carrier_name
string [ 1 .. 255 ] characters
carrier
string or null <uuid>
fee_schedule
string or null <uuid>

Fee schedule used for benefit estimation under this plan

group_number
string <= 100 characters
subscriber_id
string <= 100 characters
subscriber_name
string <= 255 characters

Policy holder name if different from patient

ordinal
integer [ 0 .. 32767 ]

1=primary, 2=secondary

RelationshipToSubscriberEnum (string) or BlankEnum (any)
effective_date
string or null <date>
termination_date
string or null <date>
custom_data
any

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "carrier_name": "string",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5",
  • "group_number": "string",
  • "subscriber_id": "string",
  • "subscriber_name": "string",
  • "ordinal": 32767,
  • "relationship_to_subscriber": "self",
  • "effective_date": "2019-08-24",
  • "termination_date": "2019-08-24",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "carrier_name": "string",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5",
  • "group_number": "string",
  • "subscriber_id": "string",
  • "subscriber_name": "string",
  • "ordinal": 32767,
  • "relationship_to_subscriber": "self",
  • "effective_date": "2019-08-24",
  • "termination_date": "2019-08-24",
  • "custom_data": null
}

practice_insurance_plan_benefit_retrieve

Update or delete a plan-level benefit.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
benefit_uid
required
string <uuid>
plan_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "custom_data": null,
  • "procedure_code": {
    },
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "benefit_type": "percentage",
  • "coverage_category": "diagnostic",
  • "percent": "string",
  • "monetary_amt": "string",
  • "time_period": "calendar_year",
  • "proc_code": "string",
  • "min_age": 32767,
  • "max_age": 32767,
  • "waiting_period_months": 32767,
  • "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4",
  • "modified_by": "e8d4374d-93a1-4e98-a6c6-fdcf00c5059f",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "patient_insurance": "e396a8de-c249-4467-871f-c8b5f28219f1"
}

practice_insurance_plan_benefit_update

Update or delete a plan-level benefit.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
benefit_uid
required
string <uuid>
plan_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
insurance_plan
string or null <uuid>
BenefitTypeEnum (string) or BlankEnum (any)
CoverageCategoryEnum (string) or BlankEnum (any)
percent
string <decimal> ^-?\d{0,3}(?:\.\d{0,2})?$
monetary_amt
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
TimePeriodEnum (string) or BlankEnum (any)
proc_code
string <= 20 characters

Benefit tied to a specific procedure code

procedure_code
string or null <uuid>
min_age
integer or null [ 0 .. 32767 ]

Minimum patient age (inclusive) for this benefit to apply

max_age
integer or null [ 0 .. 32767 ]

Maximum patient age (inclusive) for this benefit to apply

waiting_period_months
integer or null [ 0 .. 32767 ]

Months from effective date before this benefit is available

custom_data
any

Responses

Request samples

Content type
{
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "benefit_type": "percentage",
  • "coverage_category": "diagnostic",
  • "percent": "string",
  • "monetary_amt": "string",
  • "time_period": "calendar_year",
  • "proc_code": "string",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "min_age": 32767,
  • "max_age": 32767,
  • "waiting_period_months": 32767,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "benefit_type": "percentage",
  • "coverage_category": "diagnostic",
  • "percent": "string",
  • "monetary_amt": "string",
  • "time_period": "calendar_year",
  • "proc_code": "string",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "min_age": 32767,
  • "max_age": 32767,
  • "waiting_period_months": 32767,
  • "custom_data": null
}

practice_insurance_plan_benefit_partial_update

Update or delete a plan-level benefit.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
benefit_uid
required
string <uuid>
plan_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
insurance_plan
string or null <uuid>
BenefitTypeEnum (string) or BlankEnum (any)
CoverageCategoryEnum (string) or BlankEnum (any)
percent
string <decimal> ^-?\d{0,3}(?:\.\d{0,2})?$
monetary_amt
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
TimePeriodEnum (string) or BlankEnum (any)
proc_code
string <= 20 characters

Benefit tied to a specific procedure code

procedure_code
string or null <uuid>
min_age
integer or null [ 0 .. 32767 ]

Minimum patient age (inclusive) for this benefit to apply

max_age
integer or null [ 0 .. 32767 ]

Maximum patient age (inclusive) for this benefit to apply

waiting_period_months
integer or null [ 0 .. 32767 ]

Months from effective date before this benefit is available

custom_data
any

Responses

Request samples

Content type
{
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "benefit_type": "percentage",
  • "coverage_category": "diagnostic",
  • "percent": "string",
  • "monetary_amt": "string",
  • "time_period": "calendar_year",
  • "proc_code": "string",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "min_age": 32767,
  • "max_age": 32767,
  • "waiting_period_months": 32767,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "benefit_type": "percentage",
  • "coverage_category": "diagnostic",
  • "percent": "string",
  • "monetary_amt": "string",
  • "time_period": "calendar_year",
  • "proc_code": "string",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "min_age": 32767,
  • "max_age": 32767,
  • "waiting_period_months": 32767,
  • "custom_data": null
}

practice_insurance_plan_benefit_destroy

Update or delete a plan-level benefit.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
benefit_uid
required
string <uuid>
plan_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_insurance_plan_retrieve

Retrieve, update, or delete an insurance plan.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "carrier_name": "string",
  • "plan_name": "string",
  • "group_name": "string",
  • "group_number": "string",
  • "employer_name": "string",
  • "plan_type": "ppo",
  • "annual_maximum": "string",
  • "individual_deductible": "string",
  • "family_deductible": "string",
  • "plan_year_begin_month": 32767,
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5",
  • "notes": "string",
  • "is_active": true,
  • "benefits": [
    ],
  • "enrollment_count": 0,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_insurance_plan_update

Retrieve, update, or delete an insurance plan.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
carrier
string or null <uuid>
plan_name
string <= 255 characters
group_name
string <= 255 characters
group_number
string <= 100 characters
employer_name
string <= 255 characters
PlanTypeEnum (string) or BlankEnum (any)
annual_maximum
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
individual_deductible
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
family_deductible
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
plan_year_begin_month
integer or null [ 0 .. 32767 ]

Month (1-12) when the plan year resets

fee_schedule
string or null <uuid>

Carrier-specific fee schedule (allowed amounts) for this plan

notes
string
is_active
boolean
Array of objects (InsuranceBenefitWriteRequest)
custom_data
any

Responses

Request samples

Content type
{
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "plan_name": "string",
  • "group_name": "string",
  • "group_number": "string",
  • "employer_name": "string",
  • "plan_type": "ppo",
  • "annual_maximum": "string",
  • "individual_deductible": "string",
  • "family_deductible": "string",
  • "plan_year_begin_month": 32767,
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5",
  • "notes": "string",
  • "is_active": true,
  • "benefits": [
    ],
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "carrier_name": "string",
  • "plan_name": "string",
  • "group_name": "string",
  • "group_number": "string",
  • "employer_name": "string",
  • "plan_type": "ppo",
  • "annual_maximum": "string",
  • "individual_deductible": "string",
  • "family_deductible": "string",
  • "plan_year_begin_month": 32767,
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5",
  • "notes": "string",
  • "is_active": true,
  • "benefits": [
    ],
  • "enrollment_count": 0,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_insurance_plan_partial_update

Retrieve, update, or delete an insurance plan.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
carrier
string or null <uuid>
plan_name
string <= 255 characters
group_name
string <= 255 characters
group_number
string <= 100 characters
employer_name
string <= 255 characters
PlanTypeEnum (string) or BlankEnum (any)
annual_maximum
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
individual_deductible
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
family_deductible
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
plan_year_begin_month
integer or null [ 0 .. 32767 ]

Month (1-12) when the plan year resets

fee_schedule
string or null <uuid>

Carrier-specific fee schedule (allowed amounts) for this plan

notes
string
is_active
boolean
Array of objects (InsuranceBenefitWriteRequest)
custom_data
any

Responses

Request samples

Content type
{
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "plan_name": "string",
  • "group_name": "string",
  • "group_number": "string",
  • "employer_name": "string",
  • "plan_type": "ppo",
  • "annual_maximum": "string",
  • "individual_deductible": "string",
  • "family_deductible": "string",
  • "plan_year_begin_month": 32767,
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5",
  • "notes": "string",
  • "is_active": true,
  • "benefits": [
    ],
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "carrier_name": "string",
  • "plan_name": "string",
  • "group_name": "string",
  • "group_number": "string",
  • "employer_name": "string",
  • "plan_type": "ppo",
  • "annual_maximum": "string",
  • "individual_deductible": "string",
  • "family_deductible": "string",
  • "plan_year_begin_month": 32767,
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5",
  • "notes": "string",
  • "is_active": true,
  • "benefits": [
    ],
  • "enrollment_count": 0,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_insurance_plan_destroy

Retrieve, update, or delete an insurance plan.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_insurance_verification_retrieve

Retrieve a single insurance verification.

Verifications are immutable snapshots -- this view only supports GET. Emits insurance.verification_viewed on each read.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
verification_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "verified_by": "8c493be0-efe2-4a3e-bdbd-7af0eab50aa2",
  • "verified_at": "2019-08-24T14:15:22Z",
  • "source": "phone",
  • "raw_response": null,
  • "annual_max": "string",
  • "deductible_total": "string",
  • "deductible_met": "string",
  • "waiting_period_notes": "string",
  • "frequency_limits": null,
  • "plan": {
    },
  • "patient_summary": {
    },
  • "verified_by_summary": {
    },
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_intake_lookup_retrieve

Search for an existing patient by last name and date of birth.

Both last_name and date_of_birth are required query parameters to prevent patient list enumeration from a kiosk.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

practice_intake_patient_create

Create a new patient from kiosk intake data.

Creates a Patient with status="prospective" plus related medical history and insurance records in a single atomic transaction.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_intake_patient_confirm_update

Existing patient confirms or updates their data at the kiosk.

Only provided fields are updated. Sets last_medical_review to today.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_billing_balance_retrieve

GET patient balance. Returns 404 if no balance record exists.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "custom_data": null,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "balance_total": "string",
  • "insurance_estimate": "string",
  • "patient_portion": "string",
  • "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4",
  • "modified_by": "e8d4374d-93a1-4e98-a6c6-fdcf00c5059f",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb"
}

practice_patient_billing_payment_plan_retrieve

Retrieve or update a payment plan.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "custom_data": null,
  • "charges": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "plan_date": "2019-08-24",
  • "apr": "string",
  • "completed_amt": "string",
  • "is_closed": true,
  • "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4",
  • "modified_by": "e8d4374d-93a1-4e98-a6c6-fdcf00c5059f",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "guarantor": "2dc581b4-936d-4ab3-8a7d-1fc8f857bc6f"
}

practice_patient_billing_payment_plan_update

Retrieve or update a payment plan.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
guarantor
string or null <uuid>
plan_date
string or null <date>
apr
string <decimal> ^-?\d{0,3}(?:\.\d{0,2})?$
completed_amt
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
is_closed
boolean
Array of objects (PaymentPlanChargeWriteRequest)
custom_data
any

Responses

Request samples

Content type
{
  • "guarantor": "2dc581b4-936d-4ab3-8a7d-1fc8f857bc6f",
  • "plan_date": "2019-08-24",
  • "apr": "string",
  • "completed_amt": "string",
  • "is_closed": true,
  • "charges": [
    ],
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "guarantor": "2dc581b4-936d-4ab3-8a7d-1fc8f857bc6f",
  • "plan_date": "2019-08-24",
  • "apr": "string",
  • "completed_amt": "string",
  • "is_closed": true,
  • "charges": [
    ],
  • "custom_data": null
}

practice_patient_billing_payment_plan_partial_update

Retrieve or update a payment plan.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
guarantor
string or null <uuid>
plan_date
string or null <date>
apr
string <decimal> ^-?\d{0,3}(?:\.\d{0,2})?$
completed_amt
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
is_closed
boolean
Array of objects (PaymentPlanChargeWriteRequest)
custom_data
any

Responses

Request samples

Content type
{
  • "guarantor": "2dc581b4-936d-4ab3-8a7d-1fc8f857bc6f",
  • "plan_date": "2019-08-24",
  • "apr": "string",
  • "completed_amt": "string",
  • "is_closed": true,
  • "charges": [
    ],
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "guarantor": "2dc581b4-936d-4ab3-8a7d-1fc8f857bc6f",
  • "plan_date": "2019-08-24",
  • "apr": "string",
  • "completed_amt": "string",
  • "is_closed": true,
  • "charges": [
    ],
  • "custom_data": null
}

practice_patient_billing_payment_retrieve

Retrieve or update a payment record.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
payment_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "custom_data": null,
  • "splits": [
    ],
  • "patient_name": "string",
  • "patient_first_name": "string",
  • "patient_last_name": "string",
  • "provider_name": "string",
  • "pay_method": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "pay_date": "2019-08-24",
  • "pay_amount": "string",
  • "pay_type": "string",
  • "pay_note": "string",
  • "stripe_payment_intent_id": "string",
  • "stripe_status": "PENDING",
  • "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4",
  • "modified_by": "e8d4374d-93a1-4e98-a6c6-fdcf00c5059f",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9"
}

practice_patient_billing_payment_update

Retrieve or update a payment record.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
payment_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
pay_date
string or null <date>
pay_amount
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
pay_type
string <= 100 characters
pay_note
string
provider
string or null <uuid>
custom_data
any
Array of objects (PaymentSplitWriteRequest)

Responses

Request samples

Content type
{
  • "pay_date": "2019-08-24",
  • "pay_amount": "string",
  • "pay_type": "string",
  • "pay_note": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "custom_data": null,
  • "splits": [
    ]
}

Response samples

Content type
application/json
{
  • "pay_date": "2019-08-24",
  • "pay_amount": "string",
  • "pay_type": "string",
  • "pay_note": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "custom_data": null,
  • "splits": [
    ]
}

practice_patient_billing_payment_partial_update

Retrieve or update a payment record.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
payment_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
pay_date
string or null <date>
pay_amount
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
pay_type
string <= 100 characters
pay_note
string
provider
string or null <uuid>
custom_data
any
Array of objects (PaymentSplitWriteRequest)

Responses

Request samples

Content type
{
  • "pay_date": "2019-08-24",
  • "pay_amount": "string",
  • "pay_type": "string",
  • "pay_note": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "custom_data": null,
  • "splits": [
    ]
}

Response samples

Content type
application/json
{
  • "pay_date": "2019-08-24",
  • "pay_amount": "string",
  • "pay_type": "string",
  • "pay_note": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "custom_data": null,
  • "splits": [
    ]
}

practice_patient_clinical_allergy_list

List and create allergies for a patient.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_clinical_allergy_create

List and create allergies for a patient.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
allergy_name
required
string [ 1 .. 255 ] characters
reaction
string <= 255 characters
is_active
boolean
date_reaction
string or null <date>
custom_data
any

Responses

Request samples

Content type
{
  • "allergy_name": "string",
  • "reaction": "string",
  • "is_active": true,
  • "date_reaction": "2019-08-24",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "allergy_name": "string",
  • "reaction": "string",
  • "is_active": true,
  • "date_reaction": "2019-08-24",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_allergy_retrieve

Retrieve, update, or delete a patient allergy.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
allergy_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "allergy_name": "string",
  • "reaction": "string",
  • "is_active": true,
  • "date_reaction": "2019-08-24",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_allergy_update

Retrieve, update, or delete a patient allergy.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
allergy_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
allergy_name
required
string [ 1 .. 255 ] characters
reaction
string <= 255 characters
is_active
boolean
date_reaction
string or null <date>
custom_data
any

Responses

Request samples

Content type
{
  • "allergy_name": "string",
  • "reaction": "string",
  • "is_active": true,
  • "date_reaction": "2019-08-24",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "allergy_name": "string",
  • "reaction": "string",
  • "is_active": true,
  • "date_reaction": "2019-08-24",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_allergy_partial_update

Retrieve, update, or delete a patient allergy.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
allergy_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
allergy_name
string [ 1 .. 255 ] characters
reaction
string <= 255 characters
is_active
boolean
date_reaction
string or null <date>
custom_data
any

Responses

Request samples

Content type
{
  • "allergy_name": "string",
  • "reaction": "string",
  • "is_active": true,
  • "date_reaction": "2019-08-24",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "allergy_name": "string",
  • "reaction": "string",
  • "is_active": true,
  • "date_reaction": "2019-08-24",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_allergy_destroy

Retrieve, update, or delete a patient allergy.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
allergy_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_clinical_anesthesia_retrieve

Retrieve or update an anesthesia record.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
anesthesia_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "agent": "lidocaine_epi",
  • "agent_display": "string",
  • "agent_other": "string",
  • "route": "infiltration",
  • "route_display": "string",
  • "site": "string",
  • "carpules": "string",
  • "lot_number": "string",
  • "expiration_date": "2019-08-24",
  • "administered_at": "2019-08-24T14:15:22Z",
  • "note": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_anesthesia_update

Retrieve or update an anesthesia record.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
anesthesia_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
appointment
string or null <uuid>
provider
string or null <uuid>
agent
required
string (AgentEnum)
Enum: "lidocaine_epi" "lidocaine" "articaine_epi" "articaine_epi_200" "mepivacaine_epi" "mepivacaine" "bupivacaine_epi" "prilocaine_epi" "prilocaine" "topical_benzocaine" "topical_lidocaine" "nitrous" "other"
  • lidocaine_epi - Lidocaine 2% with Epinephrine 1:100,000
  • lidocaine - Lidocaine 2% (plain)
  • articaine_epi - Articaine 4% with Epinephrine 1:100,000
  • articaine_epi_200 - Articaine 4% with Epinephrine 1:200,000
  • mepivacaine_epi - Mepivacaine 2% with Levonordefrin 1:20,000
  • mepivacaine - Mepivacaine 3% (plain)
  • bupivacaine_epi - Bupivacaine 0.5% with Epinephrine 1:200,000
  • prilocaine_epi - Prilocaine 4% with Epinephrine 1:200,000
  • prilocaine - Prilocaine 4% (plain)
  • topical_benzocaine - Topical Benzocaine 20%
  • topical_lidocaine - Topical Lidocaine 5%
  • nitrous - Nitrous Oxide / Oxygen
  • other - Other
agent_other
string <= 100 characters

If agent=other, specify here

route
string (RouteEnum)
Enum: "infiltration" "block" "topical" "inhalation"
  • infiltration - Infiltration
  • block - Block
  • topical - Topical
  • inhalation - Inhalation
site
string <= 100 characters

e.g. #14 buccal infiltration, right IAN block

carpules
string <decimal> ^-?\d{0,2}(?:\.\d{0,1})?$

Number of carpules administered

lot_number
string <= 50 characters
expiration_date
string or null <date>
administered_at
required
string <date-time>

When the anesthesia was administered

note
string

Complications, reactions, or additional notes

custom_data
any

Responses

Request samples

Content type
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "agent": "lidocaine_epi",
  • "agent_other": "string",
  • "route": "infiltration",
  • "site": "string",
  • "carpules": "string",
  • "lot_number": "string",
  • "expiration_date": "2019-08-24",
  • "administered_at": "2019-08-24T14:15:22Z",
  • "note": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "agent": "lidocaine_epi",
  • "agent_other": "string",
  • "route": "infiltration",
  • "site": "string",
  • "carpules": "string",
  • "lot_number": "string",
  • "expiration_date": "2019-08-24",
  • "administered_at": "2019-08-24T14:15:22Z",
  • "note": "string",
  • "custom_data": null
}

practice_patient_clinical_anesthesia_partial_update

Retrieve or update an anesthesia record.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
anesthesia_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
appointment
string or null <uuid>
provider
string or null <uuid>
agent
string (AgentEnum)
Enum: "lidocaine_epi" "lidocaine" "articaine_epi" "articaine_epi_200" "mepivacaine_epi" "mepivacaine" "bupivacaine_epi" "prilocaine_epi" "prilocaine" "topical_benzocaine" "topical_lidocaine" "nitrous" "other"
  • lidocaine_epi - Lidocaine 2% with Epinephrine 1:100,000
  • lidocaine - Lidocaine 2% (plain)
  • articaine_epi - Articaine 4% with Epinephrine 1:100,000
  • articaine_epi_200 - Articaine 4% with Epinephrine 1:200,000
  • mepivacaine_epi - Mepivacaine 2% with Levonordefrin 1:20,000
  • mepivacaine - Mepivacaine 3% (plain)
  • bupivacaine_epi - Bupivacaine 0.5% with Epinephrine 1:200,000
  • prilocaine_epi - Prilocaine 4% with Epinephrine 1:200,000
  • prilocaine - Prilocaine 4% (plain)
  • topical_benzocaine - Topical Benzocaine 20%
  • topical_lidocaine - Topical Lidocaine 5%
  • nitrous - Nitrous Oxide / Oxygen
  • other - Other
agent_other
string <= 100 characters

If agent=other, specify here

route
string (RouteEnum)
Enum: "infiltration" "block" "topical" "inhalation"
  • infiltration - Infiltration
  • block - Block
  • topical - Topical
  • inhalation - Inhalation
site
string <= 100 characters

e.g. #14 buccal infiltration, right IAN block

carpules
string <decimal> ^-?\d{0,2}(?:\.\d{0,1})?$

Number of carpules administered

lot_number
string <= 50 characters
expiration_date
string or null <date>
administered_at
string <date-time>

When the anesthesia was administered

note
string

Complications, reactions, or additional notes

custom_data
any

Responses

Request samples

Content type
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "agent": "lidocaine_epi",
  • "agent_other": "string",
  • "route": "infiltration",
  • "site": "string",
  • "carpules": "string",
  • "lot_number": "string",
  • "expiration_date": "2019-08-24",
  • "administered_at": "2019-08-24T14:15:22Z",
  • "note": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "agent": "lidocaine_epi",
  • "agent_other": "string",
  • "route": "infiltration",
  • "site": "string",
  • "carpules": "string",
  • "lot_number": "string",
  • "expiration_date": "2019-08-24",
  • "administered_at": "2019-08-24T14:15:22Z",
  • "note": "string",
  • "custom_data": null
}

practice_patient_clinical_condition_list

List and create medical conditions for a patient.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_clinical_condition_create

List and create medical conditions for a patient.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
condition_name
required
string [ 1 .. 255 ] characters
date_start
string or null <date>
date_stop
string or null <date>
note
string
custom_data
any

Responses

Request samples

Content type
{
  • "condition_name": "string",
  • "date_start": "2019-08-24",
  • "date_stop": "2019-08-24",
  • "note": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "condition_name": "string",
  • "date_start": "2019-08-24",
  • "date_stop": "2019-08-24",
  • "note": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_condition_retrieve

Retrieve, update, or delete a patient medical condition.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
condition_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "condition_name": "string",
  • "date_start": "2019-08-24",
  • "date_stop": "2019-08-24",
  • "note": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_condition_update

Retrieve, update, or delete a patient medical condition.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
condition_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
condition_name
required
string [ 1 .. 255 ] characters
date_start
string or null <date>
date_stop
string or null <date>
note
string
custom_data
any

Responses

Request samples

Content type
{
  • "condition_name": "string",
  • "date_start": "2019-08-24",
  • "date_stop": "2019-08-24",
  • "note": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "condition_name": "string",
  • "date_start": "2019-08-24",
  • "date_stop": "2019-08-24",
  • "note": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_condition_partial_update

Retrieve, update, or delete a patient medical condition.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
condition_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
condition_name
string [ 1 .. 255 ] characters
date_start
string or null <date>
date_stop
string or null <date>
note
string
custom_data
any

Responses

Request samples

Content type
{
  • "condition_name": "string",
  • "date_start": "2019-08-24",
  • "date_stop": "2019-08-24",
  • "note": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "condition_name": "string",
  • "date_start": "2019-08-24",
  • "date_stop": "2019-08-24",
  • "note": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_condition_destroy

Retrieve, update, or delete a patient medical condition.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
condition_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_clinical_education_retrieve

Retrieve, update, or delete a patient education record.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
education_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "topic": "oral_hygiene",
  • "topic_display": "string",
  • "detail": "string",
  • "products_recommended": "string",
  • "education_date": "2019-08-24",
  • "compliance_note": "string",
  • "send_to_portal": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_education_update

Retrieve, update, or delete a patient education record.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
education_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
appointment
string or null <uuid>
provider
string or null <uuid>
topic
required
string (TopicEnum)
Enum: "oral_hygiene" "brushing" "flossing" "interproximal" "electric_toothbrush" "fluoride" "diet_counseling" "tobacco_cessation" "perio_disease" "caries_risk" "dry_mouth" "bruxism" "sensitivity" "whitening" "ortho_care" "implant_care" "post_op" "pre_med" "other"
  • oral_hygiene - Oral Hygiene Instructions
  • brushing - Brushing Technique
  • flossing - Flossing Technique
  • interproximal - Interproximal Cleaning
  • electric_toothbrush - Electric Toothbrush
  • fluoride - Fluoride Use
  • diet_counseling - Diet Counseling
  • tobacco_cessation - Tobacco Cessation
  • perio_disease - Periodontal Disease
  • caries_risk - Caries Risk
  • dry_mouth - Dry Mouth / Xerostomia
  • bruxism - Bruxism / Night Guard
  • sensitivity - Sensitivity
  • whitening - Whitening Options
  • ortho_care - Orthodontic Care
  • implant_care - Implant Care
  • post_op - Post-Operative Instructions
  • pre_med - Premedication Reminder
  • other - Other
detail
string

Specific instructions or notes about what was discussed

products_recommended
string <= 255 characters

e.g. Sonicare, Waterpik, MI Paste

education_date
required
string <date>
compliance_note
string

Patient response, compliance observations

send_to_portal
boolean

Make available in patient portal

custom_data
any

Responses

Request samples

Content type
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "topic": "oral_hygiene",
  • "detail": "string",
  • "products_recommended": "string",
  • "education_date": "2019-08-24",
  • "compliance_note": "string",
  • "send_to_portal": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "topic": "oral_hygiene",
  • "detail": "string",
  • "products_recommended": "string",
  • "education_date": "2019-08-24",
  • "compliance_note": "string",
  • "send_to_portal": true,
  • "custom_data": null
}

practice_patient_clinical_education_partial_update

Retrieve, update, or delete a patient education record.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
education_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
appointment
string or null <uuid>
provider
string or null <uuid>
topic
string (TopicEnum)
Enum: "oral_hygiene" "brushing" "flossing" "interproximal" "electric_toothbrush" "fluoride" "diet_counseling" "tobacco_cessation" "perio_disease" "caries_risk" "dry_mouth" "bruxism" "sensitivity" "whitening" "ortho_care" "implant_care" "post_op" "pre_med" "other"
  • oral_hygiene - Oral Hygiene Instructions
  • brushing - Brushing Technique
  • flossing - Flossing Technique
  • interproximal - Interproximal Cleaning
  • electric_toothbrush - Electric Toothbrush
  • fluoride - Fluoride Use
  • diet_counseling - Diet Counseling
  • tobacco_cessation - Tobacco Cessation
  • perio_disease - Periodontal Disease
  • caries_risk - Caries Risk
  • dry_mouth - Dry Mouth / Xerostomia
  • bruxism - Bruxism / Night Guard
  • sensitivity - Sensitivity
  • whitening - Whitening Options
  • ortho_care - Orthodontic Care
  • implant_care - Implant Care
  • post_op - Post-Operative Instructions
  • pre_med - Premedication Reminder
  • other - Other
detail
string

Specific instructions or notes about what was discussed

products_recommended
string <= 255 characters

e.g. Sonicare, Waterpik, MI Paste

education_date
string <date>
compliance_note
string

Patient response, compliance observations

send_to_portal
boolean

Make available in patient portal

custom_data
any

Responses

Request samples

Content type
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "topic": "oral_hygiene",
  • "detail": "string",
  • "products_recommended": "string",
  • "education_date": "2019-08-24",
  • "compliance_note": "string",
  • "send_to_portal": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "topic": "oral_hygiene",
  • "detail": "string",
  • "products_recommended": "string",
  • "education_date": "2019-08-24",
  • "compliance_note": "string",
  • "send_to_portal": true,
  • "custom_data": null
}

practice_patient_clinical_education_destroy

Retrieve, update, or delete a patient education record.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
education_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_clinical_medication_list

List and create medications for a patient.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_clinical_medication_create

List and create medications for a patient.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
medication_name
required
string [ 1 .. 255 ] characters
date_start
string or null <date>
date_stop
string or null <date>
note
string
rx_cui
string <= 20 characters

RxNorm concept unique identifier

custom_data
any

Responses

Request samples

Content type
{
  • "medication_name": "string",
  • "date_start": "2019-08-24",
  • "date_stop": "2019-08-24",
  • "note": "string",
  • "rx_cui": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "medication_name": "string",
  • "date_start": "2019-08-24",
  • "date_stop": "2019-08-24",
  • "note": "string",
  • "rx_cui": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_medication_retrieve

Retrieve, update, or delete a patient medication.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
medication_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "medication_name": "string",
  • "date_start": "2019-08-24",
  • "date_stop": "2019-08-24",
  • "note": "string",
  • "rx_cui": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_medication_update

Retrieve, update, or delete a patient medication.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
medication_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
medication_name
required
string [ 1 .. 255 ] characters
date_start
string or null <date>
date_stop
string or null <date>
note
string
rx_cui
string <= 20 characters

RxNorm concept unique identifier

custom_data
any

Responses

Request samples

Content type
{
  • "medication_name": "string",
  • "date_start": "2019-08-24",
  • "date_stop": "2019-08-24",
  • "note": "string",
  • "rx_cui": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "medication_name": "string",
  • "date_start": "2019-08-24",
  • "date_stop": "2019-08-24",
  • "note": "string",
  • "rx_cui": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_medication_partial_update

Retrieve, update, or delete a patient medication.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
medication_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
medication_name
string [ 1 .. 255 ] characters
date_start
string or null <date>
date_stop
string or null <date>
note
string
rx_cui
string <= 20 characters

RxNorm concept unique identifier

custom_data
any

Responses

Request samples

Content type
{
  • "medication_name": "string",
  • "date_start": "2019-08-24",
  • "date_stop": "2019-08-24",
  • "note": "string",
  • "rx_cui": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "medication_name": "string",
  • "date_start": "2019-08-24",
  • "date_stop": "2019-08-24",
  • "note": "string",
  • "rx_cui": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_medication_destroy

Retrieve, update, or delete a patient medication.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
medication_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_clinical_note_retrieve

Retrieve or update a clinical note. PATCH is blocked if the note is signed.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
note_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "template_name": "string",
  • "note_type": "clinical",
  • "subject": "string",
  • "content": "string",
  • "note_date": "2019-08-24",
  • "is_signed": true,
  • "signed_by": "66eaecaf-2581-4b22-b9af-2f669ed2f9ba",
  • "signed_by_name": "string",
  • "signed_at": "2019-08-24T14:15:22Z",
  • "is_addendum": true,
  • "parent_note": "47e0a283-e822-462a-a025-efa34db2b778",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4",
  • "custom_data": null
}

practice_patient_clinical_note_update

Retrieve or update a clinical note. PATCH is blocked if the note is signed.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
note_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
appointment
string or null <uuid>
provider
string or null <uuid>
template
string or null <uuid>

Template used to create this note (reference only, content is copied)

note_type
string (NoteTypeEnum)
Enum: "clinical" "exam" "hygiene" "consult" "phone" "lab" "internal" "other"
  • clinical - Clinical Note
  • exam - Exam Note
  • hygiene - Hygiene Note
  • consult - Consult Note
  • phone - Phone Note
  • lab - Lab Note
  • internal - Internal Note
  • other - Other
subject
string <= 200 characters
content
string

Plain text or structured note content

note_date
string or null <date>
is_addendum
boolean

Addendum to a previous note

parent_note
string or null <uuid>

If is_addendum=True, the original note this amends

custom_data
any

Responses

Request samples

Content type
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "note_type": "clinical",
  • "subject": "string",
  • "content": "string",
  • "note_date": "2019-08-24",
  • "is_addendum": true,
  • "parent_note": "47e0a283-e822-462a-a025-efa34db2b778",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "note_type": "clinical",
  • "subject": "string",
  • "content": "string",
  • "note_date": "2019-08-24",
  • "is_addendum": true,
  • "parent_note": "47e0a283-e822-462a-a025-efa34db2b778",
  • "custom_data": null
}

practice_patient_clinical_note_partial_update

Retrieve or update a clinical note. PATCH is blocked if the note is signed.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
note_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
appointment
string or null <uuid>
provider
string or null <uuid>
template
string or null <uuid>

Template used to create this note (reference only, content is copied)

note_type
string (NoteTypeEnum)
Enum: "clinical" "exam" "hygiene" "consult" "phone" "lab" "internal" "other"
  • clinical - Clinical Note
  • exam - Exam Note
  • hygiene - Hygiene Note
  • consult - Consult Note
  • phone - Phone Note
  • lab - Lab Note
  • internal - Internal Note
  • other - Other
subject
string <= 200 characters
content
string

Plain text or structured note content

note_date
string or null <date>
is_addendum
boolean

Addendum to a previous note

parent_note
string or null <uuid>

If is_addendum=True, the original note this amends

custom_data
any

Responses

Request samples

Content type
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "note_type": "clinical",
  • "subject": "string",
  • "content": "string",
  • "note_date": "2019-08-24",
  • "is_addendum": true,
  • "parent_note": "47e0a283-e822-462a-a025-efa34db2b778",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "note_type": "clinical",
  • "subject": "string",
  • "content": "string",
  • "note_date": "2019-08-24",
  • "is_addendum": true,
  • "parent_note": "47e0a283-e822-462a-a025-efa34db2b778",
  • "custom_data": null
}

practice_patient_clinical_perio_list

List and create periodontal exams for a patient.

GET returns exams ordered by most recent first, with readings prefetched.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_clinical_perio_create

List and create periodontal exams for a patient.

GET returns exams ordered by most recent first, with readings prefetched.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
provider
string or null <uuid>
appointment
string or null <uuid>
exam_date
required
string <date-time>
is_completed
boolean

Completed exams cannot be deleted

StageEnum (string) or BlankEnum (any)
GradeEnum (string) or BlankEnum (any)
note
string
custom_data
any

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "exam_date": "2019-08-24T14:15:22Z",
  • "is_completed": true,
  • "stage": "healthy",
  • "grade": "grade_a",
  • "note": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "exam_date": "2019-08-24T14:15:22Z",
  • "is_completed": true,
  • "stage": "healthy",
  • "grade": "grade_a",
  • "note": "string",
  • "custom_data": null
}

practice_patient_clinical_perio_retrieve

Retrieve, update, or delete a periodontal exam.

Completed exams cannot be deleted (returns 422).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
perio_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "exam_date": "2019-08-24T14:15:22Z",
  • "is_completed": true,
  • "stage": "healthy",
  • "grade": "grade_a",
  • "note": "string",
  • "readings": [
    ],
  • "reading_count": 0,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_perio_update

Retrieve, update, or delete a periodontal exam.

Completed exams cannot be deleted (returns 422).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
perio_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
provider
string or null <uuid>
appointment
string or null <uuid>
exam_date
required
string <date-time>
is_completed
boolean

Completed exams cannot be deleted

StageEnum (string) or BlankEnum (any)
GradeEnum (string) or BlankEnum (any)
note
string
custom_data
any

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "exam_date": "2019-08-24T14:15:22Z",
  • "is_completed": true,
  • "stage": "healthy",
  • "grade": "grade_a",
  • "note": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "exam_date": "2019-08-24T14:15:22Z",
  • "is_completed": true,
  • "stage": "healthy",
  • "grade": "grade_a",
  • "note": "string",
  • "custom_data": null
}

practice_patient_clinical_perio_partial_update

Retrieve, update, or delete a periodontal exam.

Completed exams cannot be deleted (returns 422).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
perio_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
provider
string or null <uuid>
appointment
string or null <uuid>
exam_date
string <date-time>
is_completed
boolean

Completed exams cannot be deleted

StageEnum (string) or BlankEnum (any)
GradeEnum (string) or BlankEnum (any)
note
string
custom_data
any

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "exam_date": "2019-08-24T14:15:22Z",
  • "is_completed": true,
  • "stage": "healthy",
  • "grade": "grade_a",
  • "note": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "exam_date": "2019-08-24T14:15:22Z",
  • "is_completed": true,
  • "stage": "healthy",
  • "grade": "grade_a",
  • "note": "string",
  • "custom_data": null
}

practice_patient_clinical_perio_destroy

Retrieve, update, or delete a periodontal exam.

Completed exams cannot be deleted (returns 422).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
perio_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_clinical_procedure_retrieve

Retrieve, update, or delete a procedure.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
procedure_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "procedure_code": {
    },
  • "proc_code": "string",
  • "description": "string",
  • "proc_date": "2019-08-24",
  • "date_complete": "2019-08-24",
  • "proc_fee": "string",
  • "status": "string",
  • "tooth_num": "string",
  • "surface": "string",
  • "discount": "string",
  • "unit_qty": 0,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_procedure_update

Retrieve, update, or delete a procedure.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
procedure_uid
required
string <uuid>
Request Body schema:
provider
string or null <uuid>
appointment
string or null <uuid>
procedure_code
string or null <uuid>
proc_code
string <= 20 characters
description
string <= 255 characters
proc_date
string or null <date>
proc_fee
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
status
string <= 30 characters

complete, existing_current, existing_other

tooth_num
string <= 10 characters
surface
string <= 20 characters
discount
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
unit_qty
integer [ 0 .. 2147483647 ]
custom_data
any

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "proc_code": "string",
  • "description": "string",
  • "proc_date": "2019-08-24",
  • "proc_fee": "string",
  • "status": "string",
  • "tooth_num": "string",
  • "surface": "string",
  • "discount": "string",
  • "unit_qty": 2147483647,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "proc_code": "string",
  • "description": "string",
  • "proc_date": "2019-08-24",
  • "proc_fee": "string",
  • "status": "string",
  • "tooth_num": "string",
  • "surface": "string",
  • "discount": "string",
  • "unit_qty": 2147483647,
  • "custom_data": null
}

practice_patient_clinical_procedure_partial_update

Retrieve, update, or delete a procedure.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
procedure_uid
required
string <uuid>
Request Body schema:
provider
string or null <uuid>
appointment
string or null <uuid>
procedure_code
string or null <uuid>
proc_code
string <= 20 characters
description
string <= 255 characters
proc_date
string or null <date>
proc_fee
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
status
string <= 30 characters

complete, existing_current, existing_other

tooth_num
string <= 10 characters
surface
string <= 20 characters
discount
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
unit_qty
integer [ 0 .. 2147483647 ]
custom_data
any

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "proc_code": "string",
  • "description": "string",
  • "proc_date": "2019-08-24",
  • "proc_fee": "string",
  • "status": "string",
  • "tooth_num": "string",
  • "surface": "string",
  • "discount": "string",
  • "unit_qty": 2147483647,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "proc_code": "string",
  • "description": "string",
  • "proc_date": "2019-08-24",
  • "proc_fee": "string",
  • "status": "string",
  • "tooth_num": "string",
  • "surface": "string",
  • "discount": "string",
  • "unit_qty": 2147483647,
  • "custom_data": null
}

practice_patient_clinical_procedure_destroy

Retrieve, update, or delete a procedure.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
procedure_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_clinical_tooth_retrieve

Retrieve, update, or delete a tooth condition.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
tooth_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "tooth_num": "strin",
  • "condition": "missing",
  • "dentition": "permanent",
  • "surfaces": "string",
  • "material": "string",
  • "note": "string",
  • "date_identified": "2019-08-24",
  • "is_current": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_tooth_update

Retrieve, update, or delete a tooth condition.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
tooth_uid
required
string <uuid>
Request Body schema:
required
tooth_num
required
string [ 1 .. 5 ] characters

Universal numbering: 1-32 (permanent), A-T (primary)

condition
required
string (ConditionEnum)
Enum: "missing" "implant" "crown" "bridge_abutment" "bridge_pontic" "veneer" "root_canal" "extraction_planned" "impacted" "unerupted" "supernumerary" "deciduous" "denture" "partial_denture" "caries" "filling" "sealant" "fracture" "watch"
  • missing - Missing
  • implant - Implant
  • crown - Crown
  • bridge_abutment - Bridge Abutment
  • bridge_pontic - Bridge Pontic
  • veneer - Veneer
  • root_canal - Root Canal
  • extraction_planned - Extraction Planned
  • impacted - Impacted
  • unerupted - Unerupted
  • supernumerary - Supernumerary
  • deciduous - Deciduous / Primary
  • denture - Denture
  • partial_denture - Partial Denture
  • caries - Caries
  • filling - Filling
  • sealant - Sealant
  • fracture - Fracture
  • watch - Watch
dentition
string (DentitionEnum)
Enum: "permanent" "primary"
  • permanent - Permanent
  • primary - Primary
surfaces
string <= 10 characters

Affected surfaces: M, O, D, B/F, L, I (e.g. 'MOD')

material
string <= 50 characters

e.g. PFM, zirconia, amalgam, composite

note
string
date_identified
string or null <date>
is_current
boolean

False = historical condition superseded by a newer one

custom_data
any

Responses

Request samples

Content type
{
  • "tooth_num": "strin",
  • "condition": "missing",
  • "dentition": "permanent",
  • "surfaces": "string",
  • "material": "string",
  • "note": "string",
  • "date_identified": "2019-08-24",
  • "is_current": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "tooth_num": "strin",
  • "condition": "missing",
  • "dentition": "permanent",
  • "surfaces": "string",
  • "material": "string",
  • "note": "string",
  • "date_identified": "2019-08-24",
  • "is_current": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_tooth_partial_update

Retrieve, update, or delete a tooth condition.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
tooth_uid
required
string <uuid>
Request Body schema:
tooth_num
string [ 1 .. 5 ] characters

Universal numbering: 1-32 (permanent), A-T (primary)

condition
string (ConditionEnum)
Enum: "missing" "implant" "crown" "bridge_abutment" "bridge_pontic" "veneer" "root_canal" "extraction_planned" "impacted" "unerupted" "supernumerary" "deciduous" "denture" "partial_denture" "caries" "filling" "sealant" "fracture" "watch"
  • missing - Missing
  • implant - Implant
  • crown - Crown
  • bridge_abutment - Bridge Abutment
  • bridge_pontic - Bridge Pontic
  • veneer - Veneer
  • root_canal - Root Canal
  • extraction_planned - Extraction Planned
  • impacted - Impacted
  • unerupted - Unerupted
  • supernumerary - Supernumerary
  • deciduous - Deciduous / Primary
  • denture - Denture
  • partial_denture - Partial Denture
  • caries - Caries
  • filling - Filling
  • sealant - Sealant
  • fracture - Fracture
  • watch - Watch
dentition
string (DentitionEnum)
Enum: "permanent" "primary"
  • permanent - Permanent
  • primary - Primary
surfaces
string <= 10 characters

Affected surfaces: M, O, D, B/F, L, I (e.g. 'MOD')

material
string <= 50 characters

e.g. PFM, zirconia, amalgam, composite

note
string
date_identified
string or null <date>
is_current
boolean

False = historical condition superseded by a newer one

custom_data
any

Responses

Request samples

Content type
{
  • "tooth_num": "strin",
  • "condition": "missing",
  • "dentition": "permanent",
  • "surfaces": "string",
  • "material": "string",
  • "note": "string",
  • "date_identified": "2019-08-24",
  • "is_current": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "tooth_num": "strin",
  • "condition": "missing",
  • "dentition": "permanent",
  • "surfaces": "string",
  • "material": "string",
  • "note": "string",
  • "date_identified": "2019-08-24",
  • "is_current": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_tooth_destroy

Retrieve, update, or delete a tooth condition.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
tooth_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_clinical_treatment_plan_retrieve

Retrieve, update, or delete a treatment plan.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "name": "string",
  • "status": "active",
  • "date_created": "2019-08-24",
  • "date_accepted": "2019-08-24",
  • "note": "string",
  • "items": [
    ],
  • "item_count": 0,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_treatment_plan_update

Retrieve, update, or delete a treatment plan.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
provider
string or null <uuid>
name
required
string [ 1 .. 200 ] characters
note
string
status
string (TreatmentPlanStatusEnum)
Enum: "active" "accepted" "declined" "completed" "archived"
  • active - Active
  • accepted - Accepted
  • declined - Declined
  • completed - Completed
  • archived - Archived
date_accepted
string or null <date>
custom_data
any
Array of objects (TreatmentPlanItemWriteRequest)

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "name": "string",
  • "note": "string",
  • "status": "active",
  • "date_accepted": "2019-08-24",
  • "custom_data": null,
  • "items": [
    ]
}

Response samples

Content type
application/json
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "name": "string",
  • "note": "string",
  • "status": "active",
  • "date_accepted": "2019-08-24",
  • "custom_data": null,
  • "items": [
    ]
}

practice_patient_clinical_treatment_plan_partial_update

Retrieve, update, or delete a treatment plan.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
provider
string or null <uuid>
name
string [ 1 .. 200 ] characters
note
string
status
string (TreatmentPlanStatusEnum)
Enum: "active" "accepted" "declined" "completed" "archived"
  • active - Active
  • accepted - Accepted
  • declined - Declined
  • completed - Completed
  • archived - Archived
date_accepted
string or null <date>
custom_data
any
Array of objects (TreatmentPlanItemWriteRequest)

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "name": "string",
  • "note": "string",
  • "status": "active",
  • "date_accepted": "2019-08-24",
  • "custom_data": null,
  • "items": [
    ]
}

Response samples

Content type
application/json
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "name": "string",
  • "note": "string",
  • "status": "active",
  • "date_accepted": "2019-08-24",
  • "custom_data": null,
  • "items": [
    ]
}

practice_patient_clinical_treatment_plan_destroy

Retrieve, update, or delete a treatment plan.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_clinical_treatment_plan_item_list

List and create items within a treatment plan.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_clinical_treatment_plan_item_create

List and create items within a treatment plan.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
provider
string or null <uuid>
procedure_code
string or null <uuid>
proc_code
string <= 20 characters
description
string <= 255 characters
tooth_num
string <= 10 characters
surface
string <= 20 characters
planned_fee
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
date_planned
string or null <date>
status
string <= 30 characters

planned, completed

plan_name
string <= 255 characters
priority
integer [ 0 .. 2147483647 ]
custom_data
any

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "proc_code": "string",
  • "description": "string",
  • "tooth_num": "string",
  • "surface": "string",
  • "planned_fee": "string",
  • "date_planned": "2019-08-24",
  • "status": "string",
  • "plan_name": "string",
  • "priority": 2147483647,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "treatment_plan": "c4c01122-8b32-4bce-bbce-bb1bda9a1a32",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "proc_code": "string",
  • "procedure_code_fee": "string",
  • "description": "string",
  • "tooth_num": "string",
  • "surface": "string",
  • "planned_fee": "string",
  • "date_planned": "2019-08-24",
  • "status": "string",
  • "est_primary_ins": "string",
  • "est_secondary_ins": "string",
  • "plan_name": "string",
  • "priority": 2147483647,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_treatment_plan_item_retrieve

Retrieve, update, or delete a treatment plan item.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
item_uid
required
string <uuid>
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "treatment_plan": "c4c01122-8b32-4bce-bbce-bb1bda9a1a32",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "proc_code": "string",
  • "procedure_code_fee": "string",
  • "description": "string",
  • "tooth_num": "string",
  • "surface": "string",
  • "planned_fee": "string",
  • "date_planned": "2019-08-24",
  • "status": "string",
  • "est_primary_ins": "string",
  • "est_secondary_ins": "string",
  • "plan_name": "string",
  • "priority": 2147483647,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_treatment_plan_item_update

Retrieve, update, or delete a treatment plan item.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
item_uid
required
string <uuid>
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
provider
string or null <uuid>
procedure_code
string or null <uuid>
proc_code
string <= 20 characters
description
string <= 255 characters
tooth_num
string <= 10 characters
surface
string <= 20 characters
planned_fee
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
date_planned
string or null <date>
status
string <= 30 characters

planned, completed

plan_name
string <= 255 characters
priority
integer [ 0 .. 2147483647 ]
custom_data
any

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "proc_code": "string",
  • "description": "string",
  • "tooth_num": "string",
  • "surface": "string",
  • "planned_fee": "string",
  • "date_planned": "2019-08-24",
  • "status": "string",
  • "plan_name": "string",
  • "priority": 2147483647,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "treatment_plan": "c4c01122-8b32-4bce-bbce-bb1bda9a1a32",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "proc_code": "string",
  • "procedure_code_fee": "string",
  • "description": "string",
  • "tooth_num": "string",
  • "surface": "string",
  • "planned_fee": "string",
  • "date_planned": "2019-08-24",
  • "status": "string",
  • "est_primary_ins": "string",
  • "est_secondary_ins": "string",
  • "plan_name": "string",
  • "priority": 2147483647,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_treatment_plan_item_partial_update

Retrieve, update, or delete a treatment plan item.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
item_uid
required
string <uuid>
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
provider
string or null <uuid>
procedure_code
string or null <uuid>
proc_code
string <= 20 characters
description
string <= 255 characters
tooth_num
string <= 10 characters
surface
string <= 20 characters
planned_fee
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
date_planned
string or null <date>
status
string <= 30 characters

planned, completed

plan_name
string <= 255 characters
priority
integer [ 0 .. 2147483647 ]
custom_data
any

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "proc_code": "string",
  • "description": "string",
  • "tooth_num": "string",
  • "surface": "string",
  • "planned_fee": "string",
  • "date_planned": "2019-08-24",
  • "status": "string",
  • "plan_name": "string",
  • "priority": 2147483647,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "treatment_plan": "c4c01122-8b32-4bce-bbce-bb1bda9a1a32",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "proc_code": "string",
  • "procedure_code_fee": "string",
  • "description": "string",
  • "tooth_num": "string",
  • "surface": "string",
  • "planned_fee": "string",
  • "date_planned": "2019-08-24",
  • "status": "string",
  • "est_primary_ins": "string",
  • "est_secondary_ins": "string",
  • "plan_name": "string",
  • "priority": 2147483647,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_treatment_plan_item_destroy

Retrieve, update, or delete a treatment plan item.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
item_uid
required
string <uuid>
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_clinical_vital_sign_retrieve

Retrieve or update a vital sign reading.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
vital_sign_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "reading_date": "2019-08-24T14:15:22Z",
  • "bp_systolic": 0,
  • "bp_diastolic": 0,
  • "pulse": 0,
  • "respiration": 0,
  • "o2_saturation": 0,
  • "temperature": "string",
  • "note": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_clinical_vital_sign_update

Retrieve or update a vital sign reading.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
vital_sign_uid
required
string <uuid>
Request Body schema:
required
appointment
string or null <uuid>
provider
string or null <uuid>
reading_date
required
string <date-time>

When the vitals were taken

bp_systolic
integer or null [ 0 .. 32767 ]

Systolic blood pressure (mmHg)

bp_diastolic
integer or null [ 0 .. 32767 ]

Diastolic blood pressure (mmHg)

pulse
integer or null [ 0 .. 32767 ]

Pulse rate (bpm)

respiration
integer or null [ 0 .. 32767 ]

Respiration rate (breaths/min)

o2_saturation
integer or null [ 0 .. 32767 ]

Oxygen saturation (%)

temperature
string or null <decimal> ^-?\d{0,3}(?:\.\d{0,1})?$

Temperature (F)

note
string
custom_data
any

Responses

Request samples

Content type
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "reading_date": "2019-08-24T14:15:22Z",
  • "bp_systolic": 32767,
  • "bp_diastolic": 32767,
  • "pulse": 32767,
  • "respiration": 32767,
  • "o2_saturation": 32767,
  • "temperature": "string",
  • "note": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "reading_date": "2019-08-24T14:15:22Z",
  • "bp_systolic": 32767,
  • "bp_diastolic": 32767,
  • "pulse": 32767,
  • "respiration": 32767,
  • "o2_saturation": 32767,
  • "temperature": "string",
  • "note": "string",
  • "custom_data": null
}

practice_patient_clinical_vital_sign_partial_update

Retrieve or update a vital sign reading.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
vital_sign_uid
required
string <uuid>
Request Body schema:
appointment
string or null <uuid>
provider
string or null <uuid>
reading_date
string <date-time>

When the vitals were taken

bp_systolic
integer or null [ 0 .. 32767 ]

Systolic blood pressure (mmHg)

bp_diastolic
integer or null [ 0 .. 32767 ]

Diastolic blood pressure (mmHg)

pulse
integer or null [ 0 .. 32767 ]

Pulse rate (bpm)

respiration
integer or null [ 0 .. 32767 ]

Respiration rate (breaths/min)

o2_saturation
integer or null [ 0 .. 32767 ]

Oxygen saturation (%)

temperature
string or null <decimal> ^-?\d{0,3}(?:\.\d{0,1})?$

Temperature (F)

note
string
custom_data
any

Responses

Request samples

Content type
{
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "reading_date": "2019-08-24T14:15:22Z",
  • "bp_systolic": 32767,
  • "bp_diastolic": 32767,
  • "pulse": 32767,
  • "respiration": 32767,
  • "o2_saturation": 32767,
  • "temperature": "string",
  • "note": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "reading_date": "2019-08-24T14:15:22Z",
  • "bp_systolic": 32767,
  • "bp_diastolic": 32767,
  • "pulse": 32767,
  • "respiration": 32767,
  • "o2_saturation": 32767,
  • "temperature": "string",
  • "note": "string",
  • "custom_data": null
}

practice_patient_comms_commlog_retrieve

Retrieve, update, or delete a communication log entry.

GH-575: every detail GET emits one comms.commlog_viewed audit event carrying is_imported so HIPAA review can filter reads of PHI-bearing historical imports specifically.

TODO(GH-575): when a replicate_of_commlog_id send endpoint is added (e.g. "resend this email" / "use as template"), it MUST 400 when the source row is is_imported=True and emit comms.commlog_resend_blocked to the audit trail. Follow-up issue tracked in escapedental/web (suppress the affordance UI-side) and in api (when the send endpoint actually lands).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
commlog_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "date_time": "2019-08-24T14:15:22Z",
  • "mode": "phone",
  • "direction": "sent",
  • "outcome": "success",
  • "subject": "string",
  • "note": "string",
  • "phi_redacted_note": "string",
  • "staff_user": "17986289-b0ef-402a-92d5-49bc6fa3367e",
  • "recall": "e7ef6ec4-8466-4387-af6a-2ed34de604a8",
  • "is_imported": true,
  • "custom_data": null,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_patient_comms_commlog_update

Retrieve, update, or delete a communication log entry.

GH-575: every detail GET emits one comms.commlog_viewed audit event carrying is_imported so HIPAA review can filter reads of PHI-bearing historical imports specifically.

TODO(GH-575): when a replicate_of_commlog_id send endpoint is added (e.g. "resend this email" / "use as template"), it MUST 400 when the source row is is_imported=True and emit comms.commlog_resend_blocked to the audit trail. Follow-up issue tracked in escapedental/web (suppress the affordance UI-side) and in api (when the send endpoint actually lands).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
commlog_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
date_time
string or null <date-time>
mode
string (ModeEnum)
Enum: "phone" "email" "text" "fax" "mail" "in_person" "web" "other"
  • phone - Phone
  • email - Email
  • text - Text
  • fax - Fax
  • mail - Mail
  • in_person - In Person
  • web - Web
  • other - Other
direction
string (Direction80cEnum)
Enum: "sent" "received" "neither"
  • sent - Sent
  • received - Received
  • neither - Neither
outcome
string
Enum: "success" "no_answer" "voicemail" "bounced" "bad_number" "other"

What happened on the contact attempt. Only success rows count toward the recall-list last_reached_at annotation.

  • success - Success
  • no_answer - No Answer
  • voicemail - Voicemail
  • bounced - Bounced
  • bad_number - Bad Number
  • other - Other
subject
string <= 255 characters

Short label, e.g. 'Recall reminder', 'Treatment plan follow-up'.

note
string
staff_user
string or null <uuid>

Staff member who logged the contact. Null for system-generated entries.

recall
string or null <uuid>

Optional link to the specific recall this contact addresses.

custom_data
any

Responses

Request samples

Content type
{
  • "date_time": "2019-08-24T14:15:22Z",
  • "mode": "phone",
  • "direction": "sent",
  • "outcome": "success",
  • "subject": "string",
  • "note": "string",
  • "staff_user": "17986289-b0ef-402a-92d5-49bc6fa3367e",
  • "recall": "e7ef6ec4-8466-4387-af6a-2ed34de604a8",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "date_time": "2019-08-24T14:15:22Z",
  • "mode": "phone",
  • "direction": "sent",
  • "outcome": "success",
  • "subject": "string",
  • "note": "string",
  • "staff_user": "17986289-b0ef-402a-92d5-49bc6fa3367e",
  • "recall": "e7ef6ec4-8466-4387-af6a-2ed34de604a8",
  • "custom_data": null
}

practice_patient_comms_commlog_partial_update

Retrieve, update, or delete a communication log entry.

GH-575: every detail GET emits one comms.commlog_viewed audit event carrying is_imported so HIPAA review can filter reads of PHI-bearing historical imports specifically.

TODO(GH-575): when a replicate_of_commlog_id send endpoint is added (e.g. "resend this email" / "use as template"), it MUST 400 when the source row is is_imported=True and emit comms.commlog_resend_blocked to the audit trail. Follow-up issue tracked in escapedental/web (suppress the affordance UI-side) and in api (when the send endpoint actually lands).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
commlog_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
date_time
string or null <date-time>
mode
string (ModeEnum)
Enum: "phone" "email" "text" "fax" "mail" "in_person" "web" "other"
  • phone - Phone
  • email - Email
  • text - Text
  • fax - Fax
  • mail - Mail
  • in_person - In Person
  • web - Web
  • other - Other
direction
string (Direction80cEnum)
Enum: "sent" "received" "neither"
  • sent - Sent
  • received - Received
  • neither - Neither
outcome
string
Enum: "success" "no_answer" "voicemail" "bounced" "bad_number" "other"

What happened on the contact attempt. Only success rows count toward the recall-list last_reached_at annotation.

  • success - Success
  • no_answer - No Answer
  • voicemail - Voicemail
  • bounced - Bounced
  • bad_number - Bad Number
  • other - Other
subject
string <= 255 characters

Short label, e.g. 'Recall reminder', 'Treatment plan follow-up'.

note
string
staff_user
string or null <uuid>

Staff member who logged the contact. Null for system-generated entries.

recall
string or null <uuid>

Optional link to the specific recall this contact addresses.

custom_data
any

Responses

Request samples

Content type
{
  • "date_time": "2019-08-24T14:15:22Z",
  • "mode": "phone",
  • "direction": "sent",
  • "outcome": "success",
  • "subject": "string",
  • "note": "string",
  • "staff_user": "17986289-b0ef-402a-92d5-49bc6fa3367e",
  • "recall": "e7ef6ec4-8466-4387-af6a-2ed34de604a8",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "date_time": "2019-08-24T14:15:22Z",
  • "mode": "phone",
  • "direction": "sent",
  • "outcome": "success",
  • "subject": "string",
  • "note": "string",
  • "staff_user": "17986289-b0ef-402a-92d5-49bc6fa3367e",
  • "recall": "e7ef6ec4-8466-4387-af6a-2ed34de604a8",
  • "custom_data": null
}

practice_patient_comms_commlog_destroy

Retrieve, update, or delete a communication log entry.

GH-575: every detail GET emits one comms.commlog_viewed audit event carrying is_imported so HIPAA review can filter reads of PHI-bearing historical imports specifically.

TODO(GH-575): when a replicate_of_commlog_id send endpoint is added (e.g. "resend this email" / "use as template"), it MUST 400 when the source row is is_imported=True and emit comms.commlog_resend_blocked to the audit trail. Follow-up issue tracked in escapedental/web (suppress the affordance UI-side) and in api (when the send endpoint actually lands).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
commlog_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_doccenter_retrieve

Retrieve or update document metadata.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
doc_id
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "category": "86d23d13-9dbb-46f3-82d0-25253c7750c3",
  • "referral": "0ff1dce1-5a61-425e-b768-f89c7726a65e",
  • "title": "string",
  • "description": "string",
  • "original_filename": "string",
  • "mime_type": "string",
  • "file_size": 0,
  • "page_count": 0,
  • "uploaded_by": "e134ce2c-a199-4e99-9c11-627b70a7ff28",
  • "source_application": 0,
  • "is_deleted": true,
  • "deleted_at": "2019-08-24T14:15:22Z",
  • "deleted_by": "d7d7cfa2-327b-4733-8887-d09252b40b06",
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "resolved_by": "d0d57369-b08b-4db8-8952-8cdeedd9aebc",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "download_url": "string",
  • "patient_name": "string",
  • "category_label": "string",
  • "uploaded_by_name": "string",
  • "caller_id": "string",
  • "processing_state": "pending",
  • "processing_error": "string",
  • "processing_updated_at": "2019-08-24T14:15:22Z",
  • "transcript": "string",
  • "transcript_confidence": "string",
  • "av_status": "pending",
  • "av_scanned_at": "2019-08-24T14:15:22Z",
  • "av_scanner": "string",
  • "av_threat_name": "string",
  • "suggested_patient_ids": [
    ],
  • "custom_data": null
}

practice_patient_doccenter_update

Retrieve or update document metadata.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
doc_id
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
patient
string or null <uuid>
category
string or null <uuid>
referral
string or null <uuid>
title
required
string [ 1 .. 255 ] characters
description
string
caller_id
string <= 32 characters ^\+\d{1,15}$

E.164 caller-ID for voicemail recordings (e.g. +14155551234). Used by the patient-link suggestion engine downstream of the voicemail-to-text pipeline.

custom_data
any

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "category": "86d23d13-9dbb-46f3-82d0-25253c7750c3",
  • "referral": "0ff1dce1-5a61-425e-b768-f89c7726a65e",
  • "title": "string",
  • "description": "string",
  • "caller_id": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "category": "86d23d13-9dbb-46f3-82d0-25253c7750c3",
  • "referral": "0ff1dce1-5a61-425e-b768-f89c7726a65e",
  • "title": "string",
  • "description": "string",
  • "original_filename": "string",
  • "mime_type": "string",
  • "file_size": 0,
  • "page_count": 0,
  • "uploaded_by": "e134ce2c-a199-4e99-9c11-627b70a7ff28",
  • "source_application": 0,
  • "is_deleted": true,
  • "deleted_at": "2019-08-24T14:15:22Z",
  • "deleted_by": "d7d7cfa2-327b-4733-8887-d09252b40b06",
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "resolved_by": "d0d57369-b08b-4db8-8952-8cdeedd9aebc",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "download_url": "string",
  • "patient_name": "string",
  • "category_label": "string",
  • "uploaded_by_name": "string",
  • "caller_id": "string",
  • "processing_state": "pending",
  • "processing_error": "string",
  • "processing_updated_at": "2019-08-24T14:15:22Z",
  • "transcript": "string",
  • "transcript_confidence": "string",
  • "av_status": "pending",
  • "av_scanned_at": "2019-08-24T14:15:22Z",
  • "av_scanner": "string",
  • "av_threat_name": "string",
  • "suggested_patient_ids": [
    ],
  • "custom_data": null
}

practice_patient_doccenter_partial_update

Retrieve or update document metadata.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
doc_id
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
patient
string or null <uuid>
category
string or null <uuid>
referral
string or null <uuid>
title
string [ 1 .. 255 ] characters
description
string
caller_id
string <= 32 characters ^\+\d{1,15}$

E.164 caller-ID for voicemail recordings (e.g. +14155551234). Used by the patient-link suggestion engine downstream of the voicemail-to-text pipeline.

custom_data
any

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "category": "86d23d13-9dbb-46f3-82d0-25253c7750c3",
  • "referral": "0ff1dce1-5a61-425e-b768-f89c7726a65e",
  • "title": "string",
  • "description": "string",
  • "caller_id": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "category": "86d23d13-9dbb-46f3-82d0-25253c7750c3",
  • "referral": "0ff1dce1-5a61-425e-b768-f89c7726a65e",
  • "title": "string",
  • "description": "string",
  • "original_filename": "string",
  • "mime_type": "string",
  • "file_size": 0,
  • "page_count": 0,
  • "uploaded_by": "e134ce2c-a199-4e99-9c11-627b70a7ff28",
  • "source_application": 0,
  • "is_deleted": true,
  • "deleted_at": "2019-08-24T14:15:22Z",
  • "deleted_by": "d7d7cfa2-327b-4733-8887-d09252b40b06",
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "resolved_by": "d0d57369-b08b-4db8-8952-8cdeedd9aebc",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "download_url": "string",
  • "patient_name": "string",
  • "category_label": "string",
  • "uploaded_by_name": "string",
  • "caller_id": "string",
  • "processing_state": "pending",
  • "processing_error": "string",
  • "processing_updated_at": "2019-08-24T14:15:22Z",
  • "transcript": "string",
  • "transcript_confidence": "string",
  • "av_status": "pending",
  • "av_scanned_at": "2019-08-24T14:15:22Z",
  • "av_scanner": "string",
  • "av_threat_name": "string",
  • "suggested_patient_ids": [
    ],
  • "custom_data": null
}

practice_patient_imaging_image_list

List images for a patient with filtering and ordering.

Query params: image_type -- filter by type (PA, BW, PANO, CEPH, etc.) image_exam -- filter by ImageExam ID (api#834) date_from -- capture_date >= (YYYY-MM-DD) date_to -- capture_date <= (YYYY-MM-DD) ordering -- comma-separated fields: capture_date, created, image_type (prefix with - for descending, default: -capture_date,-created)

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_imaging_image_exam_list

List + create :class:ImageExam rows for a patient (api#815).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_imaging_image_exam_create

List + create :class:ImageExam rows for a patient (api#815).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
template
string or null <uuid>
name
string <= 255 characters

Optional human-readable label (e.g. 'New Patient FMX').

exam_date
string or null <date>

Date the exam was performed. Defaults to created.date() on insert when omitted -- carried over from the legacy :class:Exam model so callers that filter by clinical date (timeline, share bundles) keep working.

provider
string or null <uuid>
is_complete
boolean
notes
string
custom_data
any

Responses

Request samples

Content type
{
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "name": "string",
  • "exam_date": "2019-08-24",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "is_complete": true,
  • "notes": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "template_name": "string",
  • "slot_count": "string",
  • "name": "string",
  • "exam_date": "2019-08-24",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "is_complete": true,
  • "is_deleted": true,
  • "notes": "string",
  • "image_count": 0,
  • "preview_thumbnails": [],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_imaging_image_exam_retrieve

Retrieve / update / delete a single :class:ImageExam (api#815).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
exam_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "template_name": "string",
  • "slot_count": "string",
  • "name": "string",
  • "exam_date": "2019-08-24",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "is_complete": true,
  • "is_deleted": true,
  • "notes": "string",
  • "image_count": 0,
  • "preview_thumbnails": [],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_imaging_image_exam_update

Retrieve / update / delete a single :class:ImageExam (api#815).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
exam_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
template
string or null <uuid>
name
string <= 255 characters

Optional human-readable label (e.g. 'New Patient FMX').

exam_date
string or null <date>

Date the exam was performed. Defaults to created.date() on insert when omitted -- carried over from the legacy :class:Exam model so callers that filter by clinical date (timeline, share bundles) keep working.

provider
string or null <uuid>
is_complete
boolean
notes
string
custom_data
any

Responses

Request samples

Content type
{
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "name": "string",
  • "exam_date": "2019-08-24",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "is_complete": true,
  • "notes": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "template_name": "string",
  • "slot_count": "string",
  • "name": "string",
  • "exam_date": "2019-08-24",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "is_complete": true,
  • "is_deleted": true,
  • "notes": "string",
  • "image_count": 0,
  • "preview_thumbnails": [],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_imaging_image_exam_partial_update

Retrieve / update / delete a single :class:ImageExam (api#815).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
exam_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
template
string or null <uuid>
name
string <= 255 characters

Optional human-readable label (e.g. 'New Patient FMX').

exam_date
string or null <date>

Date the exam was performed. Defaults to created.date() on insert when omitted -- carried over from the legacy :class:Exam model so callers that filter by clinical date (timeline, share bundles) keep working.

provider
string or null <uuid>
is_complete
boolean
notes
string
custom_data
any

Responses

Request samples

Content type
{
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "name": "string",
  • "exam_date": "2019-08-24",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "is_complete": true,
  • "notes": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "template_name": "string",
  • "slot_count": "string",
  • "name": "string",
  • "exam_date": "2019-08-24",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "is_complete": true,
  • "is_deleted": true,
  • "notes": "string",
  • "image_count": 0,
  • "preview_thumbnails": [],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_patient_imaging_image_exam_destroy

Retrieve / update / delete a single :class:ImageExam (api#815).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
exam_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_imaging_image_retrieve

Resolve practice_uid from the URL and enforce client-level access.

Mixed-in views automatically pick up :class:apps.practices.permissions.PracticeIsActive so writes to descendants of an inactive Client / Practice are blocked with a 403 even if the view overrides permission_classes or get_permissions(). See GH-277 for the cascade-disable rationale.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
image_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "image_exam": "0ed5a45c-af28-4d9c-a170-3b6c842bcd24",
  • "slot_index": 0,
  • "original_filename": "string",
  • "mime_type": "string",
  • "file_size": 0,
  • "width": 0,
  • "height": 0,
  • "image_type": "pa",
  • "capture_date": "2019-08-24",
  • "capture_device": "string",
  • "tooth_numbers": null,
  • "description": "string",
  • "degrees_rotated": -2147483648,
  • "is_flipped": true,
  • "display_settings": null,
  • "annotations": null,
  • "notes": "string",
  • "is_deleted": true,
  • "download_url": "string",
  • "thumbnail_url": "string",
  • "uploaded_by": "e134ce2c-a199-4e99-9c11-627b70a7ff28",
  • "deleted_by": "d7d7cfa2-327b-4733-8887-d09252b40b06",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "av_status": "pending",
  • "av_scanned_at": "2019-08-24T14:15:22Z",
  • "av_scanner": "string",
  • "av_threat_name": "string",
  • "custom_data": null
}

practice_patient_imaging_image_update

Resolve practice_uid from the URL and enforce client-level access.

Mixed-in views automatically pick up :class:apps.practices.permissions.PracticeIsActive so writes to descendants of an inactive Client / Practice are blocked with a 403 even if the view overrides permission_classes or get_permissions(). See GH-277 for the cascade-disable rationale.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
image_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
image_exam
string or null <uuid>
slot_index
integer or null >= 0
original_filename
string <= 255 characters
mime_type
string [ 1 .. 50 ] characters
ImageTypeEnum (string) or BlankEnum (any)
capture_date
required
string <date>
capture_device
string <= 255 characters

Device name from browser getUserMedia

tooth_numbers
any

Universal numbering: 1-32 permanent, A-T primary

description
string <= 255 characters

Short description/label for the image

degrees_rotated
integer [ -2147483648 .. 2147483647 ]

Rotation state: 0, 90, 180, or 270 degrees

is_flipped
boolean

Horizontal flip state

display_settings
any

Viewer display settings: brightness, contrast, inverted, etc.

annotations
any

Array of annotation objects from the viewer

notes
string
custom_data
any

Responses

Request samples

Content type
{
  • "image_exam": "0ed5a45c-af28-4d9c-a170-3b6c842bcd24",
  • "slot_index": 0,
  • "original_filename": "string",
  • "mime_type": "string",
  • "image_type": "pa",
  • "capture_date": "2019-08-24",
  • "capture_device": "string",
  • "tooth_numbers": null,
  • "description": "string",
  • "degrees_rotated": -2147483648,
  • "is_flipped": true,
  • "display_settings": null,
  • "annotations": null,
  • "notes": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "image_exam": "0ed5a45c-af28-4d9c-a170-3b6c842bcd24",
  • "slot_index": 0,
  • "original_filename": "string",
  • "mime_type": "string",
  • "file_size": 0,
  • "width": 0,
  • "height": 0,
  • "image_type": "pa",
  • "capture_date": "2019-08-24",
  • "capture_device": "string",
  • "tooth_numbers": null,
  • "description": "string",
  • "degrees_rotated": -2147483648,
  • "is_flipped": true,
  • "display_settings": null,
  • "annotations": null,
  • "notes": "string",
  • "is_deleted": true,
  • "download_url": "string",
  • "thumbnail_url": "string",
  • "uploaded_by": "e134ce2c-a199-4e99-9c11-627b70a7ff28",
  • "deleted_by": "d7d7cfa2-327b-4733-8887-d09252b40b06",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "av_status": "pending",
  • "av_scanned_at": "2019-08-24T14:15:22Z",
  • "av_scanner": "string",
  • "av_threat_name": "string",
  • "custom_data": null
}

practice_patient_imaging_image_partial_update

Resolve practice_uid from the URL and enforce client-level access.

Mixed-in views automatically pick up :class:apps.practices.permissions.PracticeIsActive so writes to descendants of an inactive Client / Practice are blocked with a 403 even if the view overrides permission_classes or get_permissions(). See GH-277 for the cascade-disable rationale.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
image_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
image_exam
string or null <uuid>
slot_index
integer or null >= 0
original_filename
string <= 255 characters
mime_type
string [ 1 .. 50 ] characters
ImageTypeEnum (string) or BlankEnum (any)
capture_date
string <date>
capture_device
string <= 255 characters

Device name from browser getUserMedia

tooth_numbers
any

Universal numbering: 1-32 permanent, A-T primary

description
string <= 255 characters

Short description/label for the image

degrees_rotated
integer [ -2147483648 .. 2147483647 ]

Rotation state: 0, 90, 180, or 270 degrees

is_flipped
boolean

Horizontal flip state

display_settings
any

Viewer display settings: brightness, contrast, inverted, etc.

annotations
any

Array of annotation objects from the viewer

notes
string
custom_data
any

Responses

Request samples

Content type
{
  • "image_exam": "0ed5a45c-af28-4d9c-a170-3b6c842bcd24",
  • "slot_index": 0,
  • "original_filename": "string",
  • "mime_type": "string",
  • "image_type": "pa",
  • "capture_date": "2019-08-24",
  • "capture_device": "string",
  • "tooth_numbers": null,
  • "description": "string",
  • "degrees_rotated": -2147483648,
  • "is_flipped": true,
  • "display_settings": null,
  • "annotations": null,
  • "notes": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "image_exam": "0ed5a45c-af28-4d9c-a170-3b6c842bcd24",
  • "slot_index": 0,
  • "original_filename": "string",
  • "mime_type": "string",
  • "file_size": 0,
  • "width": 0,
  • "height": 0,
  • "image_type": "pa",
  • "capture_date": "2019-08-24",
  • "capture_device": "string",
  • "tooth_numbers": null,
  • "description": "string",
  • "degrees_rotated": -2147483648,
  • "is_flipped": true,
  • "display_settings": null,
  • "annotations": null,
  • "notes": "string",
  • "is_deleted": true,
  • "download_url": "string",
  • "thumbnail_url": "string",
  • "uploaded_by": "e134ce2c-a199-4e99-9c11-627b70a7ff28",
  • "deleted_by": "d7d7cfa2-327b-4733-8887-d09252b40b06",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "av_status": "pending",
  • "av_scanned_at": "2019-08-24T14:15:22Z",
  • "av_scanner": "string",
  • "av_threat_name": "string",
  • "custom_data": null
}

practice_patient_imaging_image_destroy

Resolve practice_uid from the URL and enforce client-level access.

Mixed-in views automatically pick up :class:apps.practices.permissions.PracticeIsActive so writes to descendants of an inactive Client / Practice are blocked with a 403 even if the view overrides permission_classes or get_permissions(). See GH-277 for the cascade-disable rationale.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
image_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_imaging_image_upload_create

Upload a dental image via multipart form data.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
image_exam
string or null <uuid>

The ImageExam this image belongs to (api#815, api#834).

slot_index
integer or null [ 0 .. 32767 ]

0-based slot index within image_exam.template.slot_count (api#815). Required when image_exam is set.

file
required
string <binary>
ImageTypeEnum (string) or BlankEnum (any)
capture_date
required
string <date>
capture_device
string <= 255 characters

Device name from browser getUserMedia

tooth_numbers
any

Universal numbering: 1-32 permanent, A-T primary

description
string <= 255 characters

Short description/label for the image

notes
string

Responses

Response samples

Content type
application/json
{
  • "image_exam": "0ed5a45c-af28-4d9c-a170-3b6c842bcd24",
  • "slot_index": 32767,
  • "image_type": "pa",
  • "capture_date": "2019-08-24",
  • "capture_device": "string",
  • "tooth_numbers": null,
  • "description": "string",
  • "notes": "string"
}

practice_patient_insurance_claim_log_list

List status change log entries for a specific claim.

GET /practice//patient//insurance/claim//log/

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
claim_id
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_insurance_claim_retrieve

Retrieve a single insurance claim with full details.

GET /practice//patient//insurance/claim//

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
claim_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "custom_data": null,
  • "procedures": [
    ],
  • "status_log": [
    ],
  • "patient_name": "string",
  • "patient_first_name": "string",
  • "patient_last_name": "string",
  • "provider_name": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "date_service": "2019-08-24",
  • "date_sent": "2019-08-24",
  • "status": "draft",
  • "claim_status": "string",
  • "claim_fee": "string",
  • "ins_pay_est": "string",
  • "ins_pay_amt": "string",
  • "ded_applied": "string",
  • "write_off": "string",
  • "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4",
  • "modified_by": "e8d4374d-93a1-4e98-a6c6-fdcf00c5059f",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "patient_insurance": "e396a8de-c249-4467-871f-c8b5f28219f1"
}

practice_patient_insurance_claim_update_partial_update

Update an insurance claim. Only draft or imported claims may be edited.

PATCH /practice//patient//insurance/claim//

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
claim_uid
required
string <uuid>
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
provider
string or null <uuid>
patient_insurance
string or null <uuid>
date_service
string or null <date>
date_sent
string or null <date>
claim_fee
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
ins_pay_est
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
ins_pay_amt
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
ded_applied
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
write_off
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
Array of objects (ClaimProcedureWriteRequest)
custom_data
any

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "patient_insurance": "e396a8de-c249-4467-871f-c8b5f28219f1",
  • "date_service": "2019-08-24",
  • "date_sent": "2019-08-24",
  • "claim_fee": "string",
  • "ins_pay_est": "string",
  • "ins_pay_amt": "string",
  • "ded_applied": "string",
  • "write_off": "string",
  • "procedures": [
    ],
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "patient_insurance": "e396a8de-c249-4467-871f-c8b5f28219f1",
  • "date_service": "2019-08-24",
  • "date_sent": "2019-08-24",
  • "claim_fee": "string",
  • "ins_pay_est": "string",
  • "ins_pay_amt": "string",
  • "ded_applied": "string",
  • "write_off": "string",
  • "procedures": [
    ],
  • "custom_data": null
}

practice_patient_insurance_plan_benefit_retrieve

Update or delete a benefit.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
benefit_uid
required
string <uuid>
patient_id
required
string <uuid>
plan_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "custom_data": null,
  • "procedure_code": {
    },
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "benefit_type": "percentage",
  • "coverage_category": "diagnostic",
  • "percent": "string",
  • "monetary_amt": "string",
  • "time_period": "calendar_year",
  • "proc_code": "string",
  • "min_age": 32767,
  • "max_age": 32767,
  • "waiting_period_months": 32767,
  • "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4",
  • "modified_by": "e8d4374d-93a1-4e98-a6c6-fdcf00c5059f",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "patient_insurance": "e396a8de-c249-4467-871f-c8b5f28219f1"
}

practice_patient_insurance_plan_benefit_update

Update or delete a benefit.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
benefit_uid
required
string <uuid>
patient_id
required
string <uuid>
plan_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
insurance_plan
string or null <uuid>
BenefitTypeEnum (string) or BlankEnum (any)
CoverageCategoryEnum (string) or BlankEnum (any)
percent
string <decimal> ^-?\d{0,3}(?:\.\d{0,2})?$
monetary_amt
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
TimePeriodEnum (string) or BlankEnum (any)
proc_code
string <= 20 characters

Benefit tied to a specific procedure code

procedure_code
string or null <uuid>
min_age
integer or null [ 0 .. 32767 ]

Minimum patient age (inclusive) for this benefit to apply

max_age
integer or null [ 0 .. 32767 ]

Maximum patient age (inclusive) for this benefit to apply

waiting_period_months
integer or null [ 0 .. 32767 ]

Months from effective date before this benefit is available

custom_data
any

Responses

Request samples

Content type
{
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "benefit_type": "percentage",
  • "coverage_category": "diagnostic",
  • "percent": "string",
  • "monetary_amt": "string",
  • "time_period": "calendar_year",
  • "proc_code": "string",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "min_age": 32767,
  • "max_age": 32767,
  • "waiting_period_months": 32767,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "benefit_type": "percentage",
  • "coverage_category": "diagnostic",
  • "percent": "string",
  • "monetary_amt": "string",
  • "time_period": "calendar_year",
  • "proc_code": "string",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "min_age": 32767,
  • "max_age": 32767,
  • "waiting_period_months": 32767,
  • "custom_data": null
}

practice_patient_insurance_plan_benefit_partial_update

Update or delete a benefit.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
benefit_uid
required
string <uuid>
patient_id
required
string <uuid>
plan_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
insurance_plan
string or null <uuid>
BenefitTypeEnum (string) or BlankEnum (any)
CoverageCategoryEnum (string) or BlankEnum (any)
percent
string <decimal> ^-?\d{0,3}(?:\.\d{0,2})?$
monetary_amt
string <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$
TimePeriodEnum (string) or BlankEnum (any)
proc_code
string <= 20 characters

Benefit tied to a specific procedure code

procedure_code
string or null <uuid>
min_age
integer or null [ 0 .. 32767 ]

Minimum patient age (inclusive) for this benefit to apply

max_age
integer or null [ 0 .. 32767 ]

Maximum patient age (inclusive) for this benefit to apply

waiting_period_months
integer or null [ 0 .. 32767 ]

Months from effective date before this benefit is available

custom_data
any

Responses

Request samples

Content type
{
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "benefit_type": "percentage",
  • "coverage_category": "diagnostic",
  • "percent": "string",
  • "monetary_amt": "string",
  • "time_period": "calendar_year",
  • "proc_code": "string",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "min_age": 32767,
  • "max_age": 32767,
  • "waiting_period_months": 32767,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "benefit_type": "percentage",
  • "coverage_category": "diagnostic",
  • "percent": "string",
  • "monetary_amt": "string",
  • "time_period": "calendar_year",
  • "proc_code": "string",
  • "procedure_code": "d6cd26fd-67f7-4760-9d46-9e3d886de650",
  • "min_age": 32767,
  • "max_age": 32767,
  • "waiting_period_months": 32767,
  • "custom_data": null
}

practice_patient_insurance_plan_benefit_destroy

Update or delete a benefit.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
benefit_uid
required
string <uuid>
patient_id
required
string <uuid>
plan_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_insurance_plan_retrieve

Retrieve, update, or delete a patient insurance plan.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "custom_data": null,
  • "benefits": [
    ],
  • "carrier_detail": {
    },
  • "plan_detail": {
    },
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "carrier_name": "string",
  • "group_number": "string",
  • "subscriber_id": "string",
  • "subscriber_name": "string",
  • "ordinal": 1,
  • "relationship_to_subscriber": "self",
  • "effective_date": "2019-08-24",
  • "termination_date": "2019-08-24",
  • "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4",
  • "modified_by": "e8d4374d-93a1-4e98-a6c6-fdcf00c5059f",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5"
}

practice_patient_insurance_plan_update

Retrieve, update, or delete a patient insurance plan.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
insurance_plan
string or null <uuid>
carrier_name
required
string [ 1 .. 255 ] characters
carrier
string or null <uuid>
fee_schedule
string or null <uuid>

Fee schedule used for benefit estimation under this plan

group_number
string <= 100 characters
subscriber_id
string <= 100 characters
subscriber_name
string <= 255 characters

Policy holder name if different from patient

ordinal
integer [ 0 .. 32767 ]

1=primary, 2=secondary

RelationshipToSubscriberEnum (string) or BlankEnum (any)
effective_date
string or null <date>
termination_date
string or null <date>
custom_data
any

Responses

Request samples

Content type
{
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "carrier_name": "string",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5",
  • "group_number": "string",
  • "subscriber_id": "string",
  • "subscriber_name": "string",
  • "ordinal": 32767,
  • "relationship_to_subscriber": "self",
  • "effective_date": "2019-08-24",
  • "termination_date": "2019-08-24",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "carrier_name": "string",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5",
  • "group_number": "string",
  • "subscriber_id": "string",
  • "subscriber_name": "string",
  • "ordinal": 32767,
  • "relationship_to_subscriber": "self",
  • "effective_date": "2019-08-24",
  • "termination_date": "2019-08-24",
  • "custom_data": null
}

practice_patient_insurance_plan_partial_update

Retrieve, update, or delete a patient insurance plan.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
insurance_plan
string or null <uuid>
carrier_name
string [ 1 .. 255 ] characters
carrier
string or null <uuid>
fee_schedule
string or null <uuid>

Fee schedule used for benefit estimation under this plan

group_number
string <= 100 characters
subscriber_id
string <= 100 characters
subscriber_name
string <= 255 characters

Policy holder name if different from patient

ordinal
integer [ 0 .. 32767 ]

1=primary, 2=secondary

RelationshipToSubscriberEnum (string) or BlankEnum (any)
effective_date
string or null <date>
termination_date
string or null <date>
custom_data
any

Responses

Request samples

Content type
{
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "carrier_name": "string",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5",
  • "group_number": "string",
  • "subscriber_id": "string",
  • "subscriber_name": "string",
  • "ordinal": 32767,
  • "relationship_to_subscriber": "self",
  • "effective_date": "2019-08-24",
  • "termination_date": "2019-08-24",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "insurance_plan": "b384841f-92bf-462b-afca-b6f7c0177002",
  • "carrier_name": "string",
  • "carrier": "faaa07f8-ed24-4408-95d3-1d7233f61a3e",
  • "fee_schedule": "23e675e4-8697-41ef-9cf8-c46fa2b3e8c5",
  • "group_number": "string",
  • "subscriber_id": "string",
  • "subscriber_name": "string",
  • "ordinal": 32767,
  • "relationship_to_subscriber": "self",
  • "effective_date": "2019-08-24",
  • "termination_date": "2019-08-24",
  • "custom_data": null
}

practice_patient_insurance_plan_destroy

Retrieve, update, or delete a patient insurance plan.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
plan_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_scheduling_recall_list

List recalls for a specific patient (patient-scoped, read-only).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_retrieve

Retrieve or update a single patient. Staff-only.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "first_name": "string",
  • "last_name": "string",
  • "preferred_name": "string",
  • "email": "user@example.com",
  • "date_of_birth": "2019-08-24",
  • "gender": "male",
  • "status": "active",
  • "phone_home": "string",
  • "phone_work": "string",
  • "phone_mobile": "string",
  • "address": "string",
  • "address2": "string",
  • "city": "string",
  • "state": "string",
  • "zip_code": "string",
  • "primary_provider": "be2be9e9-c010-46fe-8c1e-a13cbc4f6d37",
  • "secondary_provider": "777f5dc9-f0f1-403f-9363-1023b8767d88",
  • "last_medical_review": "2019-08-24",
  • "last_medical_review_by": "32e17085-58ec-492b-b21e-23eca3985cd7",
  • "last_medical_review_by_name": "string",
  • "balance_current": "string",
  • "last_recall_date": "2019-08-24",
  • "next_recall_date": "2019-08-24",
  • "recall_risk_score": 0,
  • "noshow_risk_score": 0.1,
  • "prefers_email": true,
  • "prefers_sms": true,
  • "hipaa_consent_signed": true,
  • "hipaa_consent_date": "2019-08-24",
  • "hipaa_authorization_signed": true,
  • "hipaa_authorization_date": "2019-08-24",
  • "hipaa_privacy_practices_signed": true,
  • "hipaa_privacy_practices_date": "2019-08-24",
  • "custom_data": null,
  • "referral_source": "string",
  • "ssn_last4_masked": "string",
  • "source_system": "string",
  • "source_id": "string"
}

practice_patient_update

Retrieve or update a single patient. Staff-only.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
first_name
required
string [ 1 .. 100 ] characters
last_name
required
string [ 1 .. 100 ] characters
preferred_name
string <= 100 characters
email
string <email> <= 254 characters
date_of_birth
string or null <date>
gender
string (GenderEnum)
Enum: "male" "female" "prefer_not_to_say" "unknown"
  • male - Male
  • female - Female
  • prefer_not_to_say - Prefer not to say
  • unknown - Unknown
status
string (PatientStatusEnum)
Enum: "active" "inactive" "archived" "deceased" "prospective"
  • active - Active
  • inactive - Inactive
  • archived - Archived
  • deceased - Deceased
  • prospective - Prospective
phone_home
string or null
phone_work
string or null
phone_mobile
string or null
address
string <= 255 characters
address2
string <= 255 characters
city
string <= 100 characters
state
string <= 50 characters
zip_code
string <= 10 characters ^\d{5}(-\d{4})?$
primary_provider
string or null <uuid>
secondary_provider
string or null <uuid>
balance_current
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Current account balance, denormalized from the ledger for fast list rendering.

last_recall_date
string or null <date>

Most recent recall appointment date from the source PMS

next_recall_date
string or null <date>

Next scheduled recall appointment date from the source PMS

prefers_email
boolean

Patient opts in to email communications (per source PMS)

prefers_sms
boolean

Patient opts in to SMS/text communications (per source PMS)

hipaa_consent_signed
boolean

HIPAA treatment consent signed (per source PMS)

hipaa_consent_date
string or null <date>

Date HIPAA treatment consent was signed

hipaa_authorization_signed
boolean

HIPAA authorization (release of info) signed (per source PMS)

hipaa_authorization_date
string or null <date>

Date HIPAA authorization was signed

hipaa_privacy_practices_signed
boolean

HIPAA notice of privacy practices acknowledged (per source PMS)

hipaa_privacy_practices_date
string or null <date>

Date HIPAA notice of privacy practices was acknowledged

custom_data
any
ssn_full
string or null [ 1 .. 11 ] characters

Write-only. Sets the patient's SSN via the encrypted side table. Pass null to clear. Never returned on read -- the /ssn/full/ endpoint is the only path for audit-logged disclosure.

Responses

Request samples

Content type
{
  • "first_name": "string",
  • "last_name": "string",
  • "preferred_name": "string",
  • "email": "user@example.com",
  • "date_of_birth": "2019-08-24",
  • "gender": "male",
  • "status": "active",
  • "phone_home": "string",
  • "phone_work": "string",
  • "phone_mobile": "string",
  • "address": "string",
  • "address2": "string",
  • "city": "string",
  • "state": "string",
  • "zip_code": "string",
  • "primary_provider": "be2be9e9-c010-46fe-8c1e-a13cbc4f6d37",
  • "secondary_provider": "777f5dc9-f0f1-403f-9363-1023b8767d88",
  • "balance_current": "string",
  • "last_recall_date": "2019-08-24",
  • "next_recall_date": "2019-08-24",
  • "prefers_email": true,
  • "prefers_sms": true,
  • "hipaa_consent_signed": true,
  • "hipaa_consent_date": "2019-08-24",
  • "hipaa_authorization_signed": true,
  • "hipaa_authorization_date": "2019-08-24",
  • "hipaa_privacy_practices_signed": true,
  • "hipaa_privacy_practices_date": "2019-08-24",
  • "custom_data": null,
  • "ssn_full": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "first_name": "string",
  • "last_name": "string",
  • "preferred_name": "string",
  • "email": "user@example.com",
  • "date_of_birth": "2019-08-24",
  • "gender": "male",
  • "status": "active",
  • "phone_home": "string",
  • "phone_work": "string",
  • "phone_mobile": "string",
  • "address": "string",
  • "address2": "string",
  • "city": "string",
  • "state": "string",
  • "zip_code": "string",
  • "primary_provider": "be2be9e9-c010-46fe-8c1e-a13cbc4f6d37",
  • "secondary_provider": "777f5dc9-f0f1-403f-9363-1023b8767d88",
  • "last_medical_review": "2019-08-24",
  • "last_medical_review_by": "32e17085-58ec-492b-b21e-23eca3985cd7",
  • "last_medical_review_by_name": "string",
  • "balance_current": "string",
  • "last_recall_date": "2019-08-24",
  • "next_recall_date": "2019-08-24",
  • "recall_risk_score": 0,
  • "noshow_risk_score": 0.1,
  • "prefers_email": true,
  • "prefers_sms": true,
  • "hipaa_consent_signed": true,
  • "hipaa_consent_date": "2019-08-24",
  • "hipaa_authorization_signed": true,
  • "hipaa_authorization_date": "2019-08-24",
  • "hipaa_privacy_practices_signed": true,
  • "hipaa_privacy_practices_date": "2019-08-24",
  • "custom_data": null,
  • "referral_source": "string",
  • "ssn_last4_masked": "string",
  • "source_system": "string",
  • "source_id": "string"
}

practice_patient_partial_update

Retrieve or update a single patient. Staff-only.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
first_name
string [ 1 .. 100 ] characters
last_name
string [ 1 .. 100 ] characters
preferred_name
string <= 100 characters
email
string <email> <= 254 characters
date_of_birth
string or null <date>
gender
string (GenderEnum)
Enum: "male" "female" "prefer_not_to_say" "unknown"
  • male - Male
  • female - Female
  • prefer_not_to_say - Prefer not to say
  • unknown - Unknown
status
string (PatientStatusEnum)
Enum: "active" "inactive" "archived" "deceased" "prospective"
  • active - Active
  • inactive - Inactive
  • archived - Archived
  • deceased - Deceased
  • prospective - Prospective
phone_home
string or null
phone_work
string or null
phone_mobile
string or null
address
string <= 255 characters
address2
string <= 255 characters
city
string <= 100 characters
state
string <= 50 characters
zip_code
string <= 10 characters ^\d{5}(-\d{4})?$
primary_provider
string or null <uuid>
secondary_provider
string or null <uuid>
balance_current
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Current account balance, denormalized from the ledger for fast list rendering.

last_recall_date
string or null <date>

Most recent recall appointment date from the source PMS

next_recall_date
string or null <date>

Next scheduled recall appointment date from the source PMS

prefers_email
boolean

Patient opts in to email communications (per source PMS)

prefers_sms
boolean

Patient opts in to SMS/text communications (per source PMS)

hipaa_consent_signed
boolean

HIPAA treatment consent signed (per source PMS)

hipaa_consent_date
string or null <date>

Date HIPAA treatment consent was signed

hipaa_authorization_signed
boolean

HIPAA authorization (release of info) signed (per source PMS)

hipaa_authorization_date
string or null <date>

Date HIPAA authorization was signed

hipaa_privacy_practices_signed
boolean

HIPAA notice of privacy practices acknowledged (per source PMS)

hipaa_privacy_practices_date
string or null <date>

Date HIPAA notice of privacy practices was acknowledged

custom_data
any
ssn_full
string or null [ 1 .. 11 ] characters

Write-only. Sets the patient's SSN via the encrypted side table. Pass null to clear. Never returned on read -- the /ssn/full/ endpoint is the only path for audit-logged disclosure.

Responses

Request samples

Content type
{
  • "first_name": "string",
  • "last_name": "string",
  • "preferred_name": "string",
  • "email": "user@example.com",
  • "date_of_birth": "2019-08-24",
  • "gender": "male",
  • "status": "active",
  • "phone_home": "string",
  • "phone_work": "string",
  • "phone_mobile": "string",
  • "address": "string",
  • "address2": "string",
  • "city": "string",
  • "state": "string",
  • "zip_code": "string",
  • "primary_provider": "be2be9e9-c010-46fe-8c1e-a13cbc4f6d37",
  • "secondary_provider": "777f5dc9-f0f1-403f-9363-1023b8767d88",
  • "balance_current": "string",
  • "last_recall_date": "2019-08-24",
  • "next_recall_date": "2019-08-24",
  • "prefers_email": true,
  • "prefers_sms": true,
  • "hipaa_consent_signed": true,
  • "hipaa_consent_date": "2019-08-24",
  • "hipaa_authorization_signed": true,
  • "hipaa_authorization_date": "2019-08-24",
  • "hipaa_privacy_practices_signed": true,
  • "hipaa_privacy_practices_date": "2019-08-24",
  • "custom_data": null,
  • "ssn_full": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "first_name": "string",
  • "last_name": "string",
  • "preferred_name": "string",
  • "email": "user@example.com",
  • "date_of_birth": "2019-08-24",
  • "gender": "male",
  • "status": "active",
  • "phone_home": "string",
  • "phone_work": "string",
  • "phone_mobile": "string",
  • "address": "string",
  • "address2": "string",
  • "city": "string",
  • "state": "string",
  • "zip_code": "string",
  • "primary_provider": "be2be9e9-c010-46fe-8c1e-a13cbc4f6d37",
  • "secondary_provider": "777f5dc9-f0f1-403f-9363-1023b8767d88",
  • "last_medical_review": "2019-08-24",
  • "last_medical_review_by": "32e17085-58ec-492b-b21e-23eca3985cd7",
  • "last_medical_review_by_name": "string",
  • "balance_current": "string",
  • "last_recall_date": "2019-08-24",
  • "next_recall_date": "2019-08-24",
  • "recall_risk_score": 0,
  • "noshow_risk_score": 0.1,
  • "prefers_email": true,
  • "prefers_sms": true,
  • "hipaa_consent_signed": true,
  • "hipaa_consent_date": "2019-08-24",
  • "hipaa_authorization_signed": true,
  • "hipaa_authorization_date": "2019-08-24",
  • "hipaa_privacy_practices_signed": true,
  • "hipaa_privacy_practices_date": "2019-08-24",
  • "custom_data": null,
  • "referral_source": "string",
  • "ssn_last4_masked": "string",
  • "source_system": "string",
  • "source_id": "string"
}

practice_patient_referral_source_list

List and create referral sources for a practice.

Bulk create is supported by POSTing an array.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_referral_source_create

List and create referral sources for a practice.

Bulk create is supported by POSTing an array.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
first_name
string <= 100 characters
last_name
string <= 100 characters
specialty
string <= 100 characters
phone
string <= 20 characters
email
string <email> <= 254 characters
npi
string <= 20 characters
is_doctor
boolean
custom_data
any

Responses

Request samples

Content type
{
  • "first_name": "string",
  • "last_name": "string",
  • "specialty": "string",
  • "phone": "string",
  • "email": "user@example.com",
  • "npi": "string",
  • "is_doctor": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "first_name": "string",
  • "last_name": "string",
  • "specialty": "string",
  • "phone": "string",
  • "email": "user@example.com",
  • "npi": "string",
  • "is_doctor": true,
  • "custom_data": null
}

practice_patient_referral_source_retrieve

Retrieve, update, or delete a referral source.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
referral_source_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "first_name": "string",
  • "last_name": "string",
  • "specialty": "string",
  • "phone": "string",
  • "email": "user@example.com",
  • "npi": "string",
  • "is_doctor": true,
  • "custom_data": null,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_patient_referral_source_update

Retrieve, update, or delete a referral source.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
referral_source_uid
required
string <uuid>
Request Body schema:
first_name
string <= 100 characters
last_name
string <= 100 characters
specialty
string <= 100 characters
phone
string <= 20 characters
email
string <email> <= 254 characters
npi
string <= 20 characters
is_doctor
boolean
custom_data
any

Responses

Request samples

Content type
{
  • "first_name": "string",
  • "last_name": "string",
  • "specialty": "string",
  • "phone": "string",
  • "email": "user@example.com",
  • "npi": "string",
  • "is_doctor": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "first_name": "string",
  • "last_name": "string",
  • "specialty": "string",
  • "phone": "string",
  • "email": "user@example.com",
  • "npi": "string",
  • "is_doctor": true,
  • "custom_data": null
}

practice_patient_referral_source_partial_update

Retrieve, update, or delete a referral source.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
referral_source_uid
required
string <uuid>
Request Body schema:
first_name
string <= 100 characters
last_name
string <= 100 characters
specialty
string <= 100 characters
phone
string <= 20 characters
email
string <email> <= 254 characters
npi
string <= 20 characters
is_doctor
boolean
custom_data
any

Responses

Request samples

Content type
{
  • "first_name": "string",
  • "last_name": "string",
  • "specialty": "string",
  • "phone": "string",
  • "email": "user@example.com",
  • "npi": "string",
  • "is_doctor": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "first_name": "string",
  • "last_name": "string",
  • "specialty": "string",
  • "phone": "string",
  • "email": "user@example.com",
  • "npi": "string",
  • "is_doctor": true,
  • "custom_data": null
}

practice_patient_referral_source_destroy

Retrieve, update, or delete a referral source.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
referral_source_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_prescription_signature_retrieve

Retrieve the captured signature for an approved prescription.

GET /v1/practice//prescription//signature/

PHI — practice-scoped, staff only. binding_valid flags whether the content-hash binding still matches (tamper signal).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
prescription_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "prescription": "95b77ae3-7060-4419-9c3c-3a57c46d9d05",
  • "signing_provider": "3576a91f-666c-4531-a20d-84b511e04787",
  • "signing_provider_name": "string",
  • "signed_by_user": "6c12ae28-9909-4390-970a-2a1d9103614b",
  • "signature_svg_base64": "string",
  • "content_hash": "string",
  • "binding_valid": true,
  • "signed_at": "2019-08-24T14:15:22Z",
  • "ip_address": "string",
  • "user_agent": "string",
  • "device_type": "string",
  • "capture_method": "touch",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_provider_retrieve

Retrieve or update a single provider.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
provider_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "first_name": "string",
  • "last_name": "string",
  • "abbreviation": "string",
  • "specialty": "string",
  • "provider_type": "dentist",
  • "color": "string",
  • "npi": "string",
  • "dea_number": "string",
  • "can_prescribe": true,
  • "can_prescribe_controlled": true,
  • "is_hidden": true,
  • "is_secondary": true,
  • "is_active": true,
  • "is_web_sched": true,
  • "custom_data": null
}

practice_provider_update

Retrieve or update a single provider.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
provider_uid
required
string <uuid>
Request Body schema:
required
first_name
required
string [ 1 .. 100 ] characters
last_name
required
string [ 1 .. 100 ] characters
abbreviation
string <= 20 characters
specialty
string <= 100 characters
provider_type
string (ProviderTypeEnum)
Enum: "dentist" "hygienist" "assistant" "other"
  • dentist - Dentist
  • hygienist - Hygienist
  • assistant - Assistant
  • other - Other
color
string <= 7 characters

Hex color for calendar rendering, e.g. #3B82F6

npi
string <= 10 characters

National Provider Identifier

dea_number
string <= 9 characters

DEA registration number (2 letters + 7 digits, e.g. AB1234567). Required on paper controlled-substance prescriptions. Not required for non-controlled prescriptions. Added as part of the prescriptions module (escape#136 / api#482).

is_hidden
boolean

Hidden from dropdowns but visible on historical records

is_secondary
boolean

Legacy import field — use provider_type instead

is_active
boolean

Currently employed at this practice

is_web_sched
boolean

Available for patient online scheduling.

custom_data
any

Responses

Request samples

Content type
{
  • "first_name": "string",
  • "last_name": "string",
  • "abbreviation": "string",
  • "specialty": "string",
  • "provider_type": "dentist",
  • "color": "string",
  • "npi": "string",
  • "dea_number": "string",
  • "is_hidden": true,
  • "is_secondary": true,
  • "is_active": true,
  • "is_web_sched": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "first_name": "string",
  • "last_name": "string",
  • "abbreviation": "string",
  • "specialty": "string",
  • "provider_type": "dentist",
  • "color": "string",
  • "npi": "string",
  • "dea_number": "string",
  • "can_prescribe": true,
  • "can_prescribe_controlled": true,
  • "is_hidden": true,
  • "is_secondary": true,
  • "is_active": true,
  • "is_web_sched": true,
  • "custom_data": null
}

practice_provider_partial_update

Retrieve or update a single provider.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
provider_uid
required
string <uuid>
Request Body schema:
first_name
string [ 1 .. 100 ] characters
last_name
string [ 1 .. 100 ] characters
abbreviation
string <= 20 characters
specialty
string <= 100 characters
provider_type
string (ProviderTypeEnum)
Enum: "dentist" "hygienist" "assistant" "other"
  • dentist - Dentist
  • hygienist - Hygienist
  • assistant - Assistant
  • other - Other
color
string <= 7 characters

Hex color for calendar rendering, e.g. #3B82F6

npi
string <= 10 characters

National Provider Identifier

dea_number
string <= 9 characters

DEA registration number (2 letters + 7 digits, e.g. AB1234567). Required on paper controlled-substance prescriptions. Not required for non-controlled prescriptions. Added as part of the prescriptions module (escape#136 / api#482).

is_hidden
boolean

Hidden from dropdowns but visible on historical records

is_secondary
boolean

Legacy import field — use provider_type instead

is_active
boolean

Currently employed at this practice

is_web_sched
boolean

Available for patient online scheduling.

custom_data
any

Responses

Request samples

Content type
{
  • "first_name": "string",
  • "last_name": "string",
  • "abbreviation": "string",
  • "specialty": "string",
  • "provider_type": "dentist",
  • "color": "string",
  • "npi": "string",
  • "dea_number": "string",
  • "is_hidden": true,
  • "is_secondary": true,
  • "is_active": true,
  • "is_web_sched": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "first_name": "string",
  • "last_name": "string",
  • "abbreviation": "string",
  • "specialty": "string",
  • "provider_type": "dentist",
  • "color": "string",
  • "npi": "string",
  • "dea_number": "string",
  • "can_prescribe": true,
  • "can_prescribe_controlled": true,
  • "is_hidden": true,
  • "is_secondary": true,
  • "is_active": true,
  • "is_web_sched": true,
  • "custom_data": null
}

practice_provider_operatory_retrieve

Retrieve, update, or delete a single operatory.

Delete is an admin-rare path — the web app prefers a soft-hide (is_hidden=True + is_bookable=False) so historical appointments keep their operatory context. When an admin does choose to delete, we let the FK's CASCADE clean up dependents (schedule templates, legacy appointment rows, etc.) and emit an operatory.deleted audit event.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
operatory_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "abbreviation": "string",
  • "provider_dentist": "e47c6d02-29ee-4cef-ae75-7c7efebcc8cb",
  • "provider_dentist_name": "string",
  • "provider_hygienist": "cc1b609c-8966-4136-9bf1-9a022231718a",
  • "provider_hygienist_name": "string",
  • "is_hygiene": true,
  • "is_hidden": true,
  • "is_bookable": true,
  • "sort_order": 2147483647,
  • "is_web_sched": true,
  • "accepts_self_booking": true,
  • "custom_data": null
}

practice_provider_operatory_update

Retrieve, update, or delete a single operatory.

Delete is an admin-rare path — the web app prefers a soft-hide (is_hidden=True + is_bookable=False) so historical appointments keep their operatory context. When an admin does choose to delete, we let the FK's CASCADE clean up dependents (schedule templates, legacy appointment rows, etc.) and emit an operatory.deleted audit event.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
operatory_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 100 ] characters
abbreviation
string <= 20 characters
provider_dentist
string or null <uuid>

Default dentist assigned to this chair

provider_hygienist
string or null <uuid>

Default hygienist assigned to this chair

is_hygiene
boolean
is_hidden
boolean
is_bookable
boolean

Operatories where is_bookable=False are skipped by the slot-finder. Used for PMS 'overflow' or 'notes-only' pseudo-chairs that host free-text annotations but aren't real rooms.

sort_order
integer [ 0 .. 2147483647 ]

Display ordering in schedule views

is_web_sched
boolean

Available for patient online scheduling

accepts_self_booking
boolean

Expose this operatory to the public patient self-booking surface (api#823). Off by default -- opt-in only; distinct from is_web_sched which gates the staff-side online scheduler.

custom_data
any

Responses

Request samples

Content type
{
  • "name": "string",
  • "abbreviation": "string",
  • "provider_dentist": "e47c6d02-29ee-4cef-ae75-7c7efebcc8cb",
  • "provider_hygienist": "cc1b609c-8966-4136-9bf1-9a022231718a",
  • "is_hygiene": true,
  • "is_hidden": true,
  • "is_bookable": true,
  • "sort_order": 2147483647,
  • "is_web_sched": true,
  • "accepts_self_booking": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "abbreviation": "string",
  • "provider_dentist": "e47c6d02-29ee-4cef-ae75-7c7efebcc8cb",
  • "provider_dentist_name": "string",
  • "provider_hygienist": "cc1b609c-8966-4136-9bf1-9a022231718a",
  • "provider_hygienist_name": "string",
  • "is_hygiene": true,
  • "is_hidden": true,
  • "is_bookable": true,
  • "sort_order": 2147483647,
  • "is_web_sched": true,
  • "accepts_self_booking": true,
  • "custom_data": null
}

practice_provider_operatory_partial_update

Retrieve, update, or delete a single operatory.

Delete is an admin-rare path — the web app prefers a soft-hide (is_hidden=True + is_bookable=False) so historical appointments keep their operatory context. When an admin does choose to delete, we let the FK's CASCADE clean up dependents (schedule templates, legacy appointment rows, etc.) and emit an operatory.deleted audit event.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
operatory_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
name
string [ 1 .. 100 ] characters
abbreviation
string <= 20 characters
provider_dentist
string or null <uuid>

Default dentist assigned to this chair

provider_hygienist
string or null <uuid>

Default hygienist assigned to this chair

is_hygiene
boolean
is_hidden
boolean
is_bookable
boolean

Operatories where is_bookable=False are skipped by the slot-finder. Used for PMS 'overflow' or 'notes-only' pseudo-chairs that host free-text annotations but aren't real rooms.

sort_order
integer [ 0 .. 2147483647 ]

Display ordering in schedule views

is_web_sched
boolean

Available for patient online scheduling

accepts_self_booking
boolean

Expose this operatory to the public patient self-booking surface (api#823). Off by default -- opt-in only; distinct from is_web_sched which gates the staff-side online scheduler.

custom_data
any

Responses

Request samples

Content type
{
  • "name": "string",
  • "abbreviation": "string",
  • "provider_dentist": "e47c6d02-29ee-4cef-ae75-7c7efebcc8cb",
  • "provider_hygienist": "cc1b609c-8966-4136-9bf1-9a022231718a",
  • "is_hygiene": true,
  • "is_hidden": true,
  • "is_bookable": true,
  • "sort_order": 2147483647,
  • "is_web_sched": true,
  • "accepts_self_booking": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "abbreviation": "string",
  • "provider_dentist": "e47c6d02-29ee-4cef-ae75-7c7efebcc8cb",
  • "provider_dentist_name": "string",
  • "provider_hygienist": "cc1b609c-8966-4136-9bf1-9a022231718a",
  • "provider_hygienist_name": "string",
  • "is_hygiene": true,
  • "is_hidden": true,
  • "is_bookable": true,
  • "sort_order": 2147483647,
  • "is_web_sched": true,
  • "accepts_self_booking": true,
  • "custom_data": null
}

practice_provider_operatory_destroy

Retrieve, update, or delete a single operatory.

Delete is an admin-rare path — the web app prefers a soft-hide (is_hidden=True + is_bookable=False) so historical appointments keep their operatory context. When an admin does choose to delete, we let the FK's CASCADE clean up dependents (schedule templates, legacy appointment rows, etc.) and emit an operatory.deleted audit event.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
operatory_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_scheduling_appointment_retrieve

Retrieve or update a single appointment. Status changes must go through /transition/.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
appointment_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_hygienist": "cc1b609c-8966-4136-9bf1-9a022231718a",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "treatment_plan": "c4c01122-8b32-4bce-bbce-bb1bda9a1a32",
  • "date_time": "2019-08-24T14:15:22Z",
  • "duration_minutes": 2147483647,
  • "status": "scheduled",
  • "confirmed_status": "not_called",
  • "appointment_type": "string",
  • "is_hygiene": true,
  • "procedure_description": "string",
  • "note": "string",
  • "cancellation_reason": "string",
  • "reschedule_requested": true,
  • "arrived_at": "2019-08-24T14:15:22Z",
  • "seated_at": "2019-08-24T14:15:22Z",
  • "ready_for_doctor_at": "2019-08-24T14:15:22Z",
  • "ready_for_walkout_at": "2019-08-24T14:15:22Z",
  • "dismissed_at": "2019-08-24T14:15:22Z",
  • "dollars_scheduled": "string",
  • "patient_name": "string",
  • "patient_noshow_risk_score": 0.1,
  • "provider_name": "string",
  • "provider_hygienist_name": "string",
  • "cancelled_by": "string",
  • "cancelled_by_name": "string",
  • "scheduled_procedures": [
    ],
  • "lab_warning": "string",
  • "lab_case": {
    },
  • "custom_data": null
}

practice_scheduling_appointment_update

Retrieve or update a single appointment. Status changes must go through /transition/.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
appointment_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
patient
string or null <uuid>
provider
string or null <uuid>
provider_hygienist
string or null <uuid>
operatory
string or null <uuid>
treatment_plan
string or null <uuid>

Treatment plan this appointment was scheduled from

date_time
string or null <date-time>
duration_minutes
integer [ 0 .. 2147483647 ]
ConfirmedStatusEnum (string) or BlankEnum (any)
appointment_type
string <= 100 characters

e.g. New Patient Exam, Crown Prep

is_hygiene
boolean
procedure_description
string
note
string
cancellation_reason
string

Patient-supplied reason for cancellation

reschedule_requested
boolean

Patient asked the front desk to reschedule

arrived_at
string or null <date-time>
seated_at
string or null <date-time>
ready_for_doctor_at
string or null <date-time>

When hygienist signaled ready for doctor exam

ready_for_walkout_at
string or null <date-time>

When patient is ready for walkout (checkout/scheduling)

dismissed_at
string or null <date-time>
dollars_scheduled
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Scheduled procedure total from the source PMS; nullable when unknown

Array of objects (AppointmentProcedureRequest)
lab_case_id
string or null <uuid>

Link an existing lab case to this appointment. The case must belong to the same practice AND the same patient as the appointment; cross-tenant or cross-patient PKs are rejected with HTTP 400.

custom_data
any
allow_overbooking
boolean
Default: false
skip_validation
boolean
Default: false

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_hygienist": "cc1b609c-8966-4136-9bf1-9a022231718a",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "treatment_plan": "c4c01122-8b32-4bce-bbce-bb1bda9a1a32",
  • "date_time": "2019-08-24T14:15:22Z",
  • "duration_minutes": 2147483647,
  • "confirmed_status": "not_called",
  • "appointment_type": "string",
  • "is_hygiene": true,
  • "procedure_description": "string",
  • "note": "string",
  • "cancellation_reason": "string",
  • "reschedule_requested": true,
  • "arrived_at": "2019-08-24T14:15:22Z",
  • "seated_at": "2019-08-24T14:15:22Z",
  • "ready_for_doctor_at": "2019-08-24T14:15:22Z",
  • "ready_for_walkout_at": "2019-08-24T14:15:22Z",
  • "dismissed_at": "2019-08-24T14:15:22Z",
  • "dollars_scheduled": "string",
  • "scheduled_procedures": [
    ],
  • "lab_case_id": "89c336ec-0db7-4217-8d2c-a048f2e1ecfc",
  • "custom_data": null,
  • "allow_overbooking": false,
  • "skip_validation": false
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_hygienist": "cc1b609c-8966-4136-9bf1-9a022231718a",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "treatment_plan": "c4c01122-8b32-4bce-bbce-bb1bda9a1a32",
  • "date_time": "2019-08-24T14:15:22Z",
  • "duration_minutes": 2147483647,
  • "status": "scheduled",
  • "confirmed_status": "not_called",
  • "appointment_type": "string",
  • "is_hygiene": true,
  • "procedure_description": "string",
  • "note": "string",
  • "cancellation_reason": "string",
  • "reschedule_requested": true,
  • "arrived_at": "2019-08-24T14:15:22Z",
  • "seated_at": "2019-08-24T14:15:22Z",
  • "ready_for_doctor_at": "2019-08-24T14:15:22Z",
  • "ready_for_walkout_at": "2019-08-24T14:15:22Z",
  • "dismissed_at": "2019-08-24T14:15:22Z",
  • "dollars_scheduled": "string",
  • "patient_name": "string",
  • "patient_noshow_risk_score": 0.1,
  • "provider_name": "string",
  • "provider_hygienist_name": "string",
  • "cancelled_by": "string",
  • "cancelled_by_name": "string",
  • "scheduled_procedures": [
    ],
  • "lab_warning": "string",
  • "lab_case": {
    },
  • "custom_data": null,
  • "allow_overbooking": false,
  • "skip_validation": false
}

practice_scheduling_appointment_partial_update

Retrieve or update a single appointment. Status changes must go through /transition/.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
appointment_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
patient
string or null <uuid>
provider
string or null <uuid>
provider_hygienist
string or null <uuid>
operatory
string or null <uuid>
treatment_plan
string or null <uuid>

Treatment plan this appointment was scheduled from

date_time
string or null <date-time>
duration_minutes
integer [ 0 .. 2147483647 ]
ConfirmedStatusEnum (string) or BlankEnum (any)
appointment_type
string <= 100 characters

e.g. New Patient Exam, Crown Prep

is_hygiene
boolean
procedure_description
string
note
string
cancellation_reason
string

Patient-supplied reason for cancellation

reschedule_requested
boolean

Patient asked the front desk to reschedule

arrived_at
string or null <date-time>
seated_at
string or null <date-time>
ready_for_doctor_at
string or null <date-time>

When hygienist signaled ready for doctor exam

ready_for_walkout_at
string or null <date-time>

When patient is ready for walkout (checkout/scheduling)

dismissed_at
string or null <date-time>
dollars_scheduled
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Scheduled procedure total from the source PMS; nullable when unknown

Array of objects (AppointmentProcedureRequest)
lab_case_id
string or null <uuid>

Link an existing lab case to this appointment. The case must belong to the same practice AND the same patient as the appointment; cross-tenant or cross-patient PKs are rejected with HTTP 400.

custom_data
any
allow_overbooking
boolean
Default: false
skip_validation
boolean
Default: false

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_hygienist": "cc1b609c-8966-4136-9bf1-9a022231718a",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "treatment_plan": "c4c01122-8b32-4bce-bbce-bb1bda9a1a32",
  • "date_time": "2019-08-24T14:15:22Z",
  • "duration_minutes": 2147483647,
  • "confirmed_status": "not_called",
  • "appointment_type": "string",
  • "is_hygiene": true,
  • "procedure_description": "string",
  • "note": "string",
  • "cancellation_reason": "string",
  • "reschedule_requested": true,
  • "arrived_at": "2019-08-24T14:15:22Z",
  • "seated_at": "2019-08-24T14:15:22Z",
  • "ready_for_doctor_at": "2019-08-24T14:15:22Z",
  • "ready_for_walkout_at": "2019-08-24T14:15:22Z",
  • "dismissed_at": "2019-08-24T14:15:22Z",
  • "dollars_scheduled": "string",
  • "scheduled_procedures": [
    ],
  • "lab_case_id": "89c336ec-0db7-4217-8d2c-a048f2e1ecfc",
  • "custom_data": null,
  • "allow_overbooking": false,
  • "skip_validation": false
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_hygienist": "cc1b609c-8966-4136-9bf1-9a022231718a",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "treatment_plan": "c4c01122-8b32-4bce-bbce-bb1bda9a1a32",
  • "date_time": "2019-08-24T14:15:22Z",
  • "duration_minutes": 2147483647,
  • "status": "scheduled",
  • "confirmed_status": "not_called",
  • "appointment_type": "string",
  • "is_hygiene": true,
  • "procedure_description": "string",
  • "note": "string",
  • "cancellation_reason": "string",
  • "reschedule_requested": true,
  • "arrived_at": "2019-08-24T14:15:22Z",
  • "seated_at": "2019-08-24T14:15:22Z",
  • "ready_for_doctor_at": "2019-08-24T14:15:22Z",
  • "ready_for_walkout_at": "2019-08-24T14:15:22Z",
  • "dismissed_at": "2019-08-24T14:15:22Z",
  • "dollars_scheduled": "string",
  • "patient_name": "string",
  • "patient_noshow_risk_score": 0.1,
  • "provider_name": "string",
  • "provider_hygienist_name": "string",
  • "cancelled_by": "string",
  • "cancelled_by_name": "string",
  • "scheduled_procedures": [
    ],
  • "lab_warning": "string",
  • "lab_case": {
    },
  • "custom_data": null,
  • "allow_overbooking": false,
  • "skip_validation": false
}

practice_scheduling_recall_retrieve

Retrieve, update, or delete a single recall record.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
recall_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "prefers_sms": true,
  • "prefers_email": true,
  • "recall_type": "string",
  • "date_due": "2019-08-24",
  • "date_previous": "2019-08-24",
  • "date_scheduled": "2019-08-24",
  • "last_visit_date": "2019-08-24",
  • "has_future_appointment": true,
  • "last_reached_at": "2019-08-24T14:15:22Z",
  • "is_disabled": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

practice_scheduling_recall_update

Retrieve, update, or delete a single recall record.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
recall_uid
required
string <uuid>
Request Body schema:
required
patient
string <uuid>
recall_type
required
string [ 1 .. 100 ] characters
date_due
string or null <date>
date_previous
string or null <date>
date_scheduled
string or null <date>
is_disabled
boolean
custom_data
any

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "recall_type": "string",
  • "date_due": "2019-08-24",
  • "date_previous": "2019-08-24",
  • "date_scheduled": "2019-08-24",
  • "is_disabled": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "recall_type": "string",
  • "date_due": "2019-08-24",
  • "date_previous": "2019-08-24",
  • "date_scheduled": "2019-08-24",
  • "is_disabled": true,
  • "custom_data": null
}

practice_scheduling_recall_partial_update

Retrieve, update, or delete a single recall record.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
recall_uid
required
string <uuid>
Request Body schema:
patient
string <uuid>
recall_type
string [ 1 .. 100 ] characters
date_due
string or null <date>
date_previous
string or null <date>
date_scheduled
string or null <date>
is_disabled
boolean
custom_data
any

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "recall_type": "string",
  • "date_due": "2019-08-24",
  • "date_previous": "2019-08-24",
  • "date_scheduled": "2019-08-24",
  • "is_disabled": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "recall_type": "string",
  • "date_due": "2019-08-24",
  • "date_previous": "2019-08-24",
  • "date_scheduled": "2019-08-24",
  • "is_disabled": true,
  • "custom_data": null
}

practice_scheduling_recall_destroy

Retrieve, update, or delete a single recall record.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
recall_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_scheduling_schedule_override_retrieve

Retrieve, update, or delete a schedule override.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
override_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "schedule_date": "2019-08-24",
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "schedule_type": "office_hours",
  • "blockout_type": "string",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "status": "open",
  • "note": "string",
  • "custom_data": null
}

practice_scheduling_schedule_override_update

Retrieve, update, or delete a schedule override.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
override_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
provider
string or null <uuid>
schedule_date
required
string <date>
start_time
required
string <time>
end_time
required
string <time>
schedule_type
required
string (ScheduleOverrideScheduleTypeEnum)
Enum: "office_hours" "provider" "blockout"
  • office_hours - Office Hours
  • provider - Provider Availability
  • blockout - Blockout
blockout_type
string <= 50 characters

e.g. lunch, meeting, holiday, time_off

operatory
string or null <uuid>
status
string (ScheduleOverrideStatusEnum)
Enum: "open" "closed" "holiday"
  • open - Open
  • closed - Closed
  • holiday - Holiday
note
string
custom_data
any

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "schedule_date": "2019-08-24",
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "schedule_type": "office_hours",
  • "blockout_type": "string",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "status": "open",
  • "note": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "schedule_date": "2019-08-24",
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "schedule_type": "office_hours",
  • "blockout_type": "string",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "status": "open",
  • "note": "string",
  • "custom_data": null
}

practice_scheduling_schedule_override_partial_update

Retrieve, update, or delete a schedule override.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
override_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
provider
string or null <uuid>
schedule_date
string <date>
start_time
string <time>
end_time
string <time>
schedule_type
string (ScheduleOverrideScheduleTypeEnum)
Enum: "office_hours" "provider" "blockout"
  • office_hours - Office Hours
  • provider - Provider Availability
  • blockout - Blockout
blockout_type
string <= 50 characters

e.g. lunch, meeting, holiday, time_off

operatory
string or null <uuid>
status
string (ScheduleOverrideStatusEnum)
Enum: "open" "closed" "holiday"
  • open - Open
  • closed - Closed
  • holiday - Holiday
note
string
custom_data
any

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "schedule_date": "2019-08-24",
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "schedule_type": "office_hours",
  • "blockout_type": "string",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "status": "open",
  • "note": "string",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "schedule_date": "2019-08-24",
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "schedule_type": "office_hours",
  • "blockout_type": "string",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "status": "open",
  • "note": "string",
  • "custom_data": null
}

practice_scheduling_schedule_override_destroy

Retrieve, update, or delete a schedule override.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
override_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_scheduling_schedule_template_retrieve

Retrieve, update, or delete a schedule template.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "day_of_week": -2147483648,
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "schedule_type": "provider",
  • "blockout_type": "string",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "is_active": true,
  • "custom_data": null
}

practice_scheduling_schedule_template_update

Retrieve, update, or delete a schedule template.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_uid
required
string <uuid>
Request Body schema:
required
provider
string or null <uuid>
day_of_week
required
integer [ -2147483648 .. 2147483647 ]

0=Sunday, 1=Monday, ..., 6=Saturday

start_time
required
string <time>
end_time
required
string <time>
schedule_type
required
string (ScheduleTemplateScheduleTypeEnum)
Enum: "provider" "blockout"
  • provider - Provider Availability
  • blockout - Blockout
blockout_type
string <= 50 characters

e.g. lunch, meeting, admin

operatory
string or null <uuid>
is_active
boolean
custom_data
any

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "day_of_week": -2147483648,
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "schedule_type": "provider",
  • "blockout_type": "string",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "is_active": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "day_of_week": -2147483648,
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "schedule_type": "provider",
  • "blockout_type": "string",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "is_active": true,
  • "custom_data": null
}

practice_scheduling_schedule_template_partial_update

Retrieve, update, or delete a schedule template.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_uid
required
string <uuid>
Request Body schema:
provider
string or null <uuid>
day_of_week
integer [ -2147483648 .. 2147483647 ]

0=Sunday, 1=Monday, ..., 6=Saturday

start_time
string <time>
end_time
string <time>
schedule_type
string (ScheduleTemplateScheduleTypeEnum)
Enum: "provider" "blockout"
  • provider - Provider Availability
  • blockout - Blockout
blockout_type
string <= 50 characters

e.g. lunch, meeting, admin

operatory
string or null <uuid>
is_active
boolean
custom_data
any

Responses

Request samples

Content type
{
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "day_of_week": -2147483648,
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "schedule_type": "provider",
  • "blockout_type": "string",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "is_active": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "day_of_week": -2147483648,
  • "start_time": "14:15:22Z",
  • "end_time": "14:15:22Z",
  • "schedule_type": "provider",
  • "blockout_type": "string",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "is_active": true,
  • "custom_data": null
}

practice_scheduling_schedule_template_destroy

Retrieve, update, or delete a schedule template.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_share_list

Create / list shares scoped to the URL's practice.

  • GET -- paginated list for the My Shares UI. Supports ?status=, ?patient=, ?created_from= / ?created_to=, ?recipient_kind= (repeatable, ORs within the param), and ?mine_only=true filters. Ordered by -created (newest first).
  • POST -- mint a new share. The response is the ONLY place the caller ever sees the plaintext token / phrase / URL / QR. The model persists only hashes.
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_share_create

Create / list shares scoped to the URL's practice.

  • GET -- paginated list for the My Shares UI. Supports ?status=, ?patient=, ?created_from= / ?created_to=, ?recipient_kind= (repeatable, ORs within the param), and ?mine_only=true filters. Ordered by -created (newest first).
  • POST -- mint a new share. The response is the ONLY place the caller ever sees the plaintext token / phrase / URL / QR. The model persists only hashes.
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
patient_uid
required
string <uuid>
required
Array of objects (ShareItemInputRequest)
recipient_kind
required
string (RecipientKindEnum)
Enum: "escape_practice" "non_escape_treating" "non_treating_party" "patient"
  • escape_practice - Another Escape practice
  • non_escape_treating - Non-Escape treating practice
  • non_treating_party - Non-treating party (legal / employer / other)
  • patient - The patient themselves
recipient_label
string <= 255 characters
Default: ""
purpose
required
string [ 1 .. 2000 ] characters

Responses

Request samples

Content type
{
  • "patient_uid": "2e193f60-014a-4901-af70-2d4676096d5e",
  • "items": [
    ],
  • "recipient_kind": "escape_practice",
  • "recipient_label": "",
  • "purpose": "string"
}

Response samples

Content type
application/json
{
  • "patient_uid": "2e193f60-014a-4901-af70-2d4676096d5e",
  • "items": [
    ],
  • "recipient_kind": "escape_practice",
  • "recipient_label": "",
  • "purpose": "string"
}

practice_share_retrieve

Detail view for the My Shares audit side panel.

Reads are read-only; mutations go through the revoke endpoint. The response echoes resolved :class:ShareItem rows alongside the share fields and the embedded events timeline (api#240) so the UI can render the audit trail without a second fetch.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
share_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "share_uid": "ffaf6965-dd9b-4b11-95e4-338ab6dcedb9",
  • "patient_uid": "2e193f60-014a-4901-af70-2d4676096d5e",
  • "status": "string",
  • "recipient_kind": "string",
  • "recipient_label": "string",
  • "purpose": "string",
  • "token_preview": "string",
  • "created_at": "2019-08-24T14:15:22Z",
  • "first_viewed_at": "2019-08-24T14:15:22Z",
  • "download_count": 0,
  • "expires_at_unviewed": "2019-08-24T14:15:22Z",
  • "expires_at_post_view": "2019-08-24T14:15:22Z",
  • "revoked_at": "2019-08-24T14:15:22Z",
  • "revoke_reason": "string",
  • "created_by": {
    },
  • "items": [
    ],
  • "events": [
    ]
}

practice_share_deliver_create

Deliver an authored share to a recipient over a channel (api#1037).

POST /api/v1/practice/<practice_uid>/share/<share_uid>/deliver/ with {"channel": "fax"|"email"|"sms", "destination": "...", "redeem_token": "..."}.

  • fax -- renders the share's records to a single PDF and faxes it to destination via the Sinch path. PHI is permitted on this channel.
  • email / sms -- sends ONLY the redeem link (built from the echoed redeem_token) plus fixed non-PHI copy. No clinical/patient data is ever placed in the body.

Deny-by-default + object-level: the share is fetched scoped to the URL's practice, so a share from another practice 404s (no IDOR). Every attempt is recorded as a :class:apps.sharing.models.ShareDelivery row -- queued up front, then transitioned to sent/failed -- so the My Shares UI can show per-channel delivery state. The work itself is queued to Celery (the provider tasks), so the request never blocks on the carrier.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
share_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_share_revoke_create

Revoke a share -- stop-future-access, not recall.

Idempotent: revoking an already-revoked share returns 200 with the (unchanged) share detail so the client can retry safely. Emits a share.revoked audit event on every call, so auditors can see repeated revocation attempts (which should never happen in practice but which we log regardless).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
share_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_sms_messages_retrieve

Retrieve a single SMS row.

Read-only -- there's no legitimate reason to PATCH a message row in place. Status changes flow through the (future) SMS provider DLR webhook handler, not the user-facing API.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
message_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "direction": "inbound",
  • "from_number": "string",
  • "to_number": "string",
  • "body": "string",
  • "sinch_message_id": "string",
  • "status": "queued",
  • "error_message": "string",
  • "phi_blocked": true,
  • "sent_at": "2019-08-24T14:15:22Z",
  • "delivered_at": "2019-08-24T14:15:22Z",
  • "received_at": "2019-08-24T14:15:22Z",
  • "sent_by": "40cc1a1c-5bda-4c73-bb08-df4a7613e4ee",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_staff_members_retrieve

Retrieve or update a single practice membership.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
member_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "user_id": "a169451c-8525-4352-b8ca-070dd449a1a5",
  • "email": "string",
  • "first_name": "string",
  • "last_name": "string",
  • "role": "ADMIN",
  • "is_active": true,
  • "date_joined": "string",
  • "invited_by_name": "string",
  • "via_practice": "string",
  • "via_client": "string",
  • "origins": [
    ]
}

practice_staff_members_update

Retrieve or update a single practice membership.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
member_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
role
required
string (MemberRoleEnum)
Enum: "ADMIN" "OFFICE_MANAGER" "DOCTOR" "HYGIENIST" "CLINICAL_STAFF" "DENTIST" "FRONT_DESK" "BILLING" "READ_ONLY" "IT_SUPPORT"
  • ADMIN - Administrator
  • OFFICE_MANAGER - Office Manager
  • DOCTOR - Doctor
  • HYGIENIST - Hygienist
  • CLINICAL_STAFF - Clinical Staff
  • DENTIST - Dentist (legacy -- use DOCTOR)
  • FRONT_DESK - Front Desk
  • BILLING - Billing
  • READ_ONLY - Read Only
  • IT_SUPPORT - IT Support
is_active
boolean

Responses

Request samples

Content type
{
  • "role": "ADMIN",
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "role": "ADMIN",
  • "is_active": true
}

practice_staff_members_partial_update

Retrieve or update a single practice membership.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
member_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
role
string (MemberRoleEnum)
Enum: "ADMIN" "OFFICE_MANAGER" "DOCTOR" "HYGIENIST" "CLINICAL_STAFF" "DENTIST" "FRONT_DESK" "BILLING" "READ_ONLY" "IT_SUPPORT"
  • ADMIN - Administrator
  • OFFICE_MANAGER - Office Manager
  • DOCTOR - Doctor
  • HYGIENIST - Hygienist
  • CLINICAL_STAFF - Clinical Staff
  • DENTIST - Dentist (legacy -- use DOCTOR)
  • FRONT_DESK - Front Desk
  • BILLING - Billing
  • READ_ONLY - Read Only
  • IT_SUPPORT - IT Support
is_active
boolean

Responses

Request samples

Content type
{
  • "role": "ADMIN",
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "role": "ADMIN",
  • "is_active": true
}

practice_available_list

List practices the current user can upload to.

Returns all active practices belonging to the user's client. Staff-only: patient users should not list practices.

Authorizations:
jwtAuthbearerAuthoauth2

Responses

Response samples

Content type
application/json
[
  • {
    }
]

practice_mine_retrieve

Retrieve or update the user's default practice (first practice under their client).

Authorizations:
jwtAuthbearerAuthoauth2

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "client_name": "string",
  • "name": "string",
  • "address_line1": "string",
  • "address_line2": "string",
  • "city": "string",
  • "state": "st",
  • "zip_code": "string",
  • "phone": "string",
  • "timezone": "string",
  • "settings": null,
  • "production_goal_daily": "string",
  • "production_goal_weekly": "string",
  • "production_goal_monthly": "string",
  • "is_active": true,
  • "logo_url": "string",
  • "client_logo_url": "string",
  • "effective_logo_url": "string",
  • "client_accent_color": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null,
  • "active_banners": "string",
  • "inbound_document_email": "string",
  • "email_login_enabled": true,
  • "effective_email_login_enabled": true,
  • "auto_rescan_enabled": true
}

practice_mine_update

Retrieve or update the user's default practice (first practice under their client).

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
required
client
string or null <uuid>
name
required
string [ 1 .. 255 ] characters
address_line1
string <= 255 characters
address_line2
string <= 255 characters
city
string <= 100 characters
state
string <= 2 characters
zip_code
string <= 10 characters ^\d{5}(-\d{4})?$
phone
string <= 128 characters
timezone
string [ 1 .. 50 ] characters
settings
any

Practice-specific configuration.

production_goal_daily
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Daily production goal in USD. Null = no goal set.

production_goal_weekly
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Weekly production goal in USD. Null = no goal set.

production_goal_monthly
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Monthly production goal in USD. Null = no goal set.

is_active
boolean
custom_data
any
email_login_enabled
boolean

Allow staff at this practice to sign in via email magic link. Off by default; the owning Client must ALSO have email_login_enabled=True for the feature to be live here.

auto_rescan_enabled
boolean

Include this practice in the nightly AV re-scan sweep. On by default; turn off to skip the recurring scan. Upload-time scans always run regardless of this flag.

Responses

Request samples

Content type
{
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "address_line1": "string",
  • "address_line2": "string",
  • "city": "string",
  • "state": "st",
  • "zip_code": "string",
  • "phone": "string",
  • "timezone": "string",
  • "settings": null,
  • "production_goal_daily": "string",
  • "production_goal_weekly": "string",
  • "production_goal_monthly": "string",
  • "is_active": true,
  • "custom_data": null,
  • "email_login_enabled": true,
  • "auto_rescan_enabled": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "client_name": "string",
  • "name": "string",
  • "address_line1": "string",
  • "address_line2": "string",
  • "city": "string",
  • "state": "st",
  • "zip_code": "string",
  • "phone": "string",
  • "timezone": "string",
  • "settings": null,
  • "production_goal_daily": "string",
  • "production_goal_weekly": "string",
  • "production_goal_monthly": "string",
  • "is_active": true,
  • "logo_url": "string",
  • "client_logo_url": "string",
  • "effective_logo_url": "string",
  • "client_accent_color": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null,
  • "active_banners": "string",
  • "inbound_document_email": "string",
  • "email_login_enabled": true,
  • "effective_email_login_enabled": true,
  • "auto_rescan_enabled": true
}

practice_mine_partial_update

Retrieve or update the user's default practice (first practice under their client).

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
client
string or null <uuid>
name
string [ 1 .. 255 ] characters
address_line1
string <= 255 characters
address_line2
string <= 255 characters
city
string <= 100 characters
state
string <= 2 characters
zip_code
string <= 10 characters ^\d{5}(-\d{4})?$
phone
string <= 128 characters
timezone
string [ 1 .. 50 ] characters
settings
any

Practice-specific configuration.

production_goal_daily
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Daily production goal in USD. Null = no goal set.

production_goal_weekly
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Weekly production goal in USD. Null = no goal set.

production_goal_monthly
string or null <decimal> ^-?\d{0,8}(?:\.\d{0,2})?$

Monthly production goal in USD. Null = no goal set.

is_active
boolean
custom_data
any
email_login_enabled
boolean

Allow staff at this practice to sign in via email magic link. Off by default; the owning Client must ALSO have email_login_enabled=True for the feature to be live here.

auto_rescan_enabled
boolean

Include this practice in the nightly AV re-scan sweep. On by default; turn off to skip the recurring scan. Upload-time scans always run regardless of this flag.

Responses

Request samples

Content type
{
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "name": "string",
  • "address_line1": "string",
  • "address_line2": "string",
  • "city": "string",
  • "state": "st",
  • "zip_code": "string",
  • "phone": "string",
  • "timezone": "string",
  • "settings": null,
  • "production_goal_daily": "string",
  • "production_goal_weekly": "string",
  • "production_goal_monthly": "string",
  • "is_active": true,
  • "custom_data": null,
  • "email_login_enabled": true,
  • "auto_rescan_enabled": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "client_name": "string",
  • "name": "string",
  • "address_line1": "string",
  • "address_line2": "string",
  • "city": "string",
  • "state": "st",
  • "zip_code": "string",
  • "phone": "string",
  • "timezone": "string",
  • "settings": null,
  • "production_goal_daily": "string",
  • "production_goal_weekly": "string",
  • "production_goal_monthly": "string",
  • "is_active": true,
  • "logo_url": "string",
  • "client_logo_url": "string",
  • "effective_logo_url": "string",
  • "client_accent_color": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null,
  • "active_banners": "string",
  • "inbound_document_email": "string",
  • "email_login_enabled": true,
  • "effective_email_login_enabled": true,
  • "auto_rescan_enabled": true
}

Address Book

practice_address_book_entry_list

List and create central address book entries for the current practice.

GET /v1/practice//address-book/entry/ POST /v1/practice//address-book/entry/

Query params

kind — filter to a single :class:ContactKind value activetrue (default) / false / all search — case-insensitive substring match on name

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
active
string

'true' (default) / 'false' / 'all'.

kind
string

Filter by contact kind. One of: lab, referral_specialist, treating_provider, insurance, other.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

search
string

Case-insensitive substring match on the contact name.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_address_book_entry_create

List and create central address book entries for the current practice.

GET /v1/practice//address-book/entry/ POST /v1/practice//address-book/entry/

Query params

kind — filter to a single :class:ContactKind value activetrue (default) / false / all search — case-insensitive substring match on name

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 200 ] characters
kind
string
Enum: "lab" "referral_specialist" "treating_provider" "insurance" "other"

Discriminator for the kind of contact (lab, referral specialist, …).

  • lab - Lab
  • referral_specialist - Referral Specialist
  • treating_provider - Treating Provider
  • insurance - Insurance
  • other - Other
address
string
phone
string <= 40 characters
fax
string <= 40 characters
email
string <email> <= 254 characters
specialty
string <= 100 characters

Discipline for referral/provider kinds, e.g. 'Oral Surgery', 'Endodontics'.

notes
string
is_active
boolean
default_turnaround_days
integer or null [ 0 .. 32767 ]

Lab-only: typical days from send to receive. NULL for non-lab kinds.

Responses

Request samples

Content type
{
  • "name": "string",
  • "kind": "lab",
  • "address": "string",
  • "phone": "string",
  • "fax": "string",
  • "email": "user@example.com",
  • "specialty": "string",
  • "notes": "string",
  • "is_active": true,
  • "default_turnaround_days": 32767
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "kind": "lab",
  • "address": "string",
  • "phone": "string",
  • "fax": "string",
  • "email": "user@example.com",
  • "specialty": "string",
  • "notes": "string",
  • "is_active": true,
  • "default_turnaround_days": 32767,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_address_book_entry_retrieve

Retrieve, update, or delete a single address book entry.

Scoped to the URL practice, so an entry from another tenant 404s rather than leaking. is_active=False soft-hides an entry from pickers without losing historical context.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
entry_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "kind": "lab",
  • "address": "string",
  • "phone": "string",
  • "fax": "string",
  • "email": "user@example.com",
  • "specialty": "string",
  • "notes": "string",
  • "is_active": true,
  • "default_turnaround_days": 32767,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_address_book_entry_update

Retrieve, update, or delete a single address book entry.

Scoped to the URL practice, so an entry from another tenant 404s rather than leaking. is_active=False soft-hides an entry from pickers without losing historical context.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
entry_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 200 ] characters
kind
string
Enum: "lab" "referral_specialist" "treating_provider" "insurance" "other"

Discriminator for the kind of contact (lab, referral specialist, …).

  • lab - Lab
  • referral_specialist - Referral Specialist
  • treating_provider - Treating Provider
  • insurance - Insurance
  • other - Other
address
string
phone
string <= 40 characters
fax
string <= 40 characters
email
string <email> <= 254 characters
specialty
string <= 100 characters

Discipline for referral/provider kinds, e.g. 'Oral Surgery', 'Endodontics'.

notes
string
is_active
boolean
default_turnaround_days
integer or null [ 0 .. 32767 ]

Lab-only: typical days from send to receive. NULL for non-lab kinds.

Responses

Request samples

Content type
{
  • "name": "string",
  • "kind": "lab",
  • "address": "string",
  • "phone": "string",
  • "fax": "string",
  • "email": "user@example.com",
  • "specialty": "string",
  • "notes": "string",
  • "is_active": true,
  • "default_turnaround_days": 32767
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "kind": "lab",
  • "address": "string",
  • "phone": "string",
  • "fax": "string",
  • "email": "user@example.com",
  • "specialty": "string",
  • "notes": "string",
  • "is_active": true,
  • "default_turnaround_days": 32767,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_address_book_entry_partial_update

Retrieve, update, or delete a single address book entry.

Scoped to the URL practice, so an entry from another tenant 404s rather than leaking. is_active=False soft-hides an entry from pickers without losing historical context.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
entry_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
name
string [ 1 .. 200 ] characters
kind
string
Enum: "lab" "referral_specialist" "treating_provider" "insurance" "other"

Discriminator for the kind of contact (lab, referral specialist, …).

  • lab - Lab
  • referral_specialist - Referral Specialist
  • treating_provider - Treating Provider
  • insurance - Insurance
  • other - Other
address
string
phone
string <= 40 characters
fax
string <= 40 characters
email
string <email> <= 254 characters
specialty
string <= 100 characters

Discipline for referral/provider kinds, e.g. 'Oral Surgery', 'Endodontics'.

notes
string
is_active
boolean
default_turnaround_days
integer or null [ 0 .. 32767 ]

Lab-only: typical days from send to receive. NULL for non-lab kinds.

Responses

Request samples

Content type
{
  • "name": "string",
  • "kind": "lab",
  • "address": "string",
  • "phone": "string",
  • "fax": "string",
  • "email": "user@example.com",
  • "specialty": "string",
  • "notes": "string",
  • "is_active": true,
  • "default_turnaround_days": 32767
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "kind": "lab",
  • "address": "string",
  • "phone": "string",
  • "fax": "string",
  • "email": "user@example.com",
  • "specialty": "string",
  • "notes": "string",
  • "is_active": true,
  • "default_turnaround_days": 32767,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_address_book_entry_destroy

Retrieve, update, or delete a single address book entry.

Scoped to the URL practice, so an entry from another tenant 404s rather than leaking. is_active=False soft-hides an entry from pickers without losing historical context.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
entry_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

OAuth Apps

List navbar-enabled third-party apps for a practice

Return the ordered list of app launchers for the practice's nine-dots menu.

Filter chain (all must be true for an app to appear):

  1. The OAuth application has an OAuthAppProfile with approval_status == APPROVED and is_first_party == False (escape-web itself must never show up as a launcher tile).
  2. The profile publishes a non-empty navbar_label — apps that haven't registered for the navbar stay invisible even if otherwise fully onboarded.
  3. There is at least one active OAuthPracticeGrant tying this application to this practice — only apps the practice has actually consented to appear in its launcher.
  4. No PracticeAppVisibility row hides the app for this practice. Absence of a row = default-visible.
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Toggle a third-party app's visibility in the practice's navbar

Practice-owner-only endpoint to hide/show a single app in the navbar.

Upserts a PracticeAppVisibility row keyed on (practice, app). Only the parent client's OWNER role (or a superuser) may hit this. Other staff — including practice ADMINs — will receive a 403.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_id
required
string
practice_uid
required
string <uuid>
Request Body schema:
is_visible
boolean

Responses

Request samples

Content type
{
  • "is_visible": true
}

Response samples

Content type
application/json
{
  • "is_visible": true
}

Disconnect (revoke) a third-party app from this practice

Revoke all OAuthPracticeGrant rows for this app + practice.

The access token cascade mirrors AppRevokeView but is scoped to a single practice rather than the entire org. Requires ADMIN/OFFICE_MANAGER practice role or OWNER/TECHNICAL client role.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_id
required
string
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_apps_connect_create

Self-registration endpoint for third-party OAuth apps.

POST /api/v1/practice/<uid>/apps/<client_id>/connect/

A third-party SPA calls this endpoint after it has obtained an access token via the standard Authorization Code + PKCE flow, to create an OAuthPracticeGrant tying itself to this practice. Once the grant exists the app appears in the nine-dots launcher for the practice.

Why not PracticeScopedMixin? PracticeScopedMixin.get_practice() enforces that an active OAuthPracticeGrant already exists before the third-party caller can access any practice-scoped endpoint. That is correct for data endpoints — but /connect/ is the endpoint that creates the grant. Using the mixin here would be a chicken-and-egg deadlock: you can't connect without already being connected.

Instead we:

  1. Verify the Bearer token is authenticated (IsAuthenticated).
  2. Directly look up the practice by URL UID and confirm the requesting user has a PracticeMembership in it.
  3. Create / reactivate the grant.

Security

  • Requires a valid Bearer token (IsAuthenticated).
  • User must have an active PracticeMembership for the practice (user.has_practice_access). This prevents a malicious token holder from manufacturing grants for practices they don't belong to.
  • The connecting client_id must be an approved, non-first-party application with a non-empty navbar_label.
  • The grant is (user, application, practice) — multi-user practices each consent independently, which is the correct per-user model.

Response

  • 201 Created — grant created or reactivated.
  • 200 OK — grant already active; idempotent re-connect.
  • 403 — user has no membership in this practice.
  • 404 — practice or app not found / not launcher-eligible.
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_id
required
string
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

Audited click-through for a third-party app launcher tile

Audited resolver for a single navbar launcher click.

The web client calls this instead of rendering a raw <a href> so that every launch produces a server-side audit record — useful both for HIPAA (who opened which third-party tool) and for product analytics (which integrations are actually used).

Success contract:

  • Returns 200 {"target_url": "..."} — web opens it in a new tab with rel=noopener,noreferrer and window.open's 3rd-arg equivalent.
  • Emits an oauth_app.launch audit event only on the success path — failed or unauthorized launches are not logged as launches.

Failure contract:

  • 404 for every navbar-ineligibility reason (unapproved, first-party, missing grant, hidden by visibility row, missing navbar_label or navbar_target_url). We deliberately use the same status for every reason so the endpoint does not leak which apps the practice has granted — that information belongs only to the owner's visibility screen.
  • 401 for unauthenticated callers (DRF default).
  • 403 for users with no access to the scoped practice (raised by PracticeScopedMixin).
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
client_id
required
string
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{}

Audit

audit_right_of_access_create

Queue a new right-of-access report for a patient.

Staff-only, practice-scoped. The report generation runs asynchronously in a Celery task; callers poll the companion endpoint for completion.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
patient_uid
required
string <uuid>
date_from
string <date>
date_to
string <date>
format
string
Default: "both"
Enum: "pdf" "json" "both"
  • pdf - pdf
  • json - json
  • both - both

Responses

Request samples

Content type
{
  • "patient_uid": "2e193f60-014a-4901-af70-2d4676096d5e",
  • "date_from": "2019-08-24",
  • "date_to": "2019-08-24",
  • "format": "both"
}

Response samples

Content type
application/json
{
  • "report_uid": "bf1f3ba6-daf7-4da1-8f23-14115cc9d017",
  • "status": "string",
  • "poll_url": "string"
}

audit_right_of_access_detail

Poll an existing right-of-access report.

Returns status + (when READY) time-limited signed download URLs. 404 on unknown report_uid; 403 if the report belongs to a different practice (enforced by PracticeScopedMixin on the URL practice_uid).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
report_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "report_uid": "bf1f3ba6-daf7-4da1-8f23-14115cc9d017",
  • "status": "string",
  • "requested_at": "2019-08-24T14:15:22Z",
  • "ready_at": "2019-08-24T14:15:22Z",
  • "date_from": "2019-08-24",
  • "date_to": "2019-08-24",
  • "event_count": 0,
  • "download_urls": {
    },
  • "error_message": "string"
}

Communications

List inbox communications for a practice.

Returns the unified-inbox feed of practice-external communications (fax / email / voicemail / SMS). Filter by channel, status, direction, assignee (UUID, me, or unassigned), patient, or thread_id.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
assigned_to
string

User UUID, the literal me, or unassigned.

channel
string

Filter by channel enum.

direction
string

Filter by inbound / outbound.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

patient
string <uuid>

Filter by patient UUID.

status
string

Filter by triage status.

thread_id
string

Filter by thread identifier.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_comms_retrieve

Retrieve or PATCH a single inbox communication.

PATCH is limited to subject / body / patient per the serializer's Meta.fields -- status and assignment funnel through the dedicated action endpoints so the audit trail stays one-mutation-per-event.

PUT is intentionally not exposed (http_method_names excludes it) because the row carries channel-stamped fields the client shouldn't be asked to round-trip.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
communication_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "channel": "fax",
  • "direction": "inbound",
  • "thread_id": "string",
  • "subject": "string",
  • "body": "string",
  • "status": "new",
  • "assigned_to": "b9f52997-ff03-4166-bbff-22fd35e12939",
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "attachments": [
    ],
  • "audio_url": "string",
  • "audio_content_type": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_comms_partial_update

Retrieve or PATCH a single inbox communication.

PATCH is limited to subject / body / patient per the serializer's Meta.fields -- status and assignment funnel through the dedicated action endpoints so the audit trail stays one-mutation-per-event.

PUT is intentionally not exposed (http_method_names excludes it) because the row carries channel-stamped fields the client shouldn't be asked to round-trip.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
communication_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
subject
string <= 255 characters

Short subject or summary (email subject, SMS first line).

body
string

Plain-text body or transcript snippet. For fax / voicemail this is typically an OCR / transcription preview; the source row (via CommunicationAttachment) holds the canonical artifact.

patient
string or null <uuid>

Patient this comm is about, when known (nullable for un-triaged inbound).

Responses

Request samples

Content type
{
  • "subject": "string",
  • "body": "string",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb"
}

Response samples

Content type
application/json
{
  • "subject": "string",
  • "body": "string",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb"
}

Assign or unassign a communication.

Sets assigned_to to the given user UUID (assign) or null (unassign). Emits comms.communication_assigned with both the new and previous assignee for full diff.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
communication_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
assigned_to
required
string or null <uuid>

Responses

Request samples

Content type
{
  • "assigned_to": "b9f52997-ff03-4166-bbff-22fd35e12939"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "channel": "fax",
  • "direction": "inbound",
  • "thread_id": "string",
  • "subject": "string",
  • "body": "string",
  • "status": "new",
  • "assigned_to": "b9f52997-ff03-4166-bbff-22fd35e12939",
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "attachments": [
    ],
  • "audio_url": "string",
  • "audio_content_type": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Mark a communication done.

Transitions status to done and stamps resolved_at. Idempotent -- re-marking a done row is a no-op on the row but still emits the audit event.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
communication_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "channel": "fax",
  • "direction": "inbound",
  • "thread_id": "string",
  • "subject": "string",
  • "body": "string",
  • "status": "new",
  • "assigned_to": "b9f52997-ff03-4166-bbff-22fd35e12939",
  • "resolved_at": "2019-08-24T14:15:22Z",
  • "attachments": [
    ],
  • "audio_url": "string",
  • "audio_content_type": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_comms_commlog_list

Practice-wide commlog list and bulk create.

GET returns all commlogs for the practice (paginated, filterable by patient, date_from, date_to). POST accepts a JSON array for bulk import (up to 5000 records). PATCH accepts a JSON array of {id, ...} objects for bulk update.

Used by escape-opendental and escape-eaglesoft sync tools to avoid per-patient fetch loops. Each record must include patient in the body since the endpoint is not patient-scoped.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
date_from
string <date>

Inclusive lower bound on date_time (YYYY-MM-DD). Filters against the practice-local date portion of the comm log's timestamp.

date_to
string <date>

Inclusive upper bound on date_time (YYYY-MM-DD). Filters against the practice-local date portion of the comm log's timestamp.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

patient
string <uuid>

Filter comm logs to a single patient UID. Prefer the patient-scoped endpoint (/patient/{patient_id}/comms/commlog/) when you already have the patient in hand; this practice-wide view exists for sync tools that pull across the whole practice in one query.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_comms_commlog_create

Practice-wide commlog list and bulk create.

GET returns all commlogs for the practice (paginated, filterable by patient, date_from, date_to). POST accepts a JSON array for bulk import (up to 5000 records). PATCH accepts a JSON array of {id, ...} objects for bulk update.

Used by escape-opendental and escape-eaglesoft sync tools to avoid per-patient fetch loops. Each record must include patient in the body since the endpoint is not patient-scoped.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
patient
string or null <uuid>
date_time
string or null <date-time>
mode
string (ModeEnum)
Enum: "phone" "email" "text" "fax" "mail" "in_person" "web" "other"
  • phone - Phone
  • email - Email
  • text - Text
  • fax - Fax
  • mail - Mail
  • in_person - In Person
  • web - Web
  • other - Other
direction
string (Direction80cEnum)
Enum: "sent" "received" "neither"
  • sent - Sent
  • received - Received
  • neither - Neither
outcome
string
Enum: "success" "no_answer" "voicemail" "bounced" "bad_number" "other"

What happened on the contact attempt. Only success rows count toward the recall-list last_reached_at annotation.

  • success - Success
  • no_answer - No Answer
  • voicemail - Voicemail
  • bounced - Bounced
  • bad_number - Bad Number
  • other - Other
subject
string <= 255 characters

Short label, e.g. 'Recall reminder', 'Treatment plan follow-up'.

note
string
staff_user
string or null <uuid>

Staff member who logged the contact. Null for system-generated entries.

recall
string or null <uuid>

Optional link to the specific recall this contact addresses.

is_imported
boolean

True if this row was imported from a legacy PMS (escape-opendental, escape-eaglesoft, ...) rather than created natively in Escape. Imported rows may carry PHI in the note body that pre-dates the Escape BAA / no-PHI-in-comms policy (GH-575); clients must NOT expose 'resend' or 'use as template' affordances on imported rows, and any future send endpoint that takes a replicate_of_commlog_id MUST refuse imported sources.

custom_data
any

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "date_time": "2019-08-24T14:15:22Z",
  • "mode": "phone",
  • "direction": "sent",
  • "outcome": "success",
  • "subject": "string",
  • "note": "string",
  • "staff_user": "17986289-b0ef-402a-92d5-49bc6fa3367e",
  • "recall": "e7ef6ec4-8466-4387-af6a-2ed34de604a8",
  • "is_imported": true,
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "date_time": "2019-08-24T14:15:22Z",
  • "mode": "phone",
  • "direction": "sent",
  • "outcome": "success",
  • "subject": "string",
  • "note": "string",
  • "staff_user": "17986289-b0ef-402a-92d5-49bc6fa3367e",
  • "recall": "e7ef6ec4-8466-4387-af6a-2ed34de604a8",
  • "is_imported": true,
  • "custom_data": null
}

practice_email_messages_list

List and create email messages for the practice.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
direction
string
Enum: "inbound" "outbound"

Filter to inbound or outbound messages.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

patient
string <uuid>

Filter to messages associated with this patient.

status
string
Enum: "delivered" "failed" "queued" "received" "sending" "sent"

Filter by per-message delivery state.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_email_messages_create

List and create email messages for the practice.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>

Patient this message is addressed to. Required -- the destination address is resolved server-side from the patient's email column so staff can't accidentally type a typo and ship the message to the wrong person.

subject
required
string [ 1 .. 255 ] characters

Email subject line. Refuses PHI -- the subject must not name a diagnosis, medication, or any other clinical detail.

body
required
string [ 1 .. 20000 ] characters

Plain-text email body. Refuses PHI -- no diagnoses, prescriptions, dates of birth, account numbers, or the patient's own name in a clinical context. Use the patient portal for any clinical content.

from_practice_address
boolean
Default: false

When True, the from-address is the practice's scan-to-email local-part on MAILGUN_INBOUND_DOMAIN (replies route back to the practice's scan-to-email inbox). When False (the default) the from-address is the project-wide DEFAULT_FROM_EMAIL -- replies bounce or hit a generic mailbox.

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "subject": "string",
  • "body": "string",
  • "from_practice_address": false
}

Response samples

Content type
application/json
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "subject": "string",
  • "body": "string",
  • "from_practice_address": false
}

Get the practice's active fax number

Read the practice's active fax number (api#550).

GET /api/v1/practice/<uid>/fax/number/ returns the active :class:PracticeFaxNumber row, or 404 when none has been provisioned.

Open to any practice staff -- the cheat-sheet popover in the staff header surfaces the number for everyone, not just admins. Provision (POST /fax/provision/) stays admin-only.

The previous read path was sniffing the latest fax message in the inbox for a from_number (useActiveFaxNumber on the web side), which only worked after the first fax flowed through. A freshly-provisioned number is invisible to that path until somebody sends or receives one. This endpoint reads the actual provisioning row instead.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "e164_number": "string",
  • "sinch_number_id": "string",
  • "provisioned_at": "2019-08-24T14:15:22Z",
  • "deactivated_at": "2019-08-24T14:15:22Z",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Provision a fax number for the practice

Provision a fax number for the practice (api#531).

POST /api/v1/practice/<uid>/fax/provision/ searches the upstream number inventory, picks the first candidate, rents it, and persists a :class:PracticeFaxNumber row. The flow is admin-only and idempotent on a per-practice basis -- a practice that already has an active number gets a 409 with the existing serialized row.

Per-number cost is absorbed into the base subscription, so provisioning is not plan-gated: any practice can rent a number through this endpoint. The send-side includes_fax gate (GH-443) still applies to actually transmitting documents, which is the per-page metered cost.

Body (all fields optional)::

{
    "area_code": "541",
    "preferred_locality": "OR"
}

area_code overrides the prefix sent upstream as numberPattern.searchPattern. preferred_locality is a hint today (we forward it as the regionCode-narrowing context for future cityName support). When neither is supplied we infer from the practice's address, falling back through zip_code -> state -> any-US until the upstream returns a result.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
area_code
string <= 3 characters

US area code (3 digits, e.g. 541). Sent to the fax provider as the numberPattern prefix so the returned numbers all start with this code. Omit to infer from the practice's phone / ZIP.

preferred_locality
string <= 64 characters

Free-form locality hint (e.g. "OR" or "Eugene, OR") recorded on the audit trail. The fax provider's Numbers API does not currently filter by city, so this is informational today.

Responses

Request samples

Content type
{
  • "area_code": "str",
  • "preferred_locality": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "e164_number": "string",
  • "sinch_number_id": "string",
  • "provisioned_at": "2019-08-24T14:15:22Z",
  • "deactivated_at": "2019-08-24T14:15:22Z",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_faxes_list

List and create faxes for the practice.

GET is read-only and open to any practice staff; POST is admin-only and gated by the practice's plan tier. The view sets practice and sent_by server-side; the serializer never trusts those from the body.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
delivery_status
Array of strings
Items Enum: "delivered" "failed" "queued" "receiving" "sending" "sent"

Filter by per-fax delivery state (the status column on the row, distinct from the ?status= triage filter). Accepts repeated params (?delivery_status=delivered&delivery_status=failed) or a comma-separated list (?delivery_status=delivered,failed); values within the filter are OR-combined. Unknown values are dropped. Primary use case: the Fax Inbox excluding receiving rows server-side so the paginated count envelope matches what the user sees (GH-611).

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

status
string
Enum: "all" "discarded" "filed" "unfiled"

Filter by triage state. unfiled returns inbound faxes still pending triage (no patient, no practice link, not discarded) — used by the Practice Inbox. filed and discarded are convenience filters for focused review. all (default) returns every fax — outbound rows always appear under all since filing only applies to inbound.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_faxes_create

List and create faxes for the practice.

GET is read-only and open to any practice staff; POST is admin-only and gated by the practice's plan tier. The view sets practice and sent_by server-side; the serializer never trusts those from the body.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema: multipart/form-data
required
to_number
required
string [ 1 .. 32 ] characters

E.164 destination.

document
required
string <binary>

The PDF to fax. Must be a single document; multi-doc batching is a phase-2 feature.

Responses

Response samples

Content type
application/json
{}

Restore a discarded fax (returns it to the unfiled queue)

Discard / un-discard an inbound fax (api#508).

Soft-flag — the underlying PDF is preserved for HIPAA retention and the row remains queryable for audit. DELETE marks the fax discarded; POST on the same path restores it (returns it to the unfiled queue).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
fax_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "direction": "inbound",
  • "from_number": "string",
  • "to_number": "string",
  • "page_count": 0,
  • "status": "queued",
  • "sinch_fax_id": "string",
  • "document_url": "string",
  • "error_message": "string",
  • "completed_at": "2019-08-24T14:15:22Z",
  • "sent_by": "40cc1a1c-5bda-4c73-bb08-df4a7613e4ee",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "practice_link": true,
  • "filed_at": "2019-08-24T14:15:22Z",
  • "filed_by": "011b59c1-1189-4a11-87df-fa9753db2861",
  • "discarded_at": "2019-08-24T14:15:22Z",
  • "discarded_by": "69474e1d-c497-4e9d-9f07-e93914ef0818",
  • "av_status": "pending",
  • "av_scanned_at": "2019-08-24T14:15:22Z",
  • "av_scanner": "string",
  • "av_threat_name": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Discard an inbound fax (soft-flag — preserves PDF)

Discard / un-discard an inbound fax (api#508).

Soft-flag — the underlying PDF is preserved for HIPAA retention and the row remains queryable for audit. DELETE marks the fax discarded; POST on the same path restores it (returns it to the unfiled queue).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
fax_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "property1": null,
  • "property2": null
}

File an inbound fax against a patient or against the practice

File an inbound fax against a patient or against the practice (api#508).

POST body:

  • {"patient": "<uid>"} → file against the named patient.
  • {} (or {"patient": null}) → file against the practice.

Idempotent: re-filing refreshes filed_at and filed_by. Re-filing against a different target is allowed — staff who initially filed against the wrong patient can correct the assignment without an undo.

Outbound faxes are not eligible (they file themselves implicitly via the staff workflow that originated them); attempting to file one returns 400. Discarded faxes are not eligible either — restore via the discard endpoint's DELETE first.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
fax_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
patient
string or null <uuid>

UID of the patient to file the fax against. Omit (or send null) to file the fax against the practice.

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "direction": "inbound",
  • "from_number": "string",
  • "to_number": "string",
  • "page_count": 0,
  • "status": "queued",
  • "sinch_fax_id": "string",
  • "document_url": "string",
  • "error_message": "string",
  • "completed_at": "2019-08-24T14:15:22Z",
  • "sent_by": "40cc1a1c-5bda-4c73-bb08-df4a7613e4ee",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "practice_link": true,
  • "filed_at": "2019-08-24T14:15:22Z",
  • "filed_by": "011b59c1-1189-4a11-87df-fa9753db2861",
  • "discarded_at": "2019-08-24T14:15:22Z",
  • "discarded_by": "69474e1d-c497-4e9d-9f07-e93914ef0818",
  • "av_status": "pending",
  • "av_scanned_at": "2019-08-24T14:15:22Z",
  • "av_scanner": "string",
  • "av_threat_name": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

List inbox communications scoped to a single patient.

Per-patient timeline of practice-external communications. Same filter shape as the practice-scoped list.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_comms_commlog_list

List and create communication log entries for a patient.

Supports ?date_from= and ?date_to= query params for date filtering. Bulk create is supported by POSTing an array.

GH-575: every list GET emits one comms.commlog_listed audit event carrying the actor, patient, and result count. Per-row events would N+1 the audit index on a 50-row page so we only fire once per request.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
date_from
string <date>

Inclusive lower bound on date_time (YYYY-MM-DD). Filters against the practice-local date portion of the comm log's timestamp.

date_to
string <date>

Inclusive upper bound on date_time (YYYY-MM-DD). Filters against the practice-local date portion of the comm log's timestamp.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_comms_commlog_create

List and create communication log entries for a patient.

Supports ?date_from= and ?date_to= query params for date filtering. Bulk create is supported by POSTing an array.

GH-575: every list GET emits one comms.commlog_listed audit event carrying the actor, patient, and result count. Per-row events would N+1 the audit index on a 50-row page so we only fire once per request.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
date_time
string or null <date-time>
mode
string (ModeEnum)
Enum: "phone" "email" "text" "fax" "mail" "in_person" "web" "other"
  • phone - Phone
  • email - Email
  • text - Text
  • fax - Fax
  • mail - Mail
  • in_person - In Person
  • web - Web
  • other - Other
direction
string (Direction80cEnum)
Enum: "sent" "received" "neither"
  • sent - Sent
  • received - Received
  • neither - Neither
outcome
string
Enum: "success" "no_answer" "voicemail" "bounced" "bad_number" "other"

What happened on the contact attempt. Only success rows count toward the recall-list last_reached_at annotation.

  • success - Success
  • no_answer - No Answer
  • voicemail - Voicemail
  • bounced - Bounced
  • bad_number - Bad Number
  • other - Other
subject
string <= 255 characters

Short label, e.g. 'Recall reminder', 'Treatment plan follow-up'.

note
string
staff_user
string or null <uuid>

Staff member who logged the contact. Null for system-generated entries.

recall
string or null <uuid>

Optional link to the specific recall this contact addresses.

custom_data
any

Responses

Request samples

Content type
{
  • "date_time": "2019-08-24T14:15:22Z",
  • "mode": "phone",
  • "direction": "sent",
  • "outcome": "success",
  • "subject": "string",
  • "note": "string",
  • "staff_user": "17986289-b0ef-402a-92d5-49bc6fa3367e",
  • "recall": "e7ef6ec4-8466-4387-af6a-2ed34de604a8",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "date_time": "2019-08-24T14:15:22Z",
  • "mode": "phone",
  • "direction": "sent",
  • "outcome": "success",
  • "subject": "string",
  • "note": "string",
  • "staff_user": "17986289-b0ef-402a-92d5-49bc6fa3367e",
  • "recall": "e7ef6ec4-8466-4387-af6a-2ed34de604a8",
  • "custom_data": null
}

practice_patient_comms_commlog_bulk_partial_update

Handle PATCH on the list endpoint for bulk updates.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
patient
string or null <uuid>
date_time
string or null <date-time>
mode
string (ModeEnum)
Enum: "phone" "email" "text" "fax" "mail" "in_person" "web" "other"
  • phone - Phone
  • email - Email
  • text - Text
  • fax - Fax
  • mail - Mail
  • in_person - In Person
  • web - Web
  • other - Other
direction
string (Direction80cEnum)
Enum: "sent" "received" "neither"
  • sent - Sent
  • received - Received
  • neither - Neither
outcome
string
Enum: "success" "no_answer" "voicemail" "bounced" "bad_number" "other"

What happened on the contact attempt. Only success rows count toward the recall-list last_reached_at annotation.

  • success - Success
  • no_answer - No Answer
  • voicemail - Voicemail
  • bounced - Bounced
  • bad_number - Bad Number
  • other - Other
subject
string <= 255 characters

Short label, e.g. 'Recall reminder', 'Treatment plan follow-up'.

note
string
staff_user
string or null <uuid>

Staff member who logged the contact. Null for system-generated entries.

recall
string or null <uuid>

Optional link to the specific recall this contact addresses.

custom_data
any

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "date_time": "2019-08-24T14:15:22Z",
  • "mode": "phone",
  • "direction": "sent",
  • "outcome": "success",
  • "subject": "string",
  • "note": "string",
  • "staff_user": "17986289-b0ef-402a-92d5-49bc6fa3367e",
  • "recall": "e7ef6ec4-8466-4387-af6a-2ed34de604a8",
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "date_time": "2019-08-24T14:15:22Z",
  • "mode": "phone",
  • "direction": "sent",
  • "outcome": "success",
  • "subject": "string",
  • "note": "string",
  • "phi_redacted_note": "string",
  • "staff_user": "17986289-b0ef-402a-92d5-49bc6fa3367e",
  • "recall": "e7ef6ec4-8466-4387-af6a-2ed34de604a8",
  • "is_imported": true,
  • "custom_data": null,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_sms_consents_list

List SMS consent rows for a single patient (api#637).

Returns an array of zero or one row given the unique-together (practice, patient) constraint. The list shape mirrors what web#485 already calls -- the staff UI degrades to "no row, default opted_in" when the response is empty.

The patient query parameter is required. A practice-wide list surface for a future compliance dashboard would be a separate view (the issue's optional ?state=opted_out filter); we deliberately don't conflate the two so the OpenAPI tag stays narrow.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
patient
required
string <uuid>

Filter to the single (practice, patient) consent row. Required -- the per-practice consent list is reserved for a future compliance-dashboard surface; today the patient-scoped lookup is the only supported shape.

Responses

Response samples

Content type
application/json
[
  • {
    }
]

practice_sms_messages_list

List and create SMS messages for the practice.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
direction
string
Enum: "inbound" "outbound"

Filter to inbound or outbound messages.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

patient
string <uuid>

Filter to messages associated with this patient.

status
string
Enum: "delivered" "failed" "queued" "received" "sending" "sent"

Filter by per-message delivery state.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_sms_messages_create

List and create SMS messages for the practice.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
patient
string or null <uuid>

Patient this message is for. When supplied, to_number is resolved from the patient's E.164 phone field server-side.

to_number
string <= 32 characters

E.164 destination override. Required when patient is omitted; ignored otherwise (the patient's phone wins).

body
required
string [ 1 .. 1600 ] characters

Message body. Refuses PHI -- diagnosis, prescriptions, tooth-level detail, etc. Send patients into the portal for clinical content.

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "to_number": "string",
  • "body": "string"
}

Response samples

Content type
application/json
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "to_number": "string",
  • "body": "string"
}

List the practice's provisioned SMS numbers

List SMS numbers assigned to the practice (history + active).

Read-only -- provisioning happens via an internal support tool / admin action today (see the issue body's "out of scope" + the api#622 follow-up for an admin endpoint). The active number is distinguishable by deactivated_at IS NULL on the row.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

List the calling user's SMS read receipts for this practice

List + upsert read-receipts for the calling staff user (api#643).

GET

Returns this user's read-receipts at this practice, one row per patient. The response is shaped to be cheap for the inbox to consume: [{patient_id, last_read_at}]. ?user=me is the only supported filter today; the parameter is reserved so a future cross-user surface can share the same URL.

POST

Upserts the row for (this practice, body.patient_id, this user). Idempotent and monotonic -- a write whose last_read_at is earlier than the current row's value is silently accepted as a no-op. This makes the endpoint safe for late-arriving events (slow mobile reconnecting after a laptop has already advanced the high-water mark).

Permissions: any practice member. Read-receipts aren't HIPAA- significant access events (the actual PHI-access event is the existing sms.viewed from api#636), so no audit emission here.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
user
string

Sentinel filter -- only me is supported. The list is always scoped to the calling user; the parameter exists so the URL contract reads naturally and so future cross-user surfaces (e.g. a supervisor dashboard) can extend the same path.

Responses

Response samples

Content type
application/json
{
  • "patient_id": "3854866a-5476-48be-8313-77029ccdd7a7",
  • "last_read_at": "2019-08-24T14:15:22Z"
}

Upsert this user's read-receipt for one patient thread

List + upsert read-receipts for the calling staff user (api#643).

GET

Returns this user's read-receipts at this practice, one row per patient. The response is shaped to be cheap for the inbox to consume: [{patient_id, last_read_at}]. ?user=me is the only supported filter today; the parameter is reserved so a future cross-user surface can share the same URL.

POST

Upserts the row for (this practice, body.patient_id, this user). Idempotent and monotonic -- a write whose last_read_at is earlier than the current row's value is silently accepted as a no-op. This makes the endpoint safe for late-arriving events (slow mobile reconnecting after a laptop has already advanced the high-water mark).

Permissions: any practice member. Read-receipts aren't HIPAA- significant access events (the actual PHI-access event is the existing sms.viewed from api#636), so no audit emission here.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
patient_id
required
string <uuid>

Patient whose thread the user just finished reading.

last_read_at
required
string <date-time>

ISO-8601 UTC datetime of the most-recently-read message. Must include a timezone suffix ('Z' or '+HH:MM'). The server applies 'no earlier than' semantics -- a write older than the current row is silently accepted as a no-op.

Responses

Request samples

Content type
{
  • "patient_id": "3854866a-5476-48be-8313-77029ccdd7a7",
  • "last_read_at": "2019-08-24T14:15:22Z"
}

Response samples

Content type
application/json
{
  • "patient_id": "3854866a-5476-48be-8313-77029ccdd7a7",
  • "last_read_at": "2019-08-24T14:15:22Z"
}

Intake

practice_intake_new_patient_draft_create

POST a fresh draft from the kiosk.

Mirrors :class:apps.tablets.views_checkin.KioskCheckInView's auth contract: the calling tablet's OAuth bearer is the auth, and the tablet's bound practice must match the URL practice. A staff session is rejected with 401 -- the kiosk submit surface is exclusively for in-office tablets so we don't accidentally accept a draft from somewhere that isn't running the kiosk wizard.

On success the draft is created in pending and the response carries only the new draft uid -- the kiosk does not need the full record back.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
submitted_via
string
Default: "kiosk"
Enum: "kiosk" "portal" "staff_form"

Source channel; defaults to kiosk.

  • kiosk - Kiosk
  • portal - Patient Portal
  • staff_form - Staff-entered form
personal_info
any

Demographics; mirrors Patient model field names so approve can copy 1:1.

insurance_info
any

Insurance demographics; photo refs point at doccenter rows.

medical_history
any

Conditions / allergies / medications; mirrors clinical models' shape.

signature_b64
string
Default: ""

Base64-encoded raw signed-consent capture (image or pad blob). Stored as bytes server-side; legal evidence.

insurance_card_front
string or null <binary>

Photo of the front of the patient's insurance card (PHI); stored on object storage.

insurance_card_back
string or null <binary>

Photo of the back of the patient's insurance card (PHI); stored on object storage.

Responses

Request samples

Content type
{
  • "submitted_via": "kiosk",
  • "personal_info": null,
  • "insurance_info": null,
  • "medical_history": null,
  • "signature_b64": "",
  • "insurance_card_front": "string",
  • "insurance_card_back": "string"
}

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_intake_new_patient_drafts_list

List drafts at the calling practice.

Default filter is status=pending (the inbox view). Pass ?status=approved|merged|rejected|all to widen the scope. The list endpoint is staff manager+ because the JSON buckets contain raw PHI.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_intake_new_patient_drafts_retrieve

Full draft including JSON buckets.

Logs intake.draft_viewed on every GET because the body is PHI.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
draft_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "submitted_via": "kiosk",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "tablet": "46d0c8fb-00bd-41e9-bcab-ebcb205c05ad",
  • "personal_info": null,
  • "insurance_info": null,
  • "medical_history": null,
  • "signature_b64": "string",
  • "has_signature": true,
  • "insurance_card_front": "string",
  • "insurance_card_back": "string",
  • "status": "pending",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "merged_into_patient": "eae1c63b-a395-425f-a8d7-ec1627ff32ae",
  • "approved_patient": "57687379-a30a-4785-a564-991cdb98b023",
  • "rejection_reason": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_intake_new_patient_drafts_approve_create

Approve a draft, minting a new :class:apps.patients.models.Patient.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
draft_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_intake_new_patient_drafts_merge_create

Merge a draft into an existing :class:apps.patients.models.Patient.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
draft_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
target_patient_uid
required
string <uuid>

UUID of the existing patient that should absorb this draft.

Responses

Request samples

Content type
{
  • "target_patient_uid": "e93aa6ec-2ecf-4b23-b671-922d08049e1d"
}

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_intake_new_patient_drafts_reject_create

Reject a draft with a free-text reason.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
draft_uid
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
reason
required
string [ 1 .. 255 ] characters

Free-text reason for rejection; stays on the row for audit.

Responses

Request samples

Content type
{
  • "reason": "string"
}

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

Lab

practice_labcase_board_list

Daily lab board.

GET /v1/practice/<uid>/labcase/board/

Returns lab cases ordered by due_at ascending with NULL due dates sorted last (Postgres NULLS LAST). Each row carries the derived is_overdue flag so the SPA can render the "PAST DUE" pill without re-deriving wall-clock logic client-side.

Filters

  • status — single status enum
  • due_date_from — inclusive lower bound (YYYY-MM-DD, UTC)
  • due_date_to — inclusive upper bound (YYYY-MM-DD, UTC)
  • include_overdue_only — only sent/at_lab past due_at
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
due_date_from
string

Inclusive lower bound on due_at (YYYY-MM-DD, UTC).

due_date_to
string

Inclusive upper bound on due_at (YYYY-MM-DD, UTC).

include_overdue_only
boolean

When 'true', restrict to rows where is_overdue=true.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

status
string

Filter by status enum value.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_labcase_case_list

List and create lab cases for the current practice.

Query params

status — single status enum filter patient — patient UUID filter vendor — vendor UUID filter

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_labcase_case_create

List and create lab cases for the current practice.

Query params

status — single status enum filter patient — patient UUID filter vendor — vendor UUID filter

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>
prescribing_provider
required
string <uuid>
vendor
string or null <uuid>
contact
string or null <uuid>
case_type
string (CaseTypeEnum)
Enum: "crown" "bridge" "denture" "ortho" "other"
  • crown - Crown
  • bridge - Bridge
  • denture - Denture
  • ortho - Orthodontic Appliance
  • other - Other
tooth_numbers
string <= 120 characters

Comma-separated UNS identifiers (1-32 for permanent, A-T for primary), e.g. '8,9' or '14'.

shade
string <= 40 characters

Shade designation, e.g. 'A2' or 'BL3'.

instructions
string
sent_at
string or null <date-time>
due_at
string or null <date-time>

Expected return date; auto-seeded from vendor turnaround on first send.

received_at
string or null <date-time>
status
string (Status362Enum)
Enum: "planned" "sent" "at_lab" "received" "seated" "cancelled"
  • planned - Planned
  • sent - Sent
  • at_lab - At Lab
  • received - Received
  • seated - Seated
  • cancelled - Cancelled

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "prescribing_provider": "bf81ca88-bead-44d2-b5b7-cfff11ee9482",
  • "vendor": "0389db27-b82e-4939-a6bf-21e751cacc66",
  • "contact": "ad596931-5d7c-4d2b-907e-5b64c9432eb4",
  • "case_type": "crown",
  • "tooth_numbers": "string",
  • "shade": "string",
  • "instructions": "string",
  • "sent_at": "2019-08-24T14:15:22Z",
  • "due_at": "2019-08-24T14:15:22Z",
  • "received_at": "2019-08-24T14:15:22Z",
  • "status": "planned"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "prescribing_provider": "bf81ca88-bead-44d2-b5b7-cfff11ee9482",
  • "prescribing_provider_name": "string",
  • "vendor": "0389db27-b82e-4939-a6bf-21e751cacc66",
  • "vendor_name": "string",
  • "contact": "ad596931-5d7c-4d2b-907e-5b64c9432eb4",
  • "contact_name": "string",
  • "effective_vendor": {
    },
  • "case_type": "crown",
  • "tooth_numbers": "string",
  • "shade": "string",
  • "instructions": "string",
  • "sent_at": "2019-08-24T14:15:22Z",
  • "due_at": "2019-08-24T14:15:22Z",
  • "received_at": "2019-08-24T14:15:22Z",
  • "status": "planned",
  • "is_overdue": true,
  • "scheduling_status": "needs_scheduling",
  • "scheduling_resolved_at": "2019-08-24T14:15:22Z",
  • "scheduled_appointment": "5e6ffda0-a3a9-4828-bb5c-55077a4a0e9b",
  • "needs_scheduling": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_labcase_case_retrieve

Retrieve, update, or delete a lab case.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
case_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "prescribing_provider": "bf81ca88-bead-44d2-b5b7-cfff11ee9482",
  • "prescribing_provider_name": "string",
  • "vendor": "0389db27-b82e-4939-a6bf-21e751cacc66",
  • "vendor_name": "string",
  • "contact": "ad596931-5d7c-4d2b-907e-5b64c9432eb4",
  • "contact_name": "string",
  • "effective_vendor": {
    },
  • "case_type": "crown",
  • "tooth_numbers": "string",
  • "shade": "string",
  • "instructions": "string",
  • "sent_at": "2019-08-24T14:15:22Z",
  • "due_at": "2019-08-24T14:15:22Z",
  • "received_at": "2019-08-24T14:15:22Z",
  • "status": "planned",
  • "is_overdue": true,
  • "scheduling_status": "needs_scheduling",
  • "scheduling_resolved_at": "2019-08-24T14:15:22Z",
  • "scheduled_appointment": "5e6ffda0-a3a9-4828-bb5c-55077a4a0e9b",
  • "needs_scheduling": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_labcase_case_update

Retrieve, update, or delete a lab case.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
case_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>
prescribing_provider
required
string <uuid>
vendor
string or null <uuid>
contact
string or null <uuid>
case_type
string (CaseTypeEnum)
Enum: "crown" "bridge" "denture" "ortho" "other"
  • crown - Crown
  • bridge - Bridge
  • denture - Denture
  • ortho - Orthodontic Appliance
  • other - Other
tooth_numbers
string <= 120 characters

Comma-separated UNS identifiers (1-32 for permanent, A-T for primary), e.g. '8,9' or '14'.

shade
string <= 40 characters

Shade designation, e.g. 'A2' or 'BL3'.

instructions
string
sent_at
string or null <date-time>
due_at
string or null <date-time>

Expected return date; auto-seeded from vendor turnaround on first send.

received_at
string or null <date-time>
status
string (Status362Enum)
Enum: "planned" "sent" "at_lab" "received" "seated" "cancelled"
  • planned - Planned
  • sent - Sent
  • at_lab - At Lab
  • received - Received
  • seated - Seated
  • cancelled - Cancelled

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "prescribing_provider": "bf81ca88-bead-44d2-b5b7-cfff11ee9482",
  • "vendor": "0389db27-b82e-4939-a6bf-21e751cacc66",
  • "contact": "ad596931-5d7c-4d2b-907e-5b64c9432eb4",
  • "case_type": "crown",
  • "tooth_numbers": "string",
  • "shade": "string",
  • "instructions": "string",
  • "sent_at": "2019-08-24T14:15:22Z",
  • "due_at": "2019-08-24T14:15:22Z",
  • "received_at": "2019-08-24T14:15:22Z",
  • "status": "planned"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "prescribing_provider": "bf81ca88-bead-44d2-b5b7-cfff11ee9482",
  • "prescribing_provider_name": "string",
  • "vendor": "0389db27-b82e-4939-a6bf-21e751cacc66",
  • "vendor_name": "string",
  • "contact": "ad596931-5d7c-4d2b-907e-5b64c9432eb4",
  • "contact_name": "string",
  • "effective_vendor": {
    },
  • "case_type": "crown",
  • "tooth_numbers": "string",
  • "shade": "string",
  • "instructions": "string",
  • "sent_at": "2019-08-24T14:15:22Z",
  • "due_at": "2019-08-24T14:15:22Z",
  • "received_at": "2019-08-24T14:15:22Z",
  • "status": "planned",
  • "is_overdue": true,
  • "scheduling_status": "needs_scheduling",
  • "scheduling_resolved_at": "2019-08-24T14:15:22Z",
  • "scheduled_appointment": "5e6ffda0-a3a9-4828-bb5c-55077a4a0e9b",
  • "needs_scheduling": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_labcase_case_partial_update

Retrieve, update, or delete a lab case.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
case_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
patient
string <uuid>
prescribing_provider
string <uuid>
vendor
string or null <uuid>
contact
string or null <uuid>
case_type
string (CaseTypeEnum)
Enum: "crown" "bridge" "denture" "ortho" "other"
  • crown - Crown
  • bridge - Bridge
  • denture - Denture
  • ortho - Orthodontic Appliance
  • other - Other
tooth_numbers
string <= 120 characters

Comma-separated UNS identifiers (1-32 for permanent, A-T for primary), e.g. '8,9' or '14'.

shade
string <= 40 characters

Shade designation, e.g. 'A2' or 'BL3'.

instructions
string
sent_at
string or null <date-time>
due_at
string or null <date-time>

Expected return date; auto-seeded from vendor turnaround on first send.

received_at
string or null <date-time>
status
string (Status362Enum)
Enum: "planned" "sent" "at_lab" "received" "seated" "cancelled"
  • planned - Planned
  • sent - Sent
  • at_lab - At Lab
  • received - Received
  • seated - Seated
  • cancelled - Cancelled

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "prescribing_provider": "bf81ca88-bead-44d2-b5b7-cfff11ee9482",
  • "vendor": "0389db27-b82e-4939-a6bf-21e751cacc66",
  • "contact": "ad596931-5d7c-4d2b-907e-5b64c9432eb4",
  • "case_type": "crown",
  • "tooth_numbers": "string",
  • "shade": "string",
  • "instructions": "string",
  • "sent_at": "2019-08-24T14:15:22Z",
  • "due_at": "2019-08-24T14:15:22Z",
  • "received_at": "2019-08-24T14:15:22Z",
  • "status": "planned"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "prescribing_provider": "bf81ca88-bead-44d2-b5b7-cfff11ee9482",
  • "prescribing_provider_name": "string",
  • "vendor": "0389db27-b82e-4939-a6bf-21e751cacc66",
  • "vendor_name": "string",
  • "contact": "ad596931-5d7c-4d2b-907e-5b64c9432eb4",
  • "contact_name": "string",
  • "effective_vendor": {
    },
  • "case_type": "crown",
  • "tooth_numbers": "string",
  • "shade": "string",
  • "instructions": "string",
  • "sent_at": "2019-08-24T14:15:22Z",
  • "due_at": "2019-08-24T14:15:22Z",
  • "received_at": "2019-08-24T14:15:22Z",
  • "status": "planned",
  • "is_overdue": true,
  • "scheduling_status": "needs_scheduling",
  • "scheduling_resolved_at": "2019-08-24T14:15:22Z",
  • "scheduled_appointment": "5e6ffda0-a3a9-4828-bb5c-55077a4a0e9b",
  • "needs_scheduling": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_labcase_case_destroy

Retrieve, update, or delete a lab case.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
case_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_labcase_case_resolve_scheduling_create

Resolve a needs-scheduling queue entry (escape#370).

POST /v1/practice/<uid>/labcase/case/<case_id>/resolve-scheduling/

Body::

{"scheduling_status": "scheduled",
 "scheduled_appointment": "<uuid?>"}

Marks the case scheduled / done / dismissed, stamps scheduling_resolved_at, optionally links the booked appointment, and returns the updated case via :class:LabCaseSerializer. Idempotent in spirit -- re-resolving an already-resolved case just updates the target state and (re)links the appointment without re-stamping the original resolve time.

The queue is entered implicitly when a case is received, so this action only accepts the resolved target states; needs_scheduling is not a valid target.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
case_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
scheduling_status
required
string (LabCaseResolveSchedulingSchedulingStatusEnum)
Enum: "scheduled" "done" "dismissed"
  • scheduled - scheduled
  • done - done
  • dismissed - dismissed
scheduled_appointment
string or null <uuid>

Responses

Request samples

Content type
{
  • "scheduling_status": "scheduled",
  • "scheduled_appointment": "5e6ffda0-a3a9-4828-bb5c-55077a4a0e9b"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "prescribing_provider": "bf81ca88-bead-44d2-b5b7-cfff11ee9482",
  • "prescribing_provider_name": "string",
  • "vendor": "0389db27-b82e-4939-a6bf-21e751cacc66",
  • "vendor_name": "string",
  • "contact": "ad596931-5d7c-4d2b-907e-5b64c9432eb4",
  • "contact_name": "string",
  • "effective_vendor": {
    },
  • "case_type": "crown",
  • "tooth_numbers": "string",
  • "shade": "string",
  • "instructions": "string",
  • "sent_at": "2019-08-24T14:15:22Z",
  • "due_at": "2019-08-24T14:15:22Z",
  • "received_at": "2019-08-24T14:15:22Z",
  • "status": "planned",
  • "is_overdue": true,
  • "scheduling_status": "needs_scheduling",
  • "scheduling_resolved_at": "2019-08-24T14:15:22Z",
  • "scheduled_appointment": "5e6ffda0-a3a9-4828-bb5c-55077a4a0e9b",
  • "needs_scheduling": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_labcase_needs_scheduling_list

Needs-scheduling worklist for the unified comms page (escape#370).

GET /v1/practice/<uid>/labcase/needs-scheduling/

Returns the received lab cases whose follow-up seat/delivery visit has not yet been booked or dismissed -- i.e. status=received AND scheduling_status=needs_scheduling. These are the patients the front desk must call and schedule.

Ordering is oldest-received-first (received_at ascending, NULLs last) so the patients waiting longest float to the top of the worklist. Each row carries the full :class:LabCaseSerializer shape, including needs_scheduling (always true here) and patient_name so the SPA renders the call list without an extra round-trip.

Pagination (GH-1044)

The worklist is a bounded per-practice "call list" -- the open follow-ups for one office -- and the SPA wants the whole list in one page so the front desk can scan and triage without click-through paging. It therefore requests ?page_size=200. The project-wide default :class:~apps.common.pagination.StandardPageNumberPagination caps page_size at 100 and rejects anything larger with HTTP 400 (deliberate -- it trains web clients to paginate rather than silently clamping). That 400 is what surfaced as the comms-page "Failed to load the needs-scheduling queue" banner for any office with a queue. This is a bounded reference-data-shaped surface, so it uses :class:~apps.common.pagination.ReferenceDataPagination (100/2000) -- the same class the providers and procedure-code catalogs use to load a bounded set in one page -- which accepts the SPA's generous page_size and returns a normal paginated 200.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_labcase_vendor_list

List and create outside-lab vendors for the current practice.

GET /v1/practice//labcase/vendor/ POST /v1/practice//labcase/vendor/

Query params

activetrue (default) / false / all search — case-insensitive substring match on vendor name

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{}

practice_labcase_vendor_create

List and create outside-lab vendors for the current practice.

GET /v1/practice//labcase/vendor/ POST /v1/practice//labcase/vendor/

Query params

activetrue (default) / false / all search — case-insensitive substring match on vendor name

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 200 ] characters
address
string
phone
string <= 40 characters
default_turnaround_days
integer [ 0 .. 32767 ]

Typical days from send to receive; seeds LabCase.due_at on first send.

notes
string
is_active
boolean

Responses

Request samples

Content type
{
  • "name": "string",
  • "address": "string",
  • "phone": "string",
  • "default_turnaround_days": 32767,
  • "notes": "string",
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "address": "string",
  • "phone": "string",
  • "default_turnaround_days": 32767,
  • "notes": "string",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_labcase_vendor_retrieve

Retrieve, update, or delete a lab vendor.

DELETE is a hard delete by default but vendors with referencing :class:LabCase rows will fail with a PROTECT integrity error. Use is_active=False to soft-hide a vendor from the picker without losing historical references.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
vendor_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "address": "string",
  • "phone": "string",
  • "default_turnaround_days": 32767,
  • "notes": "string",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_labcase_vendor_update

Retrieve, update, or delete a lab vendor.

DELETE is a hard delete by default but vendors with referencing :class:LabCase rows will fail with a PROTECT integrity error. Use is_active=False to soft-hide a vendor from the picker without losing historical references.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
vendor_id
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 200 ] characters
address
string
phone
string <= 40 characters
default_turnaround_days
integer [ 0 .. 32767 ]

Typical days from send to receive; seeds LabCase.due_at on first send.

notes
string
is_active
boolean

Responses

Request samples

Content type
{
  • "name": "string",
  • "address": "string",
  • "phone": "string",
  • "default_turnaround_days": 32767,
  • "notes": "string",
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "address": "string",
  • "phone": "string",
  • "default_turnaround_days": 32767,
  • "notes": "string",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_labcase_vendor_partial_update

Retrieve, update, or delete a lab vendor.

DELETE is a hard delete by default but vendors with referencing :class:LabCase rows will fail with a PROTECT integrity error. Use is_active=False to soft-hide a vendor from the picker without losing historical references.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
vendor_id
required
string <uuid>
Request Body schema:
name
string [ 1 .. 200 ] characters
address
string
phone
string <= 40 characters
default_turnaround_days
integer [ 0 .. 32767 ]

Typical days from send to receive; seeds LabCase.due_at on first send.

notes
string
is_active
boolean

Responses

Request samples

Content type
{
  • "name": "string",
  • "address": "string",
  • "phone": "string",
  • "default_turnaround_days": 32767,
  • "notes": "string",
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "address": "string",
  • "phone": "string",
  • "default_turnaround_days": 32767,
  • "notes": "string",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_labcase_vendor_destroy

Retrieve, update, or delete a lab vendor.

DELETE is a hard delete by default but vendors with referencing :class:LabCase rows will fail with a PROTECT integrity error. Use is_active=False to soft-hide a vendor from the picker without losing historical references.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
vendor_id
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

Messaging

List conversations

List conversations the user participates in, or create a new one.

GET returns a paginated list of conversations ordered by most recent activity, filtered to only those the requesting user is a participant of. POST creates a new conversation and optionally sends the first message.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Create conversation

List conversations the user participates in, or create a new one.

GET returns a paginated list of conversations ordered by most recent activity, filtered to only those the requesting user is a participant of. POST creates a new conversation and optionally sends the first message.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
participant_ids
Array of strings <uuid> [ items <uuid > ]

UUIDs of the users to include (the sender is added automatically).

conversation_type
string
Default: "direct"
Enum: "direct" "operatory" "system"
  • direct - Direct
  • operatory - Operatory
  • system - System
title
string <= 255 characters
Default: ""
operatory
string or null <uuid>
body
string
Default: ""

Optional first message body.

Responses

Request samples

Content type
{
  • "participant_ids": [
    ],
  • "conversation_type": "direct",
  • "title": "",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "body": ""
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "title": "string",
  • "conversation_type": "direct",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "participants": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Retrieve conversation

Retrieve a single conversation.

Direct conversations require explicit participant membership. Operatory conversations are visible to any active practice member.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
conversation_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "title": "string",
  • "conversation_type": "direct",
  • "operatory": "72ef68e1-2b4e-4e3b-9284-54c2c1c89045",
  • "participants": [
    ],
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

List messages

List messages in a conversation or send a new one.

GET returns messages in chronological order (oldest first), paginated. POST creates a new message and updates the conversation's modified timestamp so it bubbles to the top of the list.

Operatory conversations are accessible to every practice member.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
conversation_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Send message

List messages in a conversation or send a new one.

GET returns messages in chronological order (oldest first), paginated. POST creates a new message and updates the conversation's modified timestamp so it bubbles to the top of the list.

Operatory conversations are accessible to every practice member.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
conversation_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

Mark conversation as read

Update the requesting user's last_read_at timestamp.

PATCH (no body required) sets last_read_at to now, clearing the unread badge for this conversation.

For operatory conversations the user may not have an explicit participant record yet, so we create one on-the-fly via update_or_create.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
conversation_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

List active chair-presence rows

Return every active chair-presence row in this practice.

Powers the messaging-menu's "OP 3 -- Jane S." occupant labels. Only rows where released_at IS NULL are returned; auto-released rows are filtered out so the UI never shows a stale claim past the 8-hour sanity cutoff.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Claim an operatory (chair presence)

Claim a chair as the calling user's current operatory.

POST body: {"operatory_id": "<uuid>"}.

Idempotent: a repeat claim on the same chair returns 200 with the existing row. A claim on a different chair releases the caller's previous claim first (a user is at one chair at a time).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
operatory_id
required
string <uuid>

Responses

Request samples

Content type
{
  • "operatory_id": "700062e2-3e2d-40d4-aa03-805aad7e7b9e"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "operatory_id": "700062e2-3e2d-40d4-aa03-805aad7e7b9e",
  • "user_id": "a169451c-8525-4352-b8ca-070dd449a1a5",
  • "first_name": "string",
  • "last_name": "string",
  • "seated_patient_id": "1fccc73e-7192-405c-bee4-28ce5bc728ab",
  • "claimed_at": "2019-08-24T14:15:22Z",
  • "auto_release_at": "2019-08-24T14:15:22Z"
}

Get the active occupant for a specific chair

Return the active occupant for <operatory_uid>, or 404.

Used when the messaging menu wants a single chair's occupant without pulling the practice-wide list (e.g. opening a thread directly).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
operatory_uid
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "operatory_id": "700062e2-3e2d-40d4-aa03-805aad7e7b9e",
  • "user_id": "a169451c-8525-4352-b8ca-070dd449a1a5",
  • "first_name": "string",
  • "last_name": "string",
  • "seated_patient_id": "1fccc73e-7192-405c-bee4-28ce5bc728ab",
  • "claimed_at": "2019-08-24T14:15:22Z",
  • "auto_release_at": "2019-08-24T14:15:22Z"
}

Release the caller's chair presence

Release the calling user's claim on an operatory.

POST body: {"operatory_id": "<uuid>"}. Returns 200 with {"released": true|false} -- false indicating the user had no active claim on the chair (still a success, just a no-op).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
operatory_id
required
string <uuid>

Responses

Request samples

Content type
{
  • "operatory_id": "700062e2-3e2d-40d4-aa03-805aad7e7b9e"
}

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

Get or create operatory conversation

Convenience endpoint for operatory-addressed messaging.

GET .../operatory/<operatory_id>/ — returns the operatory's conversation, creating it if one doesn't exist yet.

POST .../operatory/<operatory_id>/ — finds (or creates) the operatory conversation and sends a message in a single round-trip.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
operatory_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Send message to operatory conversation

Convenience endpoint for operatory-addressed messaging.

GET .../operatory/<operatory_id>/ — returns the operatory's conversation, creating it if one doesn't exist yet.

POST .../operatory/<operatory_id>/ — finds (or creates) the operatory conversation and sends a message in a single round-trip.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
operatory_id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

List practice member presence

Return online/offline status and last_seen_at for all practice members.

GET /api/v1/practice/<uid>/messaging/presence/

A member is considered online if they have an active WebSocket connection. Since presence is tracked via in-memory channel-layer groups (not database state), this endpoint reports last_seen_at from the User model as a fallback for offline users. The frontend should use the presence.update WebSocket event for real-time changes and this endpoint only for initial page load.

The roster enumerates exactly the population :meth:apps.accounts.models.User.has_practice_access admits -- the same gate the WebSocket consumer uses (_check_practice_access): direct active :class:PracticeMembership rows union users with an active :class:ClientMembership on the practice's client_id. Keeping the two sets identical guarantees that every user who can appear online on the socket has a roster row to attach that presence dot to (api#994 / web#797). Client-membership-only users carry no practice-level role, so role is emitted as null.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Patient Inbox

practice_patient_inbox_list

Staff-facing inbox for unreviewed :class:NewPatientDraft rows.

Mounted at /api/v1/practice/<uid>/patient-inbox/ with the standard ViewSet routes plus three @action transitions:

  • POST .../<id>/convert/ -- mint a new patient.
  • POST .../<id>/merge/ -- fold into an existing patient.
  • POST .../<id>/dismiss/ -- terminal, no patient created.

The endpoint is manager-or-above on read AND write because the JSON buckets ARE PHI (api#770 mirrors the api#761 pattern); the enforce_role_on_read = True flag is what makes the role gate fire on GET as well as POST.

Audit

Every state change emits an intake.* semantic event with PHI- scrubbed metadata. List + retrieve also emit access events so a HIPAA reviewer can reconstruct who read the staging table.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

status
string
Enum: "all" "approved" "converted" "dismissed" "merged" "pending" "ready_for_review" "rejected"

Filter drafts by lifecycle status. Default is the open states (pending + ready_for_review); pass an explicit value to widen, or all for every state.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_inbox_retrieve

Staff-facing inbox for unreviewed :class:NewPatientDraft rows.

Mounted at /api/v1/practice/<uid>/patient-inbox/ with the standard ViewSet routes plus three @action transitions:

  • POST .../<id>/convert/ -- mint a new patient.
  • POST .../<id>/merge/ -- fold into an existing patient.
  • POST .../<id>/dismiss/ -- terminal, no patient created.

The endpoint is manager-or-above on read AND write because the JSON buckets ARE PHI (api#770 mirrors the api#761 pattern); the enforce_role_on_read = True flag is what makes the role gate fire on GET as well as POST.

Audit

Every state change emits an intake.* semantic event with PHI- scrubbed metadata. List + retrieve also emit access events so a HIPAA reviewer can reconstruct who read the staging table.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "submitted_via": "kiosk",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "tablet": "46d0c8fb-00bd-41e9-bcab-ebcb205c05ad",
  • "personal_info": null,
  • "insurance_info": null,
  • "medical_history": null,
  • "signature_b64": "string",
  • "has_signature": true,
  • "insurance_card_front": "string",
  • "insurance_card_back": "string",
  • "status": "pending",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "merged_into_patient": "eae1c63b-a395-425f-a8d7-ec1627ff32ae",
  • "converted_to_patient": "9bc32040-0306-4132-bc06-10e779b712a9",
  • "approved_patient": "57687379-a30a-4785-a564-991cdb98b023",
  • "rejection_reason": "string",
  • "dedup_candidates": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_patient_inbox_convert_create

Convert a draft into a brand-new :class:Patient.

Mints a fresh patient row from the draft's structured fields, links it via converted_to_patient, flips the draft into converted, and audit-logs the transition. Returns the same shape the legacy approve endpoint emits plus the source draft id for the staff UI's success toast.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_inbox_dismiss_create

Dismiss a draft as spam / accidental submission.

Reason is optional; staff who supply one get it persisted on the row for audit. No patient is created or modified.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string
practice_uid
required
string <uuid>
Request Body schema:
reason
string <= 255 characters
Default: ""

Optional free-text reason; persisted on the draft for audit.

Responses

Request samples

Content type
{
  • "reason": ""
}

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_inbox_merge_create

Fold a draft into an existing :class:Patient.

Demographics on the target are left alone -- the merge only attaches the draft's insurance + medical-history child rows. Staff who want to refresh the patient's name / DOB / address should use the regular patient-edit surface.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string
practice_uid
required
string <uuid>
Request Body schema:
required
patient_id
required
string <uuid>

UUID of the existing patient that should absorb this draft.

Responses

Request samples

Content type
{
  • "patient_id": "3854866a-5476-48be-8313-77029ccdd7a7"
}

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

Prescriptions

practice_patient_prescription_list

List and create prescriptions.

GET /v1/practice//prescription/ POST /v1/practice//prescription/

Query params

patient — filter by patient UUID status — filter by status (draft/final/cancelled) search — case-insensitive drug name search

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_patient_prescription_create

List and create prescriptions.

GET /v1/practice//prescription/ POST /v1/practice//prescription/

Query params

patient — filter by patient UUID status — filter by status (draft/final/cancelled) search — case-insensitive drug name search

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>
provider
string or null <uuid>

The prescribing/responsible provider. Required to finalise.

drug_name
required
string [ 1 .. 200 ] characters

e.g. Amoxicillin

drug_strength
string <= 100 characters

e.g. 500mg

drug_form
string <= 100 characters

Dosage form: Capsule, Tablet, Solution, Cream, etc.

quantity
string <= 50 characters

e.g. #21 or 30 mL

directions
required
string non-empty

Sig / patient instructions e.g. 'Take 1 capsule by mouth three times daily for 7 days'

refills
integer [ 0 .. 32767 ]

Number of refills (0 = no refills). Controlled substances may not be refilled in many states.

substitution_permitted
boolean

Allow pharmacist to substitute generic equivalent.

cs_schedule
string
Enum: "none" "II" "III" "IV" "V"

DEA Controlled Substance Schedule. Non-Controlled for the vast majority of dental prescriptions (antibiotics, NSAIDs, fluoride, chlorhexidine). Use Schedule II–V only for opioids, benzodiazepines, etc.

  • none - Non-Controlled
  • II - Schedule II
  • III - Schedule III
  • IV - Schedule IV
  • V - Schedule V
diagnosis_description
string <= 255 characters

Brief clinical indication e.g. 'Post-extraction infection'.

appointment
string or null <uuid>
notes
string

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "notes": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_controlled": true,
  • "requires_epcs": true,
  • "epcs_warning": "string",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "status": "draft",
  • "finalized_at": "2019-08-24T14:15:22Z",
  • "prescribed_at": "2019-08-24T14:15:22Z",
  • "finalized_by": "ca059483-923c-4d0a-bf3a-a20808c35301",
  • "finalized_by_name": "string",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "cancelled_by": "da8800d0-a376-4b5c-a53d-a329d671e82b",
  • "cancelled_by_name": "string",
  • "cancellation_reason": "string",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "submitted_by_name": "string",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "reviewed_by_name": "string",
  • "rejection_reason": "string",
  • "has_signature": true,
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_patient_prescription_retrieve

Retrieve or update a prescription (draft only).

GET /v1/practice//prescription// PATCH /v1/practice//prescription//

Only draft prescriptions may be edited. Use the /finalise/ action to advance to final.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
prescription_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_controlled": true,
  • "requires_epcs": true,
  • "epcs_warning": "string",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "status": "draft",
  • "finalized_at": "2019-08-24T14:15:22Z",
  • "prescribed_at": "2019-08-24T14:15:22Z",
  • "finalized_by": "ca059483-923c-4d0a-bf3a-a20808c35301",
  • "finalized_by_name": "string",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "cancelled_by": "da8800d0-a376-4b5c-a53d-a329d671e82b",
  • "cancelled_by_name": "string",
  • "cancellation_reason": "string",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "submitted_by_name": "string",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "reviewed_by_name": "string",
  • "rejection_reason": "string",
  • "has_signature": true,
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_patient_prescription_update

Retrieve or update a prescription (draft only).

GET /v1/practice//prescription// PATCH /v1/practice//prescription//

Only draft prescriptions may be edited. Use the /finalise/ action to advance to final.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
prescription_id
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>
provider
string or null <uuid>

The prescribing/responsible provider. Required to finalise.

drug_name
required
string [ 1 .. 200 ] characters

e.g. Amoxicillin

drug_strength
string <= 100 characters

e.g. 500mg

drug_form
string <= 100 characters

Dosage form: Capsule, Tablet, Solution, Cream, etc.

quantity
string <= 50 characters

e.g. #21 or 30 mL

directions
required
string non-empty

Sig / patient instructions e.g. 'Take 1 capsule by mouth three times daily for 7 days'

refills
integer [ 0 .. 32767 ]

Number of refills (0 = no refills). Controlled substances may not be refilled in many states.

substitution_permitted
boolean

Allow pharmacist to substitute generic equivalent.

cs_schedule
string
Enum: "none" "II" "III" "IV" "V"

DEA Controlled Substance Schedule. Non-Controlled for the vast majority of dental prescriptions (antibiotics, NSAIDs, fluoride, chlorhexidine). Use Schedule II–V only for opioids, benzodiazepines, etc.

  • none - Non-Controlled
  • II - Schedule II
  • III - Schedule III
  • IV - Schedule IV
  • V - Schedule V
diagnosis_description
string <= 255 characters

Brief clinical indication e.g. 'Post-extraction infection'.

appointment
string or null <uuid>
notes
string

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "notes": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_controlled": true,
  • "requires_epcs": true,
  • "epcs_warning": "string",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "status": "draft",
  • "finalized_at": "2019-08-24T14:15:22Z",
  • "prescribed_at": "2019-08-24T14:15:22Z",
  • "finalized_by": "ca059483-923c-4d0a-bf3a-a20808c35301",
  • "finalized_by_name": "string",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "cancelled_by": "da8800d0-a376-4b5c-a53d-a329d671e82b",
  • "cancelled_by_name": "string",
  • "cancellation_reason": "string",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "submitted_by_name": "string",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "reviewed_by_name": "string",
  • "rejection_reason": "string",
  • "has_signature": true,
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_patient_prescription_partial_update

Retrieve or update a prescription (draft only).

GET /v1/practice//prescription// PATCH /v1/practice//prescription//

Only draft prescriptions may be edited. Use the /finalise/ action to advance to final.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
prescription_id
required
string <uuid>
Request Body schema:
patient
string <uuid>
provider
string or null <uuid>

The prescribing/responsible provider. Required to finalise.

drug_name
string [ 1 .. 200 ] characters

e.g. Amoxicillin

drug_strength
string <= 100 characters

e.g. 500mg

drug_form
string <= 100 characters

Dosage form: Capsule, Tablet, Solution, Cream, etc.

quantity
string <= 50 characters

e.g. #21 or 30 mL

directions
string non-empty

Sig / patient instructions e.g. 'Take 1 capsule by mouth three times daily for 7 days'

refills
integer [ 0 .. 32767 ]

Number of refills (0 = no refills). Controlled substances may not be refilled in many states.

substitution_permitted
boolean

Allow pharmacist to substitute generic equivalent.

cs_schedule
string
Enum: "none" "II" "III" "IV" "V"

DEA Controlled Substance Schedule. Non-Controlled for the vast majority of dental prescriptions (antibiotics, NSAIDs, fluoride, chlorhexidine). Use Schedule II–V only for opioids, benzodiazepines, etc.

  • none - Non-Controlled
  • II - Schedule II
  • III - Schedule III
  • IV - Schedule IV
  • V - Schedule V
diagnosis_description
string <= 255 characters

Brief clinical indication e.g. 'Post-extraction infection'.

appointment
string or null <uuid>
notes
string

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "notes": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_controlled": true,
  • "requires_epcs": true,
  • "epcs_warning": "string",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "status": "draft",
  • "finalized_at": "2019-08-24T14:15:22Z",
  • "prescribed_at": "2019-08-24T14:15:22Z",
  • "finalized_by": "ca059483-923c-4d0a-bf3a-a20808c35301",
  • "finalized_by_name": "string",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "cancelled_by": "da8800d0-a376-4b5c-a53d-a329d671e82b",
  • "cancelled_by_name": "string",
  • "cancellation_reason": "string",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "submitted_by_name": "string",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "reviewed_by_name": "string",
  • "rejection_reason": "string",
  • "has_signature": true,
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_patient_prescription_cancel_create

Cancel a prescription (draft or issued).

POST /v1/practice//prescription//cancel/

Body (optional)::

{"reason": "Wrong drug selected"}

Any staff member may cancel a draft. Cancelling an issued prescription (final or the review-workflow approved state) is restricted to ADMIN / DOCTOR and enforced server-side — deny-by-default (api#1043 / escape#414, was UI-only). The acting user and timestamp are recorded on the row for the chart's "Cancelled by {user} on {when}" attribution. api#822 / escape#277.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
prescription_id
required
string <uuid>
Request Body schema:
reason
string
Default: ""

Optional free-text reason for cancelling the prescription.

Responses

Request samples

Content type
{
  • "reason": ""
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_controlled": true,
  • "requires_epcs": true,
  • "epcs_warning": "string",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "status": "draft",
  • "finalized_at": "2019-08-24T14:15:22Z",
  • "prescribed_at": "2019-08-24T14:15:22Z",
  • "finalized_by": "ca059483-923c-4d0a-bf3a-a20808c35301",
  • "finalized_by_name": "string",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "cancelled_by": "da8800d0-a376-4b5c-a53d-a329d671e82b",
  • "cancelled_by_name": "string",
  • "cancellation_reason": "string",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "submitted_by_name": "string",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "reviewed_by_name": "string",
  • "rejection_reason": "string",
  • "has_signature": true,
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_patient_prescription_finalise_create

Finalize a draft prescription.

POST /v1/practice//prescription//finalise/

Deny-by-default authorization (api#1043 / escape#414). Two server-side gates must both pass — the rule was previously enforced only in the UI:

  1. Caller role — the acting user must hold the DOCTOR role (or the practice ADMIN override). Hygienists and clinical staff create and edit drafts; the Doctor gives the sign-off (api#822 / escape#277).
  2. Provider eligibility — the provider in whose name the Rx is issued must hold prescribing authority: an active Dentist with an NPI for a non-controlled Rx, and additionally a DEA number on file for a controlled substance. A staff member cannot finalize a prescription against a provider who is not an eligible prescriber.

For controlled substances, the doctor must still physically sign the printed paper prescription. This endpoint is NOT an EPCS action and does not constitute an electronic DEA signature.

Returns the updated prescription payload.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
prescription_id
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_patient_prescription_pdf_retrieve

Render a prescription as a printable PDF.

GET /v1/practice//prescription//pdf/

Also mounted patient-scoped at /v1/practice/<uid>/patient/<patient_id>/prescription/<id>/pdf/ — the extra patient_id URL kwarg is accepted and ignored (the Rx is already practice+id scoped), so the patient-scoped print route no longer 500s (api#1043 / escape#414).

Returns application/pdf. Only issued prescriptions may be rendered — the legacy paper final state and the review-workflow approved (signed) state both qualify; draft / pending / rejected prescriptions return 400.

The PDF is formatted as a standard paper Rx form including:

  • Practice name, address, phone
  • Provider name, NPI, DEA number
  • Patient name, date of birth
  • Date of prescription
  • Drug details and directions
  • Blank diagonal line below the drug entry (tamper-evident, required for controlled substance paper prescriptions in many states)
  • Provider signature line

Emits a prescription.printed audit event so there is a permanent record of when the form was accessed for printing.

Note: For paper controlled-substance prescriptions, the provider must physically sign the printed form. This endpoint is not an EPCS action and does not constitute a DEA electronic signature.

Role gate (api#822 / escape#277): printing is restricted to the same set that may finalise -- DOCTOR and ADMIN. Hygienists and clinical staff may view the finalised Rx through the chart but must hand the print step off to the prescribing doctor (or the practice admin acting on the doctor's behalf).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
patient_id
required
string <uuid>
practice_uid
required
string <uuid>
prescription_id
required
string <uuid>

Responses

practice_prescription_list

List and create prescriptions.

GET /v1/practice//prescription/ POST /v1/practice//prescription/

Query params

patient — filter by patient UUID status — filter by status (draft/final/cancelled) search — case-insensitive drug name search

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_prescription_create

List and create prescriptions.

GET /v1/practice//prescription/ POST /v1/practice//prescription/

Query params

patient — filter by patient UUID status — filter by status (draft/final/cancelled) search — case-insensitive drug name search

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>
provider
string or null <uuid>

The prescribing/responsible provider. Required to finalise.

drug_name
required
string [ 1 .. 200 ] characters

e.g. Amoxicillin

drug_strength
string <= 100 characters

e.g. 500mg

drug_form
string <= 100 characters

Dosage form: Capsule, Tablet, Solution, Cream, etc.

quantity
string <= 50 characters

e.g. #21 or 30 mL

directions
required
string non-empty

Sig / patient instructions e.g. 'Take 1 capsule by mouth three times daily for 7 days'

refills
integer [ 0 .. 32767 ]

Number of refills (0 = no refills). Controlled substances may not be refilled in many states.

substitution_permitted
boolean

Allow pharmacist to substitute generic equivalent.

cs_schedule
string
Enum: "none" "II" "III" "IV" "V"

DEA Controlled Substance Schedule. Non-Controlled for the vast majority of dental prescriptions (antibiotics, NSAIDs, fluoride, chlorhexidine). Use Schedule II–V only for opioids, benzodiazepines, etc.

  • none - Non-Controlled
  • II - Schedule II
  • III - Schedule III
  • IV - Schedule IV
  • V - Schedule V
diagnosis_description
string <= 255 characters

Brief clinical indication e.g. 'Post-extraction infection'.

appointment
string or null <uuid>
notes
string

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "notes": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_controlled": true,
  • "requires_epcs": true,
  • "epcs_warning": "string",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "status": "draft",
  • "finalized_at": "2019-08-24T14:15:22Z",
  • "prescribed_at": "2019-08-24T14:15:22Z",
  • "finalized_by": "ca059483-923c-4d0a-bf3a-a20808c35301",
  • "finalized_by_name": "string",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "cancelled_by": "da8800d0-a376-4b5c-a53d-a329d671e82b",
  • "cancelled_by_name": "string",
  • "cancellation_reason": "string",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "submitted_by_name": "string",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "reviewed_by_name": "string",
  • "rejection_reason": "string",
  • "has_signature": true,
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_prescription_retrieve

Retrieve or update a prescription (draft only).

GET /v1/practice//prescription// PATCH /v1/practice//prescription//

Only draft prescriptions may be edited. Use the /finalise/ action to advance to final.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
prescription_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_controlled": true,
  • "requires_epcs": true,
  • "epcs_warning": "string",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "status": "draft",
  • "finalized_at": "2019-08-24T14:15:22Z",
  • "prescribed_at": "2019-08-24T14:15:22Z",
  • "finalized_by": "ca059483-923c-4d0a-bf3a-a20808c35301",
  • "finalized_by_name": "string",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "cancelled_by": "da8800d0-a376-4b5c-a53d-a329d671e82b",
  • "cancelled_by_name": "string",
  • "cancellation_reason": "string",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "submitted_by_name": "string",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "reviewed_by_name": "string",
  • "rejection_reason": "string",
  • "has_signature": true,
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_prescription_update

Retrieve or update a prescription (draft only).

GET /v1/practice//prescription// PATCH /v1/practice//prescription//

Only draft prescriptions may be edited. Use the /finalise/ action to advance to final.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
prescription_id
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>
provider
string or null <uuid>

The prescribing/responsible provider. Required to finalise.

drug_name
required
string [ 1 .. 200 ] characters

e.g. Amoxicillin

drug_strength
string <= 100 characters

e.g. 500mg

drug_form
string <= 100 characters

Dosage form: Capsule, Tablet, Solution, Cream, etc.

quantity
string <= 50 characters

e.g. #21 or 30 mL

directions
required
string non-empty

Sig / patient instructions e.g. 'Take 1 capsule by mouth three times daily for 7 days'

refills
integer [ 0 .. 32767 ]

Number of refills (0 = no refills). Controlled substances may not be refilled in many states.

substitution_permitted
boolean

Allow pharmacist to substitute generic equivalent.

cs_schedule
string
Enum: "none" "II" "III" "IV" "V"

DEA Controlled Substance Schedule. Non-Controlled for the vast majority of dental prescriptions (antibiotics, NSAIDs, fluoride, chlorhexidine). Use Schedule II–V only for opioids, benzodiazepines, etc.

  • none - Non-Controlled
  • II - Schedule II
  • III - Schedule III
  • IV - Schedule IV
  • V - Schedule V
diagnosis_description
string <= 255 characters

Brief clinical indication e.g. 'Post-extraction infection'.

appointment
string or null <uuid>
notes
string

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "notes": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_controlled": true,
  • "requires_epcs": true,
  • "epcs_warning": "string",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "status": "draft",
  • "finalized_at": "2019-08-24T14:15:22Z",
  • "prescribed_at": "2019-08-24T14:15:22Z",
  • "finalized_by": "ca059483-923c-4d0a-bf3a-a20808c35301",
  • "finalized_by_name": "string",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "cancelled_by": "da8800d0-a376-4b5c-a53d-a329d671e82b",
  • "cancelled_by_name": "string",
  • "cancellation_reason": "string",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "submitted_by_name": "string",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "reviewed_by_name": "string",
  • "rejection_reason": "string",
  • "has_signature": true,
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_prescription_partial_update

Retrieve or update a prescription (draft only).

GET /v1/practice//prescription// PATCH /v1/practice//prescription//

Only draft prescriptions may be edited. Use the /finalise/ action to advance to final.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
prescription_id
required
string <uuid>
Request Body schema:
patient
string <uuid>
provider
string or null <uuid>

The prescribing/responsible provider. Required to finalise.

drug_name
string [ 1 .. 200 ] characters

e.g. Amoxicillin

drug_strength
string <= 100 characters

e.g. 500mg

drug_form
string <= 100 characters

Dosage form: Capsule, Tablet, Solution, Cream, etc.

quantity
string <= 50 characters

e.g. #21 or 30 mL

directions
string non-empty

Sig / patient instructions e.g. 'Take 1 capsule by mouth three times daily for 7 days'

refills
integer [ 0 .. 32767 ]

Number of refills (0 = no refills). Controlled substances may not be refilled in many states.

substitution_permitted
boolean

Allow pharmacist to substitute generic equivalent.

cs_schedule
string
Enum: "none" "II" "III" "IV" "V"

DEA Controlled Substance Schedule. Non-Controlled for the vast majority of dental prescriptions (antibiotics, NSAIDs, fluoride, chlorhexidine). Use Schedule II–V only for opioids, benzodiazepines, etc.

  • none - Non-Controlled
  • II - Schedule II
  • III - Schedule III
  • IV - Schedule IV
  • V - Schedule V
diagnosis_description
string <= 255 characters

Brief clinical indication e.g. 'Post-extraction infection'.

appointment
string or null <uuid>
notes
string

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "notes": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_controlled": true,
  • "requires_epcs": true,
  • "epcs_warning": "string",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "status": "draft",
  • "finalized_at": "2019-08-24T14:15:22Z",
  • "prescribed_at": "2019-08-24T14:15:22Z",
  • "finalized_by": "ca059483-923c-4d0a-bf3a-a20808c35301",
  • "finalized_by_name": "string",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "cancelled_by": "da8800d0-a376-4b5c-a53d-a329d671e82b",
  • "cancelled_by_name": "string",
  • "cancellation_reason": "string",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "submitted_by_name": "string",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "reviewed_by_name": "string",
  • "rejection_reason": "string",
  • "has_signature": true,
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_prescription_approve_create

Approve (sign off) a pending prescription — in-app touch capture.

POST /v1/practice//prescription//approve/

Body::

{"signature_svg_base64": "<base64 svg>", "device_type": "tablet"}

Deny-by-default gate (escape#365 / api#962):

  • caller must hold an approver role (DOCTOR / ADMIN) in the practice, AND
  • the prescription's assigned provider must carry can_prescribe.

On success the prescription moves to approved and an immutable :class:PrescriptionSignature is captured, bound to a SHA-256 of the prescription's clinical content (tamper-evidence). capture_method is fixed to touch — the QR exchange endpoint owns qr.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
prescription_id
required
string <uuid>
Request Body schema:
required
signature_svg_base64
required
string non-empty

Prescriber signature as a base64-encoded SVG document.

device_type
string <= 64 characters
Default: ""

Coarse client device classification (tablet/phone/desktop).

Responses

Request samples

Content type
{
  • "signature_svg_base64": "string",
  • "device_type": ""
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_controlled": true,
  • "requires_epcs": true,
  • "epcs_warning": "string",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "status": "draft",
  • "finalized_at": "2019-08-24T14:15:22Z",
  • "prescribed_at": "2019-08-24T14:15:22Z",
  • "finalized_by": "ca059483-923c-4d0a-bf3a-a20808c35301",
  • "finalized_by_name": "string",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "cancelled_by": "da8800d0-a376-4b5c-a53d-a329d671e82b",
  • "cancelled_by_name": "string",
  • "cancellation_reason": "string",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "submitted_by_name": "string",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "reviewed_by_name": "string",
  • "rejection_reason": "string",
  • "has_signature": true,
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_prescription_cancel_create

Cancel a prescription (draft or issued).

POST /v1/practice//prescription//cancel/

Body (optional)::

{"reason": "Wrong drug selected"}

Any staff member may cancel a draft. Cancelling an issued prescription (final or the review-workflow approved state) is restricted to ADMIN / DOCTOR and enforced server-side — deny-by-default (api#1043 / escape#414, was UI-only). The acting user and timestamp are recorded on the row for the chart's "Cancelled by {user} on {when}" attribution. api#822 / escape#277.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
prescription_id
required
string <uuid>
Request Body schema:
reason
string
Default: ""

Optional free-text reason for cancelling the prescription.

Responses

Request samples

Content type
{
  • "reason": ""
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_controlled": true,
  • "requires_epcs": true,
  • "epcs_warning": "string",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "status": "draft",
  • "finalized_at": "2019-08-24T14:15:22Z",
  • "prescribed_at": "2019-08-24T14:15:22Z",
  • "finalized_by": "ca059483-923c-4d0a-bf3a-a20808c35301",
  • "finalized_by_name": "string",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "cancelled_by": "da8800d0-a376-4b5c-a53d-a329d671e82b",
  • "cancelled_by_name": "string",
  • "cancellation_reason": "string",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "submitted_by_name": "string",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "reviewed_by_name": "string",
  • "rejection_reason": "string",
  • "has_signature": true,
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_prescription_fax_to_pharmacy_create

Fax a finalised, non-controlled prescription to a pharmacy.

POST /v1/practice//prescription//fax-to-pharmacy/

Body::

{"pharmacy_fax_number": "+15035551234"}

The handler renders the prescription PDF (via the same path the print endpoint uses) and enqueues an outbound fax through the existing apps.faxing pipeline. The carrier dispatch + delivery webhook are reused -- this view is purely the orchestration layer between prescriptions and faxing.

Role gate (escape#277 / api#822): same as print -- DOCTOR or ADMIN only. Hygienists / clinical staff create drafts; the doctor sends.

EPCS gate (escape#272 / api#821): refuses requires_epcs=True prescriptions with the same banner copy as the print endpoint. Escape does not transmit controlled-substance prescriptions; the prescriber routes those through their DEA-certified vendor.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
prescription_id
required
string <uuid>
Request Body schema:
required
pharmacy_fax_number
required
string [ 1 .. 32 ] characters

Destination pharmacy fax number in E.164 format (e.g. +15035551234).

Responses

Request samples

Content type
{
  • "pharmacy_fax_number": "string"
}

Response samples

Content type
application/json
{
  • "property1": null,
  • "property2": null
}

practice_prescription_finalise_create

Finalize a draft prescription.

POST /v1/practice//prescription//finalise/

Deny-by-default authorization (api#1043 / escape#414). Two server-side gates must both pass — the rule was previously enforced only in the UI:

  1. Caller role — the acting user must hold the DOCTOR role (or the practice ADMIN override). Hygienists and clinical staff create and edit drafts; the Doctor gives the sign-off (api#822 / escape#277).
  2. Provider eligibility — the provider in whose name the Rx is issued must hold prescribing authority: an active Dentist with an NPI for a non-controlled Rx, and additionally a DEA number on file for a controlled substance. A staff member cannot finalize a prescription against a provider who is not an eligible prescriber.

For controlled substances, the doctor must still physically sign the printed paper prescription. This endpoint is NOT an EPCS action and does not constitute an electronic DEA signature.

Returns the updated prescription payload.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
prescription_id
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_prescription_pdf_retrieve

Render a prescription as a printable PDF.

GET /v1/practice//prescription//pdf/

Also mounted patient-scoped at /v1/practice/<uid>/patient/<patient_id>/prescription/<id>/pdf/ — the extra patient_id URL kwarg is accepted and ignored (the Rx is already practice+id scoped), so the patient-scoped print route no longer 500s (api#1043 / escape#414).

Returns application/pdf. Only issued prescriptions may be rendered — the legacy paper final state and the review-workflow approved (signed) state both qualify; draft / pending / rejected prescriptions return 400.

The PDF is formatted as a standard paper Rx form including:

  • Practice name, address, phone
  • Provider name, NPI, DEA number
  • Patient name, date of birth
  • Date of prescription
  • Drug details and directions
  • Blank diagonal line below the drug entry (tamper-evident, required for controlled substance paper prescriptions in many states)
  • Provider signature line

Emits a prescription.printed audit event so there is a permanent record of when the form was accessed for printing.

Note: For paper controlled-substance prescriptions, the provider must physically sign the printed form. This endpoint is not an EPCS action and does not constitute a DEA electronic signature.

Role gate (api#822 / escape#277): printing is restricted to the same set that may finalise -- DOCTOR and ADMIN. Hygienists and clinical staff may view the finalised Rx through the chart but must hand the print step off to the prescribing doctor (or the practice admin acting on the doctor's behalf).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
prescription_id
required
string <uuid>

Responses

practice_prescription_reject_create

Reject a pending prescription with a reason.

POST /v1/practice//prescription//reject/

Body::

{"reason": "Patient is allergic to penicillin"}

Same role gate as approve — only a prescriber (or Admin) may reject a submitted prescription back to staff. The prescription moves to rejected and the reason is recorded for the drafting staff member. A provider can_prescribe check is not applied to rejection: a prescriber may always decline to sign, regardless of which provider was tentatively assigned.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
prescription_id
required
string <uuid>
Request Body schema:
required
reason
required
string non-empty

Why the prescriber rejected the prescription (returned to staff).

Responses

Request samples

Content type
{
  • "reason": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_controlled": true,
  • "requires_epcs": true,
  • "epcs_warning": "string",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "status": "draft",
  • "finalized_at": "2019-08-24T14:15:22Z",
  • "prescribed_at": "2019-08-24T14:15:22Z",
  • "finalized_by": "ca059483-923c-4d0a-bf3a-a20808c35301",
  • "finalized_by_name": "string",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "cancelled_by": "da8800d0-a376-4b5c-a53d-a329d671e82b",
  • "cancelled_by_name": "string",
  • "cancellation_reason": "string",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "submitted_by_name": "string",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "reviewed_by_name": "string",
  • "rejection_reason": "string",
  • "has_signature": true,
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_prescription_sign_token_create

Issue a short-lived QR sign-off token for a pending prescription.

POST /v1/practice//prescription//sign-token/

For a prescriber on a non-touch device: mint a ≤10-minute, single-use, prescription-scoped signed token the web app renders as a QR code (web#767). The prescriber scans it with their phone, which opens the mobile sign-off page (patients#93) and exchanges the token via the exchange endpoint below.

Same deny-by-default gate as approve: caller must hold an approver role AND the assigned provider must carry can_prescribe. The token carries no PHI — only opaque UUIDs and timestamps — so it is safe to embed in a QR code / URL. The redeeming prescriber is pinned to request.user so a scanned QR is useless to anyone else.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
prescription_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "token": "string",
  • "expires_at": "2019-08-24T14:15:22Z"
}

practice_prescription_submit_create

Submit a draft prescription to a prescriber for review.

POST /v1/practice//prescription//submit/

Any staff member may submit a draft they have drafted; this moves the Rx to pending_review where it surfaces in the prescriber's review queue. A prescribing provider must be assigned before submission so the reviewer is unambiguous.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
prescription_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_controlled": true,
  • "requires_epcs": true,
  • "epcs_warning": "string",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "status": "draft",
  • "finalized_at": "2019-08-24T14:15:22Z",
  • "prescribed_at": "2019-08-24T14:15:22Z",
  • "finalized_by": "ca059483-923c-4d0a-bf3a-a20808c35301",
  • "finalized_by_name": "string",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "cancelled_by": "da8800d0-a376-4b5c-a53d-a329d671e82b",
  • "cancelled_by_name": "string",
  • "cancellation_reason": "string",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "submitted_by_name": "string",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "reviewed_by_name": "string",
  • "rejection_reason": "string",
  • "has_signature": true,
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_prescription_sign_token_exchange_create

Exchange a QR sign-off token to capture the prescriber signature.

POST /v1/practice//prescription/sign-token/exchange/

Body::

{"token": "<jwt>", "signature_svg_base64": "<base64 svg>", "device_type": "phone"}

Used by the mobile sign-off page (patients#93). Validates that the token is well-formed, unexpired, single-use (burned on success), maps to a pending_review prescription in this practice, and that the authenticated submitter is the prescriber the token was issued to and still holds approver authority. On success the prescription moves to approved with a qr :class:PrescriptionSignature.

Failure modes: malformed/expired token → 401; already redeemed → 410; wrong prescriber / lost authority → 403; stale prescription state → 400.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
token
required
string non-empty

The sign-off JWT scanned from the QR code.

signature_svg_base64
required
string non-empty

Prescriber signature as a base64-encoded SVG document.

device_type
string <= 64 characters
Default: ""

Coarse client device classification (tablet/phone/desktop).

Responses

Request samples

Content type
{
  • "token": "string",
  • "signature_svg_base64": "string",
  • "device_type": ""
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "provider": "017a51ba-65fb-4bca-a631-012d4d8d49b9",
  • "provider_name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_controlled": true,
  • "requires_epcs": true,
  • "epcs_warning": "string",
  • "diagnosis_description": "string",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "status": "draft",
  • "finalized_at": "2019-08-24T14:15:22Z",
  • "prescribed_at": "2019-08-24T14:15:22Z",
  • "finalized_by": "ca059483-923c-4d0a-bf3a-a20808c35301",
  • "finalized_by_name": "string",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "cancelled_by": "da8800d0-a376-4b5c-a53d-a329d671e82b",
  • "cancelled_by_name": "string",
  • "cancellation_reason": "string",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "submitted_by_name": "string",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "reviewed_by_name": "string",
  • "rejection_reason": "string",
  • "has_signature": true,
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_prescription_template_list

List and create practice prescription templates.

GET /v1/practice//prescription/template/ POST /v1/practice//prescription/template/

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_prescription_template_create

List and create practice prescription templates.

GET /v1/practice//prescription/template/ POST /v1/practice//prescription/template/

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 200 ] characters

Template display name shown in the picker e.g. 'Amoxicillin 500mg #21'

drug_name
required
string [ 1 .. 200 ] characters
drug_strength
string <= 100 characters
drug_form
string <= 100 characters
quantity
string <= 50 characters
directions
required
string non-empty
refills
integer [ 0 .. 32767 ]
substitution_permitted
boolean
cs_schedule
string (CsScheduleEnum)
Enum: "none" "II" "III" "IV" "V"
  • none - Non-Controlled
  • II - Schedule II
  • III - Schedule III
  • IV - Schedule IV
  • V - Schedule V
is_active
boolean

Responses

Request samples

Content type
{
  • "name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_prescription_template_retrieve

Retrieve, update, or delete a prescription template.

GET /v1/practice//prescription/template// PATCH /v1/practice//prescription/template// DELETE /v1/practice//prescription/template//

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_prescription_template_update

Retrieve, update, or delete a prescription template.

GET /v1/practice//prescription/template// PATCH /v1/practice//prescription/template// DELETE /v1/practice//prescription/template//

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_id
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 200 ] characters

Template display name shown in the picker e.g. 'Amoxicillin 500mg #21'

drug_name
required
string [ 1 .. 200 ] characters
drug_strength
string <= 100 characters
drug_form
string <= 100 characters
quantity
string <= 50 characters
directions
required
string non-empty
refills
integer [ 0 .. 32767 ]
substitution_permitted
boolean
cs_schedule
string (CsScheduleEnum)
Enum: "none" "II" "III" "IV" "V"
  • none - Non-Controlled
  • II - Schedule II
  • III - Schedule III
  • IV - Schedule IV
  • V - Schedule V
is_active
boolean

Responses

Request samples

Content type
{
  • "name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_prescription_template_partial_update

Retrieve, update, or delete a prescription template.

GET /v1/practice//prescription/template// PATCH /v1/practice//prescription/template// DELETE /v1/practice//prescription/template//

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_id
required
string <uuid>
Request Body schema:
name
string [ 1 .. 200 ] characters

Template display name shown in the picker e.g. 'Amoxicillin 500mg #21'

drug_name
string [ 1 .. 200 ] characters
drug_strength
string <= 100 characters
drug_form
string <= 100 characters
quantity
string <= 50 characters
directions
string non-empty
refills
integer [ 0 .. 32767 ]
substitution_permitted
boolean
cs_schedule
string (CsScheduleEnum)
Enum: "none" "II" "III" "IV" "V"
  • none - Non-Controlled
  • II - Schedule II
  • III - Schedule III
  • IV - Schedule IV
  • V - Schedule V
is_active
boolean

Responses

Request samples

Content type
{
  • "name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "drug_name": "string",
  • "drug_strength": "string",
  • "drug_form": "string",
  • "quantity": "string",
  • "directions": "string",
  • "refills": 32767,
  • "substitution_permitted": true,
  • "cs_schedule": "none",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_prescription_template_destroy

Retrieve, update, or delete a prescription template.

GET /v1/practice//prescription/template// PATCH /v1/practice//prescription/template// DELETE /v1/practice//prescription/template//

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
template_id
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

Patient Submissions

practice_portal_patient_submissions_list

List patient submissions for a practice.

GET /api/v1/practice//patient-submissions/

Defaults to pending submissions. Use ?status=approved or ?status=rejected to filter.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json

Default ordering is newest-first by created. Filter with ?status=pending / ?status=approved / ?status=rejected to scope the front-desk review queue.

{
  • "count": 123,
  • "results": [
    ]
}

practice_portal_patient_submissions_retrieve

Retrieve a single patient submission with full detail.

GET /api/v1/practice//patient-submissions//

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json

Returned to staff reviewing a submission. submitted_data is an open JSON object -- shape is defined by the intake form the patient filled out. No schema validation is enforced here; the approve step copies known fields to the Patient record.

{
  • "id": "abababab-abab-4bab-8bab-abababababab",
  • "practice": "99999999-9999-4999-8999-999999999999",
  • "invite_token": "example-synthetic-token-DO-NOT-USE-0123456789",
  • "invite_expires_at": "2026-05-20T00:00:00Z",
  • "status": "approved",
  • "submitted_at": "2026-05-14T10:15:00Z",
  • "reviewed_at": "2026-05-14T11:02:47Z",
  • "reviewed_by": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
  • "patient": "11111111-1111-4111-8111-111111111111",
  • "created": "2026-05-13T12:00:00Z",
  • "submitted_data": {
    },
  • "rejection_reason": ""
}

practice_portal_patient_submissions_approve_create

Approve a patient submission — creates a Patient record.

POST /api/v1/practice//patient-submissions//approve/

Extracts demographics from submitted_data to create the Patient record, links it to the submission, and sets status=approved.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json

The server creates a Patient record from submitted_data and sets status=approved, reviewed_by to the current user, and patient to the new record's id.

{
  • "id": "abababab-abab-4bab-8bab-abababababab",
  • "practice": "99999999-9999-4999-8999-999999999999",
  • "invite_token": "example-synthetic-token-DO-NOT-USE-0123456789",
  • "invite_expires_at": "2026-05-20T00:00:00Z",
  • "status": "approved",
  • "submitted_at": "2026-05-14T10:15:00Z",
  • "reviewed_at": "2026-05-14T11:02:47Z",
  • "reviewed_by": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
  • "patient": "11111111-1111-4111-8111-111111111111",
  • "created": "2026-05-13T12:00:00Z",
  • "submitted_data": {
    },
  • "rejection_reason": ""
}

practice_portal_patient_submissions_reject_create

Reject a patient submission with a reason.

POST /api/v1/practice//patient-submissions//reject/

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string <uuid>
practice_uid
required
string <uuid>
Request Body schema:
required
rejection_reason
required
string non-empty

Staff-provided reason for the rejection.

Responses

Request samples

Content type

rejection_reason is required and surfaced to the patient (not stored as PHI).

{
  • "rejection_reason": "Duplicate submission -- patient already has an active record."
}

Response samples

Content type
application/json

Returns the full submission with status=rejected and the reviewer stamped.

{
  • "id": "abababab-abab-4bab-8bab-abababababab",
  • "practice": "99999999-9999-4999-8999-999999999999",
  • "invite_token": "example-synthetic-token-DO-NOT-USE-0123456789",
  • "invite_expires_at": "2026-05-20T00:00:00Z",
  • "status": "rejected",
  • "submitted_at": "2026-05-14T10:15:00Z",
  • "reviewed_at": "2026-05-14T11:02:47Z",
  • "reviewed_by": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
  • "patient": null,
  • "created": "2026-05-13T12:00:00Z",
  • "submitted_data": {
    },
  • "rejection_reason": "Duplicate submission -- patient already has an active record."
}

practice_portal_patient_submissions_invite_create

Generate a one-time invite link for a prospective patient.

POST /api/v1/practice//patient-submissions/invite/

Only Office Manager or above may generate invites. Creates a PatientSubmission with a unique token and 7-day expiry.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
send_email
boolean
Default: false
send_sms
boolean
Default: false
email
string <email>
Default: ""
phone
string <= 32 characters
Default: ""

Responses

Request samples

Content type
Example

The server generates the token and 7-day expiry; no request fields are required.

{ }

Response samples

Content type
application/json

When no delivery was requested, deliveries is empty and front-desk staff copies invite_token into the invite URL to share manually. When email/SMS delivery was requested, each channel's queued/failed result is listed in deliveries. The invite expires after 7 days or on first use, whichever comes first.

{
  • "id": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
  • "invite_token": "example-synthetic-token-DO-NOT-USE-0123456789",
  • "invite_expires_at": "2026-05-20T00:00:00Z",
  • "created": "2026-05-13T12:00:00Z",
  • "deliveries": [
    ]
}

Referrals

practice_referral_board_list

Referral worklist board (api#967).

GET /v1/practice/<uid>/referral/board/

Returns referrals ordered by expected_back_at ascending with NULL expected dates sorted last. Each row carries the derived is_overdue flag so the SPA renders the "PAST DUE" pill without re-deriving wall-clock logic client-side.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
include_overdue_only
boolean

When 'true', restrict to in-flight referrals past expected_back_at.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

status
string

Filter by status enum value.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_referral_case_list

List and create referrals for the current practice.

Query params

status — single status enum filter patient — patient UUID filter specialist — recipient UUID filter

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_referral_case_create

List and create referrals for the current practice.

Query params

status — single status enum filter patient — patient UUID filter specialist — recipient UUID filter

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>
referring_provider
required
string <uuid>
specialist
string or null <uuid>
specialist_contact
string or null <uuid>
specialty
string <= 100 characters

Discipline the referral is for, e.g. 'Oral Surgery'. Often mirrors the recipient's specialty.

reason
string <= 255 characters

Short reason for the referral, e.g. 'Extraction #17', 'Evaluate periodontal disease'.

reason_note
string

Longer free-text clinical context for the specialist.

referred_procedures
string <= 255 characters

Comma-separated CDT/procedure codes or descriptions the patient is referred for.

tooth_numbers
string <= 120 characters

Comma-separated UNS identifiers (1-32 permanent, A-T primary), e.g. '17,32'.

date_referred
string or null <date>

Calendar date the referral was issued (practice-local intent; stored as a date).

expected_back_at
string or null <date-time>

When the specialist's report is expected back; drives the derived is_overdue flag.

notes
string

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "referring_provider": "ace80624-42bd-43bb-8e5e-8e95839464db",
  • "specialist": "50d7932a-b550-4ae2-b067-660cc6e85e00",
  • "specialist_contact": "78482ff3-66d4-4f39-9b1e-7af686ff6c9e",
  • "specialty": "string",
  • "reason": "string",
  • "reason_note": "string",
  • "referred_procedures": "string",
  • "tooth_numbers": "string",
  • "date_referred": "2019-08-24",
  • "expected_back_at": "2019-08-24T14:15:22Z",
  • "notes": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "referring_provider": "ace80624-42bd-43bb-8e5e-8e95839464db",
  • "referring_provider_name": "string",
  • "specialist": "50d7932a-b550-4ae2-b067-660cc6e85e00",
  • "specialist_name": "string",
  • "specialist_contact": "78482ff3-66d4-4f39-9b1e-7af686ff6c9e",
  • "specialist_contact_name": "string",
  • "effective_specialist": {
    },
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "appointment_detail": {
    },
  • "specialty": "string",
  • "reason": "string",
  • "reason_note": "string",
  • "referred_procedures": "string",
  • "tooth_numbers": "string",
  • "date_referred": "2019-08-24",
  • "expected_back_at": "2019-08-24T14:15:22Z",
  • "status": "draft",
  • "is_overdue": true,
  • "referred_out_at": "2019-08-24T14:15:22Z",
  • "documents_received_at": "2019-08-24T14:15:22Z",
  • "awaiting_doctor_approval_at": "2019-08-24T14:15:22Z",
  • "signed_off_at": "2019-08-24T14:15:22Z",
  • "scheduled_at": "2019-08-24T14:15:22Z",
  • "treatment_complete_at": "2019-08-24T14:15:22Z",
  • "closed_at": "2019-08-24T14:15:22Z",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "rejection_reason": "string",
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_referral_case_retrieve

Retrieve, update, or delete a referral. status is read-only.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
referral_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "referring_provider": "ace80624-42bd-43bb-8e5e-8e95839464db",
  • "referring_provider_name": "string",
  • "specialist": "50d7932a-b550-4ae2-b067-660cc6e85e00",
  • "specialist_name": "string",
  • "specialist_contact": "78482ff3-66d4-4f39-9b1e-7af686ff6c9e",
  • "specialist_contact_name": "string",
  • "effective_specialist": {
    },
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "appointment_detail": {
    },
  • "specialty": "string",
  • "reason": "string",
  • "reason_note": "string",
  • "referred_procedures": "string",
  • "tooth_numbers": "string",
  • "date_referred": "2019-08-24",
  • "expected_back_at": "2019-08-24T14:15:22Z",
  • "status": "draft",
  • "is_overdue": true,
  • "referred_out_at": "2019-08-24T14:15:22Z",
  • "documents_received_at": "2019-08-24T14:15:22Z",
  • "awaiting_doctor_approval_at": "2019-08-24T14:15:22Z",
  • "signed_off_at": "2019-08-24T14:15:22Z",
  • "scheduled_at": "2019-08-24T14:15:22Z",
  • "treatment_complete_at": "2019-08-24T14:15:22Z",
  • "closed_at": "2019-08-24T14:15:22Z",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "rejection_reason": "string",
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_referral_case_update

Retrieve, update, or delete a referral. status is read-only.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
referral_id
required
string <uuid>
Request Body schema:
required
patient
required
string <uuid>
referring_provider
required
string <uuid>
specialist
string or null <uuid>
specialist_contact
string or null <uuid>
specialty
string <= 100 characters

Discipline the referral is for, e.g. 'Oral Surgery'. Often mirrors the recipient's specialty.

reason
string <= 255 characters

Short reason for the referral, e.g. 'Extraction #17', 'Evaluate periodontal disease'.

reason_note
string

Longer free-text clinical context for the specialist.

referred_procedures
string <= 255 characters

Comma-separated CDT/procedure codes or descriptions the patient is referred for.

tooth_numbers
string <= 120 characters

Comma-separated UNS identifiers (1-32 permanent, A-T primary), e.g. '17,32'.

date_referred
string or null <date>

Calendar date the referral was issued (practice-local intent; stored as a date).

expected_back_at
string or null <date-time>

When the specialist's report is expected back; drives the derived is_overdue flag.

notes
string

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "referring_provider": "ace80624-42bd-43bb-8e5e-8e95839464db",
  • "specialist": "50d7932a-b550-4ae2-b067-660cc6e85e00",
  • "specialist_contact": "78482ff3-66d4-4f39-9b1e-7af686ff6c9e",
  • "specialty": "string",
  • "reason": "string",
  • "reason_note": "string",
  • "referred_procedures": "string",
  • "tooth_numbers": "string",
  • "date_referred": "2019-08-24",
  • "expected_back_at": "2019-08-24T14:15:22Z",
  • "notes": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "referring_provider": "ace80624-42bd-43bb-8e5e-8e95839464db",
  • "referring_provider_name": "string",
  • "specialist": "50d7932a-b550-4ae2-b067-660cc6e85e00",
  • "specialist_name": "string",
  • "specialist_contact": "78482ff3-66d4-4f39-9b1e-7af686ff6c9e",
  • "specialist_contact_name": "string",
  • "effective_specialist": {
    },
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "appointment_detail": {
    },
  • "specialty": "string",
  • "reason": "string",
  • "reason_note": "string",
  • "referred_procedures": "string",
  • "tooth_numbers": "string",
  • "date_referred": "2019-08-24",
  • "expected_back_at": "2019-08-24T14:15:22Z",
  • "status": "draft",
  • "is_overdue": true,
  • "referred_out_at": "2019-08-24T14:15:22Z",
  • "documents_received_at": "2019-08-24T14:15:22Z",
  • "awaiting_doctor_approval_at": "2019-08-24T14:15:22Z",
  • "signed_off_at": "2019-08-24T14:15:22Z",
  • "scheduled_at": "2019-08-24T14:15:22Z",
  • "treatment_complete_at": "2019-08-24T14:15:22Z",
  • "closed_at": "2019-08-24T14:15:22Z",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "rejection_reason": "string",
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_referral_case_partial_update

Retrieve, update, or delete a referral. status is read-only.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
referral_id
required
string <uuid>
Request Body schema:
patient
string <uuid>
referring_provider
string <uuid>
specialist
string or null <uuid>
specialist_contact
string or null <uuid>
specialty
string <= 100 characters

Discipline the referral is for, e.g. 'Oral Surgery'. Often mirrors the recipient's specialty.

reason
string <= 255 characters

Short reason for the referral, e.g. 'Extraction #17', 'Evaluate periodontal disease'.

reason_note
string

Longer free-text clinical context for the specialist.

referred_procedures
string <= 255 characters

Comma-separated CDT/procedure codes or descriptions the patient is referred for.

tooth_numbers
string <= 120 characters

Comma-separated UNS identifiers (1-32 permanent, A-T primary), e.g. '17,32'.

date_referred
string or null <date>

Calendar date the referral was issued (practice-local intent; stored as a date).

expected_back_at
string or null <date-time>

When the specialist's report is expected back; drives the derived is_overdue flag.

notes
string

Responses

Request samples

Content type
{
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "referring_provider": "ace80624-42bd-43bb-8e5e-8e95839464db",
  • "specialist": "50d7932a-b550-4ae2-b067-660cc6e85e00",
  • "specialist_contact": "78482ff3-66d4-4f39-9b1e-7af686ff6c9e",
  • "specialty": "string",
  • "reason": "string",
  • "reason_note": "string",
  • "referred_procedures": "string",
  • "tooth_numbers": "string",
  • "date_referred": "2019-08-24",
  • "expected_back_at": "2019-08-24T14:15:22Z",
  • "notes": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "referring_provider": "ace80624-42bd-43bb-8e5e-8e95839464db",
  • "referring_provider_name": "string",
  • "specialist": "50d7932a-b550-4ae2-b067-660cc6e85e00",
  • "specialist_name": "string",
  • "specialist_contact": "78482ff3-66d4-4f39-9b1e-7af686ff6c9e",
  • "specialist_contact_name": "string",
  • "effective_specialist": {
    },
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "appointment_detail": {
    },
  • "specialty": "string",
  • "reason": "string",
  • "reason_note": "string",
  • "referred_procedures": "string",
  • "tooth_numbers": "string",
  • "date_referred": "2019-08-24",
  • "expected_back_at": "2019-08-24T14:15:22Z",
  • "status": "draft",
  • "is_overdue": true,
  • "referred_out_at": "2019-08-24T14:15:22Z",
  • "documents_received_at": "2019-08-24T14:15:22Z",
  • "awaiting_doctor_approval_at": "2019-08-24T14:15:22Z",
  • "signed_off_at": "2019-08-24T14:15:22Z",
  • "scheduled_at": "2019-08-24T14:15:22Z",
  • "treatment_complete_at": "2019-08-24T14:15:22Z",
  • "closed_at": "2019-08-24T14:15:22Z",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "rejection_reason": "string",
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_referral_case_destroy

Retrieve, update, or delete a referral. status is read-only.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
referral_id
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_referral_case_approve_create

Provider sign-off on a referral's returned report (api#967).

POST /v1/practice/<uid>/referral/case/<referral_id>/approve/

Body::

{"signer_name_typed": "Dr Jane Roe",
 "signature_image_base64": "<base64 png>"}

Deny-by-default: the caller must hold an approver role (DOCTOR / ADMIN) in the practice — this is the doctor sign-off gate. The referral must be awaiting_doctor_approval. On success it moves to signed_off (stamping signed_off_at / reviewed_at / reviewed_by) and an immutable generic :class:apps.signatures.models.Signature is bound to the referral via its GFK — no new signature table. Only after sign-off can the referral be scheduled (api#1052 / escape#417).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
referral_id
required
string <uuid>
Request Body schema:
required
signer_name_typed
required
string [ 1 .. 255 ] characters
signature_image_base64
required
string non-empty

Signature image as a base64-encoded PNG (or SVG) from the signature pad.

Responses

Request samples

Content type
{
  • "signer_name_typed": "string",
  • "signature_image_base64": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "referring_provider": "ace80624-42bd-43bb-8e5e-8e95839464db",
  • "referring_provider_name": "string",
  • "specialist": "50d7932a-b550-4ae2-b067-660cc6e85e00",
  • "specialist_name": "string",
  • "specialist_contact": "78482ff3-66d4-4f39-9b1e-7af686ff6c9e",
  • "specialist_contact_name": "string",
  • "effective_specialist": {
    },
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "appointment_detail": {
    },
  • "specialty": "string",
  • "reason": "string",
  • "reason_note": "string",
  • "referred_procedures": "string",
  • "tooth_numbers": "string",
  • "date_referred": "2019-08-24",
  • "expected_back_at": "2019-08-24T14:15:22Z",
  • "status": "draft",
  • "is_overdue": true,
  • "referred_out_at": "2019-08-24T14:15:22Z",
  • "documents_received_at": "2019-08-24T14:15:22Z",
  • "awaiting_doctor_approval_at": "2019-08-24T14:15:22Z",
  • "signed_off_at": "2019-08-24T14:15:22Z",
  • "scheduled_at": "2019-08-24T14:15:22Z",
  • "treatment_complete_at": "2019-08-24T14:15:22Z",
  • "closed_at": "2019-08-24T14:15:22Z",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "rejection_reason": "string",
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_referral_case_reject_create

Provider rejects a referral review with a reason (api#967).

POST /v1/practice/<uid>/referral/case/<referral_id>/reject/

Body::

{"reason": "Report incomplete — request perio charting"}

Same approver-role gate as approve. The referral must be awaiting_doctor_approval; on rejection it returns to documents_received (so staff can follow up and re-submit) and rejection_reason / reviewed_at / reviewed_by are recorded.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
referral_id
required
string <uuid>
Request Body schema:
required
reason
required
string [ 1 .. 2000 ] characters

Responses

Request samples

Content type
{
  • "reason": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "referring_provider": "ace80624-42bd-43bb-8e5e-8e95839464db",
  • "referring_provider_name": "string",
  • "specialist": "50d7932a-b550-4ae2-b067-660cc6e85e00",
  • "specialist_name": "string",
  • "specialist_contact": "78482ff3-66d4-4f39-9b1e-7af686ff6c9e",
  • "specialist_contact_name": "string",
  • "effective_specialist": {
    },
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "appointment_detail": {
    },
  • "specialty": "string",
  • "reason": "string",
  • "reason_note": "string",
  • "referred_procedures": "string",
  • "tooth_numbers": "string",
  • "date_referred": "2019-08-24",
  • "expected_back_at": "2019-08-24T14:15:22Z",
  • "status": "draft",
  • "is_overdue": true,
  • "referred_out_at": "2019-08-24T14:15:22Z",
  • "documents_received_at": "2019-08-24T14:15:22Z",
  • "awaiting_doctor_approval_at": "2019-08-24T14:15:22Z",
  • "signed_off_at": "2019-08-24T14:15:22Z",
  • "scheduled_at": "2019-08-24T14:15:22Z",
  • "treatment_complete_at": "2019-08-24T14:15:22Z",
  • "closed_at": "2019-08-24T14:15:22Z",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "rejection_reason": "string",
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_referral_case_submit_create

Submit a referral's returned documents to a provider for review.

POST /v1/practice/<uid>/referral/case/<referral_id>/submit/

Any staff member may submit; the referral must already have its documents back (documents_received). Advances the referral to awaiting_doctor_approval (stamping awaiting_doctor_approval_at on first entry), records submitted_by / submitted_at, and surfaces it in the provider sign-off queue.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
referral_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "referring_provider": "ace80624-42bd-43bb-8e5e-8e95839464db",
  • "referring_provider_name": "string",
  • "specialist": "50d7932a-b550-4ae2-b067-660cc6e85e00",
  • "specialist_name": "string",
  • "specialist_contact": "78482ff3-66d4-4f39-9b1e-7af686ff6c9e",
  • "specialist_contact_name": "string",
  • "effective_specialist": {
    },
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "appointment_detail": {
    },
  • "specialty": "string",
  • "reason": "string",
  • "reason_note": "string",
  • "referred_procedures": "string",
  • "tooth_numbers": "string",
  • "date_referred": "2019-08-24",
  • "expected_back_at": "2019-08-24T14:15:22Z",
  • "status": "draft",
  • "is_overdue": true,
  • "referred_out_at": "2019-08-24T14:15:22Z",
  • "documents_received_at": "2019-08-24T14:15:22Z",
  • "awaiting_doctor_approval_at": "2019-08-24T14:15:22Z",
  • "signed_off_at": "2019-08-24T14:15:22Z",
  • "scheduled_at": "2019-08-24T14:15:22Z",
  • "treatment_complete_at": "2019-08-24T14:15:22Z",
  • "closed_at": "2019-08-24T14:15:22Z",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "rejection_reason": "string",
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_referral_case_transition_create

Advance a referral's status through a legal transition (api#967).

POST /v1/practice/<uid>/referral/case/<referral_id>/transition/

Body::

{"status": "referred_out"}

Validates the target against the legal transitions for the current status (treatment_complete is skippable; cancelled is reachable from any in-flight state up to scheduled). The matching *_at timestamp is stamped on first entry. signed_off is not reachable here — it carries a signature and is owned by the approve action, and scheduling is gated behind it.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
referral_id
required
string <uuid>
Request Body schema:
required
status
required
string (Status2cbEnum)
Enum: "draft" "referred_out" "documents_received" "awaiting_doctor_approval" "signed_off" "scheduled" "treatment_complete" "closed" "cancelled"
  • draft - Draft
  • referred_out - Referred Out
  • documents_received - Documents Received
  • awaiting_doctor_approval - Awaiting Doctor Approval
  • signed_off - Signed Off
  • scheduled - Scheduled
  • treatment_complete - Treatment Complete
  • closed - Closed
  • cancelled - Cancelled
appointment
string or null <uuid>

Optional id of the Appointment booked for this referral. Only honoured when transitioning to 'scheduled'; must belong to the same practice and patient as the referral.

Responses

Request samples

Content type
{
  • "status": "draft",
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "patient": "a7129932-7174-432d-a8dd-570510e145bb",
  • "patient_name": "string",
  • "referring_provider": "ace80624-42bd-43bb-8e5e-8e95839464db",
  • "referring_provider_name": "string",
  • "specialist": "50d7932a-b550-4ae2-b067-660cc6e85e00",
  • "specialist_name": "string",
  • "specialist_contact": "78482ff3-66d4-4f39-9b1e-7af686ff6c9e",
  • "specialist_contact_name": "string",
  • "effective_specialist": {
    },
  • "appointment": "c776433a-7ab1-49de-96dc-e0f963546e2e",
  • "appointment_detail": {
    },
  • "specialty": "string",
  • "reason": "string",
  • "reason_note": "string",
  • "referred_procedures": "string",
  • "tooth_numbers": "string",
  • "date_referred": "2019-08-24",
  • "expected_back_at": "2019-08-24T14:15:22Z",
  • "status": "draft",
  • "is_overdue": true,
  • "referred_out_at": "2019-08-24T14:15:22Z",
  • "documents_received_at": "2019-08-24T14:15:22Z",
  • "awaiting_doctor_approval_at": "2019-08-24T14:15:22Z",
  • "signed_off_at": "2019-08-24T14:15:22Z",
  • "scheduled_at": "2019-08-24T14:15:22Z",
  • "treatment_complete_at": "2019-08-24T14:15:22Z",
  • "closed_at": "2019-08-24T14:15:22Z",
  • "cancelled_at": "2019-08-24T14:15:22Z",
  • "submitted_at": "2019-08-24T14:15:22Z",
  • "submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
  • "reviewed_at": "2019-08-24T14:15:22Z",
  • "reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
  • "rejection_reason": "string",
  • "notes": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_referral_recipient_list

List and create outside-specialist directory entries.

GET /v1/practice//referral/recipient/ POST /v1/practice//referral/recipient/

Query params

activetrue (default) / false / all search — case-insensitive substring match on name or specialty

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

practice_referral_recipient_create

List and create outside-specialist directory entries.

GET /v1/practice//referral/recipient/ POST /v1/practice//referral/recipient/

Query params

activetrue (default) / false / all search — case-insensitive substring match on name or specialty

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 200 ] characters
specialty
string <= 100 characters

Specialist's discipline, e.g. 'Oral Surgery', 'Endodontics', 'ENT'.

address
string
phone
string <= 40 characters
fax
string <= 40 characters
email
string <email> <= 254 characters
notes
string
is_active
boolean

Responses

Request samples

Content type
{
  • "name": "string",
  • "specialty": "string",
  • "address": "string",
  • "phone": "string",
  • "fax": "string",
  • "email": "user@example.com",
  • "notes": "string",
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "specialty": "string",
  • "address": "string",
  • "phone": "string",
  • "fax": "string",
  • "email": "user@example.com",
  • "notes": "string",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_referral_recipient_retrieve

Retrieve, update, or delete a specialist directory entry.

DELETE is a hard delete but recipients with referencing :class:Referral rows fail with a PROTECT integrity error. Use is_active=False to hide a recipient from the picker without losing historical references.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
recipient_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "specialty": "string",
  • "address": "string",
  • "phone": "string",
  • "fax": "string",
  • "email": "user@example.com",
  • "notes": "string",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_referral_recipient_update

Retrieve, update, or delete a specialist directory entry.

DELETE is a hard delete but recipients with referencing :class:Referral rows fail with a PROTECT integrity error. Use is_active=False to hide a recipient from the picker without losing historical references.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
recipient_id
required
string <uuid>
Request Body schema:
required
name
required
string [ 1 .. 200 ] characters
specialty
string <= 100 characters

Specialist's discipline, e.g. 'Oral Surgery', 'Endodontics', 'ENT'.

address
string
phone
string <= 40 characters
fax
string <= 40 characters
email
string <email> <= 254 characters
notes
string
is_active
boolean

Responses

Request samples

Content type
{
  • "name": "string",
  • "specialty": "string",
  • "address": "string",
  • "phone": "string",
  • "fax": "string",
  • "email": "user@example.com",
  • "notes": "string",
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "specialty": "string",
  • "address": "string",
  • "phone": "string",
  • "fax": "string",
  • "email": "user@example.com",
  • "notes": "string",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_referral_recipient_partial_update

Retrieve, update, or delete a specialist directory entry.

DELETE is a hard delete but recipients with referencing :class:Referral rows fail with a PROTECT integrity error. Use is_active=False to hide a recipient from the picker without losing historical references.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
recipient_id
required
string <uuid>
Request Body schema:
name
string [ 1 .. 200 ] characters
specialty
string <= 100 characters

Specialist's discipline, e.g. 'Oral Surgery', 'Endodontics', 'ENT'.

address
string
phone
string <= 40 characters
fax
string <= 40 characters
email
string <email> <= 254 characters
notes
string
is_active
boolean

Responses

Request samples

Content type
{
  • "name": "string",
  • "specialty": "string",
  • "address": "string",
  • "phone": "string",
  • "fax": "string",
  • "email": "user@example.com",
  • "notes": "string",
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "name": "string",
  • "specialty": "string",
  • "address": "string",
  • "phone": "string",
  • "fax": "string",
  • "email": "user@example.com",
  • "notes": "string",
  • "is_active": true,
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

practice_referral_recipient_destroy

Retrieve, update, or delete a specialist directory entry.

DELETE is a hard delete but recipients with referencing :class:Referral rows fail with a PROTECT integrity error. Use is_active=False to hide a recipient from the picker without losing historical references.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
recipient_id
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

Signatures

List signature evidence rows for the practice.

Returns the practice's signature rows in -signed_at order. Compact list shape -- the signed image URL is omitted to keep payloads small; open the detail view to fetch it.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
query Parameters
attached_content_type
string

Filter to signatures attached to a given content type, as "app_label.model" (e.g. "portal.formsubmission").

object_id
string

Filter to signatures attached to a specific object id. Typically combined with attached_content_type.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

patient
string <uuid>

Filter to signatures by a specific patient.

signer_type
string

Filter by signer type: patient / staff.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

Capture a digital signature (staff-side, multipart upload).

Accepts a rendered signature PNG plus signer metadata and stores the row as immutable evidence. Body is multipart/form-data with the PNG attached as the image field; the remaining fields ride alongside as standard form fields. Server-managed fields (practice, signed_at, ip_address, user_agent) are populated server-side and any client-supplied values are ignored. Returns the detail shape on 201 so the caller can render or download the just-captured signature without an extra GET.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
signer_type
required
string
Enum: "patient" "staff"

Whether a patient or a staff user signed.

  • patient - Patient
  • staff - Staff
signer_patient
string or null <uuid>

Patient who signed (set when signer_type='patient').

signer_user
string or null <uuid>

Staff user who signed (set when signer_type='staff').

signer_name_typed
required
string [ 1 .. 255 ] characters

Full name the signer typed alongside the signature pad (legal identity claim).

image
required
string <binary>

Rendered signature PNG produced by the signature-pad widget.

image_mime_type
string [ 1 .. 64 ] characters

MIME type of the stored signature image.

attached_content_type
string

ContentType of the attached object as "app_label.model" (e.g. "portal.formsubmission").

object_id
string <= 64 characters

PK of the attached object (generic FK; CharField to accept either UUID or int).

consent_text_snapshot
required
string non-empty

Literal text the signer agreed to, frozen at signing time (non-repudiation).

Responses

Request samples

Content type
No sample

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "signer_type": "patient",
  • "signer_patient": "e2df84cb-0278-4b4c-808c-00db992be652",
  • "patient_first_name": "string",
  • "patient_last_name": "string",
  • "signer_user": "468f6f61-a020-441a-9595-8fee67f9ae9e",
  • "signer_email": "user@example.com",
  • "signer_name_typed": "string",
  • "image_url": "string",
  • "image_mime_type": "string",
  • "attached_content_type": "string",
  • "object_id": "string",
  • "consent_text_snapshot": "string",
  • "signed_at": "2019-08-24T14:15:22Z",
  • "ip_address": "string",
  • "user_agent": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Read a single signature evidence row (with signed image URL).

Returns the full row, including a short-lived signed URL for the captured image and the consent-text snapshot. Every read fires a signature.viewed audit event so the access trail is complete -- signature images are legal evidence and access must be traced.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
signature_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "practice": "735297b8-a875-445a-9746-8588a75f65f2",
  • "signer_type": "patient",
  • "signer_patient": "e2df84cb-0278-4b4c-808c-00db992be652",
  • "patient_first_name": "string",
  • "patient_last_name": "string",
  • "signer_user": "468f6f61-a020-441a-9595-8fee67f9ae9e",
  • "signer_email": "user@example.com",
  • "signer_name_typed": "string",
  • "image_url": "string",
  • "image_mime_type": "string",
  • "attached_content_type": "string",
  • "object_id": "string",
  • "consent_text_snapshot": "string",
  • "signed_at": "2019-08-24T14:15:22Z",
  • "ip_address": "string",
  • "user_agent": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Render a standalone PDF preview of a signature row.

Returns a single-page application/pdf containing the captured signature image, the typed signer name, the signed-at timestamp, and the verbatim consent-text snapshot. Useful for letting a practice user eyeball a captured signature before binding it to a final document, and as an appendix the form-generation pipeline can attach to generated paperwork.

Emits a signature.viewed audit event because the rendered PDF contains the same evidence the detail GET exposes -- the access trail must remain complete.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
signature_uid
required
string <uuid>

Responses

Voting

practice_voting_poll_list

CRUD for practice polls with vote, results, and active-count actions.

  • list: All visible polls (unexpired + up to 12h after expiration).
  • create: OFFICE_MANAGER or ADMIN only.
  • retrieve: Any practice member.
  • destroy: Creator or ADMIN only.
  • vote: POST /poll/{id}/vote/ with option_id.
  • results: GET /poll/{id}/results/ (403 if poll not yet expired).
  • active_count: GET /poll/active-count/ for badge display.
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
[
  • {
    }
]

practice_voting_poll_create

CRUD for practice polls with vote, results, and active-count actions.

  • list: All visible polls (unexpired + up to 12h after expiration).
  • create: OFFICE_MANAGER or ADMIN only.
  • retrieve: Any practice member.
  • destroy: Creator or ADMIN only.
  • vote: POST /poll/{id}/vote/ with option_id.
  • results: GET /poll/{id}/results/ (403 if poll not yet expired).
  • active_count: GET /poll/active-count/ for badge display.
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>
Request Body schema:
required
question
required
string [ 1 .. 500 ] characters
is_anonymous
boolean

When true, results show vote counts but not voter identity.

expires_at
required
string <date-time>

UTC timestamp when the poll closes for voting.

required
Array of objects (PollOptionWriteRequest)

Responses

Request samples

Content type
{
  • "question": "string",
  • "is_anonymous": true,
  • "expires_at": "2019-08-24T14:15:22Z",
  • "options": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "question": "string",
  • "is_anonymous": true,
  • "expires_at": "2019-08-24T14:15:22Z",
  • "options": [
    ]
}

practice_voting_poll_retrieve

CRUD for practice polls with vote, results, and active-count actions.

  • list: All visible polls (unexpired + up to 12h after expiration).
  • create: OFFICE_MANAGER or ADMIN only.
  • retrieve: Any practice member.
  • destroy: Creator or ADMIN only.
  • vote: POST /poll/{id}/vote/ with option_id.
  • results: GET /poll/{id}/results/ (403 if poll not yet expired).
  • active_count: GET /poll/active-count/ for badge display.
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "question": "string",
  • "is_anonymous": true,
  • "expires_at": "2019-08-24T14:15:22Z",
  • "is_expired": true,
  • "options": [
    ],
  • "has_voted": "string",
  • "my_vote_option_id": "string",
  • "created_by_name": "string",
  • "created": "2019-08-24T14:15:22Z"
}

practice_voting_poll_destroy

CRUD for practice polls with vote, results, and active-count actions.

  • list: All visible polls (unexpired + up to 12h after expiration).
  • create: OFFICE_MANAGER or ADMIN only.
  • retrieve: Any practice member.
  • destroy: Creator or ADMIN only.
  • vote: POST /poll/{id}/vote/ with option_id.
  • results: GET /poll/{id}/results/ (403 if poll not yet expired).
  • active_count: GET /poll/active-count/ for badge display.
Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_voting_poll_results_retrieve

Return aggregated results. Returns 403 if the poll has not yet expired.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string
practice_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "poll_id": "712230da-d683-493a-8a4d-ca41e4ceb233",
  • "question": "string",
  • "is_anonymous": true,
  • "total_votes": 0,
  • "options": [
    ]
}

practice_voting_poll_vote_create

Cast a vote on this poll. Returns 409 if the user already voted.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
id
required
string
practice_uid
required
string <uuid>
Request Body schema:
required
option_id
required
string <uuid>

Responses

Request samples

Content type
{
  • "option_id": "ab22e710-5ce4-4e7e-a3db-bd6fdad8fe36"
}

Response samples

Content type
application/json
Example
{
  • "detail": "This practice or its parent organization is disabled.",
  • "code": "inactive_practice"
}

practice_voting_poll_active_count_retrieve

Return the count of unexpired polls for the practice (badge display).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
practice_uid
required
string <uuid>

Responses

Plans

practice_plans_list

List active subscription tiers, cheapest first.

Public-readable: the marketing site renders pricing tiles from this endpoint, so AnonymousUser is allowed. Pagination is disabled because the result set is bounded by the four canonical tiers and the frontend expects a flat array, not a paginated envelope.

Authorizations:
bearerAuthoauth2None

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Public Booking Resolver

Resolve an inbound referrer to Client and practice(s) for book.escape.dental.

Given a referrer URL or domain + path, returns the Client and practices to surface on book.escape.dental. Unauthenticated; returns only public booking information (no PHI). Unverified and inactive domains never match.

query Parameters
domain
string

Bare domain (e.g. acme.com). Ignored when referrer is present.

path
string

URL path (e.g. /north/). Only used with domain parameter.

referrer
string

Full referrer URL (e.g. https://acme.com/north/). Takes precedence over domain+path.

Responses

Response samples

Content type
application/json
{
  • "matched": true,
  • "client_name": "string",
  • "domain": "string",
  • "practices": [
    ]
}

PublicBooking

public_practice_booking_create

No-auth booking endpoint.

Body::

{
  "first_name": "Alice",
  "last_name": "Smith",
  "dob": "1990-04-12",
  "last_4": "1234",
  "slot": "2026-05-30T10:00:00-07:00",
  "appointment_type": "hygiene"
}

On success returns 201 with::

{
  "appointment_id": "<uuid>",
  "status": "self_booked_pending_review",
  "matched_existing_patient": true|false
}

Match flow:

  • The (name, dob, last_4) tuple is run through the same :meth:PatientSSN.objects.verify_last4 server-side comparison the staff-side verify endpoint uses (api#819). A single unambiguous match -> reuse that patient.
  • Multiple name+dob candidates with no last-4 match, or zero candidates -> create a fresh Patient with status=PROSPECTIVE and store the supplied last-4 as a PIN on PatientSSN. Staff reviews the row at confirm time and can merge into an existing record if the prospective patient turns out to be a duplicate of an existing one with a different PIN.
Authorizations:
bearerAuthoauth2None
path Parameters
slug
required
string
Request Body schema:
required
first_name
required
string [ 1 .. 100 ] characters
last_name
required
string [ 1 .. 100 ] characters
dob
required
string <date>
last_4
required
string = 4 characters ^\d{4}$
slot
required
string <date-time>
appointment_type
required
string (AppointmentTypeEnum)
Enum: "hygiene" "new_patient_exam" "quick_exam"
  • hygiene - hygiene
  • new_patient_exam - new_patient_exam
  • quick_exam - quick_exam

Responses

Request samples

Content type
{
  • "first_name": "string",
  • "last_name": "string",
  • "dob": "2019-08-24",
  • "last_4": "stri",
  • "slot": "2019-08-24T14:15:22Z",
  • "appointment_type": "hygiene"
}

public_practice_booking_availability_retrieve

No-auth slot-availability surface for the patient booking flow.

Returns slots in the union of:

  • operatories with is_hidden=False AND is_bookable=True AND accepts_self_booking=True, and
  • providers with is_web_sched=True (the existing patient online scheduling gate -- self-booking is a stricter superset).

Response shape::

{
  "practice": {"name": "...", "timezone": "..."},
  "appointment_type": "hygiene",
  "duration_minutes": 60,
  "days": [
    {"date": "2026-05-28", "slots": [{"time": "...", ...}]},
    ...
  ]
}
Authorizations:
bearerAuthoauth2None
path Parameters
slug
required
string

Responses

share

share_retrieve

GET /api/v1/share/<share_uid>/ -- landing-page payload.

Requires a share-session JWT whose per-share audience matches the URL share_uid. Cross-share JWT reuse is rejected by :class:SharePermission with HTTP 403 so the recipient UI can distinguish "not logged in" (401) from "wrong share" (403).

Authorizations:
bearerAuthoauth2
path Parameters
share_uid
required
string <uuid>

Responses

share_download_create

POST /api/v1/share/<share_uid>/download/ -- bundle URL.

Returns {bundle_url, expires_in, status}.

  • status="ready" -- a cached bundle exists and its object is still live in storage. bundle_url is a 15-minute presigned GET URL (DO Spaces in prod, a filesystem path in local-dev).
  • status="pending" -- no matching bundle; a Celery task has been queued to build one. Callers poll this endpoint until the status flips.

On the happy path this endpoint also flips the share to downloaded status and records a bundle_downloaded audit event. The status transition happens on the FIRST successful signed-URL issuance; subsequent polls against the same bundle don't re-flip the status (the model's helper short-circuits) but do emit additional audit events so the download timeline is complete.

.. note:: The bundle generator itself ships in api#174. This endpoint assumes :func:apps.sharing.tasks.generate_bundle returns a Spaces object key on success; if the task is stubbed or failing locally we fall through to a filesystem-backed URL so the recipient at least sees something rather than a confusing 500.

Authorizations:
bearerAuthoauth2
path Parameters
share_uid
required
string <uuid>

Responses

share_import_create

Copy share items into the destination practice (api#175).

Auth: regular staff-session JWT on Authorization AND a share-session JWT on X-Share-Token. The dual-credential requirement is what makes this the "authenticated scope" version of the share JWT: the caller has proven both that they are a known Escape user and that they hold a valid share-session token whose audience matches the share being imported.

Body: see :class:apps.sharing.serializers.ShareImportRequestSerializer.

Per-item transaction: each item is copied inside its own atomic block so a single bad UUID does not roll back the whole batch. The response errors[] array carries a short non-PHI reason code for each failure. The outer request is NOT transactional -- callers get partial success on purpose.

Audit: on success, a single share.imported event is emitted with dest_practice_uid, dest_patient_uid, imported_count. The share row is also transitioned to downloaded via :meth:Share.mark_downloaded so the sender-side My Shares UI shows the correct terminal state.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
share_uid
required
string <uuid>

Responses

share_items_retrieve

Render a single item in the share.

Routing is resource-type aware:

  • Document -> streamed application/pdf (or the original mime if non-PDF).
  • Imaging Exam -> streamed application/dicom (first image of the exam; multi-image bundles go through /download/).
  • Perio Exam / Clinical Note / Patient Summary -> application/json with the same shape as the legacy /items/<type>/<id>/ endpoint so web#158 can consume either.

The item_uid is looked up inside the share -- an item UUID that isn't listed in the share returns 404 rather than 200, even if it exists on the same patient. Combined with the per-share JWT audience check this gives us defence in depth against JWT reuse.

Authorizations:
bearerAuthoauth2
path Parameters
item_uid
required
string <uuid>
share_uid
required
string <uuid>

Responses

share_redeem_authenticated_create

Authenticated redemption -- caller proves staff session AND token.

Uses DRF's default authentication stack so the staff session JWT on Authorization: Bearer ... is validated normally by SimpleJWT. On top of that, the caller must still present a valid share token or Diceware phrase in the body. Both checks must pass; a caller with only a session token sees a 400 (missing body field) rather than a free pass, and a caller with only a token is routed to the guest endpoint by the URL.

The resulting JWT carries scope=authenticated and sub=user:<user_uid> so audit records can link the redemption to the Escape staff user who drove it. The session JWT is not re-embedded -- spec §6 calls for re-issue via the staff session, but the details of that re-issue (e.g. auto-re-mint on JWT expiry from the portal UI) are outside the HTTP surface defined here.

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
token
string [ 1 .. 128 ] characters
phrase
string [ 1 .. 256 ] characters

Responses

Request samples

Content type
{
  • "token": "string",
  • "phrase": "string"
}

Response samples

Content type
application/json
{
  • "token": "string",
  • "phrase": "string"
}

share_redeem_guest_create

Guest redemption -- anyone with a valid token / phrase may call.

No session required. The resulting JWT carries scope=guest and a hashed-IP sub claim so downstream audit records can distinguish guest traffic from authenticated-staff traffic.

Rate limited to 5 per IP per 5 minutes per share_uid prefix via :class:ShareSessionRedeemThrottle; on top of that, 5 consecutive failures trip a 15-minute lockout tracked in the cache.

Authorizations:
bearerAuthoauth2None
Request Body schema:
token
string [ 1 .. 128 ] characters
phrase
string [ 1 .. 256 ] characters

Responses

Request samples

Content type
{
  • "token": "string",
  • "phrase": "string"
}

Response samples

Content type
application/json
{
  • "token": "string",
  • "phrase": "string"
}

status

List currently active status messages (public, no auth).

Returns all :class:StatusMessage rows with resolved=False newest-first. No pagination -- there are at most a handful of active messages at any time. Response carries Cache-Control: public, max-age=30 so a herd-of-tabs scenario collapses to a handful of database hits per minute. Resolved rows are never surfaced on this endpoint -- authoring/resolve lives behind the private internal API.

Authorizations:
bearerAuthoauth2None

Responses

Response samples

Content type
application/json
[
  • {
    }
]

support

List inbound import issues (staff-only).

Supports ?status=, ?kind=, ?importer=, ?occurred_from= / ?occurred_to= filters. Ordered by -created (newest first). Returns the compact list shape; open a detail view to read the full context payload.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

Receive an import-error report from an escape-importer instance.

Accepts a structured failure report (schema_change / data_shape / runtime). Authenticated by a first-party OAuth token carrying import:write scope -- the importer holds this token; the web app and third-party apps cannot reach this endpoint. The request body may carry unredacted PHI in context; rows are PHI-bearing and gated to staff users on the read side.

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
required
importer
required
string [ 1 .. 64 ] characters

Slug of the reporting importer, e.g. 'escape-eaglesoft'.

importer_version
string <= 64 characters

Self-reported version of the importer that raised the issue.

pms
required
string [ 1 .. 32 ] characters

Slug of the upstream practice management system.

pms_version
string <= 64 characters

Self-reported PMS version, when the importer can read it.

practice_uid
string or null <uuid>

Practice UUID the importer was syncing, when established.

client_uid
string or null <uuid>

Client (parent of practice) UUID, when established.

kind
required
string
Enum: "schema_change" "data_shape" "runtime"

Failure class (schema change / data shape / runtime).

  • schema_change - Schema change
  • data_shape - Data shape surprise
  • runtime - Runtime error
occurred_at
required
string <date-time>

Timestamp the importer recorded the error (importer's clock).

summary
required
string [ 1 .. 500 ] characters

One-line description for the inbox list view (PHI-free).

context
any

Structured failure payload (PHI permitted; staff-only on read).

Responses

Request samples

Content type
{
  • "importer": "string",
  • "importer_version": "string",
  • "pms": "string",
  • "pms_version": "string",
  • "practice_uid": "5a13cce7-156f-4a3d-9428-686a502340e4",
  • "client_uid": "b865ed9a-e140-4b8a-85ef-febd691ba840",
  • "kind": "schema_change",
  • "occurred_at": "2019-08-24T14:15:22Z",
  • "summary": "string",
  • "context": null
}

Response samples

Content type
application/json
{
  • "importer": "string",
  • "importer_version": "string",
  • "pms": "string",
  • "pms_version": "string",
  • "practice_uid": "5a13cce7-156f-4a3d-9428-686a502340e4",
  • "client_uid": "b865ed9a-e140-4b8a-85ef-febd691ba840",
  • "kind": "schema_change",
  • "occurred_at": "2019-08-24T14:15:22Z",
  • "summary": "string",
  • "context": null
}

Read a single import issue (staff-only).

Returns the full report including the PHI-bearing context JSON. Staff-only.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
issue_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "importer": "string",
  • "importer_version": "string",
  • "pms": "string",
  • "pms_version": "string",
  • "practice_uid": "5a13cce7-156f-4a3d-9428-686a502340e4",
  • "client_uid": "b865ed9a-e140-4b8a-85ef-febd691ba840",
  • "kind": "schema_change",
  • "occurred_at": "2019-08-24T14:15:22Z",
  • "summary": "string",
  • "context": null,
  • "status": "new",
  • "assigned_to": "b9f52997-ff03-4166-bbff-22fd35e12939",
  • "assigned_to_email": "user@example.com",
  • "resolution_note": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Update triage state on an import issue (staff-only).

Writable fields: status, assigned_to, resolution_note. Everything else is read-only -- the originating report body is immutable after intake.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
issue_uid
required
string <uuid>
Request Body schema:
status
string
Enum: "new" "triaged" "resolved" "wontfix"

Triage state.

  • new - New
  • triaged - Triaged
  • resolved - Resolved
  • wontfix - Won't fix
assigned_to
string or null <uuid>

Staff user who owns this issue's triage, when assigned.

resolution_note
string

Free-form note set when the issue moves to resolved/wontfix.

Responses

Request samples

Content type
{
  • "status": "new",
  • "assigned_to": "b9f52997-ff03-4166-bbff-22fd35e12939",
  • "resolution_note": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "importer": "string",
  • "importer_version": "string",
  • "pms": "string",
  • "pms_version": "string",
  • "practice_uid": "5a13cce7-156f-4a3d-9428-686a502340e4",
  • "client_uid": "b865ed9a-e140-4b8a-85ef-febd691ba840",
  • "kind": "schema_change",
  • "occurred_at": "2019-08-24T14:15:22Z",
  • "summary": "string",
  • "context": null,
  • "status": "new",
  • "assigned_to": "b9f52997-ff03-4166-bbff-22fd35e12939",
  • "assigned_to_email": "user@example.com",
  • "resolution_note": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z"
}

Support Notes

List support notes attached to a single subject.

List + create endpoint for :class:SupportNote rows.

The list path filters by subject_type + subject_id -- cross-subject queries belong on :class:SupportNoteForUserView, where the join semantics are explicit. Listing without filters returns an empty queryset rather than the full table (which would be a foot-gun against a growing notes corpus).

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
include_archived
boolean

Include archived notes in the response. Default false.

page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

subject_id
required
string

UUID of the subject row.

subject_type
required
string

One of: client, practice, user.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

Create a support note attached to a Client, Practice, or User.

List + create endpoint for :class:SupportNote rows.

The list path filters by subject_type + subject_id -- cross-subject queries belong on :class:SupportNoteForUserView, where the join semantics are explicit. Listing without filters returns an empty queryset rather than the full table (which would be a foot-gun against a growing notes corpus).

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
required
subject_type
required
string (SubjectTypeEnum)
Enum: "client" "practice" "user"
  • client - Client
  • practice - Practice
  • user - User
subject_id
required
string <uuid>
body
required
string [ 1 .. 10000 ] characters

Responses

Request samples

Content type
{
  • "subject_type": "client",
  • "subject_id": "80e197be-61ad-4068-b4ff-a483fb5c18f9",
  • "body": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "subject_type": "string",
  • "subject_id": "string",
  • "body": "string",
  • "is_archived": true,
  • "archived_at": "2019-08-24T14:15:22Z",
  • "archived_by_email": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4",
  • "created_by_email": "string",
  • "created_by_name": "string",
  • "can_edit": true
}

Edit a support note's body. Author-only, within 24h.

PATCH-only detail view for :class:SupportNote.

The list endpoint above covers reads; a single-note GET would only be useful for permalink-by-id, which the support tool does not use today. PATCH gating happens before serialiser construction so a stale-window response carries the 403 message rather than a misleading 400 validation error.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
note_id
required
string <uuid>
Request Body schema:
body
string [ 1 .. 10000 ] characters

Responses

Request samples

Content type
{
  • "body": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "subject_type": "string",
  • "subject_id": "string",
  • "body": "string",
  • "is_archived": true,
  • "archived_at": "2019-08-24T14:15:22Z",
  • "archived_by_email": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4",
  • "created_by_email": "string",
  • "created_by_name": "string",
  • "can_edit": true
}

Archive a support note. Any support-staff user.

Shared base for archive / unarchive POST endpoints.

The two actions are symmetrical -- both gated on support-staff, both idempotent on the underlying model. Splitting them into two thin subclasses keeps OpenAPI schemas clean (one summary per surface) while sharing the lookup + permission code.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
note_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "subject_type": "string",
  • "subject_id": "string",
  • "body": "string",
  • "is_archived": true,
  • "archived_at": "2019-08-24T14:15:22Z",
  • "archived_by_email": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4",
  • "created_by_email": "string",
  • "created_by_name": "string",
  • "can_edit": true
}

Restore an archived support note. Any support-staff user.

Shared base for archive / unarchive POST endpoints.

The two actions are symmetrical -- both gated on support-staff, both idempotent on the underlying model. Splitting them into two thin subclasses keeps OpenAPI schemas clean (one summary per surface) while sharing the lookup + permission code.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
note_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "subject_type": "string",
  • "subject_id": "string",
  • "body": "string",
  • "is_archived": true,
  • "archived_at": "2019-08-24T14:15:22Z",
  • "archived_by_email": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "created_by": "ee824cad-d7a6-4f48-87dc-e8461a9201c4",
  • "created_by_email": "string",
  • "created_by_name": "string",
  • "can_edit": true
}

Return User notes + parent Practice notes + parent Client notes for a single user, in one envelope.

Combined view returning all notes relevant when looking at one user.

The spec calls out this shape directly:

when looking up a User, return User notes + Practice notes
for the practices the user belongs to + Client notes for
those clients.

Each section is returned as its own list so the UI can render them under distinct headings (User-level visible by default, the Practice / Client sections collapsed by default per Aaron's UI guidance).

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
user_id
required
string <uuid>
query Parameters
include_archived
boolean

Include archived notes in each section. Default false.

Responses

Support

List support sessions (audit log). Support-staff only.

GET lists past sessions (filterable); POST mints a new one.

Both methods are restricted to support staff (:class:apps.support.permissions.IsSupportStaff) -- the audit list exposes the inverse side of the redemption surface and so inherits the same gate.

Authorizations:
jwtAuthbearerAuthoauth2
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{
  • "count": 123,
  • "results": [
    ]
}

Mint a support code + subscriber token. Support-staff only.

Mint a :class:SupportSession row + subscriber token.

The row, the audit event, and the token mint are committed together inside an explicit transaction.atomic() block -- a partial commit on a LiveKit-config failure would leave dangling sessions for which no token was ever issued. The atomic block re-raises :class:LiveKitNotConfigured, which triggers a clean rollback; the outer try catches it after the rollback has run and surfaces the 503 response.

Authorizations:
jwtAuthbearerAuthoauth2

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "status": "string",
  • "code": "string",
  • "code_expires_at": "2019-08-24T14:15:22Z",
  • "livekit_url": "string",
  • "livekit_token": "string",
  • "livekit_room": "string",
  • "token_expires_at": 0
}

End a support session. Either party may call.

End an active session. Idempotent on already-ended rows.

Either the originating tech or the redeeming user may call; any other authenticated user gets 403. The endpoint deliberately does not let an arbitrary support-staff member end someone else's session -- the audit story is cleaner if the actor is one of the two participants.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
session_id
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "status": "string",
  • "ended_at": "2019-08-24T14:15:22Z"
}

Redeem a support code. Any authenticated user.

Validate the code, mark redeemed, mint publisher token.

The endpoint runs two distinct transactions:

  1. An "expired-or-bust" atomic block that picks up the row, checks the TTL, and -- if expired -- commits the EXPIRED transition + audit event before raising :class:ValidationError. Without the split, a single outer atomic would roll back the EXPIRED save when the ValidationError propagates out, and the row would stay stuck in PENDING for the next reader.

  2. A "redeem-or-bust" atomic block that flips the row to ACTIVE, mints the publisher token, and emits the REDEEMED audit event. On :class:LiveKitNotConfigured the block rolls back so the user does not end up associated with a session it cannot connect to.

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
required
code
required
string [ 1 .. 32 ] characters

Responses

Request samples

Content type
{
  • "code": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "status": "string",
  • "livekit_url": "string",
  • "livekit_token": "string",
  • "livekit_room": "string",
  • "token_expires_at": 0
}

webhooks

webhooks_subscriptions_list

List and create webhook subscriptions.

GET — returns all subscriptions owned by the authenticated user's OAuth applications. POST — creates a new subscription (URL must pass validation, events must be known).

Authorizations:
jwtAuthbearerAuthoauth2

Responses

Response samples

Content type
application/json
[
  • {
    }
]

webhooks_subscriptions_create

List and create webhook subscriptions.

GET — returns all subscriptions owned by the authenticated user's OAuth applications. POST — creates a new subscription (URL must pass validation, events must be known).

Authorizations:
jwtAuthbearerAuthoauth2
Request Body schema:
required
application
required
integer
client
required
string <uuid>
target_url
required
string <uri> [ 1 .. 2048 ] characters
events
any

List of event patterns, e.g. ['patient.created', 'appointment.*']

all_practices
boolean

Subscribe to events across all practices, or select specific ones

practices
Array of strings <uuid> [ items <uuid > ]

Specific practices (when all_practices=False)

custom_data
any

Responses

Request samples

Content type
{
  • "application": 0,
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "target_url": "http://example.com",
  • "events": null,
  • "all_practices": true,
  • "practices": [
    ],
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "application": 0,
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "target_url": "http://example.com",
  • "events": null,
  • "all_practices": true,
  • "practices": [
    ],
  • "custom_data": null
}

webhooks_subscriptions_retrieve

Retrieve, update, or delete a single webhook subscription.

Scoped to subscriptions owned by the authenticated user's OAuth applications.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
subscription_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "application": 0,
  • "application_name": "string",
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "client_name": "string",
  • "target_url": "http://example.com",
  • "events": null,
  • "all_practices": true,
  • "practices": [
    ],
  • "is_active": true,
  • "is_verified": true,
  • "consecutive_failures": 0,
  • "last_failure_at": "2019-08-24T14:15:22Z",
  • "disabled_reason": "string",
  • "created": "2019-08-24T14:15:22Z",
  • "modified": "2019-08-24T14:15:22Z",
  • "custom_data": null
}

webhooks_subscriptions_update

Retrieve, update, or delete a single webhook subscription.

Scoped to subscriptions owned by the authenticated user's OAuth applications.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
subscription_uid
required
string <uuid>
Request Body schema:
required
application
required
integer
client
required
string <uuid>
target_url
required
string <uri> [ 1 .. 2048 ] characters
events
any

List of event patterns, e.g. ['patient.created', 'appointment.*']

all_practices
boolean

Subscribe to events across all practices, or select specific ones

practices
Array of strings <uuid> [ items <uuid > ]

Specific practices (when all_practices=False)

custom_data
any

Responses

Request samples

Content type
{
  • "application": 0,
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "target_url": "http://example.com",
  • "events": null,
  • "all_practices": true,
  • "practices": [
    ],
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "application": 0,
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "target_url": "http://example.com",
  • "events": null,
  • "all_practices": true,
  • "practices": [
    ],
  • "custom_data": null
}

webhooks_subscriptions_partial_update

Retrieve, update, or delete a single webhook subscription.

Scoped to subscriptions owned by the authenticated user's OAuth applications.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
subscription_uid
required
string <uuid>
Request Body schema:
application
integer
client
string <uuid>
target_url
string <uri> [ 1 .. 2048 ] characters
events
any

List of event patterns, e.g. ['patient.created', 'appointment.*']

all_practices
boolean

Subscribe to events across all practices, or select specific ones

practices
Array of strings <uuid> [ items <uuid > ]

Specific practices (when all_practices=False)

custom_data
any

Responses

Request samples

Content type
{
  • "application": 0,
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "target_url": "http://example.com",
  • "events": null,
  • "all_practices": true,
  • "practices": [
    ],
  • "custom_data": null
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "application": 0,
  • "client": "95b7f642-4812-4c19-ba03-689f2fdf42f8",
  • "target_url": "http://example.com",
  • "events": null,
  • "all_practices": true,
  • "practices": [
    ],
  • "custom_data": null
}

webhooks_subscriptions_destroy

Retrieve, update, or delete a single webhook subscription.

Scoped to subscriptions owned by the authenticated user's OAuth applications.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
subscription_uid
required
string <uuid>

Responses

webhooks_subscriptions_deliveries_list

List delivery logs for a specific subscription.

Paginated (50 per page) and scoped to subscriptions owned by the authenticated user's OAuth applications.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
subscription_uid
required
string <uuid>
query Parameters
page
integer

A page number within the paginated result set.

page_size
integer

Number of results to return per page.

Responses

Response samples

Content type
application/json
{}

xrays

xrays_sessions_retrieve

Get capture session status for crash recovery.

Returns session state, image count, and template info.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
session_uid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "status": "pending",
  • "exam": "76d06126-4ce7-4fb4-98c2-d484d7e9ee38",
  • "template": "060ce75e-87d6-4677-b330-eaee58e54138",
  • "template_name": "string",
  • "workstation_name": "string",
  • "image_count": "string",
  • "created": "2019-08-24T14:15:22Z"
}

xrays_sessions_images_create

Upload a single dental image to a capture session.

Called by the desktop app after each image is captured via TWAIN/WIA.

Authorizations:
jwtAuthbearerAuthoauth2
path Parameters
session_uid
required
string <uuid>
Request Body schema:
required
file
required
string <binary>
ImageTypeEnum (string) or BlankEnum (any)
capture_device
string <= 255 characters

Device name from browser getUserMedia

tooth_numbers
any

Universal numbering: 1-32 permanent, A-T primary

description
string <= 255 characters

Short description/label for the image

notes
string

Responses

Response samples

Content type
application/json
{
  • "image_type": "pa",
  • "capture_device": "string",
  • "tooth_numbers": null,
  • "description": "string",
  • "notes": "string"
}