Troubleshooting data pipelines
What goes wrong when you copy practice data, and the fix for each.
Read the response body first. A failed request has code: false and the message in error. A successful one can still carry a warning in description.
Loading
Location with id 123 not found on any list endpoint
- Cause: You sent the institution ID instead of the location ID, your key cannot reach that location, or the location was deactivated.
- Fix: Use a location
idfromGET /locations, with a key for the right environment. Institutions and locations have separate IDs.
You don't have access to perform this action. on every call for one subdomain
- Cause: The
subdomainhas capital letters, or it was sent in the body instead of the query string, or your key is for the other environment. Subdomains are checked for case. - Fix: Send the subdomain in lower case, exactly as the Developer Portal shows it, in the URL.
A list call fails with no filter on GET /charges, GET /payments, GET /adjustments or GET /guarantor_balances
- Cause: These endpoints need at least one filter.
- Fix: For a full load, send
updated_sincewith a date before the practice went live.
GET /appointments fails without dates
- Cause:
startandendare required. The endpoint returns appointments starting inside the window. - Fix: Load one date range at a time and pass both.
Note that following parameters are ignored: include. in description on GET /appointments
- Cause:
include[]is not supported on the list endpoint. The request still succeeds, without the included records. - Fix: Use
GET /appointments/{id}withinclude[], or cache appointment types and join onappointment_type_id.
Patients from other offices show up
- Cause: Several locations share one health record system server, and
GET /patientssearches the whole server unless you say otherwise. - Fix: Send
location_strict=true. Readlocation_idsonGET /patients/{id}to see where a patient belongs.
You've exceeded our rate limit. Please wait and retry. with 429
- Cause: Too many requests for the API key. The limit covers every location the key reaches, so a parallel load across locations hits it first. Each key gets 1,000 requests a minute on the patients and appointments endpoints and 2,000 a minute on the others.
- Fix: Spread calls over 10 to 60 seconds. Queue and retry with backoff. Ask for 1,000 records a page. Use webhooks instead of polling.
Gateway Time-out with 503 or 504
- Cause: NexHealth did not answer in time. Large
updated_sincewindows on a big practice are the usual reason. - Fix: Keep
updated_sincewindows short, sort byupdated_atand retry with backoff.
Keeping current
Records are missing or stale
- Cause: The sync has not read the change yet. NexHealth reads on-premises systems every 10 to 15 minutes, and gaps are longer overnight and on weekends. Or the sync is down:
read_statusonGET /sync_statusisred. - Fix: Check
read_status_atonGET /sync_status. A gap of up to 20 minutes during office hours is normal. On an on-premises system, a long gap means the office server is off or the NexHealthSync service has stopped. Ask the office to check it, and email [email protected] if it staysred.
You missed changes between runs
- Cause:
updated_sincewas set to the exact end of the last run, and a record that changed at the same second fell through. - Fix: Overlap by a few minutes.
updated_sincereturns records updated at or after the time you send, so an overlap returns a few records twice and misses none.
The same webhook event arrived twice
- Cause: Your endpoint did not answer with a
2xxin time, so NexHealth sent the event again. Payloads carry no event ID. - Fix: Answer right away and do the work after. Store each record's
idandupdated_at, and skip an event you have already applied.
Webhooks stopped
- Cause: NexHealth deactivated your endpoint because it answered with codes other than
2xxtoo many times. You get an email when that happens. Its subscriptions stay inactive after you turn the endpoint back on. - Fix: Set the endpoint back to
active: true, then set each subscription back toactive: trueas well. See Setting up webhooks.
Deleted records are still in your copy
- Cause: Charges, payments and adjustments leave the list when the office deletes them, unless you ask for them.
- Fix: Send
include_deleted=trueand drop records withdeleted_atset. Subscribe tocharge_deleted,payment_deleted,adjustment_deletedandclaim_deleted.
A patient you stored is gone
- Cause: It was a
new_patientplaceholder from an API booking. When the office created the real record and NexHealth read it, NexHealth linked the records and deleted the placeholder. - Fix: Treat
new_patient: truerecords as temporary. Subscribe topatient_createdandpatient_updatedso your copy follows the change.
Appointments disappeared
- Cause: There is no
appointment_deletedevent. The office cancelled them, or they moved outside the window you load. - Fix: Load with
cancelledleft unset so cancelled appointments come back, and storecancelledandcancelled_at.
Ledger data stops at a date
- Cause: Financial data was turned on for the key recently and the ledger backfill, which takes up to a day, is still running. Or financial data is not turned on for your production key at all.
- Fix: Wait a day. If it is still missing, email [email protected] with the
subdomainandlocation_id.
Still stuck
Email [email protected] with the request, the full response body, the subdomain, the location_id and the time of the call in UTC. Every message the API returns is in the Errors reference.
Updated about 1 hour ago