How to Set Up EHR Integration APIs That Actually Sync Patient Data
April 18, 2026 · Claire Whitfield

From the team at Formisoft, the HIPAA-ready platform for patient intake, scheduling, and payments. Learn more →
Your front desk platform collects patient intake data. Your EHR stores clinical records. If those systems don't talk to each other, someone on your staff manually keys data from one to the other. That's not automation. That's just digitized paperwork.
Real EHR integration APIs setup means bidirectional data flow: patient demographics, appointments, insurance details, and intake responses move between systems without manual intervention. Here's how to build that connection correctly.
What EHR Integration Actually Means
EHR integration isn't a single API call. It's a set of connections that handle different data types:
- Patient demographics sync: name, DOB, contact info, MRN
- Appointment scheduling: create, update, cancel appointments in both systems
- Insurance verification: pull eligibility data, push verification status
- Clinical data exchange: intake responses, vitals, chief complaints
- Document transfer: consent forms, intake PDFs, signed documents
Each integration point requires its own endpoint, authentication method, and error handling. Most EHRs expose these through HL7 v2, FHIR APIs, or vendor-specific REST endpoints.
HL7 vs. FHIR: Which Standard to Use
HL7 v2 has been the clinical data exchange standard since the 1980s. It's pipe-delimited, verbose, and extremely reliable. If your EHR is more than five years old, it probably speaks HL7 v2 by default.
FHIR (Fast Healthcare Interoperability Resources) is the newer standard. It uses JSON or XML, follows RESTful conventions, and maps cleanly to modern web APIs. It's easier to work with but not universally supported yet.
For patient demographics and appointments, FHIR is cleaner:
{
"resourceType": "Patient",
"id": "12345",
"identifier": [{
"system": "urn:oid:2.16.840.1.113883.4.1",
"value": "123-45-6789"
}],
"name": [{
"use": "official",
"family": "Smith",
"given": ["John"]
}],
"telecom": [{
"system": "phone",
"value": "555-0123"
}]
}
The equivalent HL7 v2 ADT message is twelve lines of pipes and carets. FHIR wins on readability. HL7 v2 wins on adoption. Use whichever your EHR vendor supports.
Authentication and Security Requirements
Every EHR integration must comply with HIPAA's Technical Safeguards (45 CFR § 164.312). That means:
- OAuth 2.0 or SMART on FHIR for API authentication
- TLS 1.2 or higher for data in transit
- Audit logs for every API call that touches PHI
- Role-based access control to limit which users can trigger syncs
Some EHRs still use basic auth or API keys. That's not compliant. Push for OAuth or certificate-based authentication. Your BAA with the EHR vendor should explicitly cover API access.
Real-Time Sync vs. Scheduled Batch Jobs
You have two options for data sync timing:
Webhooks push data immediately when an event occurs. When a patient completes intake in Formisoft, a webhook fires and sends that data to your EHR in seconds. This works well for appointment scheduling and new patient registration.
Scheduled batch jobs pull or push data on a fixed interval (every 15 minutes, hourly, nightly). This works for insurance verification or non-urgent document transfers.
Real-time sync reduces manual work but increases API load. Batch jobs reduce server overhead but introduce lag. For front desk workflows, webhooks usually win.
Mapping Data Fields Between Systems
Your intake form asks for "Emergency Contact." Your EHR expects "Responsible Party." The API integration needs to map those fields correctly.
This is where most integrations break. Field mapping isn't automatic. You need a translation layer:
// Example field mapping
Const mapIntakeToEHR = (intakeData) => {
return {
patient: {
firstName: intakeData.first_name,
lastName: intakeData.last_name,
dob: formatDate(intakeData.date_of_birth),
mrn: intakeData.chart_number || null
},
insurance: {
carrier: intakeData.insurance_company,
memberId: intakeData.insurance_id,
groupNumber: intakeData.group_number
},
emergencyContact: {
name: intakeData.emergency_contact_name,
phone: intakeData.emergency_contact_phone,
relationship: intakeData.emergency_contact_relationship
}
};
};
Document every field mapping. When your EHR vendor updates their API schema, your mappings break. Version control this code.
Handling Duplicate Records and Merge Conflicts
What happens when a patient exists in your EHR but not in your front desk system? Or vice versa? You need a merge strategy.
Most practices use MRN (Medical Record Number) as the single source of truth. If your intake system collects MRN, use that to match existing patients. If the patient doesn't provide an MRN, search by DOB + last name + first initial.
When conflicts occur (same name, different DOB), flag for manual review. Do not auto-merge. Merging the wrong patient records is a HIPAA violation and a clinical safety risk.
Error Handling and Retry Logic
APIs fail. Network requests time out. EHR servers go down for maintenance. Your integration must handle this gracefully.
Implement exponential backoff for retries:
Const syncWithRetry = async (data, maxRetries = 3) => {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await ehrAPI.post('/patients', data);
return response;
} catch (error) {
if (i === maxRetries - 1) throw error;
await sleep(Math.pow(2, i) * 1000); // 1s, 2s, 4s
}
}
};
Log every failed sync attempt. Store failed payloads in a dead letter queue so staff can manually retry them. Never silently drop patient data.
Testing Your Integration Before Going Live
Don't test EHR integrations in production. Use a sandbox environment or test EHR instance.
Create test cases for:
- New patient registration
- Existing patient update
- Appointment creation and cancellation
- Insurance verification lookup
- Document upload and retrieval
- Duplicate patient detection
Run these tests weekly. EHR vendors change their APIs without warning. Your integration that worked last month might return 500 errors today.
Monitoring and Maintenance
Once your EHR integration APIs are live, monitor:
- Sync success rate: percentage of successful API calls
- Average sync latency: time from intake submission to EHR update
- Failed sync queue depth: how many payloads are awaiting retry
- API rate limit usage: are you approaching vendor throttling limits?
Set alerts for sync failures. If your success rate drops below 95%, something's broken. Don't wait for staff to notice missing data.
When to Build vs. Buy
Building a custom EHR integration takes 40-80 hours of development time. Factor in ongoing maintenance, API version updates, and debugging.
If your EHR has a published API and your practice has engineering resources, build it. If not, use a platform like Formisoft that handles the integration layer for you. Our webhook system and workflow automation connect to most major EHRs without custom code.
Your front desk staff shouldn't wait for engineering sprints to get intake data into the EHR. Set up the integration once, test it thoroughly, and let it run.