API Reference

Holds

Reserve a bookable slot while your patient finishes booking, then book it with the Jump EHR Appointments API.

A hold reserves one slot from the Availability API for a few minutes, so nobody else can book it while your patient enters their details or pays. When they are done, book it with POST /holds/{id}/confirm, or with POST /appointments and the hold's id as hold_id. The two do the same thing.

Holds are the same reservations Jump's own online booking uses: a held slot disappears from GET /availability and from the practice's online booking until the hold is used, released or expires.

The booking flow

  1. GET /availability to list slots.
  2. POST /holds naming the slot, either as appointment_type_id, clinician_id, date and start_time (HH:MM, the slot's local time), or by echoing the slot's appointment_template_id, clinician_profile_id and start_time exactly as availability returned them.
  3. Create or update the patient with POST /patients or PATCH /patients/{id}. To record their NHS GP, send a gp_registration block, naming the practice by gp_practice_ods_code (see Patients).
  4. POST /holds/{id}/confirm with patient_id (or POST /appointments with hold_id and patient_id). The time, clinician, template and location come from the hold.

If the patient abandons the flow, DELETE /holds/{id} frees the slot straight away.

Holds last 15 minutes by default. Set hold_minutes between 5 and 35 when you need longer (for example while a payment page is open). A hold cannot be extended; if it lapses, hold the slot again.

Errors to handle

CodeStatusMeaningWhat to do
SLOT_UNAVAILABLE409The slot was booked or held by someone else, or the diary changedQuery GET /availability again and offer another slot
HOLD_EXPIRED410The hold ran out before bookingHold the slot again (it may have gone)
HOLD_RELEASED410The hold was releasedHold the slot again
HOLD_ALREADY_USED409The hold already became an appointmentLook up the appointment; do not book twice
VALIDATION_ERROR (TIMEZONE_REQUIRED)422start_time had no Z and no UTC offsetSend the slot's start_time exactly as GET /availability returned it

GET /holds/{id} returns expired and released holds with that status rather than a 404, and DELETE /holds/{id} on a hold that is already inactive succeeds without changing it.

Holds use the write_appointments scope to create and release, and read_appointments to read.

Try-it is disabled for POST /holds

This operation writes data. Running it from these docs would target the production API and change a real record. Copy the request sample and run it against staging first.

Authorization

BearerApiKey
AuthorizationBearer <token>

API key with the pk_live_ prefix. pk_test_ keys are refused (403 TEST_MODE_UNAVAILABLE) until a sandbox exists.

In: header

Header Parameters

Idempotency-Key?string

Optional UUID for request deduplication. Same key + same body returns the cached response. Same key + different body returns 409 CONFLICT. Keys are scoped to your organisation and endpoint, and expire after 24 hours.

Formatuuid

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Name the template, the clinician and the slot's start. Each of the first two has two accepted names (send either); the start is either date plus an HH:MM start_time, or a start_time echoed from GET /availability.

Response Body

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/holds" \  -H "Content-Type: application/json" \  -d '{    "appointment_type_id": "123e4567-e89b-12d3-a456-426614174013",    "clinician_id": "123e4567-e89b-12d3-a456-426614174012",    "location_id": "123e4567-e89b-12d3-a456-426614174014",    "date": "2026-10-05",    "start_time": "09:00"  }'
{  "data": {    "id": "123e4567-e89b-12d3-a456-426614174020",    "status": "active",    "appointment_type_id": "123e4567-e89b-12d3-a456-426614174013",    "appointment_template_id": "123e4567-e89b-12d3-a456-426614174013",    "clinician_id": "123e4567-e89b-12d3-a456-426614174012",    "clinician_profile_id": "123e4567-e89b-12d3-a456-426614174012",    "location_id": "123e4567-e89b-12d3-a456-426614174014",    "patient_id": null,    "start_time": "2026-10-05T09:00:00+01:00",    "end_time": "2026-10-05T09:30:00+01:00",    "timezone": "Europe/London",    "is_remote": false,    "remote_channel": null,    "expires_at": "2026-10-01T12:15:00.000Z",    "released_at": null,    "appointment_id": null,    "created_at": "2026-10-01T12:00:00.000Z"  },  "meta": {    "request_id": "req_abc123"  }}
GET
/holds/{id}

Authorization

BearerApiKey
AuthorizationBearer <token>

API key with the pk_live_ prefix. pk_test_ keys are refused (403 TEST_MODE_UNAVAILABLE) until a sandbox exists.

In: header

Path Parameters

id*string
Formatuuid

Response Body

application/json

application/json

application/json

curl -X GET "https://example.com/holds/497f6eca-6276-4993-bfeb-53cbbbba6f08"
{  "data": {    "id": "123e4567-e89b-12d3-a456-426614174020",    "status": "active",    "appointment_type_id": "123e4567-e89b-12d3-a456-426614174013",    "appointment_template_id": "123e4567-e89b-12d3-a456-426614174013",    "clinician_id": "123e4567-e89b-12d3-a456-426614174012",    "clinician_profile_id": "123e4567-e89b-12d3-a456-426614174012",    "location_id": "123e4567-e89b-12d3-a456-426614174014",    "patient_id": null,    "start_time": "2026-10-05T09:00:00+01:00",    "end_time": "2026-10-05T09:30:00+01:00",    "timezone": "Europe/London",    "is_remote": false,    "remote_channel": null,    "expires_at": "2026-10-01T12:15:00.000Z",    "released_at": null,    "appointment_id": null,    "created_at": "2026-10-01T12:00:00.000Z"  },  "meta": {    "request_id": "req_abc123"  }}

Try-it is disabled for DELETE /holds/{id}

This operation writes data. Running it from these docs would target the production API and change a real record. Copy the request sample and run it against staging first.

Authorization

BearerApiKey
AuthorizationBearer <token>

API key with the pk_live_ prefix. pk_test_ keys are refused (403 TEST_MODE_UNAVAILABLE) until a sandbox exists.

In: header

Path Parameters

id*string
Formatuuid

Response Body

application/json

application/json

application/json

application/json

curl -X DELETE "https://example.com/holds/497f6eca-6276-4993-bfeb-53cbbbba6f08"
{  "data": {    "id": "123e4567-e89b-12d3-a456-426614174020",    "status": "active",    "appointment_type_id": "123e4567-e89b-12d3-a456-426614174013",    "appointment_template_id": "123e4567-e89b-12d3-a456-426614174013",    "clinician_id": "123e4567-e89b-12d3-a456-426614174012",    "clinician_profile_id": "123e4567-e89b-12d3-a456-426614174012",    "location_id": "123e4567-e89b-12d3-a456-426614174014",    "patient_id": null,    "start_time": "2026-10-05T09:00:00+01:00",    "end_time": "2026-10-05T09:30:00+01:00",    "timezone": "Europe/London",    "is_remote": false,    "remote_channel": null,    "expires_at": "2026-10-01T12:15:00.000Z",    "released_at": null,    "appointment_id": null,    "created_at": "2026-10-01T12:00:00.000Z"  },  "meta": {    "request_id": "req_abc123"  }}

Try-it is disabled for POST /holds/{id}/confirm

This operation writes data. Running it from these docs would target the production API and change a real record. Copy the request sample and run it against staging first.

Authorization

BearerApiKey
AuthorizationBearer <token>

API key with the pk_live_ prefix. pk_test_ keys are refused (403 TEST_MODE_UNAVAILABLE) until a sandbox exists.

In: header

Path Parameters

id*string
Formatuuid

Header Parameters

Idempotency-Key?string

Optional UUID for request deduplication. Same key + same body returns the cached response. Same key + different body returns 409 CONFLICT. Keys are scoped to your organisation and endpoint, and expire after 24 hours.

Formatuuid

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/holds/497f6eca-6276-4993-bfeb-53cbbbba6f08/confirm" \  -H "Content-Type: application/json" \  -d '{    "patient_id": "123e4567-e89b-12d3-a456-426614174000",    "attendee_name": "Sarah Johnson",    "attendee_email": "sarah.johnson@example.com",    "notes": "First visit"  }'
{  "data": {    "id": "123e4567-e89b-12d3-a456-426614174006",    "patient_id": "P-100428",    "clinician_profile_id": "123e4567-e89b-12d3-a456-426614174007",    "title": "Ms",    "description": "Example description",    "start_time": "2026-10-12T18:45:00+01:00",    "end_time": "2026-10-12T19:15:00+01:00",    "timezone": "Europe/London",    "booking_mode": "slot",    "status": "pending_approval",    "appointment_type_id": "123e4567-e89b-12d3-a456-426614174008",    "location_id": "123e4567-e89b-12d3-a456-426614174009",    "is_remote": true,    "remote_channel": "video",    "video_link": "Example video link",    "video_provider": "Example video provider",    "duration_minutes": 1,    "attendee_email": "Example attendee email",    "attendee_name": "Example attendee name",    "meeting_url": "https://example.com/resource",    "meeting_started_at": "2026-01-15T10:30:00Z",    "meeting_ended_at": "2026-01-15T10:30:00Z",    "attendance_status": "Example attendance status",    "arrived_at": "2026-01-15T10:30:00Z",    "sent_in": "2026-01-15T10:30:00Z",    "left_at": "2026-01-15T10:30:00Z",    "cancellation_reason": "Example cancellation reason",    "rejection_reason": "Example rejection reason",    "reschedule_reason": "Example reschedule reason",    "booking_source": "api",    "is_guest_booking": true,    "guest_first_name": "Example guest first name",    "guest_last_name": "Example guest last name",    "guest_dob": "2026-01-15",    "guest_mobile": "Example guest mobile",    "guest_relationship": "Example guest relationship",    "is_team_booking": true,    "is_untimed": false,    "list_position": null,    "patient_time_display": null,    "arrival_time": null,    "episode_id": "123e4567-e89b-12d3-a456-426614174010",    "patient_timezone": "Example patient timezone",    "booked_by_patient_id": "123e4567-e89b-12d3-a456-426614174011",    "created_at": "2026-01-15T10:30:00Z",    "updated_at": "2026-01-15T10:30:00Z"  },  "meta": {    "request_id": "req_abc123"  }}

On this page