-
Notifications
You must be signed in to change notification settings - Fork 1
Webhook and Email Notifications
Webhook notifications allow suppliers to subscribe to the Book a Secure Move API system and receive notifications of when a move record is created or updated. The notification is transmitted via an HTTP POST to an endpoint specified by the supplier. The notification is signed with a shared key to ensure the authenticity of the message. If the endpoint is unavailable then the Book a Secure Move system will re-attempt the delivery later, retrying up to 25 times.
The subscription process is currently manual - please contact the Book a Secure Move team via your Slack channel with the following details:
-
Callback URL: this must be an
https://
endpoint which is publicly accessible and should not require authentication - Secret: this is a shared secret which is used to generate a SHA-256 HMAC signature to guarantee the authenticity of the notification
If your server supports HTTP Basic Authorization, you can also supply:
- Username: optional, used for basic authorization
- Password: optional, used for basic authorization
Once the Book a Secure Move team have actioned the request, notifications of moves events will be immediately sent to the specified callback_url
.
There is also the ability to send emails as well as webook notifications. Each supplier has two entries in the subscriptions
table, one for webhooks and one for email notifications, you can enable and disable these by changing the enabled
flag to true or false depending on the suppliers needs.
The supplier should ensure that the designated endpoint is available to receive notifications at all times. If for any reason the endpoint is offline when a notification is attempted, the system will retry the notification later with an increasing random exponential delay. The system will continue to retry the notification up to 25 times. On the first day the notification will be attempted approximately 14 times (see this table for the approximate schedule). Once 25 failed delivery attempts are reached the notification record will be failed and will not be attempted again.
When a notification is received at the supplier's endpoint, it must:
- Verify the PECS-SIGNATURE header of the notification
- Upon verification return an HTTP success code (in the range 200-299)
The notification is not considered to have been delivered until an HTTP success is received.
The endpoint should return success (or failure) immediately after signature verification and success should not be contingent on subsequent processing.
I.e. if a notification was successfully received and the signature verified, it is not correct to return a failure code because of some other problem in the subsequent processing as this would compromise the decoupled nature of the systems.
An example move notification message is given below:
POST / HTTP/1.1
Host: webhook-receiver.example.com
Accept: */*
Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Connection: keep-alive
Content-Length: 415
Content-Type: application/vnd.api+json
Keep-Alive: 30
Pecs-Notification-Id: 2cb108dd-8d47-4a5f-8d36-29324a770f05
Pecs-Signature: 5cWQEe9emC7Myvj8jxVDIWI0jxoshOhitXfsCQBtTS4=
User-Agent: pecs-webhooks/v1
{
"data": {
"id": "2cb108dd-8d47-4a5f-8d36-29324a770f05",
"type": "notifications",
"attributes": {
"event_type": "create_move",
"timestamp": "2020-02-18T11:05:00+00:00"
},
"relationships": {
"move": {
"data": {
"id": "149f1c27-1b7d-4c60-a4d4-ae8afbe92501",
"type": "moves"
},
"links": {
"self": "https://server/api/moves/149f1c27-1b7d-4c60-a4d4-ae8afbe92501"
}
}
}
}
}
It is necessary to verify the signature of the notification with the following algorithm in order to guarantee the authenticity of the message:
- Calculate the SHA-256 HMAC of the message body using the pre-agreed
<SECRET>
when the subscription was created - Base64 encode the calculated HMAC
- Check that the encoded value matches the PECS-SIGNATURE header. If it does match, return an HTTP success status (e.g.
202 - Accepted
). If it does not match, return an error code (e.g. 403 - Forbidden).
Ruby code for calculating the signature is given below:
require 'base64'
require 'openssl'
expected_signature = Base64.strict_encode64(OpenSSL::HMAC.digest('sha256', secret, body))
The supplier should store the id
(also in the PECS-NOTIFICATION-ID
header) of every successful notification received. If a subsequent notification with the same id
is received, it should be ignored.
In the event that the notification is ultimately ignored it is still necessary to return a success
status (e.g. 202 - Accepted
).
The supplier should be mindful that because notifications may need to be retried several times before they are successfully delivered, the order in which they are received will not necessarily match the order in which the events occurred. For example, it is possible for the update_move
notification to be received before the create_move
notification, if the create_move
notification was not successfully delivered on the first try.
To allow for this, the supplier must always fetch the latest move record from the API and must not rely on the event_type
field in the notification.
The notification typically contains minimal data: an id
, a timestamp
, an event_type
, a move:id
and a link to the move record:
{
"data": {
"id": "0706f16b-d849-4f3e-a324-6a43bca5f0e5",
"type": "notifications",
"attributes": {
"event_type": "update_move",
"timestamp": "2020-02-18T17:43:08+00:00"
},
"relationships": {
"move": {
"data": {
"id": "149f1c27-1b7d-4c60-a4d4-ae8afbe92501",
"type": "moves"
},
"links": {
"self": "https://server/api/moves/149f1c27-1b7d-4c60-a4d4-ae8afbe92501"
}
}
}
}
}
Upon receiving (any) notification the supplier should always retrieve the latest record using the self
link in the JSON document.
Please note that the update_move
event does not imply that a move record requires updating on the Book a Secure Move API: rather, the supplier should retrieve the latest record from the API and then take any further action as neccesary (if any).
For example, updating a move status from requested => booked
on the API will in turn trigger an update_move_status
notification. In that case the supplier should retrieve the latest record but no further action is required.
When a move is first created within the system, a notification of event_type
: create_move
is sent. This will normally be followed by an Update Move, and as it progresses will also have Update Move Status events.
Move updates come through as a notification of event_type
: update_move
. Suppliers should expect to receive these when either the move itself is updated or the associated Profile/Person is updated. The only exception is where the move's status is updated in the same transaction. In that case, an Update Move Status notification will be sent and the supplier should also check whether there are associated move changes.
If the status of a move is changed, a notification of event_type
: update_move_status
will be sent. This will mean that either just the status of the move has changed, or some other details have changed and the status has changed. A supplier is expected to watch for a move status of requested
in order to process the move booking. This is considered formal notification of the move.
When a Youth Risk Assessment is first completed a notification of event_type
: complete_youth_risk_assessment
will be sent. Note that the relationship and associated link within this notification is the actual assessment, rather than the move associated with the assessment. A supplier is expected to check the Youth Risk Assessment linked in the notification to ensure all data and records are up to date.
Example:
{
"data": {
"id": "ffffd468-6020-42f9-8fc8-84164f169ceb",
"type": "notifications",
"attributes": {
"event_type": "complete_youth_risk_assessment",
"timestamp": "2020-06-18T12:32:37+01:00"
},
"relationships": {
"youth_risk_assessment": {
"data": {
"id": "fe49dd5e-d783-476e-9e67-51cdb630e948",
"type": "youth_risk_assessments"
},
"links": {
"self": "http://localhost:3000/api/v1/youth_risk_assessments/fe49dd5e-d783-476e-9e67-51cdb630e948"
}
}
}
}
}
If the status of a Youth Risk Assessment is changed to "confirmed", a notification of event_type
: confirm_youth_risk_assessment
will be sent. Note that the relationship and associated link within this notification is the actual assessment, rather than the move associated with the assessment. A supplier is expected to check the Youth Risk Assessment linked in the notification to ensure all data and records are up to date.
Example:
{
"data": {
"id": "ffffd468-6020-42f9-8fc8-84164f169ceb",
"type": "notifications",
"attributes": {
"event_type": "confirm_youth_risk_assessment",
"timestamp": "2020-06-18T12:32:37+01:00"
},
"relationships": {
"youth_risk_assessment": {
"data": {
"id": "fe49dd5e-d783-476e-9e67-51cdb630e948",
"type": "youth_risk_assessments"
},
"links": {
"self": "http://localhost:3000/api/v1/youth_risk_assessments/fe49dd5e-d783-476e-9e67-51cdb630e948"
}
}
}
}
}
When a Person Escort Record is first completed a notification of event_type
: complete_person_escort_record
will be sent. Note that the relationship and associated link within this notification is the actual PER, rather than the move associated with the PER. A supplier is expected to check the Person Escort Record linked in the notification to ensure all data and records are up to date.
Example:
{
"data": {
"id": "ffffd468-6020-42f9-8fc8-84164f169ceb",
"type": "notifications",
"attributes": {
"event_type": "complete_person_escort_record",
"timestamp": "2020-06-18T12:32:37+01:00"
},
"relationships": {
"person_escort_record": {
"data": {
"id": "fe49dd5e-d783-476e-9e67-51cdb630e948",
"type": "person_escort_records"
},
"links": {
"self": "http://localhost:3000/api/v1/person_escort_records/fe49dd5e-d783-476e-9e67-51cdb630e948"
}
}
}
}
}
If a Person Escort Record is amended after completion a notification of event_type
: amend_person_escort_record
will be sent. Note that the relationship and associated link within this notification is the actual PER, rather than the move associated with the PER. A supplier is expected to check the Person Escort Record linked in the notification to ensure all data and records are up to date.
Example:
{
"data": {
"id": "ffffd468-6020-42f9-8fc8-84164f169ceb",
"type": "notifications",
"attributes": {
"event_type": "amend_person_escort_record",
"timestamp": "2020-06-18T12:32:37+01:00"
},
"relationships": {
"person_escort_record": {
"data": {
"id": "fe49dd5e-d783-476e-9e67-51cdb630e948",
"type": "person_escort_records"
},
"links": {
"self": "http://localhost:3000/api/v1/person_escort_records/fe49dd5e-d783-476e-9e67-51cdb630e948"
}
}
}
}
}
Once a Person Escort Record is handed over a notification of event_type
: handover_person_escort_record
will be sent. Note that the relationship and associated link within this notification is the actual PER, rather than the move associated with the PER. A supplier is expected to check the Person Escort Record linked in the notification to ensure all data and records are up to date, as handover details can be amended in the Person Escort Record.
Example:
{
"data": {
"id": "ffffd468-6020-42f9-8fc8-84164f169ceb",
"type": "notifications",
"attributes": {
"event_type": "handover_person_escort_record",
"timestamp": "2020-06-18T12:32:37+01:00"
},
"relationships": {
"person_escort_record": {
"data": {
"id": "fe49dd5e-d783-476e-9e67-51cdb630e948",
"type": "person_escort_records"
},
"links": {
"self": "http://localhost:3000/api/v1/person_escort_records/fe49dd5e-d783-476e-9e67-51cdb630e948"
}
}
}
}
}
If an event is created on a move or a person escort record by a non-supplier user (for example, police users while someone is held in police custody), this will be sent to suppliers using the create_event
event type. Relationships to the associated move, person escort record and event will be included.
Example:
{
"data": {
"id": "ffffd468-6020-42f9-8fc8-84164f169ceb",
"type": "notifications",
"attributes": {
"event_type": "create_event",
"timestamp": "2020-06-18T12:32:37+01:00"
},
"relationships": {
"event": {
"data": {
"id": "946405b0-c97a-466e-9294-5e1490f2a5dd",
"type": "events"
}
},
"person_escort_record": {
"data": {
"id": "fe49dd5e-d783-476e-9e67-51cdb630e948",
"type": "person_escort_records"
},
"links": {
"self": "http://localhost:3000/api/v1/person_escort_records/fe49dd5e-d783-476e-9e67-51cdb630e948"
}
},
"move": {
"data": {
"id": "6a4a1e56-9f9b-403b-a12e-76715492fcb3",
"type": "moves"
},
"links": {
"self": "http://localhost:3000/api/v1/moves/6a4a1e56-9f9b-403b-a12e-76715492fcb3"
}
}
}
}
}
When a lodging is scheduled, suppliers will be notified via a create_lodging
notification.
Example:
{
"data": {
"id": "8155f35b-5035-479b-8e7b-e9ff5df99f73",
"type": "notifications",
"attributes": {
"event_type": "create_lodging",
"timestamp": "2024-04-05 14:52:35 +0100"
},
"relationships": {
"move": {
"data": {
"id": "d6e231b6-45de-466c-81de-3ce503b71c70",
"type": "moves"
},
"links": {
"self": "http://hmpps-book-secure-move-api-staging.apps.cloud-platform.service.justice.gov.uk/api/v1/moves/d6e231b6-45de-466c-81de-3ce503b71c70"
}
},
"lodging": {
"data": {
"id": "ae8e045b-9a99-4218-b283-001379d33fde",
"type": "lodgings"
},
"links": {
"self": "http://hmpps-book-secure-move-api-staging.apps.cloud-platform.service.justice.gov.uk/api/v1/moves/d6e231b6-45de-466c-81de-3ce503b71c70/lodgings/ae8e045b-9a99-4218-b283-001379d33fde"
}
}
}
}
}
When the details of a lodging are updated, suppliers will be notified via an update_lodging
notification.
Example:
{
"data": {
"id": "c6315785-b827-4a61-81b9-fbd8cda6fd19",
"type": "notifications",
"attributes": {
"event_type": "update_lodging",
"timestamp": "2024-03-28 15:57:04 +0000"
},
"relationships": {
"move": {
"data": {
"id": "b88eb60e-3204-4887-8d91-92de55c551cb",
"type": "moves"
},
"links": {
"self": "http://hmpps-book-secure-move-api-staging.apps.cloud-platform.service.justice.gov.uk/api/v1/moves/b88eb60e-3204-4887-8d91-92de55c551cb"
}
},
"lodging": {
"data": {
"id": "e3f019d9-8e4e-43b5-9b87-fd3c32a7f082",
"type": "lodgings"
},
"links": {
"self": "http://hmpps-book-secure-move-api-staging.apps.cloud-platform.service.justice.gov.uk/api/v1/moves/b88eb60e-3204-4887-8d91-92de55c551cb/lodgings/e3f019d9-8e4e-43b5-9b87-fd3c32a7f082"
}
}
}
}
}
When a lodging is cancelled, suppliers will be notified via a cancel_lodging
notification.
Example:
{
"data": {
"id": "ef0d7f9e-aa5c-4b15-8172-4f76333a4cc0",
"type": "notifications",
"attributes": {
"event_type": "cancel_lodging",
"timestamp": "2024-03-28 16:09:20 +0000"
},
"relationships": {
"move": {
"data": {
"id": "5498d74d-bb96-42a4-9360-4e970676e60d",
"type": "moves"
},
"links": {
"self": "http://hmpps-book-secure-move-api-staging.apps.cloud-platform.service.justice.gov.uk/api/v1/moves/5498d74d-bb96-42a4-9360-4e970676e60d"
}
},
"lodging": {
"data": {
"id": "43acabb6-100c-4e1e-ae1a-8085656852ae",
"type": "lodgings"
},
"links": {
"self": "http://hmpps-book-secure-move-api-staging.apps.cloud-platform.service.justice.gov.uk/api/v1/moves/5498d74d-bb96-42a4-9360-4e970676e60d/lodgings/43acabb6-100c-4e1e-ae1a-8085656852ae"
}
}
}
}
}
- API Guide
- Version 2
- Asked Questions
- Webhook & Email notifications
- Walkthroughs
- Deployment
- Useful Queries
- Data quality improvements
-
Journeys and Payment Related Calls
- Single journey move
- Redirection before move commences
- Redirection after move commences
- Lockouts and Lodgings
- Assessments
- Event Documentation
- GPS Track a move