Use case
The typical flow to book an appointment is:
- Search by
NHS Number
for, or otherwise obtain, aPatient
resource. - Search for available
Slot
resources by date range. - Create an
Appointment
for the chosenSlot
andPatient
resources.
Refer to Consumer sessions illustrated for how this API use case could be used in the context of a typical consumer appointment management session.
Security
- GP Connect utilises TLS Mutual Authentication for system level authorization
- GP Connect utilises a JSON Web Tokens (JWT) to transmit clinical audit and provenance details
Prerequisites
Consumer
The consumer system:
- SHALL have previously resolved the organisation’s FHIR® endpoint base URL through the Spine Directory Service
- SHALL have previously traced the patient’s NHS Number using the Personal Demographics Service or an equivalent service.
- SHALL have previously obtained the details for one or more free slots that are to be booked.
- SHALL have previously performed a GP Connect
Find a Patient
request to obtain the logical identifier for the patient on the organisation’s FHIR server.
API usage
The consumer system SHALL only use the book appointment capability to book future appointments, where the appointment start dateTime is after the current date and time. If the appointment start date is in the past the provider SHALL return an error.
Adherence is expected to local business rules, agreements and policies defining good practice in GP Connect-enabled cross-organisational appointment booking. This will discourage for example the over-booking and subsequent cancellation of Slots.
Booking multiple adjacent slots
To book more than one slot in the same Book Appointment message, a consumer needs to be able to identify which adjacent slots may be booked together. This is determined by the following rules:
- Two slots (Slot A and Slot B) are adjacent when the start time of Slot B equals the end time of Slot A
- The adjacent slots SHALL reference the same
Schedule
resource - The adjacent slots SHALL both have the same
deliveryChannel
value - If the slots do not conform to one or more of the rules above, they SHALL NOT be accepted as part of the same appointment booking
Request operation
FHIR® relative request
POST /Appointment
FHIR absolute request
POST https://[proxy_server]/https://[provider_server]/[fhir_base]/Appointment
Request headers
Consumers SHALL include the following additional HTTP request headers:
Header | Value |
---|---|
Ssp-TraceID |
Consumer’s TraceID (i.e. GUID/UUID) |
Ssp-From |
Consumer’s ASID |
Ssp-To |
Provider’s ASID |
Ssp-InteractionID |
urn:nhs:names:services:gpconnect:fhir:rest:create:appointment-1 |
Payload request body
The request payload is a profiled version of the standard FHIR Appointment resource. See the FHIR resources page for more detail.
Consumer systems:
- SHALL send an
Appointment
resource that conforms to the GPConnect-Appointment-1 profile. - SHALL include the URI of the
GPConnect-Appointment-1
profile StructureDefinition in theAppointment.meta.profile
element of the appointment resource.
The following data elements are mandatory (that is, data MUST be present):
- a patient
participant
of the appointment. - a location
participant
of the appointment, representing the physical location where the appointment is to take place (see Design decisions page). - an
actor
reference in any suppliedparticipant
. - the
start
andend
of the appointment.- where multiple slots are being booked, the
start
SHALL be the start time of the earlier slot, and theend
shall be the end time of the latest slot
- where multiple slots are being booked, the
- the
status
identifying the appointment as “booked”. - the
slot
details of one or more free slots to be booked.- where multiple slots are being booked, they SHALL meet the conditions required to be booked together - see Booking multiple adjacent slots
- the
bookingOrganisation
extension referencing acontained
organization
resource within the appointment resource.- the contained organization resource SHALL represent the organization booking the appointment.
- the contained organization resource SHALL conform to CareConnect-GPC-Organization-1 profile.
- the contained organization resource SHALL contain an
identifier
with the organisation’s ODS code. - the contained organization resource SHALL contain at least
Name
andTelecom
details. - the contained organization resource SHALL include the
type
element with a value matching the organization type sent as asearchFilter
with the Search for free slots request. If organization type was not passed to thesearchFilter
thentype
SHALL not be populated.
- the
created
element SHALL be populated with the date and time the appointment was created.
The following data elements SHOULD be included when available:
- a practitioner
participant
of the appointment.
The following data elements MUST NOT be included:
reason
specialty
Element specific guidance
The following guidance around the Appointment resource element SHALL be followed when populating any of the listed fields:
Resource Element | Guidance |
---|---|
Appointment.description | This field SHALL be populated with a “Summary Label”, a brief description of the appointment as would be shown on a subject line in a meeting request, or appointment list. Consumers SHALL impose a character limit of 100 characters for this element. |
Appointment.comment | This field SHALL be used for “Patient specific notes” and any additional comments relating to the appointment. Consumers SHALL impose a character limit of 500 characters for this element. |
Appointment.reason | Consumers and providers SHALL NOT use the appointment reason element as the GP Connect appointment management capability is for administration of appointment booking and should not be used to transfer clinical data between systems. As the reason element is for recording ‘clinical’ codes it goes against the purpose of the GP Connect Appointment Management capability, so it should not be used by consumers or providers. |
Appointment.specialty | This field SHALL NOT be populated |
Resource guidance
The following guidance SHALL be followed when populating an appointment resource:
- For providers who only support the mandatory
description
element and not thecomment
element. If acomment
is received as part of the booking the provider SHOULD append the content of the comment to the description within the appointment so that the additional information is not lost. The consumer imposed character limit specified above should restrict the total number of characters received so that all providers can store any text they receive. - If the consumer wishes to include patient temporary contact details for the purposes of the appointment they SHALL include them within the
description
element of the appointment, so that the details are retained against that specific appointment. - Elements within the appointment (such as ‘comment’ and ‘description’) SHALL only contain limited amounts of information to support the appointment. The content of the appointment SHALL NOT be used for “Transfer of Care” clinical information.
Example request body
On the wire, a JSON serialised request would look something like the following:
{
"resourceType": "Appointment",
"meta": {
"profile": [
"https://fhir.nhs.uk/STU3/StructureDefinition/GPConnect-Appointment-1"
]
},
"contained": [
{
"resourceType": "Organization",
"id": "1",
"meta": {
"profile": [
"https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-Organization-1"
]
},
"identifier": [
{
"system": "https://fhir.nhs.uk/Id/ods-organization-code",
"value": "A00001"
}
],
"name": "Test Organization Name",
"telecom": [
{
"system": "phone",
"value": "0300 303 5678"
}
]
}
],
"extension": [
{
"url": "https://fhir.nhs.uk/STU3/StructureDefinition/Extension-GPConnect-BookingOrganisation-1",
"valueReference": {
"reference": "#1"
}
}
],
"status": "booked",
"description": "Free text description.",
"start": "2016-05-30T10:00:00+01:00",
"end": "2016-05-30T10:25:00+01:00",
"slot": [
{
"reference": "Slot/1",
"display": "Slot 1"
}
],
"created": "2017-10-09T13:48:41+01:00",
"comment": "Free text comment.",
"participant": [
{
"actor": {
"reference": "Patient/1",
"display": "Mr. Mike Smith"
},
"status": "accepted"
},
{
"actor": {
"reference": "Location/32",
"display": "Leeds GP Clinic"
},
"status": "accepted"
}
]
}
Error handling
Provider systems:
- SHALL return a http status “409” with an error message “DUPLICATE_REJECTED” when an appointment can not be booked because the referenced slots within the appointment resource no longer have the status
free
, such as when the slot has been used to book a different appointment between the “search for free slots” request and the “book appointment” request. - SHALL return an error if
Appointment.reason
is included in the appointment resource send by the consumer. - SHALL return a GPConnect-OperationOutcome-1 resource that provides additional detail when one or more request fields are corrupt or a specific business rule/constraint is breached.
For example:
- the submitted
start
andend
date range does not match that of the requestedSlot(s)
- one or more of the requested
Slot
resources does not exist or already has astatus
of busy - a business rule imposed by Slot Availability Management is breached, e.g. an organisational slot limit
- multiple slots were requested for booking but do not meet the criteria for booking multiple adjacent slots
Refer to Development - FHIR API guidance - error handling for details of error codes.
Request response
Response headers
Provider systems are not expected to add any specific headers beyond that described in the HTTP and FHIR® standards.
Payload response body
Provider systems:
- SHALL return a
201
Created HTTP status code on successful execution of the operation. - SHALL return a
Location
header as described in FHIR API guidance. - SHALL return an
Appointment
resource that conform to the GPConnect-Appointment-1 profile. - SHALL include the URI of the
GPConnect-Appointment-1
profile StructureDefinition in theAppointment.meta.profile
element of the returned appointment resource. -
SHALL include the
versionId
of the current version of each appointment resource. -
SHALL meet General FHIR resource population requirements populating all fields where data is available, excluding those listed below
- SHALL NOT populate the following fields:
reason
specialty
{
"resourceType": "Appointment",
"id": "9",
"meta": {
"versionId": "636068818095315079",
"profile": [
"https://fhir.nhs.uk/STU3/StructureDefinition/GPConnect-Appointment-1"
]
},
"contained": [
{
"resourceType": "Organization",
"id": "1",
"meta": {
"profile": [
"https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-Organization-1"
]
},
"identifier": [
{
"system": "https://fhir.nhs.uk/Id/ods-organization-code",
"value": "A00001"
}
],
"name": "Test Organization Name",
"telecom": [
{
"system": "phone",
"value": "0300 303 5678"
}
]
}
],
"extension": [
{
"url": "https://fhir.nhs.uk/STU3/StructureDefinition/Extension-GPConnect-BookingOrganisation-1",
"valueReference": {
"reference": "#1"
}
},
{
"url": "https://fhir.nhs.uk/STU3/StructureDefinition/Extension-GPConnect-PractitionerRole-1",
"valueCodeableConcept": {
"coding": [
{
"system": "https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-SDSJobRoleName-1",
"code": "R0260",
"display": "General Medical Practitioner"
}
]
}
},
{
"url": "https://fhir.nhs.uk/STU3/StructureDefinition/Extension-GPConnect-DeliveryChannel-2",
"valueCode": "In-person"
}
],
"status": "booked",
"description": "Free text description.",
"start": "2016-05-30T10:00:00+01:00",
"end": "2016-05-30T10:25:00+01:00",
"slot": [
{
"reference": "Slot/1",
"display": "Slot 1"
}
],
"created": "2017-10-09T13:48:41+01:00",
"comment": "Free text comment.",
"participant": [
{
"actor": {
"reference": "Patient/1",
"display": "Mr. Mike Smith"
},
"status": "accepted"
},
{
"actor": {
"reference": "Location/32",
"display": "Leeds GP Clinic"
},
"status": "accepted"
}
]
}
Examples
C#
var client = new FhirClient("http://gpconnect.aprovider.nhs.net/GP001/STU3/1/");
client.PreferredFormat = ResourceFormat.Json;
Appointment appointment = new Appointment();
appointment.Status = Appointment.AppointmentStatus.Booked;
appointment.Start = System.DateTimeOffset.Now;
appointment.End = System.DateTimeOffset.Now.AddMinutes(30);
var slotReference = new ResourceReference();
slotReference.Reference = "Slot/1982";
appointment.Slot.Add(slotReference);
var patientParticipant = new Appointment.ParticipantComponent();
patientParticipant.Actor = new ResourceReference();
patientParticipant.Actor.Reference = "Patient/2";
patientParticipant.Status = Appointment.ParticipationStatus.Accepted;
appointment.Participant.Add(patientParticipant);
var locationParticipant = new Appointment.ParticipantComponent();
locationParticipant.Actor = new ResourceReference();
locationParticipant.Actor.Reference = "Location/1";
locationParticipant.Status = Appointment.ParticipationStatus.Accepted;
appointment.Participant.Add(locationParticipant);
appointment.created = new FhirDateTime(DateTime.Now);
Organization organization = new Organization();
organization.Name = "Example Organization Name";
var contactPoint = new ContactPoint();
contactPoint.System = ContactPoint.ContactPointSystem.Phone;
contactPoint.Value = "0300 303 5678";
organization.Telecom.Add(contactPoint);
organization.Id = "1";
appointment.Contained.Add(organization);
var reference = new ResourceReference
{
Reference = "#1",
};
appointment.AddExtension("https://fhir.nhs.uk/StructureDefinition/extension-gpconnect-booking-organisation-1", reference);
Appointment appointmentCreated = client.Create<Appointment>(appointment);
FhirSerializer.SerializeResourceToJson(appointmentCreated).Dump();
Java
FhirContext fhirContext = FhirContext.forStu3();
IGenericClient client = fhirContext.newRestfulGenericClient("http://gpconnect.aprovider.nhs.net/GP001/STU3/1/");
Appointment appointment = new Appointment();
appointment.setStatus(AppointmentStatusEnum.BOOKED);
Calendar startTime = Calendar.getInstance();
Calendar endTime = Calendar.getInstance();
endTime.add(Calendar.MINUTE, 30);
appointment.setStart(new InstantDt(startTime));
appointment.setEnd(new InstantDt(endTime));
appointment.setSlot(Collections.singletonList(new ResourceReferenceDt("Slot/1982")));
Appointment.Participant patientParticipant = new Appointment.Participant();
patientParticipant.setActor(new ResourceReferenceDt("Patient/2"));
patientParticipant.setStatus(ParticipationStatusEnum.ACCEPTED);
appointment.addParticipant(patientParticipant);
Appointment.Participant locationParticipant = new Appointment.Participant();
locationParticipant.setActor(new ResourceReferenceDt("Location/1"));
locationParticipant.setStatus(ParticipationStatusEnum.ACCEPTED);
appointment.addParticipant(locationParticipant);
Organization organization = new Organization();
organization.setName("Test Organization Name");
ContactPointDt telecom = new ContactPointDt();
telecom.setSystem(ContactPointSystemEnum.PHONE);
telecom.setValue("0300 303 5678");
organization.setTelecom(Collections.singletonList(telecom));
ExtensionDt extension = new ExtensionDt(false);
extension.setUrl("https://fhir.nhs.uk/StructureDefinition/extension-gpconnect-booking-organisation-1");
extension.setValue(new ResourceReferenceDt(organization));
appointment.addUndeclaredExtension(extension);
MethodOutcome response = client.create()
.resource(appointment)
.prefer(PreferReturnEnum.REPRESENTATION)
.preferResponseType(Appointment.class)
.execute();
System.out.println(fhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(response.getResource()));