DEV Community

Cover image for Why Dental APIs Fail (and how I finally fixed them with Synchronizer.io)
CAmador
CAmador

Posted on

Why Dental APIs Fail (and how I finally fixed them with Synchronizer.io)

When I tell people I spent weeks untangling dental APIs, they usually laugh. “How complicated can an appointment be?” Spoiler: more complicated than my last IKEA shelf build. It's crooked, I can't follow directions....it kind of holds things up.

I had appointments moving around on their own. After awhile I decided it was either haunted from legacy or I needed to do something.

One of my friends told me about how they’d fixed their patient scheduling mess using Synchronizer API by NexHealth. They had double-bookings and a front desk staff that has warmed up after the change. Here's what I found:

Appointment Shapes That Actually Make Sense

The first time I pulled an appointment from a legacy system, the status came back as 3. Did that mean “scheduled,” “arrived,” or “canceled”?

Synchronizer’s GET /appointments/{id} endpoint gave me something clean and predictable:

curl --location 'https://nexhealth.info/appointments/1010012427?subdomain=mysmiles' \
--header 'Accept: application/vnd.Nexhealth+json;version=2' \
--header 'Authorization: ••••••' 
{
    "code": true,
    "description": null,
    "error": null,
    "data": {
        "id": 1010013711,
        "provider_name": "[REDACTED]",
        "start_time": "2025-09-24T00:00:00.000Z",
        "end_time": "2025-09-24T01:00:00.000Z",
        "cancelled": true,
        "timezone": "America/Chicago",
        "patient": {
            "name": "[REDACTED]",
            "email": "[REDACTED]",
            "phone_number": "[REDACTED]"
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Readable fields. Clear status. UTC timestamps. Suddenly my code stopped looking like a crime scene of if status == 3 then ???.

Stop Worrying About Lost Information

Before Synchronizer, I was missing updates left and right because I could not reliably get real time updates.

With POST /webhook_endpoints/{id}/webhook_subscriptions I didn’t have to worry about data loss:

curl --request POST \
     --url 'https://nexhealth.info/webhook_endpoints/id/webhook_subscriptions?subdomain=test' \
     --header 'Accept: application/vnd.Nexhealth+json; version=2' \
     --header 'Content-Type: application/json' \
     --data '
{
     "resource_type": "appointment",
     "event": "appointment_insertion"
}
'
Webhook Response Example: {
  "resource_type": "appointment",
  "event_name": "appointment_updated",
  "event_time": "2025-09-23T05:47:21.214+00:00",
  "data": {
    "appointment": {
      "id": 1136829,
      "patient_missed": true
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Slots That Match Reality

We had a 3:30 slot available… except the provider didn’t actually work then. More than a bad day, the office was not happy with me.

Synchronizer fixed this by giving me real slots via GET /appointment_slots:

curl --location --globoff 'https://nexhealth.info/appointment_slots?subdomain=mysmiles&start_date=2025-09-23&days=5&lids[]=19617&pids[]=142749492&slot_length=60' \
--header 'Accept: application/vnd.Nexhealth+json;version=2' \
--header 'Authorization: ••••••' 

{
  "lid": 19617,
  "pid": 142749492,
  "slots": [
    { "time": "2025-09-24T09:00:00.000-04:00", "end_time": "2025-09-24T10:00:00.000-04:00" },
    { "time": "2025-09-24T10:00:00.000-04:00", "end_time": "2025-09-24T11:00:00.000-04:00" }
  ]
}
Enter fullscreen mode Exit fullscreen mode

That one change ended the “phantom slot” problem for good.

Time Zones That Don’t Betray You

Daylight savings wrecked my calendar at least once a year. An appointment at 9:30 would suddenly appear at 10:30.

Synchronizer gives everything in UTC (2025-09-14T09:30:00Z). I store UTC internally and render local time at the edge. Problem solved.

Guardrails With Postman

Even with Synchronizer, I wanted guardrails. Postman became my safety net:

pm.test("Appointment has start and end in UTC", function () {
  const json = pm.response.json();
  pm.expect(json.start).to.include("Z");
  pm.expect(json.end).to.include("Z");
  pm.expect(new Date(json.end) > new Date(json.start)).to.be.true;
});

pm.test("Appointment is confirmed", function () {
  var jsonData = pm.response.json();
  pm.expect(jsonData.data).to.have.property('confirmed');
  pm.expect(jsonData.data.confirmed).to.be.true;
});
Enter fullscreen mode Exit fullscreen mode

Instead of me discovering broken data on a Friday afternoon, Postman tells me in seconds.

Give it a try. I’m here for it.

  • Status codes with mystery numbers
  • Webhooks that update in real time
  • Slots that look real but aren’t
  • Time zones that shift under you

For anyone who’d rather skip boilerplate and see it live, check out the Synchronizer GitHub quickstart.

It shows how to set up Postman collections and normalize responses right out of the box.

Check out the Synchronizer GitHub quickstart

Top comments (0)