DEV Community

Cover image for How I Learned to Love the Legacy Dental PMS: A Developer's Guide
CAmador
CAmador

Posted on

How I Learned to Love the Legacy Dental PMS: A Developer's Guide

When I first started integrating with dental systems, I thought I understood legacy APIs. Then I met practice management systems.

They’re like vintage cars, elegant, historic, and one wrong call away from leaking data oil all over your console.

That’s why working with something like Synchronizer API by NexHealth feels like therapy for developers who’ve seen too much.

The Data Layer Developers Deserve

One of the hardest parts of healthcare integrations is just…keeping the data clean.

In Synchronizer, the /appointments endpoint abstracts away the chaos of different systems (Dentrix, Eaglesoft, Open Dental, Denticon, etc.) and gives you normalized, structured data you can actually build with.

GET /appointments/{id}

Response:

{
    "code": true,
    "description": null,
    "error": null,
    "data": {
        "id": 1010361170,
        "patient_id": 392928661,
        "provider_id": 142749489,
        "provider_name": "Dr. Sarah Mitchell",
        "start_time": "2025-09-29T18:00:00.000Z",
        "confirmed": false,
        "patient_missed": false,
        "created_at": "2025-09-24T10:51:12.865Z",
        "updated_at": "2025-09-24T10:51:12.865Z",
        "note": "",
        "end_time": "2025-09-29T19:00:00.000Z",
        "unavailable": false,
        "cancelled": false,
        "timezone": "America/Chicago",
        "institution_id": 1748,
        "appointment_type_id": null,
        "checkin_at": null,
        "location_id": 19617,
        "foreign_id": "612",
        "foreign_id_type": "msg-eaglesoft-DataSource-4569",
        "misc": {},
        "last_sync_time": "2025-09-24T10:51:12.865Z",
        "patient_confirmed": false,
        "created_by_user_id": null,
        "is_guardian": false,
        "patient_confirmed_at": null,
        "cancelled_at": null,
        "is_new_clients_patient": null,
        "confirmed_at": null,
        "sooner_if_possible": false,
        "operatory_id": 22,
        "deleted": false,
        "checked_out": false,
        "checked_out_at": null,
        "referrer": null,
        "is_past_patient": true,
        "timezone_offset": "-04:00",
        "patient": {
            "id": 392928661,
            "email": "john.smith@example.com",
            "first_name": "John",
            "middle_name": null,
            "last_name": "Smith",
            "name": "John Smith",
            "created_at": "2025-07-24T11:24:38.618Z",
            "updated_at": "2025-09-28T18:01:43.574Z",
            "institution_id": 1748,
            "foreign_id": "381",
            "foreign_id_type": "msg-eaglesoft-DataSource-4569",
            "bio": {
                "city": "",
                "state": "",
                "gender": "Male",
                "zip_code": "90210",
                "new_patient": false,
                "non_patient": false,
                "phone_number": "5559871234",
                "date_of_birth": "1990-03-15",
                "address_line_1": null,
                "address_line_2": null,
                "street_address": null,
                "cell_phone_number": "",
                "home_phone_number": "",
                "work_phone_number": "",
                "previous_foreign_id": null
            },
            "inactive": false,
            "last_sync_time": "2025-07-24T11:24:38.618Z",
            "guarantor_id": null,
            "unsubscribe_sms": false,
            "balance": {
                "amount": "0.00",
                "currency": "USD"
            },
            "billing_type": "Standard",
            "chart_id": null,
            "preferred_language": "en",
            "preferred_locale": null,
            "location_ids": [
                19617
            ]
        }
    },
    "count": null
}

Enter fullscreen mode Exit fullscreen mode

There it is, no SOAP envelopes, no XML gymnastics, just clean code.

When I build my application, I have the confidence that I only need to write my logic once, then integrate seamlessly with multiple practice management systems.

What Changed Everything for Me

In most older PMS systems, the only way to know if something changed is to ask constantly.

Polling every few seconds.

Burning bandwidth.

Losing hair. I have great hair, I don't want to lose any more than I have to.

Synchronizer.io by NexHealth let me keep it with webhook events that fire automatically when appointments, patients, or recalls change.

Webhook Event Payload

{
  "resource_type": "appointment",
  "event_name": "appointment_updated",
  "event_time": "2024-04-19T05:47:21.214+00:00",
  "data": {
    "appointment": {
      "id": 1136829,
      "patient_missed": true,
    }
  },
  "delivery_errors": [
    {
      "code": "500",
      "timestamp": "2024-04-19T05:53:44.844Z",
      "message": "500 Internal Server Error",
      "attempts": 1
    }
  ]

Enter fullscreen mode Exit fullscreen mode

So now, instead of spamming the API like an overcaffeinated intern, you get instant updates from every integrated system.

It’s elegant.
It’s efficient.
And it’s the closest thing to peace you’ll find in healthcare tech.

Real-World Example: Sync Without Fear

When a webhook fires, your app can process updates immediately, meaning appointment cancellations, reschedules, or new bookings show up across every connected PMS.

That’s the kind of architecture that let companies like Dentina.AI and All Star Pediatric Dentistry move from chaos to real-time automation.

Because once you stop waiting for syncs to finish, you start building products that move at the speed of care.

The Real Lesson

Legacy systems aren’t evil, they’re survivors.

They’ve kept clinics running for decades.

But they were never designed for what we’re trying to do now: AI scheduling, real-time sync, or instant patient onboarding.

APIs like Synchronizer bridge that gap, they let modern developers work with the past instead of fighting it.

So yeah, I’ve learned to stop worrying and love the legacy system.

Not because it’s perfect, but because the right API makes it feel like it might be.

GitHub

Webhooks

Postman

Top comments (0)