API access approval
Some areas of the Hub hold health information and criminal record information. Their API calls, and the webhook events they send, are not open to every API key in live. Your organisation asks for access once, in the Hub, and a member of our team reviews the request. This page explains which areas need approval, how to ask, what your integration sees before and after the decision, the error codes, and how to test your handling in the sandbox.
The sandbox is always open. It never asks for approval, so you can build and test every area there without asking for anything. This rule applies to live keys only.
Which areas need approval
By default two areas need approval:
Occupational Health (
occupational-health), andDBS & Right To Work (
dbs-rtw).The team can change which areas need approval, so do not hard-code the list. Read it from
GET /api/v2/account/api-access (see Check where you stand).Approval covers both halves of an area:
API calls. Every endpoint of the area, for any key that holds a scope of it.
Webhook events. All the events that start with
occupational-health., plus dbs-rtw.dbs.status_changed, dbs-rtw.rtw.status_changed and dbs-rtw.alert.raised.Every other area (Hub core candidates, Online Training, Practical Training, Virtual BLS Training, Clinical Interviews, Clinical Appraisals, References, Registration Monitoring and Training Verification) is open to any key that holds the scope.
The Zapier app never uses these areas: it has no steps for them and refuses a key that can read them.
How to ask for access
Approval belongs to your organisation (your client in the Hub), not to one key. A user of your organisation who may manage developer settings asks for it in the Hub.
- Sign in to the Hub client portal and open Developer, then API access.
- Choose one area or all of the areas that need approval.
- Answer the questions on the form:
What you will build and how the integration will use the data.
Why you need access.
Who receives the data and where it is stored.
A confirmation that you have a lawful basis for using the data and a data processing agreement in place.
- Send the request. The page shows it as Waiting for review. You can withdraw it while it is waiting.
What the team reviews
A member of the HB Compliance team reads your answers, then approves or rejects the request. You are emailed the decision. A rejection comes with a reason, which you can read in the Hub and in the email. After a rejection or a withdrawal you can send a new request.
After an approval, keys that hold the scopes of the area work, and webhook endpoints receive its events. The team can withdraw an approval later, with a reason. Calls are refused again and events stop. Your keys and webhook endpoints are not deleted.
What you can do before approval
You can create an API key with the scopes of an area before it is approved, so the key is ready on the day. Its calls to that area are refused until approval (see the codes below). Calls to every other area work as normal.
You can also create or change a webhook endpoint at any time, but you cannot subscribe it to events of an area you are not approved for. See Webhooks.
Check where you stand
GET /api/v2/account/api-access works with any valid key, whatever its scopes. It lists every area:status is one of:Status | Meaning |
|---|---|
not_required | The area is open. Nothing to do. |
not_requested | The area needs approval and nobody has asked yet. |
pending | A request is waiting for review. You will be emailed when it is decided. |
approved | Calls and webhook events work. |
rejected | The last request was not approved. Read the reason in the Hub. |
revoked | The team withdrew an earlier approval. Read the reason in the Hub. |
decided_at is when the current state was decided, or null for not_required, not_requested and pending. The reason for a rejection or a withdrawal is never part of an API answer: your users read it in the Hub and in the email.Call it when your integration starts and show a clear message in your own tool, instead of waiting for a
403.Error codes
A call to an area that needs approval, from a key that holds a scope of that area, is answered with
403 and one of these codes. A key with no scope for the area gets the usual insufficient_scope.Code | When | Message |
|---|---|---|
api_access_not_approved | Nobody at your organisation has asked for the area | Access to Occupational Health needs approval. Request it in the Hub under API access. |
api_access_pending | A request is waiting for review | Your request for access to Occupational Health is waiting for review. You will be emailed when it is decided. |
api_access_rejected | The last request was not approved | Your request for access to Occupational Health was not approved. See API access in the Hub for the answer. |
api_access_revoked | The team withdrew the approval | Access to Occupational Health was withdrawn. See API access in the Hub for the reason and to request it again. |
The body is the usual error body with two extra fields:
areas lists the portal keys involved and docs_url points to this page. These errors are not retryable: retrying changes nothing until the state changes, so do not loop on them. Treat them as a configuration problem to show to a person, not as an outage.Webhooks
Creating or updating a webhook endpoint with events of an area you are not approved for is refused with
403 and the code webhook_events_not_approved. The body has areas (the portal keys) and events (the event names that were refused):Nothing is saved when this happens. When you update an endpoint, only the events it did not already hold are checked, so you can keep editing an endpoint that already held an event.
Events of an area that needs approval are never sent to an organisation without an active approval. The Hub does not queue them and does not retry them later, so they are not replayed after an approval: fetch what you missed from the API. When the team withdraws an approval, events of that area stop from that moment, including deliveries that were waiting for a retry, which fail with a message saying so. Endpoints are kept, and events of other areas keep flowing.
Test it in the sandbox
The sandbox is always open: Occupational Health and DBS & Right To Work work normally, any webhook endpoint may subscribe to their events, and
GET /api/v2/account/api-access reports every area as not_required (with sensitive: true for the two areas that need approval in live). Your code that reads the status runs the same way in the sandbox and in live.To test how your integration handles a refusal, add the
X-HB-Simulate-Access header to a sandbox request. It takes one of four values:Value | Simulated state | Code the area's calls get | status in the status call |
|---|---|---|---|
not_approved | Nobody asked for access | api_access_not_approved | not_requested |
pending | A request is waiting for review | api_access_pending | pending |
rejected | The last request was not approved | api_access_rejected | rejected |
revoked | The team withdrew the approval | api_access_revoked | revoked |
With the header set, the sandbox answers exactly as the live Hub does in that state: the same status,
error, message, areas, events and docs_url.A call to Occupational Health or DBS & Right To Work from a key that holds a scope of that area is answered
403 with the code of the state. A key with no scope for the area still gets insufficient_scope, and every other area works.Creating or updating a webhook endpoint with events of those two areas is answered
403 webhook_events_not_approved, with areas and events. On an update only the events the endpoint did not already hold count.GET /api/v2/account/api-access reports the simulated status for the two areas that need approval. For rejected and revoked, decided_at is a fixed time (2026-01-05T09:00:00Z) so your tests can compare it. Every other area stays not_required.A value that is not one of the four is answered
422 validation_failed, so a typo never passes silently. An empty header is ignored.The header changes one request. Nothing is stored, no approval exists in the sandbox, and webhook deliveries are not paused: the sandbox keeps sending the events you subscribed to. Do not send the header to the live Hub: it ignores it.
The base address of every sandbox is
https://dev.hbcompliance.co.uk/sandbox/api/v2: your sandbox key decides which sandbox answers. See Sandboxes.What to do in your integration
Call
GET /api/v2/account/api-access when your integration starts, and show the status of the areas you need.Treat the four
api_access_* codes as configuration problems, not outages, and never retry them in a loop.Create webhook endpoints for Occupational Health and DBS & Right To Work only after the area is
approved.Handle health and criminal record data with care in your own systems. The approval does not replace your own data protection duties.
How the Hub API protects this data in general, and what is your side of it, is on the Data security page.
Was this page helpful?
