Dental Practice Management API Integration: Open Dental, NexHealth and What Breaks in Production
CTO & Co-Founder
CTO & Co-Founder at Nirmitee.io. Architects healthcare integrations across FHIR, SMART on FHIR, ABDM and NHCX, writing from production experience taking hospital software from sandbox to go-live.

If you are building a scheduling product, an AI voice agent, a patient engagement tool or an intake product for dental practices, you will meet the same problem in your first week. There is no single dental API. There are two architectures, roughly a dozen practice management systems behind them, and a set of operational failure modes that none of the marketing pages mention.
This guide covers both architectures, what each one actually requires, and the failures that only appear once real practices are live. It is written for engineers and technical founders who have to make the integration work, not choose a vendor. We build and run EHR integration for product teams, so the guidance here comes from the operational side rather than a feature comparison.
The two architectures
Direct to the practice management system. You hold credentials for that system and call it yourself. Open Dental is the clearest example, and the only widely used dental system with a public, self-serve developer route.
Through middleware. You integrate once with a vendor who has already integrated with many practice systems. NexHealth is the common choice in dental. You get one API and one data model across systems you would otherwise integrate with one at a time.
Most products end up using both, because the direct route gives depth where it exists and the middleware route gives reach where it does not.
Direct: how Open Dental access actually works
Two keys, not one. A developer key that identifies you, and a customer key that identifies one practice's relationship with you. Both travel in the same header.
Authorization: ODFHIR {DeveloperKey}/{CustomerKey} The developer key comes from the Developer Portal. The customer key is generated by you, inside the portal, per customer. That pairing matters: revoking one practice does not affect any other, and a leaked customer key is scoped to a single practice rather than your whole estate.
Getting started is a manual step that teams routinely forget to put in the project plan. You email vendor relations with your company name, contact phone, billing email and address, and a list of the API resources you need with read, create or update marked against each one. Open Dental states one to three business days for processing.
The practice then activates you on their side, at Setup, Advanced Setup, API, Add Key. Note what the practice can and cannot do there: they can enable or disable your key, and they can view the permissions granted to it, but they cannot change those permissions. If you discover in month three that you need one more resource, that is a request back to the vendor, not a toggle the practice can flip for you.
Open Dental's documentation also states that API developers should have a Business Associate Agreement in place with their clients. Treat that as a gating item in your sales process, not a legal detail to handle at go-live.
Plan for: a request cycle before any code runs, a per-practice activation step in your onboarding, and a permission set you have to get right early because widening it later is slow.
Middleware: how the NexHealth model works
NexHealth publishes support for over fifteen dental and medical record systems. The important distinction for your architecture is not which systems are on the list, but how each one is reached.
Cloud systems are reached directly by the vendor. Their documentation names Athena, Cloud9, Curve Hero, Denticon, Dentrix Ascend and Dentrix Enterprise in their cloud versions.
Server-based systems are not. For Dentrix G6.2 and above, Eaglesoft and Open Dental, the connection runs through the NexHealth Synchronizer, and the Synchronizer is software that runs on a machine inside the practice.
Authentication is an API key exchanged for a bearer token, with a JWT used on subsequent requests. Webhook subscriptions are pinned to a specific API version, and can be scoped to an institution or left unscoped. There is a rate limiting section in the API reference, so design for it rather than discovering it.
The fact that changes your architecture
For server-based practices, a piece of software on a computer inside the practice is a required part of your production path.
That computer is on a dental surgery's network. It gets restarted. It gets Windows updates. The front desk signs out of things. A member of staff turns the machine off before a long weekend. The vendor's own documentation includes troubleshooting for failed Synchronizer deployments, which tells you how common this is.
Here is why it matters more than it first appears. When that link stops, your API calls do not fail. You keep getting well-formed responses. They are simply answers about a practice system that has stopped being updated. Your product carries on booking, confirming and reminding against a picture of the diary that is quietly going stale.
This is the single most important operational fact in dental integration, and it is the one least likely to be in your test plan, because it cannot be reproduced in a sandbox.
Build this on day one: record the time of the last successful read and the last successful write, per practice. Alarm on the age of that timestamp, not on error rates. An integration that has silently stopped produces no errors at all.
Availability is a configuration problem before it is a code problem
The NexHealth available slots endpoint returns bookable slots over a date range and requires either provider IDs or an appointment type ID. That single line in the documentation is responsible for a large share of the "the integration does not work" tickets in this market.
Slots are not a property of the practice. They are a function of providers, operatories and appointment types, all of which are configured inside the practice management system by the practice. If those are not set up, or are set up differently from how your product assumes, you get one of two outcomes. Either the availability call returns nothing, or it returns times that the booking call then refuses.
The failure surfaces at your product, so it looks like your bug. It is almost always a configuration gap at the practice, and it is best caught during onboarding with an explicit check rather than during a patient's phone call.
Build this on day one: a per-practice readiness check that confirms providers, operatories and appointment types resolve before the practice goes live, and that re-runs on a schedule.
Connecting a product to dental or medical practice systems? We build and run practice system and EHR integrations for product teams. Talk to our team and we will map what each of your target systems actually exposes, and what it will require from the practice.
Read and write are two different integrations
It is tempting to treat an integration as one project. In practice, reading and writing have different permissions, different failure modes and different commercial terms.
Reading is forgiving. A failed read produces a retry or an empty screen.
Writing is not. A write can half succeed. The practice system can accept the appointment and return a response your code cannot parse, at which point your product believes the booking failed while the practice's diary says otherwise. Both records now exist and disagree, and nobody finds out until the patient arrives or does not.
Three rules make write paths survivable.
- Confirm from the response, not from the request. A booking is confirmed when the practice system returns an identifier for it. Never tell a patient an appointment is made because the call did not throw.
- Never retry a write on a timeout without reading back first. A timeout means you do not know whether it worked. Retrying blindly is how a patient ends up with two appointments.
- Validate the response shape. Parse it against a schema. Vendors change response formats, and a value your code silently reads as empty will travel a long way before anyone notices.
The direction most teams forget
Almost every product starts write-only, because writing is what the demo shows. You book an appointment, it appears in the practice system, the room nods.
Then the practice uses the product for a month and the gaps appear. An appointment booked at the front desk never reaches your product, so that patient gets no intake form and no reminder. An appointment cancelled inside the practice system never reaches your product either, so you send a reminder for an appointment that no longer exists. Your dashboard shows a fraction of the real schedule and nobody can explain the discrepancy.
If you serve practices through more than one architecture, check this per architecture rather than per product. It is entirely possible to have a working inbound path for practices on one system and none at all for practices on another, and for nobody to notice, because the product looks identical from the outside.
Where teams get stuck
Assuming the sandbox represents production. Sandboxes have clean configuration, no local agent and no front desk. Every failure mode in this guide is invisible in a sandbox.
Treating each practice as identical. Appointment types, operatories, provider availability and closure periods vary per practice. Your integration has a per-practice configuration surface whether you designed one or not.
Building per-practice settings as code. Teams start by putting a practice's appointment type numbers or provider identifiers in a migration or a constant. It works for the first three customers. By the tenth, adding a customer requires a release, and removing one requires reversing a release. Move that configuration into data before you need to.
No staleness signal. Teams monitor error rates. The expensive failure produces no errors. Monitor the age of the last successful exchange per practice.
One timeout budget for the whole path. A single booking can involve several sequential calls to the practice system. If your caller-facing budget is measured in seconds, that budget belongs to the whole operation, not to each request inside it.
Assuming a patient can be identified by their telephone number. In dental especially, calls are forwarded through a front desk line, families share a mobile and one number can legitimately belong to several patients. A telephone number is a hint. Identity needs a second field.
A short pre-launch list
Before a practice takes real calls or real bookings through your product:
- Providers, operatories and appointment types resolve for that practice, checked automatically.
- Last successful read and write timestamps are recorded per practice, and alarmed on age.
- Every write confirms from a returned identifier, and no write retries on timeout without a read-back.
- Responses are schema-validated at the boundary.
- An inbound path exists for changes made inside the practice system, and it is verified for each architecture you support, not once for the product.
- Per-practice configuration lives in data, not in code.
- Closure periods and holidays are applied when writing, not only when offering times.
None of this is exotic. All of it is the difference between an integration that demonstrates well and one that survives a year of real practices.
Getting it right the first time
Dental and medical practice system integration is not technically hard. It is operationally unforgiving, and the failures are quiet. The teams that struggle are rarely the ones who wrote poor code. They are the ones who built for the sandbox and discovered the local agent, the per-practice configuration and the one-way data flow after real patients were already relying on the product.
Need help connecting a product to dental or medical practice systems? Explore our healthcare interoperability solutions to see how we connect systems that were never designed to talk to each other. If your product is an AI phone or scheduling agent, our healthcare AI agents practice covers the integration and guardrail layer underneath it. Talk to our team to get started.
Sources
- Open Dental API setup, key model and registration process: opendental.com/site/apisetup.html
- Open Dental API specification and BAA guidance: opendental.com/site/apispecification.html
- NexHealth developer documentation, authentication, webhooks, rate limits and available slots: docs.nexhealth.com
- NexHealth supported health record systems: docs.nexhealth.com/docs/supported-health-record-systems
- NexHealth Synchronizer installation guide: docs.nexhealth.com/docs/nexhealth-synchronizer-installation-guide-1
Ready to scale?
Talk to our healthcare engineering team about building, integrating, and shipping faster.
Frequently Asked Questions
Do I need Open Dental and NexHealth, or can I pick one?
Why does the availability call return no slots when the practice clearly has openings?
What happens when the Synchronizer stops running at the practice?
Is a read-only integration enough to start with?
Do I need a Business Associate Agreement to integrate with a dental practice system?


