DEA-compliant dispensing with a mandatory two-person witness requirement.

app.chartling.io C Chartling GETTING STARTED Quick start PATIENTS & CLIENTS Patients Clients CLINICAL Visits & SOAP AI scribe Medications & Rx Controlled subs. Lab orders Discharge & comms AI FEATURES Clinic Copilot Clinical support SCHEDULING Appointments BILLING Invoicing & pmts SERVICE MODULES Boarding Daycare Grooming Training TEAM & SETTINGS Team & permissions Clinic settings SMS & reminders Audit log Docs › Chartling › Controlled substances Controlled substances Dispensed at finalize Drug name Tramadol 50 mg Quantity dispensed 14 tablets Dispensing vet Dr. Chen, DVM Pending witness Witness (Controlled log) Witness name Dr. Park, DVM Must be a different account Cannot witness own dispense Signature Logged to DEA audit trail · 21 CFR Part 1304
Default pack access

The Vet, Associate Vet, and Locum packs include rx.controlled.dispense and rx.controlled.witness by default. The Vet Tech pack includes rx.controlled.witness on its own, though see the note further down about the Controlled log page also requiring rx.controlled.reconcile today. The Senior Tech pack includes rx.controlled.witness and rx.controlled.reconcile. All other staff must be granted these permissions explicitly by an Admin. See Team & permissions.

Dispensing a controlled substance

  1. Prescribe on the visit's SOAP

    Add the controlled substance to the Plan like any other medication. It's proposed for review, same as the rest of the visit. Nothing is written to inventory or the DEA log yet.

  2. Sign & finalize the visit

    Finalizing (which requires visit.sign) dispenses the drug and writes the DEA log entry automatically as part of signing. This doesn't wait on a witness. The entry is created in a pending witness state: drug, quantity, lot, patient, prescriber, and dispenser are all recorded, but it isn't complete until a second person signs off.

  3. A second person witnesses

    The pending dispense appears on Inventory → Controlled log, filtered to Unwitnessed only. Confirming it checks rx.controlled.witness, but that page is the only place in the app to reach the confirm step, and opening the page at all also requires rx.controlled.reconcile (see the note under the permissions table below). The witness (who must be a different account from the dispenser; Chartling enforces this server-side) reviews the quantity and confirms with their name, credentials, and a signature.

  4. Dispensing outside a visit

    A controlled substance can also be dispensed directly against a patient (no SOAP), for a refill for example. The same permission checks, and the same pending-witness step, apply.

Dispenser and witness must be different users

Chartling enforces this server-side. The same account cannot complete both actions on the same dispense record. A colleague with witness permission must sign off on their own account.

Required permissions

Permission keyWhat it allowsWho typically holds it
rx.controlled.dispense Initiate and sign off a controlled substance dispense Vet, Associate Vet, Locum, Owner / Admin
rx.controlled.witness Countersign a dispense as the second witness Vet, Associate Vet, Locum, Vet Tech, Senior Tech, Owner / Admin
rx.controlled.reconcile View/export the full DEA log and run the biennial physical count Senior Tech, Owner / Admin
A plain Vet Tech can't currently reach the witness step

The Vet Tech pack holds rx.controlled.witness by default, but the only screen that exposes the witness action (Inventory → Controlled log) is itself gated on rx.controlled.reconcile, which the Vet Tech pack does not include. In the app today, only Senior Tech, Owner/Admin, or a custom pack holding both permissions can actually open that page and complete a witness. If your clinic needs a Vet Tech to witness independently of a Senior Tech or Admin, grant them rx.controlled.reconcile too (or build a custom pack) in the meantime.

The DEA log

Go to Inventory → Controlled log (requires rx.controlled.reconcile) to view all dispense records. The log is:

Biennial inventory

Staff with rx.controlled.reconcile permission run the physical count from Inventory → Biennial Inventory, the wizard required under 21 CFR 1304.11. It walks each controlled item, records the physical count against what the log expects, and finalizes with a witness attestation, same two-person principle as a dispense.

21 CFR 1304 sets the biennial (every-two-year) cadence as the federal floor; check your state board for any additional cadence it requires and keep your own schedule for informal counts in between. Chartling doesn't set that schedule for you.

FAQ

What drug schedules does this cover?

Chartling's controlled substance log applies to any medication whose inventory item you flag as a controlled substance (from that item's page under Inventory). You'll also set its DEA schedule there. There is no separate flow per schedule; the two-person dispense/witness rule applies uniformly to anything flagged, Schedule II through V.

What if we only have one staff member available to witness?

The witness must be a different user account than the dispenser. Chartling doesn't allow a same-account workaround. The dispense sits in a pending-witness state on the Controlled log until someone who can open that page is available and signs off. It isn't lost or timed out in the meantime. Opening that page today also requires rx.controlled.reconcile, as noted above. Contact your state veterinary board for guidance on witnessing requirements in your jurisdiction.

How often should we run the biennial count?

21 CFR Part 1304 requires a full physical inventory every two years at minimum. That's what the Biennial Inventory wizard is for. Many state boards and clinics also do more frequent informal counts against the log; Chartling doesn't prescribe a cadence for those, so follow your state board and your own SOP.

Can I export the log for a DEA audit?

Yes, if you hold rx.controlled.reconcile. From Inventory → Controlled log, filter by date range and/or schedule, then export a CSV, or use the print view for a paper/PDF copy for the inspector.

Something missing? We're always improving these docs.

Contact support Open app