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_id and doctor_external_id returns 422 with the code ambiguous_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 Found with the code not_found and the attribute that was looked up, for example doctor_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_id or organization_external_id.
  • External IDs need an organization. Because external IDs are only unique within an organization, an instance token cannot resolve a *_external_id reference without naming the organization. The request returns 422 with the code organization_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.

Questions? Contact us at support@meetone.io.