Life Event Verification (LEV) API Guide
=======================================
:toc:
:numbered:
[role=hideable]
NOTE: This documentation is limited by GitHub's version of ASCII Docs, the full
version may be viewed in the docs repo: https://ukhomeoffice.github.io/lev-api-docs
[IMPORTANT,role=unhideable]
====
The contents of this repo are automatically generated; to make changes
follow these steps:
. `git clone https://gitlab.digital.homeoffice.gov.uk/lev/lev-api-scala`
. edit the `lev-api-scala/docs/README.adoc` file
. `commit` and `push` your changes (to a new branch)
. create a *merge request* detailing the changes
. upon successful approval of the merge request the changes will be automatically added
to the `lev-api-docs` repo
====
== Mock API
It is possible to run a mock version of the API as follows:
=== Running a mock API with docker (from Quay.io)
The latest version of the mock API can be run straight from the `quay.io` hosted image:
```
docker pull quay.io/ukhomeofficedigital/lev-api-mock
docker run -p 8080:8080 quay.io/ukhomeofficedigital/lev-api-mock
```
=== Running a mock API with docker (from this repo)
[role=hideable]
NOTE: The paths in this section refer to the root of the docs project:
https://github.com/UKHomeOffice/lev-api-docs
The easiest way to run the mock API is with Docker
```
./mock/build_mock_api_docker.sh
./mock/run_mock_api_docker.sh
```
=== Running a mock API without docker
It is also possible to run it without docker if you have the *wiremock* jar file:
```
cd mock
java -jar wiremock.jar --port=8080
```
== Authenticating with the API
To use the API you will need to provide 2 forms of authentication:
. A client certificate
. An auth token, which must be obtained by hitting the `/oauth/login` endpoint
[IMPORTANT]
====
*The client certificate must be included in every request to the API, but is NOT shown
in this documentation for simplicity.*
Adding a client certificate to a `curl` request can easily be achieved by adding the
following arguments:
[source,bash]
----
curl --cert-type pem --key client.key --cert client.crt ...
----
====
NOTE: The client certificate is not needed when sending requests to the _mock API_.
The rest of this section contains examples which have been provided to help
troubleshoot issues with authentication.
=== A successful request with valid credentials
+++ +++
*Example `curl` request* with dummy credentials
+++
+++
include::snippets/auth/valid-auth/curl-request.adoc[]
+++
+++
+++ +++
*Example `HTTP` request* with dummy credentials
+++
+++
include::snippets/auth/valid-auth/http-request.adoc[]
+++
+++
+++ +++
*Example response* containing the *access token*
+++
+++
include::snippets/auth/valid-auth/http-response.adoc[]
+++
+++
=== Authentication problems
Generally authentication problems are reported as `401 Unauthorized` errors.
==== A request with invalid credentials
+++ +++
*Example `curl` request* with invalid credentials
+++
+++
include::snippets/auth/invalid-credentials/curl-request.adoc[]
+++
+++
+++ +++
*Example `HTTP` request* with invalid credentials
+++
+++
include::snippets/auth/invalid-credentials/http-request.adoc[]
+++
+++
+++ +++
*Example response* detailing the error
+++
+++
include::snippets/auth/invalid-credentials/http-response.adoc[]
+++
+++
==== An unauthorised request
+++ +++
*Example `curl` request* without the required `Authorization` header
+++
+++
include::snippets/auth/unauthorized/curl-request.adoc[]
+++
+++
+++ +++
*Example `HTTP` request* without the required `Authorization` header
+++
+++
include::snippets/auth/unauthorized/http-request.adoc[]
+++
+++
+++ +++
*Example response* detailing the error
+++
+++
include::snippets/auth/unauthorized/http-response.adoc[]
+++
+++
==== A request with missing credentials
+++ +++
*Example `curl` request* without the required `password` parameter
+++
+++
include::snippets/auth/invalid-post/curl-request.adoc[]
+++
+++
+++ +++
*Example `HTTP` request* without the required `password` parameter
+++
+++
include::snippets/auth/invalid-post/http-request.adoc[]
+++
+++
+++ +++
*Example response* detailing the error
+++
+++
include::snippets/auth/invalid-post/http-response.adoc[]
+++
+++
==== A request with no client certificate
Whilst none of the examples here contain the required client certificate, this example
has been explicitly included to show how the resulting `403 Forbidden` error would
look.
+++ +++
*Example `curl` request* without the required client certificate
+++
+++
include::snippets/auth/no-client-cert/curl-request.adoc[]
+++
+++
+++ +++
*Example `HTTP` request* without the required client certificate
+++
+++
include::snippets/auth/no-client-cert/http-request.adoc[]
+++
+++
+++ +++
*Example response* detailing the error
+++
+++
include::snippets/auth/no-client-cert/http-response.adoc[]
+++
+++
== Requesting birth record data
All successful requests to the API will result in a `200 OK` HTTP status code and are
described in this section.
=== Requesting a specific birth record using a System Number
The best way to get birth data is by providing the relevant System Number, a nine
digit unique identifier for the birth record.
+++ +++
*Example `curl` request* specifying a *System Number*
+++
+++
include::snippets/system-number/matching-record-999999901/curl-request.adoc[]
+++
+++
+++ +++
*Example `HTTP` request* specifying a *System Number*
+++
+++
include::snippets/system-number/matching-record-999999901/http-request.adoc[]
+++
+++
+++ +++
*Example response* is a *JSON object* containing the birth record data
+++
+++
include::snippets/system-number/matching-record-999999901/http-response.adoc[]
+++
+++
=== Searching for a birth record
When the System Number of the birth record is not known, a search of the records can
be made by supplying the following three parameters in the URL query string:
- `forenames` : the first name is mandatory, and can be accompanied by any middle
names (all separated by spaces)
- `lastname` : the last name is mandatory
- `dateofbirth` : the date of birth is also mandatory
+++ +++
*Example `curl` request* with search parameters
+++
+++
include::snippets/search/multiple-matching-record/curl-request.adoc[]
+++
+++
+++ +++
*Example `HTTP` request* with search parameters
+++
+++
include::snippets/search/multiple-matching-record/http-request.adoc[]
+++
+++
+++ +++
*Example response* is a *JSON array* containing three matching birth records
+++
+++
include::snippets/search/multiple-matching-record/http-response.adoc[]
+++
+++
TIP: The API will only return at most *25* matching records. In the unlikely case
where there might be more than 25 people with the same first name, last name, and
date of birth; you will have to add middle names to the query to make the search more
exacting.
=== When no matching records are found
If no records matching the search terms can be found, the API will return an empty
array.
+++ +++
*Example `curl` request*
+++
+++
include::snippets/search/no-matches/curl-request.adoc[]
+++
+++
+++ +++
*Example `HTTP` request*
+++
+++
include::snippets/search/no-matches/http-request.adoc[]
+++
+++
+++ +++
*Example response* is an *empty JSON array*
+++
+++
include::snippets/search/no-matches/http-response.adoc[]
+++
+++
== Common errors and responses
=== Non-existent route
Making a request to an invalid end point will result in the standard `404 Not Found`
error.
==== Requesting an endpoint that doesn't exist
+++ +++
*Example `curl` request* to an invalid endpoint
+++
+++
include::snippets/invalid-endpoint/curl-request.adoc[]
+++
+++
+++ +++
*Example `HTTP` request* to an invalid endpoint
+++
+++
include::snippets/invalid-endpoint/http-request.adoc[]
+++
+++
+++ +++
*Example response* detailing the error
+++
+++
include::snippets/invalid-endpoint/http-response.adoc[]
+++
+++
==== Specifying a System Number that doesn't exist
+++ +++
*Example `curl` request* with a non-existing System Number
+++
+++
include::snippets/system-number/no-record/curl-request.adoc[]
+++
+++
+++ +++
*Example `HTTP` request* with a non-existing System Number
+++
+++
include::snippets/system-number/no-record/http-request.adoc[]
+++
+++
+++ +++
*Example response* detailing the error
+++
+++
include::snippets/system-number/no-record/http-response.adoc[]
+++
+++
=== Missing search parameters
Missing search parameters will result in a standard `400 Bad Request` error.
==== Missing forenames parameter
+++ +++
*Example `curl` request* without the `forenames` parameter
+++
+++
include::snippets/search/no-forenames/curl-request.adoc[]
+++
+++
+++ +++
*Example `HTTP` request* without the `forenames` parameter
+++
+++
include::snippets/search/no-forenames/http-request.adoc[]
+++
+++
+++ +++
*Example response* detailing the error
+++
+++
include::snippets/search/no-forenames/http-response.adoc[]
+++
+++
==== Missing last name parameter
+++ +++
*Example `curl` request* without the `lastname` parameter
+++
+++
include::snippets/search/no-lastname/curl-request.adoc[]
+++
+++
+++ +++
*Example `HTTP` request* without the `lastname` parameter
+++
+++
include::snippets/search/no-lastname/http-request.adoc[]
+++
+++
+++ +++
*Example response* detailing the error
+++
+++
include::snippets/search/no-lastname/http-response.adoc[]
+++
+++
==== Missing date of birth parameter
+++ +++
*Example `curl` request* without the required `dateofbirth` parameter
+++
+++
include::snippets/search/no-dob/curl-request.adoc[]
+++
+++
+++ +++
*Example `HTTP` request* without the required `dateofbirth` parameter
+++
+++
include::snippets/search/no-dob/http-request.adoc[]
+++
+++
+++ +++
*Example response* detailing the error
+++
+++
include::snippets/search/no-dob/http-response.adoc[]
+++
+++
=== Other request errors
==== Invalid date of birth provided
+++ +++
*Example `curl` request* with an incorrect `dateofbirth` parameter
+++
+++
include::snippets/search/invalid-dob/curl-request.adoc[]
+++
+++
+++ +++
*Example `HTTP` request* with an incorrect `dateofbirth` parameter
+++
+++
include::snippets/search/invalid-dob/http-request.adoc[]
+++
+++
+++ +++
*Example response* detailing the error
+++
+++
include::snippets/search/invalid-dob/http-response.adoc[]
+++
+++
NOTE: Currently the response status is `500 Internal Server Error`; this is not the
intention and will be fixed in a future release to show the proper `400 Bad Request`
instead.
==== Incorrectly providing forenames
The easiest way to provide forenames is using the `forenames` parameter, however
forenames may alternatively be provided using the numbered version: `forename1`,
`forename2`, `forename3`, and `forenames4`. Providing a mix of the forename parameters
will result in a standard `400 Bad Request` error.
+++ +++
*Example `curl` request* with both `forenames` and `forename1` parameters
+++
+++
include::snippets/search/forenames-and-forename1/curl-request.adoc[]
+++
+++
+++ +++
*Example `HTTP` request* with both `forenames` and `forename1` parameters
+++
+++
include::snippets/search/forenames-and-forename1/http-request.adoc[]
+++
+++
+++ +++
*Example response* detailing the error
+++
+++
include::snippets/search/forenames-and-forename1/http-response.adoc[]
+++
+++
NOTE: The use of `forename1`, `forename2`, `forename3`, and `forename4` is strongly
discouraged and should be considered deprecated in favour of the `forenames` parameter.
++++
++++
== Retrieving audit information
For certain users with special permissions, it is possible to retrieve an aggregated
count of system users' search activity.
=== Auditor level access
All requests to the audit information end points must be made by a user with auditor
level permissions, otherwise the request will fail with the standard `401
Unauthorised` error.
+++ +++
*Example `curl` request* by an API user without the special auditor permissions
+++
+++
include::snippets/audit/invalid-permissions/curl-request.adoc[]
+++
+++
+++ +++
*Example `HTTP` request* by an API user without the special auditor permissions
+++
+++
include::snippets/audit/invalid-permissions/http-request.adoc[]
+++
+++
+++ +++
*Example response* detailing the error
+++
+++
include::snippets/audit/invalid-permissions/http-response.adoc[]
+++
+++
=== Audit record filters
The audit record data returned can be filtered by providing the following
parameters.
==== A date range
The date range is optional. It can be omitted entirely, only one part specified, or
fully specified by providing the `from` and `to` date parameters.
+++ +++
*Example `curl` request* filtering out records except those made between yesterday
and one minute ago
+++
+++
include::snippets/audit/from-yesterday-until-a-minute-ago/curl-request.adoc[]
+++
+++
+++ +++
*Example `HTTP` request* filtering out records except those made between yesterday
and one minute ago
+++
+++
include::snippets/audit/from-yesterday-until-a-minute-ago/http-request.adoc[]
+++
+++
+++ +++
*Example response* detailing the error
+++
+++
include::snippets/audit/from-yesterday-until-a-minute-ago/http-response.adoc[]
+++
+++