How to Manage Patients via the API

Use the Dentare REST API to create, update, list, and view patients programmatically. This guide covers creating an API token, authenticating requests, and using the patient endpoints β€” all without opening the Dentare web interface.

Written by Feti Jashari
Updated over a week ago

How to Manage Patients via the API

Use the Dentare REST API to create, update, list, and view patients programmatically. This guide covers creating an API token, authenticating requests, and using the patient endpoints β€” all without opening the Dentare web interface.


In this article:



What You'll Need

  • An active Dentare account with admin access

  • A tool for making HTTP requests (e.g., curl, Postman, or your own code)



Step 1 β€” Create an API Token

Before you can call the API, you need an API token. This token authenticates your requests and links them to your Dentare account.

  1. Log in to Dentare as an account admin

  2. Go to API Tokens from the account navigation (or navigate directly to API Tokens)

  3. Click Create an API Token

  4. Enter a descriptive name (e.g., "Patient Integration" or "Migration Script")

  5. Click Create

After creation, Dentare shows your token. Copy it immediately β€” for security, the full token is only visible at this point.

Important: Treat your API token like a password. Do not share it publicly or commit it to source control. Anyone with the token can access your account's data.

To revoke a token:

  1. Go to API Tokens

  2. Click the token name

  3. Click Revoke

The token is deleted immediately and can no longer be used.



Step 2 β€” Authenticate API Requests

Every API request must include your token in the Authorization header using the Bearer scheme:

Authorization: Bearer YOUR_TOKEN_HERE

Example with curl:

curl https://dentare.io/api/v1/me.json -H "Authorization: Bearer YOUR_TOKEN_HERE" -H "Accept: application/json"

A successful response returns your user profile, confirming the token works.

If you receive a 401 Unauthorized response, check that:

  • The token is copied correctly (no extra spaces)

  • The token has not been revoked

  • The Authorization header uses the Bearer prefix



Create a Patient

Request:

POST https://dentare.io/api/v1/patients

Headers:

  • Authorization: Bearer YOUR_TOKEN_HERE

  • Content-Type: application/json

Body (JSON):

{"first_name": "John", "last_name": "Doe", "email": "john@example.com", "phone": "+38970123456", "birthdate": "1990-05-15", "gender": "male"}

Example with curl:

curl -X POST https://dentare.io/api/v1/patients -H "Authorization: Bearer YOUR_TOKEN_HERE" -H "Content-Type: application/json" -d '{"first_name": "John", "last_name": "Doe", "email": "john@example.com", "phone": "+38970123456"}'

Successful response (201 Created):

Returns the full patient record in {data: {...}} format including the assigned id, display_name, phone_e164 (normalized phone), created_at, and all other fields.

Error response (422 Unprocessable Entity):

Returns {error: "...", errors: {...}} with validation messages (e.g., "First name can't be blank").

Note: Only first_name and last_name are required. All other fields are optional.



Update a Patient

Request:

PATCH https://dentare.io/api/v1/patients/PATIENT_ID

Headers:

  • Authorization: Bearer YOUR_TOKEN_HERE

  • Content-Type: application/json

Body (JSON) β€” include only the fields you want to change:

{"email": "newemail@example.com", "phone": "+38971999888"}

Example with curl:

curl -X PATCH https://dentare.io/api/v1/patients/123 -H "Authorization: Bearer YOUR_TOKEN_HERE" -H "Content-Type: application/json" -d '{"email": "newemail@example.com"}'

Successful response (200 OK):

Returns the updated full patient record in {data: {...}} format.

Error responses:

  • 404 Not Found β€” patient does not exist or belongs to a different account

  • 422 Unprocessable Entity β€” validation error



List Patients

Request:

GET https://dentare.io/api/v1/patients

Headers:

  • Authorization: Bearer YOUR_TOKEN_HERE

Query parameters (all optional):

  • q β€” search query (searches name, email, phone, personal number)

  • page β€” page number (default: 1)

  • per_page β€” items per page (default: 20, max: 100)

  • lang β€” locale for display names: en, sq, or mk

  • email β€” filter by exact email

  • phone β€” filter by phone number (partial match)

  • personal_no β€” filter by personal number (EMBG)

  • external_id β€” filter by external ID

  • legacy_id β€” filter by legacy ID

  • is_active β€” filter by active status (true or false; defaults to active only)

Example with curl:

curl "https://dentare.io/api/v1/patients?q=John&per_page=50" -H "Authorization: Bearer YOUR_TOKEN_HERE"

Successful response (200 OK):

The response contains a data array and a meta object:

  • data β€” array of patient records, each with: id, first_name, last_name, display_name, email, phone, phone_e164, locale, is_active, created_at

  • meta β€” pagination info with page, per_page, total

Note: By default, only active patients are returned. Pass is_active=false to include inactive patients.



Get Patient Details

Request:

GET https://dentare.io/api/v1/patients/PATIENT_ID

Headers:

  • Authorization: Bearer YOUR_TOKEN_HERE

Query parameters (optional):

  • lang β€” locale for display names: en, sq, or mk

  • fields β€” comma-separated list of expansion fields (see Expansion Fields section below)

Example with curl:

curl "https://dentare.io/api/v1/patients/123?fields=allergies,medical_conditions,insurance_provider" -H "Authorization: Bearer YOUR_TOKEN_HERE"

Successful response (200 OK):

Returns the full patient record in {data: {...}} format including: id, first_name, last_name, display_name, display_first_name, display_last_name, email, phone, phone_e164, phone_country, birthdate, gender, personal_no, external_id, legacy_id, locale, is_active, created_at, updated_at, plus any requested expansion fields.

Error response:

  • 404 Not Found β€” patient does not exist or belongs to a different account



Available Fields

The following fields can be used when creating or updating a patient. Only first_name and last_name are required.

Required:

  • first_name β€” patient's first name

  • last_name β€” patient's last name

Optional:

  • email β€” email address

  • phone β€” phone number (automatically normalized to E.164 international format)

  • phone_country β€” two-letter country code for phone normalization (e.g., "MK", "XK", "AL")

  • birthdate β€” date of birth in ISO 8601 format (YYYY-MM-DD)

  • gender β€” male, female, or other

  • personal_no β€” national ID / EMBG

  • locale β€” preferred language for messages: en, sq, or mk

  • external_id β€” ID from another system (for reference)

  • blood_type β€” blood type

  • allergies β€” known allergies (free text)

  • medical_conditions β€” known medical conditions (free text)

  • emergency_contact_name β€” name of emergency contact

  • emergency_contact_relationship β€” relationship to patient

  • emergency_contact_phone β€” phone number of emergency contact

  • insurance_provider β€” name of insurance company

  • insurance_id β€” insurance policy number

  • is_active β€” whether the patient is active (true or false)

  • preferred_doctor_id β€” ID of the preferred doctor



Expansion Fields

By default, the patient detail response includes core fields only. To include additional fields, pass them as a comma-separated fields parameter on the GET request.

Available expansion fields:

  • allergies β€” known allergies

  • medical_conditions β€” known medical conditions

  • blood_type β€” blood type

  • emergency_contact_name β€” emergency contact name

  • emergency_contact_relationship β€” emergency contact relationship

  • emergency_contact_phone β€” emergency contact phone

  • insurance_provider β€” insurance company name

  • insurance_id β€” insurance policy number

  • vip β€” VIP status

  • vip_start_date β€” VIP start date

  • vip_expiration_date β€” VIP expiration date

  • vip_notes β€” VIP notes

  • preferences β€” patient preferences

  • medical_issues β€” medical issues

Example:

GET /api/v1/patients/123?fields=allergies,insurance_provider,emergency_contact_name



API Reference Summary

Authentication:

  • Header: Authorization: Bearer YOUR_TOKEN_HERE

  • Content type: application/json

Endpoints:

  • POST /api/v1/patients β€” create a patient

  • PATCH /api/v1/patients/:id β€” update a patient

  • GET /api/v1/patients β€” list patients (paginated, searchable, filterable)

  • GET /api/v1/patients/:id β€” get patient details (with optional expansion fields)

Common HTTP status codes:

  • 200 β€” success

  • 201 β€” created successfully

  • 401 β€” unauthorized (invalid or missing token)

  • 404 β€” not found

  • 422 β€” validation error (missing required fields, bad format)



Troubleshooting

401 Unauthorized on every request Check that your Authorization header uses the correct format: Bearer YOUR_TOKEN_HERE. Make sure the token has not been revoked.

404 Not Found when accessing a patient The patient either does not exist or belongs to a different account. API requests are scoped to your account β€” you cannot access patients from other accounts.

422 Validation error on create At minimum, first_name and last_name are required. Check the errors object in the response for specific field errors.

Phone number appears different after create/update Dentare automatically normalizes phone numbers to E.164 international format (e.g., +38970123456). The normalized number is returned in the phone_e164 field. Pass phone_country to help with normalization if your phone numbers don't include a country code.

Search returns no results The q parameter searches across name, email, phone, and personal number. Make sure the search term matches at least one of these fields. By default, only active patients are returned β€” pass is_active=false to include inactive ones.

Special characters appear garbled Ensure your request uses UTF-8 encoding. Set the Content-Type: application/json; charset=utf-8 header.

Need help? Contact Support.

Updated over a week ago

On this page