Resources

Open Dental Treats Recall as a First-Class Object

By Federico Ruiz Cassarino, CEO and founder, Puppeteer AI · · 7 min read

In almost every EHR covered in this series, recall is something you compute. You pull appointment history, find the last visit, apply a rule about how often this patient should be seen, and decide whether they're due. The EHR has no opinion. It stores appointments and you infer the rest.

Open Dental doesn't work that way. Recall is a real object with its own table, its own endpoints, its own status field, and its own scheduling semantics. Dentistry is built around recall in a way primary care isn't, since six-month hygiene is the business model rather than an afterthought, and the data model reflects it.

If you've built recall against a medical EHR, the useful adjustment is this: stop computing, start reading. The practice has already configured what you were about to derive.

First, the part that stops most projects

Everything below is about a genuinely good API. None of it matters if you skip this.

Open Dental is desktop software. The database lives on a machine in the practice, not in a data centre, so a cloud service can't simply call it. Bridging that gap requires the practice to run Open Dental's eConnector on a Windows machine that stays powered on and connected, or to be on Open Dental Cloud. The eConnector itself is included in the practice's support plan rather than billed separately. The friction isn't the licence, it's that somebody at the clinic now owns a machine that must never be shut off, and clinics are not data centres.

The API is also metered, and Open Dental publishes the rates openly, which is rarer than it should be. Pricing runs per location per month: read-only is free but throttled to one request every five seconds, $15 buys a named set covering communications, documents, setup and queries at one request per second, $30 covers everything except payments, payment plans and the special permissions, and $35 covers everything except the special permissions. No tier includes the special permissions.

Two consequences for planning. Recall automation needs write access, so budget the $30 tier per location and say so out loud before anyone is surprised by an invoice. And the free tier's five-second floor isn't a rate limit you can engineer around. It's a different product.

Two endpoints, two different jobs

GET /recalls returns recall records, optionally filtered by PatNum. The fields include RecallNum, DateDue, DatePrevious, RecallInterval, RecallStatus, IsDisabled, RecallTypeNum, DisableUntilBalance, DisableUntilDate, DateScheduled, and Priority.

GET /recalls/List is the different one, and it's the one most integrations actually want. It takes DateStart, DateEnd, ProvNum, ClinicNum, RecallType, and IncludeReminded, and returns a work-list shape: due date, patient, age, type, interval, and status, plus contact info and a note.

That second shape is the recall list a front desk works from, and it already contains the two fields your outreach logic needs most: NumRemind, how many reminders this patient has already received, and LastRemind, when the most recent one went out.

You do not have to track contact history yourself. It's there. Building your own reminder counter next to Open Dental's is how you end up sending a fourth reminder to someone the practice already contacted three times.

And note IncludeReminded. The parameter exists precisely so you can ask for people who haven't been contacted yet. Use it rather than filtering client-side.

The interval syntax

RecallInterval is not a number of days. It's a compact string: a digit followed by a unit character, where the units are y for years, m for months, w for weeks, and d for days. Segments combine, so 1y6m20d means one year, six months, and twenty days.

Parse it properly, and specifically do not assume a single segment. Code that reads the leading integer and the first character will read 1y6m20d as one year and be silently wrong for every patient on a compound interval.

It's also not convertible to a fixed number of days without a reference date, since months and years vary in length. Compute from DatePrevious rather than normalizing the interval to days up front.

Recall types are configured per practice

RecallTypeNum points at a recall type the practice has defined, and those definitions are local. A prophy interval, a perio maintenance interval, and a periodic exam are separate types with separate default intervals, and two practices will number them differently.

This has a direct consequence for anyone building a multi-practice product: never hardcode a recall type ID, and never assume the same ID means the same thing at the next practice. Read the practice's types during onboarding, map them to your own internal categories once, and store that mapping per practice.

It also affects messaging. A six-month hygiene reminder and a three-month perio maintenance reminder are different conversations with different urgency, and patients on shorter intervals are usually on them for a clinical reason. Sending both groups the same generic reminder flattens a distinction the practice deliberately made.

PUT /recalls/SwitchType exists because patients move between types: someone who completes perio treatment may step back to a standard interval. If your system caches recall type per patient, that endpoint is a reminder that the cache goes stale.

Recall can be suppressed, and you must respect it

Three fields turn recall off, each for a different reason, and honoring all three is non-negotiable.

IsDisabled is the blunt one: recall is off for this patient. DisableUntilDate suppresses it until a date, which is how a practice handles a patient who asked not to be contacted for a while. DisableUntilBalance suppresses recall until the patient's account balance drops below a threshold, which is a business rule you would never have guessed and absolutely should not override.

That third field is worth dwelling on because it encodes a decision the practice made deliberately: don't invite this patient back for more work while they owe us money. A recall system that ignores DisableUntilBalance will actively undermine the practice's collections policy, and the practice will notice.

Writing back

Recall isn't read-only. POST /recalls creates one, requiring PatNum and RecallTypeNum. PUT /recalls/{RecallNum} updates fields including DateDue, RecallInterval, and RecallStatus.

Two purpose-built endpoints are more useful than the generic update for outreach work. PUT /recalls/Status takes PatNum and recallType along with RecallStatus, commlogMode, and commlogNote. That last pair writes a communication log entry as part of the same call, so your outreach shows up in the patient's history where staff will see it.

The commlog integration is the detail that makes an automated system feel native rather than bolted on. When someone at the front desk opens a patient and sees the reminder that went out on Tuesday, your system is part of the practice. When they see nothing and the patient mentions a text they received, it isn't.

The ASAP list has its own API

Open Dental models the short-notice fill list as AsapComm, and it's a genuinely unusual thing to find in an EHR API.

POST /asapcomms requires op, dateTimeStart, and either aptNum or recallNum, so you can offer a freed slot to someone with an existing appointment to move, or to someone who's merely due for recall and has nothing booked.

Three constraints are documented and all three matter. The practice must be subscribed to two eServices, WebSched ASAP and the Integrated Texting Feature, so confirm this during onboarding rather than at go-live. On the API side, ASAP texting is one of the special permissions, which means it sits outside every published tier and is priced on its own. The $30 key that covers the recall endpoints does not carry it. And the API only sends SMS text messages, so there is no email or voice path here.

One more field worth knowing: appointments booked through WebSched carry an eServiceLogType of Recall, NewPat, ExistingPat, or ASAP. That's attribution built into the record. You can report on how many appointments your recall actually produced without maintaining a separate tracking table.

Honest limits

Open Dental is not in our integration set, and this page is written from Open Dental's public API documentation rather than from a system we run. Field names and endpoints are quoted as of August 2026.

Open Dental deployments are commonly self-hosted, so API availability and version depend on the individual practice's setup and on which eServices they subscribe to. Verify per practice.

Sources

  1. Open Dental: API Recalls
  2. Open Dental: API AsapComms
  3. Open Dental: API Appointments
  4. Open Dental: Recall List manual
  5. Open Dental: API permissions and pricing
  6. Open Dental: API setup

About the author

Federico Ruiz Cassarino is the CEO and founder of Puppeteer AI, the company behind Recupra. He works with clinic operators on the scheduling and outreach problems that decide how much of a practice's booked capacity turns into revenue. Connect on LinkedIn.

FAQ

Frequently asked questions

How do I get a practice's recall list?

GET /recalls/List with a date range. Use IncludeReminded to control whether already-contacted patients are returned.

What does an interval like 1y6m20d mean?

One year, six months, and twenty days. Segments combine, so parse all of them.

Can I add someone to the ASAP list via the API?

Yes, POST /asapcomms, referencing either an appointment or a recall. It requires the practice to be subscribed to WebSched ASAP and Integrated Texting.

How do I know which appointments came from recall?

Appointments booked through WebSched carry an eServiceLogType, with Recall as one of its values.

Recall outreach that checks the suppression fields first.

Connect Open Dental and Recupra reads the recall list, skips anyone the practice has paused or capped on balance, and writes every contact back to the patient's history automatically.