Every error message, what causes it and the fix.
Read the response body first
Every response has the same shape. code tells you whether the request worked.
{
"code": false,
"description": null,
"data": null,
"error": ["You don't have access to perform this action."]
}- Treat
code: falseas a failure. The message inerrornames the problem. - A response can have
code: trueand still carry a warning indescription. For example, a parameter the endpoint does not accept returnsNote that following parameters are ignored: location_id.and the request still succeeds. Read it as a warning and fix the request.
For the HTTP methods and the status codes of a successful request, see Response codes.
What each status means
| Status | Meaning | What to do |
|---|---|---|
400 | The request is not valid. A field is missing, a value is wrong, or the record is not in a state that allows the change. | Find the message below and apply the fix. |
401 | The API key or bearer token was not accepted. | See Authentication and the Invalid Credentials entry below. |
403 | The key is valid but cannot reach that subdomain, location or endpoint. | Find your cause under Authentication and access below. |
404 | The record does not exist for that key, subdomain or location, or the request is missing the version header. | Check the ID, the subdomain, the location_id and the Nex-Api-Version header. |
429 | Too many requests for this API key. | Sleep and retry. See Rate limiting. |
500 | A problem on NexHealth's side, or a request NexHealth could not handle. | Check status.nexhealth.com. Retry. After a failed create, read the record back before you send it again. |
503, 504 | NexHealth did not answer in time. | Retry with backoff. |
Every error message
The causes and fixes below come from the API support tickets. Messages are grouped by what you were doing.
Authentication and access
Invalid Credentials on POST /authenticates
- Cause: The
Authorizationheader did not hold the API key by itself. This endpoint takes the raw key, with noBearerprefix. A bearer token is not accepted here. API keys do not expire. Only bearer tokens do. - Fix: Send
Authorization: YOUR_API_KEYon/authenticatesandAuthorization: Bearer TOKENeverywhere else. If it still fails, rotate the key in the Developer Portal.
403 with Error code: 1010 and Server: cloudflare on any endpoint
- Cause: Your HTTP client sent a default
User-Agentsuch asPython-urllib. Cloudflare blocks it before the request reaches the API, so it never shows in NexHealth's logs. - Fix: Send a
User-Agentheader that names your app, such asYourApp/1.0.
You don't have access to perform this action.
One message, nine causes. Check them in this order.
- Expired token, on any endpoint. A token lasts 1 hour in production and 24 hours in the sandbox. Fix: Call
POST /authenticatesagain and retry. - Wrong environment, on any endpoint. A sandbox key was used on a production subdomain, or a production key on your demo practice. Fix: Use the key for that environment. The Test mode toggle in the Developer Portal shows which institutions each key reaches.
- Capital letters in the subdomain, on any endpoint. Subdomains are checked for case. Fix: Send the subdomain exactly as the Developer Portal shows it, in lower case.
- Scope in the body, on
POST /webhook_endpoints/{id}/webhook_subscriptionsandPATCH /appointments/{id}.subdomainorlocation_idwas sent in the request body instead of the query string. Fix: Putsubdomainandlocation_idin the URL. - Location still Pending, on every endpoint for one location. The location is still Pending in the Developer Portal. NexHealth prepares the sync and reads the practice's history first. Access opens when the location turns Active. Fix: Wait for the install to finish. If the errors continue after that, rotate your API key.
- Access removed, on every endpoint for a location you had before. The practice or your own team removed your access to that location. Webhook events for it stop too. Fix: Ask the practice to grant access again. Nothing in the request needs to change.
- Financial endpoints not enabled, on
/charges,/claims,/payments,/fee_schedulesand/insurance_plans. They are not enabled for your production key. They start enabled for sandbox locations only. Fix: Email [email protected]. The ledger backfill takes up to a day. - Conversations not supported, on
POST /conversations/{id}/messages. The endpoint is not supported. Fix: Send messages through your own SMS provider with the phone number fromGET /patients. - Production key needs an administrator, in the Developer Portal when creating a production key. Only administrators of your API organization can create or rotate production keys. Fix: Ask your organization's administrator.
Patients
A patient with that information already exists -id=123 on POST /patients
- Cause: A patient with the same date of birth, name and phone number exists in NexHealth or in the health record system.
123is their ID. - Fix: Use that patient. Let office staff confirm the match. See Patients quickstart.
Patient with id 123 not found on POST /appointments
- Cause: The patient was created through the API for one location and their first appointment went to another location.
- Fix: Book the first appointment at the location where you created the patient.
Patient with ID 123 not found in location 456 on POST /payments and POST /appointments
- Cause: The patient belongs to another location on the same server.
GET /patientsreturns patients from every location on that server unless you say otherwise. - Fix: Send
location_strict=trueonGET /patients. Checklocation_idsonGET /patients/{id}.
Data source must exist on POST /patients/{id}/alerts
- Cause: The patient exists only in NexHealth. Their
foreign_idisnullandforeign_id_typeisnex. - Fix: Book the patient's first appointment. That is what writes them into the health record system.
Appointments
Unfortunately this time is no longer available, please go back and choose another time. on POST /appointments
- Cause: The slot was taken between your slots call and your booking.
- Fix: Call
GET /available_slotsagain and offer another time.
Time slot is not during working hours, please choose another time on POST /appointments with v2.2.2
- Cause: The time is outside the provider's working hours, the slots call did not use the same
appointment_type_id, or the appointment spans a synced working hour and a schedulable block. v2.2.2 cannot join those two. v3.0.0 can. - Fix: Query slots with the
appointment_type_idyou book with. Check the working hours. SendNex-Api-Version: v3.0.0.
Provided appointment_type_id was not found to be configured for the requested slot on POST /appointments
- Cause: The slot came from a slots call without
appointment_type_id, so it is not open for that type. - Fix: Pass the same
appointment_type_idtoGET /available_slotsandPOST /appointments.
Cannot create an appointment where the patient attribute new_patient=true on POST /appointments
- Cause: Dentrix and Denticon. A new patient exists only on their first appointment until the office makes them a patient of record. Their
foreign_idends in_np. A second appointment cannot be booked before that. - Fix: Ask the office to convert the patient in the health record system. On Dentrix, you can move the first appointment with
PATCH /appointments/{id}until then.
Cannot create an appointment where the patient belongs to a location from a different EHR on POST /appointments
- Cause: The patient was created through the API for one location and is not in the health record system yet. The first appointment has to go to that location.
- Fix: Book the first appointment at the location where you created the patient.
Missing parameter appt[patient_id] with unavailable: true on POST /appointments
- Cause: The API does not create unavailability blocks.
- Fix: The office blocks the time in the health record system. Read blocks with
GET /appointmentsandunavailable: true.
Cannot update appointment because it is not synced with the PMS and/or a live client on PATCH /appointments/{id}
- Cause: The appointment is not in the health record system yet. Its
foreign_idisnull. Either the write has not landed, or the sync is down. - Fix: Wait for
appointment_insertion.complete, then send thePATCH. CheckGET /sync_status.
Working hours and slots
User with id 123 not found on POST /working_hours (v2.2.2: /availabilities)
- Cause: The provider belongs to a different location.
- Fix: Call
GET /providerswith thatlocation_idand use one of those providers.
Operatory uuid can't be blank on POST /working_hours (v2.2.2: /availabilities)
- Cause: The record needs one
operatory_idinside theworking_hourobject.operatory_idsis not a parameter. One record covers one operatory. - Fix: Send a single
operatory_idinsideworking_hour. Post one record per operatory.
Next available slot not found. Please confirm that the provider has active availabilities. in description on GET /available_slots (v2.2.2: /appointment_slots)
- Cause: The provider has no working hours.
- Fix: Create working hours first. See the Scheduling configuration guide.
Payments and ledger
Payment Type with id 1 not found in location 456 on POST /payments
- Cause: The payment type does not exist at that location.
- Fix: Use an
idfromGET /payment_typesfor the samelocation_id.
Adjustment Type with id 1 not found in location 456 on POST /adjustments
- Cause: The adjustment type does not exist at that location.
- Fix: Use an
idfromGET /adjustment_typesfor the samelocation_id.
Something went wrong. Please try again or contact our support team. on POST /payments
- Cause: The patient is not in the health record system yet.
- Fix: Book an appointment for the patient first, then post the payment.
Locations and versions
Location with id 123 not found on any endpoint with location_id or lids[]
- Cause: You sent the institution ID instead of the location ID, your key cannot reach that location, or the location was deactivated.
- Fix: Use the
idfromGET /locations, with a key for the right environment.
Resource not found on any endpoint
- Cause: The
Nex-Api-Versionheader is missing. - Fix: Send
Nex-Api-Version: v3.0.0on every call.
Rate limit and server errors
You've exceeded our rate limit. Please wait and retry. on any endpoint, status 429
- Cause: Too many requests for the API key. The limit covers every location the key reaches. A short burst can hit it.
- Fix: Spread calls over 10 to 60 seconds. Queue and retry with backoff. Use webhooks instead of polling slots. Cache appointment types instead of reading them on every webhook. See Rate limiting.
Something went wrong. Please try again or contact our support team. on any endpoint, status 500
- Cause: A problem on NexHealth's side.
- Fix: Check status.nexhealth.com. Retry. After a failed create, read the record back before you send it again.
Gateway Time-out on any endpoint, status 503 or 504
- Cause: NexHealth did not answer in time.
- Fix: Retry with backoff. Keep
updated_sincewindows short on large reads and sort byupdated_at.
Warnings on a successful response
Note that following parameters are ignored: include. in description on GET /appointments
- Cause:
include[]is not supported on the list endpoint. - Fix: Use
GET /appointments/{id}withinclude[], or cache appointment types and join onappointment_type_id.
Note that following parameters are ignored: location_id. in description on GET /patients/{id}
- Cause:
location_idis not a parameter on this endpoint. - Fix: Read
location_idsin the response instead.
Failures that come after a successful response
NexHealth writes to the health record system after it answers you. A 201 means NexHealth accepted the request. The write happens next, and these are the ways it fails.
appointment_insertion.failed
- Cause: The health record system rejected the write. Causes seen in tickets: an appointment took the slot during the 10 to 15 minute read cycle; the time is outside the provider's hours in the health record system; the patient is inactive there; the patient's name has characters the system strips; the provider was deleted there; a new patient could not be matched. The reason is not in the payload. Failed writes are not retried.
- Fix: Fix the cause and book again. Search patients with
inactive=falseandnon_patient=false. If the reason is not clear, email [email protected] with the appointment ID. See Troubleshooting appointment writes.
appointment_insertion.timed_out
- Cause: The write could not happen before the start time passed. The sync was down, or no workstation had the NexHealth Chrome extension open. Past appointments are dropped, not written.
- Fix: Check
GET /sync_status, then offer another time.
No insertion webhook, and the appointment keeps foreign_id: null and foreign_id_type: "nex"
- Cause: The record exists only in NexHealth. On an on-premises system the Synchronizer service on the office server may have stopped.
- Fix: Check
GET /sync_status. Ask the office to restart the NexHealthSync service. If that fails, email [email protected].
Writes land hours or days later on Dentrix Ascend or Curve
- Cause: These systems accept writes only while a staff workstation is logged in with the NexHealth Chrome extension. Evenings and weekends wait for the next login.
- Fix: Subscribe to
appointment_insertionand tell the patient the booking is pending until it fires.
POST /insurance_plans returns 201 but the plan never appears
- Cause: The
plan_nameis longer than the health record system allows. Dentrix allows 32 characters. - Fix: Keep plan names under 32 characters.
POST /payments returns 202 but the payment is not on the ledger
- Cause: The payment type is inactive or does not belong to that location.
- Fix: Use a
payment_type_idfromGET /payment_typesfor that location. Subscribe topayment_createdto confirm the write.
GET /available_slots returns no slots
- Cause: No working hours in the window, an appointment type that is not linked to the working hours, a missing operatory, or a slot length that does not fit.
- Fix: See Troubleshooting available slots.
Old data, or writes that wait
- Cause: The sync is down.
GET /sync_statusshowsread_statusorwrite_statusasred. Writes queue and land when the sync returns, except appointments that are in the past by then. - Fix: Check
GET /sync_status. On an on-premises system, ask the office whether the server is on and the NexHealthSync service is running.
An email that says NexHealth deactivated your webhook endpoint because of too many failed response codes
- Cause: Your endpoint answered with codes other than
2xx. NexHealth turned the endpoint off, and its subscriptions stay inactive after you turn it back on. - Fix: Answer every webhook with a
2xxright away and do the work after. Reactivate the endpoint, then set each subscription back toactive: true.
When you are stuck
Email [email protected]. It reaches the API team directly. Include the request, the full response body, the subdomain, the location_id and the time of the call in UTC.