Most clinics and medspas run two systems that never talk to each other. The CRM — whether that's HubSpot, GoHighLevel, or a shared spreadsheet — holds the leads: people who filled out a form, called in, or messaged on Instagram. DrChrono holds the patients: people who have actually booked and shown up.
The gap between those two systems is where revenue leaks. A lead submits a contact form. Someone follows up. The lead agrees to book. Someone manually enters them into DrChrono. Or no one does. Or they get entered twice, without the original lead source attached. By the time you sit down to ask "where are our new patients coming from?" the data is too dirty to trust.
Closing that gap isn't complicated, but it requires building the connection intentionally. Here's how we approach it.
What the Funnel Actually Looks Like
Before wiring anything, it's worth being precise about the stages a prospective patient moves through. In a medspa or cash-pay clinic context, the funnel typically looks like this:
- Inquiry — someone fills out a form, calls, or DMs. They exist in your CRM or in your inbox, not in DrChrono.
- Contact made — your team has spoken with or texted the lead. A consultation might be proposed.
- Appointment scheduled — the lead books. At this point, they need to exist in DrChrono as a patient with an appointment.
- Checked in / showed — the patient arrived. DrChrono records this as an appointment status change.
- Converted — they completed the visit and may have purchased a treatment or made a follow-up booking.
The handoff between step 2 and step 3 is where most practices have a manual gap. We want that gap to close automatically.
Where DrChrono Fits In
DrChrono is the system of record for everything clinical: patient demographics, appointments, clinical notes, and billing. The CRM is the system of record for lead activity: contact history, source attribution, follow-up sequences.
The right model is not to pick one as the master — it's to define what each system owns and build a two-way connection:
- CRM → DrChrono: when a lead converts to a booking, create or update the patient in DrChrono and schedule the appointment.
- DrChrono → CRM: when an appointment is completed, cancelled, or no-showed, push that status back to the CRM contact record.
That second direction is often skipped. Without it, your CRM shows every lead as perpetually "pending" and you lose the ability to trigger re-engagement campaigns based on actual appointment outcomes.
Creating the Patient and Appointment via API
The DrChrono API gives us the building blocks we need:
POST /api/patients— creates a patient record from demographics. At minimum: first name, last name, email, date of birth, and the doctor ID.POST /api/appointments— books the appointment. Requires the patient ID (from the step above), a doctor, an exam room, a scheduled time, and an appointment profile (which maps to visit type and duration).
When a lead books through your CRM workflow — via an intake form, a scheduler link, or a coordinator marking them as confirmed — our integration fires both calls in sequence. If the patient already exists in DrChrono (same email), we look them up with GET /api/patients?email=... and use the existing patient ID rather than creating a duplicate.
Deduplication is the first place these integrations go wrong in production. Always query by email before creating. If you get multiple matches, fall back to a manual review queue rather than creating yet another duplicate.
What to Write to the Patient Record
Beyond the required fields, a few optional fields pay dividends later:
referring_source— DrChrono supports free-text referring source on the patient record. We write the CRM lead source here (e.g., "Meta Ad – June Botox Campaign") so it survives even if the CRM data is later modified.patient_flags— a text field we use to flag first-visit vs. returning patient, since DrChrono doesn't have a native new-patient indicator that surfaces cleanly in reporting.- Custom demographic fields — if your DrChrono plan includes custom patient fields, this is where to record the CRM contact ID so you can always look the other direction.
Pushing Appointment Outcomes Back to the CRM
This is the part most teams don't build, and it's where the funnel closes.
After each appointment, we poll GET /api/appointments filtered by date and doctor. We check the status field — DrChrono uses values like Complete, No Show, Cancelled — and push those outcomes back to the corresponding CRM contact.
In HubSpot, that means updating a contact property. In GoHighLevel, it means tagging the contact or updating a custom field that triggers the next automation. The exact mechanism depends on your CRM's API, but the pattern is the same: DrChrono is the source, the CRM is the destination, and status changes flow nightly (or in near-real-time via webhook if your setup supports it).
With this in place, your CRM re-engagement sequences finally work correctly. A no-show can trigger a "We missed you" text. A completed first visit can trigger a review request. A cancellation can re-open the lead for follow-up. None of that is possible if the CRM doesn't know what happened after the booking.
What You Learn When the Funnel Is Closed
Once both directions are wired, you can answer questions that were previously impossible to answer accurately:
- Lead-to-booking rate by source — of the inquiries that came from Meta ads vs. Google vs. organic search, what percentage actually booked?
- Booking-to-show rate — how many booked appointments resulted in a completed visit, and does that vary by lead source or appointment type?
- Time to book — how many days on average between first contact and appointment scheduled? Are some lead sources faster than others?
- Revenue per lead source — if you're writing appointment charges back to the CRM or pulling from your billing data, you can close the loop all the way to revenue.
These aren't vanity metrics. They're the numbers that tell you where to spend your next marketing dollar and whether your follow-up process is working.
Building This Without Disrupting What's Already Working
Practices that come to us with this problem are rarely starting from zero. There's usually an existing CRM workflow, an existing intake process, and a front desk team that has its own habits. The integration has to fit around those habits rather than replace them.
In practice, that means:
- Fallback to manual — if the API call to create the patient fails (e.g., a required field is missing), the system should alert the coordinator and let them complete it manually. Silently dropping the booking is far worse than a notification.
- Dry-run mode — before going live, run the integration against a test DrChrono account and verify that patients and appointments look exactly right before touching production data.
- Audit log — every API call in should be logged with the CRM contact ID, the DrChrono patient ID it resolved to, and the result. When something goes wrong (and it will), you need to trace it.
The DrChrono apps we've built for clinics follow this same pattern — a thin integration layer that talks to the EHR's API, handles the edge cases, and leaves the staff workflow largely intact.
The Payoff
When the CRM and DrChrono are connected properly, the manual work drops and the visibility goes up. Your coordinators aren't re-entering patients. Your reporting reflects reality. Your re-engagement sequences fire on actual appointment outcomes rather than guesses.
If you're currently managing this gap manually — or if you've tried to build it and ran into the deduplication or write-back edge cases — reach out and describe your setup. We'll walk through the integration approach, the API calls involved, and what it would take to close your funnel.