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 id from GET /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 subdomain has 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_since with a date before the practice went live.

GET /appointments fails without dates

  • Cause: start and end are 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} with include[], or cache appointment types and join on appointment_type_id.

Patients from other offices show up

  • Cause: Several locations share one health record system server, and GET /patients searches the whole server unless you say otherwise.
  • Fix: Send location_strict=true. Read location_ids on GET /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_since windows on a big practice are the usual reason.
  • Fix: Keep updated_since windows short, sort by updated_at and 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_status on GET /sync_status is red.
  • Fix: Check read_status_at on GET /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 stays red.

You missed changes between runs

  • Cause: updated_since was 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_since returns 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 2xx in 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 id and updated_at, and skip an event you have already applied.

Webhooks stopped

  • Cause: NexHealth deactivated your endpoint because it answered with codes other than 2xx too 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 to active: true as 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=true and drop records with deleted_at set. Subscribe to charge_deleted, payment_deleted, adjustment_deleted and claim_deleted.

A patient you stored is gone

  • Cause: It was a new_patient placeholder 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: true records as temporary. Subscribe to patient_created and patient_updated so your copy follows the change.

Appointments disappeared

  • Cause: There is no appointment_deleted event. The office cancelled them, or they moved outside the window you load.
  • Fix: Load with cancelled left unset so cancelled appointments come back, and store cancelled and cancelled_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 subdomain and location_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.


Did this page help you?