API Implementation

See API Specification


Resources in the URL are lowercase plural. Example: /patients

Resource identifiers are the database primary keys and are specified in the URL instead of as a parameter for individual resources. Example: /patients/421

When creating a resource (POST) or retrieving a list, no identifier is used. Example: /patients

All fields and parameters use Pascal casing, where the first letter is capitalized, and optional other letters are capitalized. This is different than the style of most other REST implementations, but it is far more consistent with our existing codebase and db schema.

Fields can start with lower case whenever they are not standard database fields. See details below, in the Data Types section.

Parameters are listed in this documentation in order of importance instead of db order. Fields returned in JSON files are generally in the same order as in the database.

Some methods do not fall under the normal CRUD paradigm. Here are some examples:


For any method that returns a list of items, you will need to use pagination to get chunks of up to 100 items at a time. Use Limit and Offset. Limit is usually not specified, and it defaults to the hard limit of 100 items for any request. With no Limit or Offset specified, results will include items 0 through 99.

Example usage:
GET /appointments?Offset=400

This will return appointments 400 through 499. The risk of page drift, where another record is added to the database in the middle of a series of requests, is miniscule.

The general strategy you should use is to first perform an ordinary GET without any offset or limit. If your result is exactly 100 rows, then perform sequential GETs with offsets until your result is less than 100 rows. The local API has an increased limit of 1000 items per request.

Date Format

Added in version 22.2.26

For all methods that return a Date of format "yyyy-MM-dd", you have the ability to specify a Date format. Use DateFormatString, which is "yyyy-MM-dd" by default.

Example usage:
GET /procedurelogs?PatNum=52&DateFormatString=MM/dd/yyyy

This will return Dates that have been formatted to match the input, e.g. "05/21/2022".

DateTime Format

Added in version 22.2.14

For all methods that return a DateTime of format "yyyy-MM-dd HH:mm:ss", you have the ability to specify a DateTime format. Use DateTimeFormatString, which is "yyyy-MM-dd HH:mm:ss" by default.

Example usage:
GET /patients/Simple?DateTimeFormatString=dd/MM/yyyy HH:mm:ss zzz

This will return DateTimes that have been formatted to match the input, e.g. "21/05/2022 14:30:00 -07:00".


The current version of the API has the following endpoint:

Example usage:
GET https://api.opendental.com/api/v1/patients

Our intent is to never change this URL, but if there is an important breaking change in the future, then we may create v2, etc. These version numbers do not correspond to versions of Open Dental. This API is intended to work smoothly with multiple versions of Open Dental. But the version of the customer database must be at least as high as the version that the method was added.

URL Parameter Encoding

Use percent encoding for all reserved characters in the URL query parameters. Quotes are not used in URL parameters. For example, De Angelo would be encoded as De%20Angelo.


All API requests require a Content-Type header of "application/json".


In PUT and POST requests, the JSON body can have a maximum content length of 16.8M characters.

Data Types

This API documentation does not generally repeat information which can be found in the Database Schema.
So we frequently just list out the fields available for a resource without further explanation.

Enumerations: These are stored in the database as numbers, but this API uses the text equivalent.
Example: "Male" instead of 0. Fields are still capitalized, just like the original.

Booleans: Fields that are boolean in the database are string in the API, either "true" or "false".

Dates: String with "yyyy-MM-dd" format by default. See Date Format.

DateTime: String with "yyyy-MM-dd HH:mm:ss" format by default. See DateTime Format.

Foreign Keys: These are stored in the database as numbers, but we frequently use a string version for parameters and fields. The string version field will start with a lower case letter to indicate that it's not a standard database field. The lower case letter versions are usually read-only and are not used to set values.
appointment.Confirmed=145 (FK to definition.DefNum)

Strings: The JSON serializer currently outputs carriage returns (\r\n) as spaces. There may be other issues with complex text as well.

Returned Status Codes

All API requests return one of the following HTTP Status Codes: 200 OK, 201 Created, 400 BadRequest, 401 Unauthorized, or 404 Not Found. See the API resource documentation pages for status codes specific to each method. General API status codes are described below.

400 BadRequest:
  • eConnector issues - Including when the eConnector is not running or two eConnectors are attempting to use the same registration key
  • Versioning - The version of the dental office is not high enough to use the specified API method
  • Network Issues - Request timeouts and other dental office connectivity issues
  • General API request formatting - Missing request headers, invalid Content-Types, and URL elements

  • 401 Unauthorized:
  • Invalid Credentials - Either the Customer or Developer key is invalid, unassigned, or has been disabled
  • Invalid Permissions - The Developer Key does not have the ApiPermission necessary to use the specified API method

  • 404 NotFound:
  • The specified API resource does not exist (usually a typo)

  • Behavior

    The behavior of actions in the API are similar to when using the UI in Open Dental, but not identical. There tends to be a bit less automation. There are also no prompts for back and forth logic with user interaction. The advantage of the API is that it will not allow you to make changes that would corrupt the database, so it's safe. If you were to use similar direct queries to try to change the database, you would quickly corrupt it. The API also makes the appropriate security log entries and performs some housekeeping duties such as archival, synchronization, and hashing in certain tables. In contrast, direct queries that change the database are strictly forbidden and we use our Database Integrity feature to actively block such queries.


    API developers who only have the ApiReadAll permission have their customers' requests throttled to one request per five seconds. This time includes the execution of the request itself. Throttling is relaxed to one request per one second if the API user possesses any other API permission (such as ApiComm, etc). This reduced throttle will apply to all API requests, even those falling under the ApiReadAll permission. Throttling occurs on a per customer key basis, not a per developer key basis.

    Most API requests take less than a second to complete. The exact time will vary with the complexity of the specific endpoint used. The API request data flow chain has several links. The request is sent to api.opendental.com, is routed to servers at Open Dental, its credentials validated, and sent to the dental office via their eConnector. After executing the API method on the dental office's server, the response travels back through the chain to the Developer who made the request. This full chain contains 10 hops start to finish.

    Requests made using the Local API or the API Service are not throttled at all. All requests are made locally at the dental office workstations and communicate with the running Open Dental Program. They do not need to travel through Open Dental servers, reducing execution time considerably. API key credentials are still verified via web call to HQ, but are valid for 6 hours. This allows the local API to continue functioning during periods of internet downtime.