Skip to content

API Consumer Guide

This guide provides everything you need to integrate with the Ascend Public API.


Sample Applications

Sample applications can be found here.


Rate Limiting

Rate-limited endpoints include a Rate-Limiting-Remaining response header indicating how many requests remain before a 429 Too Many Requests error is triggered. If the limit is exceeded, the response will also include a Retry-After header specifying when it is safe to make another call. It is the responsibility of the calling application to monitor these headers and implement self-throttling logic accordingly. This approach helps avoid unnecessary rate-limited errors while still enabling near real-time processing. Please note that rate limits will change dynamically based on server volatility; therefore, your code must adapt in real time based on the response headers to remain functional.


Versioning

Beta endpoints are not versioned. They are typically not safe to use in any production environment. The data formats are subject to change at any time.

Once an endpoint has been versioned, the Dentrix Ascend team will try to keep that version working even if we make a breaking change. This will not always be possible in the beginning of the project.

The API is a separate code base from the core product. Versioned endpoints are treated as stable integration contracts whenever possible.

Endpoints will only be versioned if there are clear breaking changes for clients. Changing how a domain model's data is organized is probably a breaking change.

Adding new fields to a domain model is typically not a breaking change. Your client code that uses the Ascend API should follow the tolerant reader pattern. As new fields are added to API domain models, your client code should be able to handle and ignore fields that your code doesn't know about.


Security

The Ascend API uses the standard OAuth2 client credentials flow. We will give you a client_id and a client_secret. Always make sure that your credentials are never compromised.

Never expose your client_id and client_secret in a browser, iOS, or Android application. If you need to access the Ascend API directly from a browser, iOS, or Android application, use a secure backend server application to fetch an OAuth token and pass the OAuth access token to your browser, iOS, or Android application. If or when your access token expires after an hour, use your secure backend application to renegotiate a new access token.

To use the API, fetch an access token with a request like this:

POST https://test.hs1api.com/oauth/client_credential/accesstoken?grant_type=client_credentials

Body should be of type "x-www-form-urlencoded" with key value pairs of:
  client_id: your_client_id
  client_secret: your_client_secret

Headers:
  Content-Type: application/x-www-form-urlencoded

You can also fetch an access token using the curl command like this:

curl --data "grant_type=client_credentials&client_id=xxx&client_secret=xxx" https://test.hs1api.com/oauth/client_credential/accesstoken?grant_type=client_credentials

If successful, you will receive a 200 status response code and a body that looks like this:

{
  "access_token": "rldbHIMMk9NXGVvWXh0023klkdZP",
  "expires_in": "3599",
  "token_type": "Bearer"
}

The access_token you receive will be good for 1 hour. It can be used to access all Ascend dental organizations that you have been granted access to.

You must always pass the access token to all API requests as a header that looks like this:

Authorization: Bearer access_token

A dental organization is a dental company. A dental organization can have 1 to many locations. A location is normally a physical dental office.

You always need to pass an Organization-ID header for each request made to the API. Ascend will verify that your client_id has access to the requested Organization-ID with the access_token.


HTTP API Requests

The Ascend API follows normal REST API conventions. You always need to pass a header named Organization-ID for each request.

Base URL: The Public API base URL includes /api. For example: https://test.hs1api.com/ascend-gateway/api (Sandbox) and https://prod.hs1api.com/ascend-gateway/api (Production). All versioned paths are relative to this base (e.g. /v1/patients → …/api/v1/patients).

You can quickly see which OrgMapper organizations your client_id has access to by calling OrgMapper’s LinkedOrgs endpoint with the same Bearer token you use for Public API requests:

GET https://test.hs1api.com/orgmapper/LinkedOrgs

(Production: https://prod.hs1api.com/orgmapper/LinkedOrgs.)

OrgMapper returns plain JSON (not the Ascend Public API statusCode / data envelope):

{
  "organizations": [
    "5xxxxxxxxxxxxxxxxxxxxxxx0f",
    "5xxxxxxxxxxxxxxxxxxxxxx66"
  ]
}

These strings are OrgMapper organization identifiers you can use together with your credentials (for example when choosing an Organization-ID context where applicable). This operation is documented alongside the Public API in Redocly for convenience; it is served by OrgMapper, not by the Public API application process.

Like a normal REST API, the Ascend API exposes single model GET endpoints and bulk GET endpoints that return multiple models.

A single GET request follows the pattern of /v1/patients/123 where 123 is the id of the patient.

To make a bulk GET request for multiple models, just omit the id at the end of the URL (123 above).


GET Requests

All GET requests can accept a responseFields parameter.

responseFields

All GET requests can take an optional responseFields parameter in the URL. The responseFields is a comma-delimited string of field names that you want to fetch.

GET /v1/patients/123?responseFields=firstName,lastName

The response body will look like this:

{
  "statusCode": 200,
  "data": {
    "type": "PatientV1",
    "id": "123",
    "firstName": "Ari",
    "lastName": "Stone"
  }
}

The API will always return the id and type fields plus all the other fields specified in the responseFields parameter.


Bulk GET Requests

If you are fetching multiple objects in a GET request, the following URL parameters are normally available.

filter

Most bulk GET endpoints can take a filter parameter to specify what data you want.

GET /v1/patients?filter=firstName==Bobby
{
  "statusCode": 200,
  "data": [
    {
      "type": "PatientV1",
      "firstName": "Bobby"
    }
  ],
  "meta": {
    "pagination": {
      "limit": 100,
      "offset": 0,
      "total": 8
    }
  }
}

We will only return patients with firstName == Bobby.

The meta result includes a total of 8 - meaning there were 8 patients found with this filter of firstName==Bobby.

Filter Operators

OperatorDescription
==equals
!=not equals
>greater than
>=greater than or equals
<less than
<=less than or equals
->contains
~=partial match (LIKE / contains substring)
<>=not partial match (NOT LIKE)

Example of contains:

GET /v1/patients?filter=id->[123, 456]

This will return the patients with the ids of 123 and 456.

You can add multiple filters to a single bulk GET request:

GET /v1/patients?filter=firstName~=Ba,lastName~=Wo

pageSize and lastId

By default, the API will return the first 100 models. Bulk GET requests include a meta response that includes the limit, offset and total fields. The total field is how many possible models that exist in the API at the time you made the request. If no lastModified date is supplied, the API will add a default one. It is highly recommended that you supply your own for predictable behavior.

You can page through sets of models by passing in a lastId parameter and a filter of some sort will be required going forward.

Pretend that you fetched 100 patients and the last patient's id in the set was 12345.

GET /v1/patients?filter=lastModified>2000-01-01

You could fetch the next set of 100 patients with this request:

GET /v1/patients?lastId=12345&filter=lastModified>2000-01-01

You can page through huge sets of data using the lastId parameter. Please avoid doing this very often. If you need a data sync, use StreamAPI webhooks (SNS) described below.

You can combine the parameters responseField, filter, pageSize and lastId together for requests:

GET /v1/patients?lastId=123,filter=lastName~=Wo,lastModified>2000-01-01,responseFields=firstName,lastName

Future re-syncs would utilize the lastModified date of the last record.


POST, PUT Requests

POST and PUT requests follow normal REST API conventions for the most part.

POST and PUT response bodies contain fields that have been updated.

For example, if you update a patient's firstName to "Bob" and the value was already "Bob" you will not see the firstName in the response payload because the value did not change.

If you want to manually clear out a field, you must pass in the value of null. Example of a PUT body to set a title field to null:

{ "title": null }

Setting fields to null only works if the field is nullable.


Data Sync / StreamAPI Webhooks

Many customers only need a data sync between Dentrix Ascend and their own application. In all of these cases, do NOT use the bulk GET requests in the API to keep your application in sync with Ascend.

In some situations, customers need to know what data has been deleted in Ascend. Ascend typically does not retain deleted data. In situations like this, customers would need to fetch the entire set of data in Ascend and compare their own local copies of the data to see what has been deleted. This is very harmful to the Ascend product and should not be done. If customers need to synchronize data changes, they should use StreamAPI webhooks. Webhooks let you know if something has been deleted in around 1 second.

StreamAPI webhooks push a notification whenever a create, update, or delete has happened in the API. Notifications are delivered over Amazon SNS as an HTTP POST to your HTTPS endpoint. Often messages arrive in less than a second.

Customers can receive updates for a subset of domain models they care about. Filter incoming SNS messages with MessageAttributes.RoutingKey (organization, location, entity type, and operation).

Register your webhook URL with a support ticket. AWS SNS then sends a SubscriptionConfirmation that you must confirm, or you will not receive events. Verify the SNS signature and treat deliveries as at-least-once (use MessageId for idempotency).

RabbitMQ deprecation: RabbitMQ (AMQP/STOMP) is no longer the consumer connection path and will end on 9/27/2026. Migrate remaining listeners to SNS webhooks by that date.

The best place to start is the webhook setup guide: Creating and Setting Up Webhooks for the StreamAPI


StreamAPI Availability

There are 2 paths where data can be mutated (create, update, delete) in Ascend. The core application (what you see in a browser) and this API.

Many mutations in the core application (what you see in a browser) spawn StreamAPI webhook events but not all. If you find a critical mutation in the core application that does not spawn a StreamAPI event let us know and we can probably hook it up.


Dentrix Ascend API Security Best Practices

API keys, shared secrets or other forms of API authentication such as Username and Password authentication should be protected by following these guidelines:

  • Only trusted and authorized users may configure or set up the connection with authentication secrets and keys. Make sure they do not inappropriately or insecurely store that credential anywhere but in an unencrypted location. (Ex: hand written notes, photos, or online notes, DropBox etc.)

  • Maintain least privilege access to the machine that acts as the API consumer and the device or machine that holds a copy of the secrets or credentials or certificates or keys. We will refer to these types of secrets and credentials generally as "keys" for the purpose of this document.

  • Any personal computer or user level machine with API access to Ascend must follow the principles of least privilege and least number of users, and it is strongly recommended to limit the number of machines and users with access to API capability and API keys.

  • Machines accessing the API should do so from a protected corporate network where possible. It is not recommended to make API connections from machines on home or public networks. Configure API machines in such a way as to be able to audit the users who have access and be able to record and show who did what with the API and API config files and when. (App logs, Machine & User logs etc.)

  • Encrypt all API keys, secrets and passwords while not in use. (To achieve maximum protection, it is recommended by NIST to xOR-split and then encrypt the two pieces of a key. See Wikipedia for key splitting.) Control access to the key that encrypts the API keys and secrets and limit access to it. If that is the password to a password manager database then limit access and knowledge of the key to unlock any such key storage or encrypted configuration.

  • Back up key encryption keys to safe locations following the patterns of least privilege and encryption at rest and resiliency.

  • Keep API keys and credentials logically and physically separated from other user access on any given machine in which they reside. For example do not store API keys in a part of a drive where users without specific privileges assigned can access them. Ideally, only the service or process that initializes the API activity should have sufficient privileges to read the configuration and, at least temporarily, the admin user who installed the configuration containing the key or credential.

  • Never provide your API credential or key to another party or over the phone, or by email etc., regardless of who is asking.

  • All keys or Patient and/or sensitive Data should be encrypted in such a way as to meet HIPAA standards which typically means the latest safe and validated implementation of properly configured and coded Advanced Encryption Standard.