Errors

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: false as a failure. The message in error names the problem.
  • A response can have code: true and still carry a warning in description. For example, a parameter the endpoint does not accept returns Note 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

StatusMeaningWhat to do
400The 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.
401The API key or bearer token was not accepted.See Authentication and the Invalid Credentials entry below.
403The key is valid but cannot reach that subdomain, location or endpoint.Find your cause under Authentication and access below.
404The 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.
429Too many requests for this API key.Sleep and retry. See Rate limiting.
500A 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, 504NexHealth 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 Authorization header did not hold the API key by itself. This endpoint takes the raw key, with no Bearer prefix. A bearer token is not accepted here. API keys do not expire. Only bearer tokens do.
  • Fix: Send Authorization: YOUR_API_KEY on /authenticates and Authorization: Bearer TOKEN everywhere 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-Agent such as Python-urllib. Cloudflare blocks it before the request reaches the API, so it never shows in NexHealth's logs.
  • Fix: Send a User-Agent header that names your app, such as YourApp/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 /authenticates again 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_subscriptions and PATCH /appointments/{id}. subdomain or location_id was sent in the request body instead of the query string. Fix: Put subdomain and location_id in 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_schedules and /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 from GET /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. 123 is 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 /patients returns patients from every location on that server unless you say otherwise.
  • Fix: Send location_strict=true on GET /patients. Check location_ids on GET /patients/{id}.

Data source must exist on POST /patients/{id}/alerts

  • Cause: The patient exists only in NexHealth. Their foreign_id is null and foreign_id_type is nex.
  • 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_slots again 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_id you book with. Check the working hours. Send Nex-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_id to GET /available_slots and POST /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_id ends 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 /appointments and unavailable: 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_id is null. Either the write has not landed, or the sync is down.
  • Fix: Wait for appointment_insertion.complete, then send the PATCH. Check GET /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 /providers with that location_id and 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_id inside the working_hour object. operatory_ids is not a parameter. One record covers one operatory.
  • Fix: Send a single operatory_id inside working_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)

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 id from GET /payment_types for the same location_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 id from GET /adjustment_types for the same location_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 id from GET /locations, with a key for the right environment.

Resource not found on any endpoint

  • Cause: The Nex-Api-Version header is missing.
  • Fix: Send Nex-Api-Version: v3.0.0 on 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_since windows short on large reads and sort by updated_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} with include[], or cache appointment types and join on appointment_type_id.

Note that following parameters are ignored: location_id. in description on GET /patients/{id}

  • Cause: location_id is not a parameter on this endpoint.
  • Fix: Read location_ids in 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=false and non_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_insertion and tell the patient the booking is pending until it fires.

POST /insurance_plans returns 201 but the plan never appears

  • Cause: The plan_name is 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_id from GET /payment_types for that location. Subscribe to payment_created to 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_status shows read_status or write_status as red. 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 2xx right away and do the work after. Reactivate the endpoint, then set each subscription back to active: 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.