Every record in the Scheduling API can be addressed by an ID MeetOne assigns and by a key from your own system. This article explains both, how they are used in requests, and where they must be unique.
Two identifiers per record
| Identifier | Set by | Format | Description |
|---|---|---|---|
id |
MeetOne | UUID, e.g. 3f6c1a52-8d4e-4b7a-9e21-5c0d7a4b1e90 |
Assigned when the record is created and never changes. It is the {id} in every URL path. |
external_id |
You | String, at most 255 characters, optional | Your own key for the record, for example the primary key in your CRM. Writable when you create or update the record; null if you never set one. |
Organizations, users, availability types, appointment resources, availabilities and appointments all have both. The API never exposes MeetOne's internal numeric IDs.
{
"data": {
"id": "3f6c1a52-8d4e-4b7a-9e21-5c0d7a4b1e90",
"external_id": "crm-4711",
"name": "Praxis Dr. Muster"
}
}
Leading and trailing whitespace in an external_id is removed, and a blank value is stored as no external ID at all. A malformed id in a URL, one that is not a UUID, simply answers 404.
References between records
Many requests point at another record: a booking names a patient, an availability names a practitioner and a type. Each reference can be written in two ways, as <name>_id or as <name>_external_id:
| Reference | By MeetOne ID | By your ID |
|---|---|---|
| Organization (instance tokens) | organization_id |
organization_external_id |
| Practitioner | doctor_id |
doctor_external_id |
| Patient | patient_id |
patient_external_id |
| Availability type | availability_type_id |
availability_type_external_id |
| Appointment resource | appointment_resource_id |
appointment_resource_external_id |
The same names work as query parameters when you filter or look things up, and as body fields when you create or update a record. This booking uses external IDs only, so your system never has to store a MeetOne ID:
curl -X POST "https://acme.meetone.io/api/v1/appointments" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"availability_type_external_id": "first-visit",
"doctor_external_id": "staff-12",
"patient_external_id": "pat-1001",
"starts_at": "2026-10-12T09:00:00+02:00"
}'
Rules for references:
- One form per reference. Sending both
doctor_idanddoctor_external_idreturns422with the codeambiguous_reference. - Unknown or foreign records return 404. A reference to a record that does not exist, or that belongs to another organization, returns
404 Not Foundwith the codenot_foundand theattributethat was looked up, for exampledoctor_external_id. The API does not tell you whether a record exists in an organization you cannot reach. - References stay inside one organization. They resolve in the organization of the request. With an organization token that is its own organization. With an instance token it is the organization you name with
organization_idororganization_external_id. - External IDs need an organization. Because external IDs are only unique within an organization, an instance token cannot resolve a
*_external_idreference without naming the organization. The request returns422with the codeorganization_required.
Uniqueness
An external_id identifies one record of one resource type:
| Resource | Unique within |
|---|---|
| Users, availability types, appointment resources, availabilities, appointments | The organization. |
| Organizations | The installation (all organizations of the tenant). |
Two different resource types may use the same value: a user and an appointment can both have external_id 1001. Within a type, a value that is already taken returns 422 with the code taken and attribute external_id:
{
"errors": [
{ "code": "taken", "attribute": "external_id", "message": "External ID has already been taken" }
]
}
Two concurrent requests that try to write the same external_id are also answered with 422 taken; one of them wins.
Filtering lists by external_id
Every list endpoint accepts external_id as an exact-match filter, except waitlist entries, which have no external_id. It is the quickest way to find out whether your record already exists in MeetOne:
curl "https://acme.meetone.io/api/v1/users?external_id=pat-1001" \
-H "Authorization: Bearer $TOKEN"
{
"data": [
{
"id": "e41c8a0f-6b9d-4d27-a3f5-90c2b7d1e8a4",
"external_id": "pat-1001",
"email": "mary.major@example.com",
"role": "patient"
}
]
}
(Abbreviated; see Users endpoints for the complete object.) The list is empty when nothing matches. An instance token that does not name an organization searches across all of them, so it can receive one match per organization; add organization_id or organization_external_id to narrow it down.
Choose external IDs that never change and are never reused for another record. If your system recycles keys, put a prefix or the record type into the value, or keep using MeetOne's id.
Related
Questions? Contact us at support@meetone.io.