Skip to content

Assessments

Martyn Whitwell edited this page Mar 22, 2021 · 8 revisions

Assessment API Calls

The API supports the creation of multiple types of assessments, which are a list of questions that aim to capture different types of information about a person that is being moved.

The assessments currently supported by the API include:

In the following document we have outlined a high level approach to the assessment endpoints and how to answer those questions. It is worth noting that this is still a draft and subject to change and is being circulated to gather early feedback.

An assessment's list of questions, their content and hierarchy, as well as the expected answers will be provided via a "questions and answers" framework as a set of YAML definitions, one for each section. These definitions will describe the questions, their format and validation rules. The supplier can choose to import them (for example to enable them to apply validations themselves) or simply use them as a reference to understand the structure of the questions. The framework will also be used to version different sets of questions in the API.

The question definitions will be versioned. To view all versions available through the API please refer to framework endpoints.

Endpoint walkthrough

All supported assessments follow the same rules and patterns around creation (POST), update (PATCH), answering questions (PATCH) and retrieving data (GET) methods, however endpoint path names are particular to each assessment: /person-escort-records and /youth-risk-assessments.

Given a new profile has been created and attached to a move. As a supplier I want to be able to:

Create a new Assessment

Given an existing move with id: ea5ace8e-e9ad-4ca3-9977-9bf69e3b6154, the following endpoint can be used to create a new assessment (either a person escort record or youth risk assessment), associated to the move and the attached profile, as well as the version of the questions framework as follows :

POST /person_escort_records
POST /youth_risk_assessments
{
  "data": {
    "type": "assessment_type_name", # Either `person_escort_records` or `youth_risk_assessments` depending on the assessment endpoint
    "attributes": {
      "version": "1.2.0"
    },
    "relationships": {
      "move": {
        "data": {
          "type": "moves",
          "id": "ea5ace8e-e9ad-4ca3-9977-9bf69e3b6154"
        }
      }
    }
  }
}

Specifying the version will associate the appropriate framework and associated questions matching the version.

When successful, a new assessment will be created and associated with the move, profile and framework:

{
  "data": {
    "id": "f0a91e16-1b0e-4e1f-93fe-319dda9933e6",
    "type": "assessment_type_name", # Either `person_escort_records` or `youth_risk_assessments` depending on the assessment endpoint
    "attributes": {
      "status": "not_started",
      "version": "1.2.0",
      "confirmed_at": null
    },
    "relationships": {
      "move": {
        "data": {
          "type": "moves",
          "id": "ea5ace8e-e9ad-4ca3-9977-9bf69e3b6154"
        }
      },
      "profile": {
        "data": {
          "type": "profiles",
          "id": "df4sxq7e-e9ad-4ca3-9977-9bf69e3b9977"
        }
      },
      "responses": {
        "data": [
          {
            "type": "framework_responses",
            "id": "96b16573-db3c-4daa-aa56-42e7b2e20f31"
          },
          {
            "type": "framework_responses",
            "id": "b254f1ff-a7cd-443b-8e92-9c6340ead840"
          }
        ]
      },
      "framework": {
        "data": {
          "type": "frameworks",
          "id": "9977ce8e-e9ad-4ca3-9977-9bf69e3b6154"
        }
      }
    }
  }
}

The responses will be created unanswered and will be based on the version of the framework that was supplied during creation. Each response will have a relationship to the question and the questions will show the relationship to any dependent questions.

Get an existing Assessment

Given an existing Assessment with id: f0a91e16-1b0e-4e1f-93fe-319dda9933e6, use the following endpoint to get an assessment with all the responses associated to the relevant questions:

GET /person_escort_records/:recordId
GET /youth_risk_assessments/:recordId

{
  "data": {
    "id": "f0a91e16-1b0e-4e1f-93fe-319dda9933e6",
    "type": "assessment_type_name", # Either `person_escort_records` or `youth_risk_assessments` depending on the assessment endpoint
    "attributes": {
      "version": "1.2.0",
      "status": "not_started",
      "confirmed_at": null
    },
    "relationships": {
      "move": {
        "data": {
          "type": "moves",
          "id": "ea5ace8e-e9ad-4ca3-9977-9bf69e3b6154"
        }
      },
      "profile": {
        "data": {
          "type": "profiles",
          "id": "df4sxq7e-e9ad-4ca3-9977-9bf69e3b9977"
        }
      },
      "responses": {
        "data": [
          {
            "type": "framework_responses",
            "id": "96b16573-db3c-4daa-aa56-42e7b2e20f31"
          },
          {
            "type": "framework_responses",
            "id": "b254f1ff-a7cd-443b-8e92-9c6340ead840"
          }
        ]
      },
      "framework": {
        "data": {
          "type": "frameworks",
          "id": "9977ce8e-e9ad-4ca3-9977-9bf69e3b6154"
        }
      }

    }
  },
  "included": [
    {
      "type": "framework_responses",
      "id": "96b16573-db3c-4daa-aa56-42e7b2e20f31",
      "attributes": {...},
      "relationships": {
        "question": {
          "data": {
            "type": "framework_questions",
            "id": "81b16573-db3c-4daa-aa56-42e7b2e20f31"
          }
        }
      }
    },
    {
      "type": "framework_responses",
      "id": "b254f1ff-a7cd-443b-8e92-9c6340ead840",
      "attributes": {...},
      "relationships": {
        "question": {
          "data": {
            "type": "framework_questions",
            "id": "b268h1hh-a7cd-443b-8e52-9c3440ead760"
          }
        }
      }
    },
    {
      "type": "frameworks",
      "id": "9977ce8e-e9ad-4ca3-9977-9bf69e3b6154",
      "attributes": {...},
      "relationships": {
        "questions": {
          "data": [
            {
              "type": "framework_questions",
              "id": "b268h1hh-a7cd-443b-8e52-9c3440ead760"
            },
            {
              "type": "framework_questions",
              "id": "b268h1hh-a7cd-443b-8e52-9c3440ead760"
            }
          ]
        }
      }
    }
  ]
}

Submit a response for an assessment question

To answer a question, a value can be passed to the response using the following endpoint:

PATCH /framework_responses/:responseId

{
  "data": {
    "type": "framework_responses",
    "attributes": {
      "value": "Some value"
    }
  }
}

When successful, a response will now be marked as answered with the given value, and the responded field will be marked as true. If an invalid answer was otherwise supplied, a validation error will be returned instead.

There are different types of values according to the type of question being answered:

String

If a question is of type text, textarea or radio, the following response with the value attribute can be submitted, either with one of the options of the radio question, or any text if the question is of type text/textarea

PATCH /framework_responses/:responseId

{
  "data": {
    "type": "framework_responses",
    "attributes": {
      "value": "Yes"
    }
  }
}

Array

If a question is of type checkbox, the following response with the value attribute can be submitted, either with one or multiple options of the checkbox question.

PATCH /framework_responses/:responseId

{
  "data": {
    "type": "framework_responses",
    "attributes": {
      "value": ["Level 1", "Level 2"]
    }
  }
}

Object::followup_comment

If a question is of type radio but requires further details for one or all options, the following response with the value attribute can be submitted, with the keys option and details. The option key will hold one of the question options required, and details the extra comments and details for the selected option.

PATCH /framework_responses/:responseId

{
  "data": {
    "type": "framework_responses",
    "attributes": {
      "value": {
        "option": "Yes",
        "details": "Some further details"
      }
    }
  }
}

Collection::followup_comment

If a question is of type checkbox but requires further details for one or all options, the following response with the value attribute can be submitted, with an array of objects. The keys of each object include an option and details. The option key will hold one of the question options required, and details the extra comments and details for the selected option.

PATCH /framework_responses/:responseId

{
  "data": {
    "type": "framework_responses",
    "attributes": {
      "value": [
        {
          "option": "Level 1",
          "details": "Some further details"
        },
        {
          "option": "Level 3",
          "details": "Some further details"
        }
      ]
    }
  }
}

Collection::add_multiple_items

If a question is of type add_multiple_items, a response with the value attribute can be submitted, with an array of objects. The add_multiple_items question type aims to let users add multiple items of the same thing. Each object represents the item mapped to a list of grouped responses for that item.

Each response in the list of responses maps to a nested or descendant question for that item, where the keys of each response include a value and framework_question_id attribute. The value attribute will hold the response for that question, in the same format defined for the above question types. The framework_question_id maps to the id of the question. The questions for an item can be accessed by the parent add_multiple_items question through the descendants relationship.

For example, to add additional property items where each item requires specifying a serial number (a question with type text) and selecting the item type from a list (a question with type checkbox), the following response can be submitted:

PATCH /framework_responses/:responseId

{
  "data": {
    "type": "framework_responses",
    "attributes": {
      "value": [
        {
          "item": 1,
          "responses": [
            { "value": "U7565", "framework_question_id": "652193fa-e564-4823-b91d-b39fad659f16" },
            { "value": ["Medication"], "framework_question_id": "9dfc7c51-89b3-47dd-8f0f-9ee8b11de14e" }
          ]
        },
        {
          "item": 2,
          "responses": [
            { "value": "U7566", "framework_question_id": "652193fa-e564-4823-b91d-b39fad659f16" },
            { "value": ["UK currency"], "framework_question_id": "9dfc7c51-89b3-47dd-8f0f-9ee8b11de14e" }
          ]
        }
      ]
    }
  }
}

Hand-over / Confirming the Person Escort Record

When all responses for questions have been provided, an assessment can now be confirmed and handed over, using the following endpoints:

PATCH /person_escort_records/:recordId
{
  "data": {
    "type": "person_escort_records",
    "attributes": {
      "status": "confirmed",
      "handover_occurred_at": "2021-03-22T11:03:12+00:00",
      "handover_details": {
        "receiving_officer": "ST",
        "dispatching_officer": "Zarka Sultana",
        "receiving_officer_id": "AB13456X",
        "dispatching_officer_id": "1234",
        "receiving_organisation": "Supplier Bros & Co",
        "receiving_officer_contact": "0123 456 789",
        "dispatching_officer_contact": "07987654321"
      }
    }
  }
}

The intention is that when the PATCH endpoint is used to attempt to set the status to confirmed, then the Book a Secure move API will validate that all relevant questions have been answered, including any that are dependent on the answers to previous questions. Setting the status as confirmed will also record the timestamp of confirmation.

Note that the fields handover_occurred_at and handover_details are specific to Person Escort Records and are not relevant to Youth Risk Assessments:

  • handover_occurred_at - timestamp for when the handover (change of custody supplier <==> authority) took place

  • handover_details - optional free-form json field to record the dispatching and receiving officiers. It may be comprised of the following optional sub-fields:

    • receiving_officer - name or initials of officer receiving the person being moved
    • dispatching_officer - name or initials of officer handing over the person being moved
    • receiving_officer_id - ID of officer receiving the person being moved
    • dispatching_officer_id - ID of officer handing over the person being moved
    • receiving_organisation- organisation receiving the person being moved - e.g. Geoamey / Serco / Police / HMPPS / MoJ
    • receiving_officer_contact - phone number or contact details of officer receiving the person being moved
    • dispatching_officer_contact - phone number or contact details of officer handing over the person being moved

The completion status of all relevant questions being answered is calculated by the responded field on each response. The responded field is marked as true if a response has been reviewed by a user and a response value is sent back to the API. For conditional questions that are not required, an empty value needs to be sent to the API to indicate a review has been attempted to ensure that a user has viewed the question and chose not to answer it, even if no response was provided. The values to responses only need to be provided for the path of responses required, including any that are dependent on the answers to previous questions, regardless if they are optional or not.

Completing the Youth Risk Assessment

When all responses for questions have been provided, an assessment can now be signed-off to mark completion, using the following endpoints:

PATCH /youth_risk_assessments/:recordId
{
  "data": {
    "type": "youth_risk_assessments",
    "attributes": {
      "status": "confirmed"
    }
  }
}

The intention is that when the PATCH endpoint is used to attempt to set the status to confirmed, then the Book a Secure move API will validate that all relevant questions have been answered, including any that are dependent on the answers to previous questions. Setting the status as confirmed will also record the timestamp of confirmation.

The completion status of all relevant questions being answered is calculated by the responded field on each response. The responded field is marked as true if a response has been reviewed by a user and a response value is sent back to the API. For conditional questions that are not required, an empty value needs to be sent to the API to indicate a review has been attempted to ensure that a user has viewed the question and chose not to answer it, even if no response was provided. The values to responses only need to be provided for the path of responses required, including any that are dependent on the answers to previous questions, regardless if they are optional or not.

Submitting an entire Assessment

The approach above requires a response to be sent for each question, and for dependent questions this may necessitate waiting for the response to the first request before sending another, depending on the payload received. If this approach is not preferable, an additional endpoint can be utilised to submit all assessment responses in a single request.

Since JSON:API does not formally support BULK endpoints and does not have an official specification, we have used previously supported extensions for BULK endpoints found here as a guidance for submitting multiple responses at once.

The following endpoint can accept multiple responses for the assessment at once:

PATCH /person_escort_records/:personEscortRecordId/framework_responses
PATCH /youth_risk_assessments/:youthRiskAssessmentId/framework_responses

{
  "data": [
    {
      "id": "96b16573-db3c-4daa-aa56-42e7b2e20f31",
      "type": "framework_responses",
      "attributes": {
        "value": "Yes"
      }
    },
    {
      "id": "b254f1ff-a7cd-443b-8e92-9c6340ead840",
      "type": "framework_responses",
      "attributes": {
        "value": [
          {
            "option": "Level 1",
            "details": "Some further details"
          },
          {
            "option": "Level 3",
            "details": "Some further details"
          }
        ]
      }
    }
  ]
}

If all responses are valid, all responses will be submitted and updated with their respective values, otherwise no responses are updated, and the relevant validation errors will be returned as follows:

{
  "errors": [
    {
      "id": "96b16573-db3c-4daa-aa56-42e7b2e20f31",
      "title": "Invalid Attribute",
      "detail": "Value is not included in the list"
      "source": { "pointer": "/data/attributes/value" },
    },
    {
      "id": "b254f1ff-a7cd-443b-8e92-9c6340ead840",
      "title": "Invalid Attribute",
      "detail": "Value: ["foo-bar"] is incorrect type"
      "source": { "pointer": "/data/attributes/value" },
    }
  ]
}

Reuse the assessment for a different move

If an existing assessment is to be reused for a different move (e.g. a return move), the following endpoint can accept an existing profile associated to the assessment type when creating the new move.

Given an existing profile with id: ea5ace8e-e9ad-4ca3-9977-9bf69e3b6154 which is associated to an existing PER from a previous move, create a new move associated to this existing profile, assessment answers and PER using the following endpoint:

POST /moves
{
  "data": {
    "type": "moves",
    "attributes": {...},
    "relationships": {
      "profiles": {
        "type": "profiles",
        "id": "ea5ace8e-e9ad-4ca3-9977-9bf69e3b6154"
      }
    }
  }
}

If successful the move will now be associated to the same profile, assessment answers and PER as the previous move. The PER will be accessible from the new move through the profile, however the PER itself will remain associated to the previous move for maintaining data integrity, and audit reasons.

NOMIS resources

When a Person escort record is created from a prison location, NOMIS alerts, personal care needs and reasonable adjustments are synchronised with the responses to the new Person escort record. The specific codes that map each type of NOMIS resource to a question can be found in the framework under the nomis_mappings key. This curated list of mappings to each question have been selected to help answer questions when NOMIS resources are present.

An example of a NOMIS resource associated to a response would look like:

{
  "type": "framework_nomis_mappings",
  "id": "96b16573-db3c-4daa-aa56-42e7b2e20f31",
  "attributes": {
    "code": "WHEEL_ACC",
    "code_type": "reasonable_adjustment",
    "code_description" "Wheelchair access",
    "comments": "setup ramp to building"
    "start_date": "2013-03-29"
    "end_date":, "2013-03-29"
    "creation_date": null,
    "expiry_date": null
  },
  "relationships": {
    "response": {
      "data": {
        "type": "framework_responses",
        "id": "81b16573-db3c-4daa-aa56-42e7b2e20f31"
      }
    }
  }
}

NOMIS resources are not associated to a response if they are no longer relevant. The following rules apply to each type of NOMIS resource for them to be synchronised to a response:

  • Alerts: should be active and not expired
  • Personal care needs: the status should equal the value ‘ON’, and the end date should be either empty, today or in the future
  • Reasonable adjustments: the end date should be either empty, today or in the future

Pre-filling from a previous assessment

If a previous assessment for a person has been completed and confirmed, responses can be used to pre-populate a new assessment's responses on creation for the same person. The specific questions that can be pre-filled by previous ones can be found in the framework where the prefill key is set to either true or false.

When a response is pre-filled the prefilled attribute will be marked as true on the response, and the value attribute will be populated with the previous value for the same question:

{
  "id": "84ec1f25-1c41-48d5-b912-71478e413da0",
  "type": "framework_responses",
  "attributes": {
    "value": "Yes",
    "responded": false,
    "prefilled": true,
    "value_type": "string"
  }
},

The previous assessment will also be associated to the current assessment through the prefill_source relationship as follows:

"relationships": {
  "prefill_source": {
    "data": {
      "id": "895cdca1-f690-431e-8c73-2e8c1d91c166",
      "type": "assessment_type_name", # Either `person_escort_records` or `youth_risk_assessments` depending on the assessment endpoint
    }
  },
  ...
}

Question versioning

To support changes to the assessment such as adding or removing a question or changing the structure of sections, we will be providing support for multiple versions of question sets and their responses. This allows for us to support previous versions of questions for an agreed period of time.

Versioning for the assessments' question definitions will be separate from API versioning because the API will not change when only changing the assessment questions or definitions.

Notifications

After all responses of an assessment have been provided, an assessment can be signed-off to mark completion. This is done by "confirming" the assessment. After this action is successful, a Webhook Notification​ will be triggered for the associated move as well as an email notification. We will be utilising the move notification, with the event type ​confirm_person_escort_record​ or confirm_youth_risk_assessment​ for this action. Please ensure checking the assessment associated with the move after receiving a confirm_person_escort_record or confirm_youth_risk_assessment notification to ensure all data and records are up to date, as special vehicle requests can be amended in the PER. An example of a confirm_person_escort_record Webhook notification:

{
  "data": {
    "id": "​0706f16b-d849-4f3e-a324-6a43bca5f0e5​",
    "type": "​notifications​",
    "attributes": {
      "event_type": "​confirm_person_escort_record​",
      "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"
        }
      }
    }
  }
}

Frameworks

To view frameworks available via the API, for both the Person Escort Record and Youth Risk Assessment, the following endpoint can be used to retrieve all versions available:

GET /reference/frameworks
{
  "data": [
    {
      "id": "c1a49a29-66fc-4f27-91b1-1435b4bbc881",
      "type": "frameworks",
      "attributes": {
        "name": "youth-risk-assessment",
        "version": "2.1.0"
      },
      "relationships": {}
    },
    {
      "id": "ca6bdd16-66ae-4b4a-8ea1-301f5fd95825",
      "type": "frameworks",
      "attributes": {
        "name": "person-escort-record",
        "version": "2.1.0"
      },
      "relationships": {}
    },
    {
      "id": "21979a9f-7e92-45e7-870a-87ef448ea591",
      "type": "frameworks",
      "attributes": {
        "name": "youth-risk-assessment",
        "version": "2.0.0"
      },
      "relationships": {}
    },
    {
      "id": "5eec5ea5-0bda-42bb-a87f-1b8b1840910f",
      "type": "frameworks",
      "attributes": {
        "name": "person-escort-record",
        "version": "2.0.0"
      },
      "relationships": {}
    }
  ]
}

To view all questions and flags for a single framework version, the following endpoint and query parameters can be used to retrieve all those included resources:

GET /reference/frameworks/:frameworkId?include=questions,questions.flags,questions.descendants.**,questions.descendants.flags
{
  "data": {
    "id": "ca6bdd16-66ae-4b4a-8ea1-301f5fd95825",
    "type": "frameworks",
    "attributes": {
      "name": "person-escort-record",
      "version": "2.1.0"
    },
    "relationships": {
      "questions": {
        "data": [
          {
            "id": "4bf27cbb-e55d-4b5d-8165-89261c53780c",
            "type": "framework_questions"
          },
          ...
        ]
      }
    }
  },
  "included": [
    {
      "id": "4bf27cbb-e55d-4b5d-8165-89261c53780c",
      "type": "framework_questions",
      "attributes": {
        "key": "communication-needs",
        "section": "risk-information",
        "question_type": "radio",
        "options": [
          "Yes",
          "No"
        ],
        "response_type": "object::followup_comment"
      },
      "relationships": {
        "descendants": {
          "data": [
            {
              "id": "77376765-6047-4978-8252-d02623ae4a27",
              "type": "framework_questions"
            }
          ]
        },
        "flags": {
          "data": [
            {
              "id": "eed2edd2-d78c-4af1-8b9e-0d74892876c5",
              "type": "framework_flags"
            }
          ]
        }
      }
    },
    {
      "id": "eed2edd2-d78c-4af1-8b9e-0d74892876c5",
      "type": "framework_flags",
      "attributes": {
        "flag_type": "alert",
        "title": "Other risks",
        "question_value": "Yes"
      }
    },
    ...
  ]
}

Further discussions and communication

To invite further discussions and feedback, we propose that both the technical supplier teams as well as the API teams communicate directly via Slack to shorten the feedback loop and to allow for technical questions and concerns to be addressed quickly and efficiently.

Clone this wiki locally