Changelog

Latest updates and changes to the Jump EHR API. Track new features and breaking changes.

All notable changes to the Jump EHR API will be documented here.

Subscribe to API updates by following our blog or contacting hello@usejump.co.uk.


This changelog tracks the public REST API surface (the api-v1 service). It is derived from the openapi.yaml contract — every endpoint listed here has a matching entry in the API Reference.

2026-10-17 — Cancelling or rescheduling through the API has the same effects as in Jump

If your own system tells the patient about cancellations or changes, send notify_patient: false on POST /appointments/{id}/cancel and PATCH /appointments/{id}. The flag is not remembered from the booking, so send it on every call.

1. Cancelling sends the cancellation message. POST /appointments/{id}/cancel now sends the patient the practice's cancellation message for the appointment type, cancels the appointment's queued reminders and follow-ups, and records the cancellation on the patient's record, exactly as a cancellation made in Jump does. It takes no refund: refund through Jump if one is due. Previously only the status changed.

2. Rescheduling sends the rescheduled message. A PATCH /appointments/{id} that changes the time, clinician, appointment type, location, is_remote or remote_channel of a confirmed or scheduled appointment now sends the practice's rescheduled message, re-queues reminders and follow-ups for the new time, and records the change on the appointment's audit trail and the patient's record.

3. notify_patient on cancel and PATCH. Defaults to true. false keeps the patient message from going out; the change is still recorded, queued reminders are still cancelled on a cancel, and reminders already queued still move to the new time on a reschedule. Anything other than a boolean returns 422 VALIDATION_ERROR.

4. Video bookings get their meeting room at booking time. A confirmed or scheduled booking with is_remote: true and remote_channel: "video" now gets its video room when it is booked, as one made in Jump does, so the confirmation can carry the join link. This happens whatever notify_patient says.

2026-10-16 — API bookings send the practice's confirmation and reminders

If your own system already sends the booking confirmation, send send_confirmation: false so the patient isn't confirmed twice. They still get the practice's reminders. To send nothing at all, send notify_patient: false.

1. Patients hear about an API booking. A confirmed or scheduled appointment created with POST /appointments (with or without hold_id) or POST /holds/{id}/confirm now sends the patient the practice's booking confirmation and queues the appointment type's reminders and follow-ups, exactly as a booking made in Jump does. What is sent follows the practice's notification settings for that appointment type. Previously an API booking sent nothing.

2. Two new booleans control it, both defaulting to true. send_confirmation: false skips only the immediate booking confirmation, and reminders and follow-ups are still queued. notify_patient: false sends nothing at all. Anything other than a boolean returns 422 VALIDATION_ERROR naming the field. Both are part of the request body, so reusing an Idempotency-Key with a different value returns 409 CONFLICT.

3. Moving an appointment moves its reminders. A PATCH /appointments/{id} that changes the time, clinician or appointment type re-times the appointment's queued reminders and follow-ups, so none go out for the old time.

4. scheduled appointments get their reminders. Reminders for an appointment with status scheduled are now sent. Previously only confirmed appointments received them.

2026-10-10 — Reschedules must be a real slot; holds and webhooks carry the practice's offset (breaking change)

Breaking change. If your integration moves appointments with PATCH /appointments/{id}, or creates holds with a start_time, read points 1 and 2.

1. Moving an appointment follows the same slot rule as booking one. A PATCH /appointments/{id} that changes start_time, end_time or clinician_profile_id must land on a slot GET /availability offers for the appointment's template, clinician and location. Any other time returns 409 SLOT_UNAVAILABLE with details.reason: "NOT_A_SLOT" and details.next_available, and the slot sets end_time (meta.warnings carries END_TIME_ADJUSTED if you sent a different one). An appointment booked as custom, or a request that sends booking_mode: "custom", can still move to any time; a custom move that sends only start_time keeps the appointment's length. The overlap check runs either way. A PATCH that leaves the times alone, or resends them unchanged, is not checked.

2. POST /holds reads start_time as the instant it names. A start_time with no Z and no offset now returns 422 VALIDATION_ERROR with details.reason: "TIMEZONE_REQUIRED". Previously only the date and clock digits were read, so 2026-10-12T08:00:00Z held the 08:00 UK slot, an hour early during British Summer Time. The date + HH:MM form is unchanged.

3. Holds and webhooks carry the practice's offset. Hold responses and the data.object / data.previous times on appointment.* webhooks are now written in the practice's local time with its UTC offset, and both add a timezone field, matching availability and appointment responses. It is the same instant, so a parser that understands offsets is unaffected. Audit timestamps (created_at, updated_at, expires_at) are unchanged.

2026-10-10 — Bookings must be a real slot, and times carry the practice's offset (breaking change)

Breaking change. If your integration books with POST /appointments without a hold_id, read points 1 to 3.

1. POST /appointments books only a real slot by default. Without hold_id, start_time must be a slot GET /availability offers right now for the appointment_type_id you send (now required) and, if you send them, the clinician_profile_id and location_id. It is checked exactly as POST /availability/verify checks it. Any other time returns 409 SLOT_UNAVAILABLE with details.reason: "NOT_A_SLOT" and details.next_available. The slot sets end_time (you may omit it; a different value is replaced and meta.warnings carries END_TIME_ADJUSTED) and, if you did not name one, the clinician. Previously any time was accepted, so a time-zone mistake on the integration's side became a wrong appointment with no error.

2. Custom times are an explicit opt-in. Send booking_mode: "custom" to book a time outside the slot list, as before. It is still refused if it overlaps another booking or a held slot, and the appointment records it: appointments now carry booking_mode ("slot", "custom", or null for bookings not made through the API).

3. Times you send must include a zone. A start_time (or a custom booking's end_time) with no Z and no offset, such as 2026-10-12T18:45:00, now returns 422 VALIDATION_ERROR with details.reason: "TIMEZONE_REQUIRED", on POST /appointments, PATCH /appointments/{id} and POST /availability/verify. POST /availability/verify used to read such a value as UK time.

4. Times we send carry the practice's offset. GET /availability, GET /availability/next, POST /availability/verify and every appointment response now write times in the practice's local time with its UTC offset, plus a timezone field: "start_time": "2026-10-12T18:45:00+01:00", "timezone": "Europe/London" rather than "2026-10-12T17:45:00Z". It is the same instant, so a parser that understands offsets is unaffected; a reader that takes the clock time at face value now gets the practice's clock time. created_at and other audit timestamps are unchanged.

2026-10-09 — Patient immunisation history reads (#15488)

Fixed GET /patients/{id}/immunisations selecting a retired database column, which caused the read to fail. The response retains date_administered, now sourced from the administration timestamp (administered_at) with timezone. Historical date-only values were migrated to midnight UTC. Patient/organisation scoping is unchanged.

2026-10-07 — Bookings made through the API are labelled as yours

Change. Appointments created with POST /appointments or POST /holds/{id}/confirm now have booking_source: "api", where they previously took admin. The practice sees them as patient bookings made through your app (named after your API key), and its "Patient booked" automations apply to them. Nothing you send changes.

2026-10-07 — Direct bookings can no longer overlap

Change. POST /appointments with an explicit start_time / end_time and a clinician_profile_id now refuses a time that overlaps:

  • one of that clinician's live appointments — 409 SLOT_UNAVAILABLE, details.reason: "OVERLAPS_APPOINTMENT"
  • a slot another patient is holding while they book — 409 SLOT_UNAVAILABLE, details.reason: "OVERLAPS_HOLD"

Previously the time was written as given, so two patients could be booked into one clinician's slot. Back-to-back appointments are fine, a group appointment template may share the time, and a hold for the same patient_id is theirs to book over. Booking outside the clinician's published availability is unchanged; to book only what GET /availability offers, use POST /holds and then book with hold_id.

2026-10-07 — Availability times are true UTC during British Summer Time

Fix. GET /availability, GET /availability/next and POST /availability/verify now treat every start_time / end_time / next_available as a real UTC instant, as the contract always said.

Between the last Sunday in March and the last Sunday in October, these endpoints were an hour out:

  • GET /availability and GET /availability/next returned the practice's UK clock time with a Z on the end, so a 09:00 slot was published as 09:00Z (10:00 UK).
  • POST /availability/verify checked the slot an hour before the one you asked about, so it could confirm a time that was already taken.

If you display our times by converting them from UTC (the expected use), you need do nothing: summer slots now show at the right time. If you worked around the offset by reading our values as UK clock time, remove the workaround. Winter times are unchanged.

verify also now matches an identical instant written with milliseconds (…T09:00:00.000Z), and its unavailable reason reads "Slot is no longer available".

2026-09-16 — Slot holds and GP registration

Build a complete booking flow on the API: find a slot, hold it, register the patient with their GP, and book.

  • Holds — POST /holds, GET /holds/{id}, DELETE /holds/{id}, POST /holds/{id}/confirm. A hold reserves a slot from GET /availability for 15 minutes by default (5-35 with hold_minutes), and the slot is withdrawn from availability until the hold is used, released or expires. If you built against the Holds endpoints we described earlier this year, the same requests now work; an expired hold returns 410 HOLD_EXPIRED, and the scope is write_appointments.
  • Book a held slot — POST /holds/{id}/confirm, or POST /appointments with hold_id and patient_id; the time, clinician and template come from the hold.
  • GP registration by ODS code — the gp_registration block on POST /patients and PATCH /patients/{id} accepts gp_practice_ods_code, so you no longer need to look up a GP practice id first.
  • New error codes — SLOT_UNAVAILABLE, HOLD_EXPIRED, HOLD_RELEASED, HOLD_ALREADY_USED.

Nothing existing has changed.

2026-04-03 — Booking & Scheduling

Added the read endpoints partners need to drive online booking, plus webhook subscriptions.

  • Availability — GET /availability, GET /availability/next, and POST /availability/verify to find bookable slots and validate one before booking.
  • Locations — GET /locations, GET /locations/{id}.
  • Clinician Profiles — GET /clinician-profiles, GET /clinician-profiles/{id}.
  • Webhooks — GET, POST /webhooks, GET, PATCH, DELETE /webhooks/{id}, and POST /webhooks/{id}/test. HMAC-SHA256 signature verification with automatic retry and exponential backoff.

2026-03-26 — Clinical records, episodes & questionnaires

  • Consultations — GET /consultations, GET /consultations/{id}, and per-section reads exposed as sub-resources: problems, medications, prescriptions, observations, procedures, referrals, lab-orders, allergies, immunisations, documents, family-history, social-history, invoices, and amendments.
  • Episodes — GET, POST /episodes, GET, PATCH /episodes/{id}, lifecycle actions (close, reopen, assign, change-priority), and GET, POST /episodes/{id}/events.
  • Episode Events — GET /episode-events/{id}.
  • Questionnaire Templates — GET /questionnaire-templates, GET /questionnaire-templates/{id}.
  • Questionnaire Responses — GET, POST /questionnaire-responses, GET, PATCH /questionnaire-responses/{id}.
  • Pathway Configs — GET /pathway-configs, GET, PATCH /pathway-configs/{id}.
  • Pathway Rules — GET, POST /pathway-rules, GET, PATCH, DELETE /pathway-rules/{id}.
  • Patient clinical collections — GET /patients/{id}/{observations|medications|problems|referrals|allergies|immunisations}.

2026-03-25 — v1.0.0 (initial release)

The first public release of the Jump EHR API.

  • Health — GET /health, an unauthenticated health check.
  • Patients — GET, POST /patients and GET, PATCH /patients/{id} with search, filtering and pagination.
  • Appointments — GET, POST /appointments, GET, PATCH /appointments/{id} (idempotency-key support on POST), and POST /appointments/{id}/cancel with state-machine validation and audit logging.
  • Appointment Templates — GET, POST /appointment-templates, GET, PATCH /appointment-templates/{id}, with an immutability guard on in-use templates.
  • Authentication & security — Bearer-token API keys (pk_live_* / pk_test_*), granular scopes, per-key rate limiting, and multi-tenant data isolation.
  • Developer experience — interactive API Explorer (Swagger UI) and code examples in cURL, JavaScript and Python.

Versioning Policy

The Jump EHR API follows semantic versioning:

  • Major versions (v1, v2) may include breaking changes
  • Minor versions add functionality in a backward-compatible manner
  • Patch versions include backward-compatible bug fixes

We provide advance notice of breaking changes and maintain previous major versions during transition periods.

API Stability

The v1 API is considered stable. We commit to:

  • No breaking changes within a major version
  • 12-month deprecation notice before removing endpoints
  • Migration guides for all major version upgrades

On this page