00 · Authenticate
Authenticate is the step where the rail learns which system is asking and where it is asking from. Every other stop is about a patient; this one is about your system.
Everything below elaborates this sentence.
What this step is
Your system presents the credentials it was issued and gets back a token that says "this is a known integrator". Nothing about a patient can happen until that token exists.
You establish two separate things here, and confusing them is the commonest way this stop goes wrong.
| Call | What it does | What you keep |
|---|---|---|
Who you are | A client id and secret exchanged for an access token. This is your identity as the vendor, and it does not change from one facility, patient, visit or day to the next. | access_token |
Which facility you are acting for | Sent as headers on every call. You are one system serving many facilities, and almost every rule downstream (price, empanelment, which consent factors are offered) is scoped to this rather than to you. | facility code + its type |
This matters more for an HMIS than it would for a single clinic's own software. Your token is issued once to you, the vendor, and it does not change when the user switches site. The facility does change, and it decides the answer. A correct token with the wrong or missing facility authenticates perfectly and then fails three stops later, where the failure looks like something else entirely: an empty benefit list for a member who is plainly covered, biometrics demanded at a site that does not use them, a price that is wrong the same way every time.
Nothing in those symptoms mentions a facility, which is why this is a trap rather than an ordinary mistake.
The rule that makes it work is that the token says who you are, the headers say where you are, and the rail needs both on every call.
There are three things to do.
- 01Exchange credentials for a tokenOne call with your client id and secret. You get back an access token and the number of seconds it is good for.
- 02Derive the facility headers, do not configure themHave one place in your HTTP client read the facility from whichever site the session belongs to, so no call site can omit it and no call can carry the wrong one. A hard-coded facility code works in a single-site pilot and then silently misprices everything the day a second site goes live.
- 03Decide where decisions get deliveredPreauthorisation and claim outcomes come back asynchronously, so the rail needs somewhere to send them. Register an endpoint here and every call uses it, or pass one per request in the X-Callback-Url header where a particular call needs its own. Settle this at 00 rather than finding out about it at Submit.
If you only remember one thing: the facility headers are as required as the token, and both belong in the HTTP client rather than at the call site.
Two ways to look at the step: who answers whom, and what happens to the token over its life.
Two exchanges, and only the first one involves your secret.
The call
Two calls make up this step. One exchanges credentials for a token. The other registers where decisions should be delivered. Both are in the reference with every parameter, and with a Try it console for when the sandbox is live.
| Call | What it does | What you keep |
|---|---|---|
POST · token | Exchanges your client id and secret for an access token, with the seconds it is valid for. | access_token, expires_in |
POST · callbacks | Registers the endpoint that preauth, claim and remittance decisions are delivered to. | callback_id |
Open 00 · Authenticate in the Rail API reference to read or run
both. They are the whole of this stop, and there is no wider authentication surface to go and
find: one grant type (client_credentials), tokens good for thirty minutes, and no refresh
token, so you request a new token on expiry rather than refreshing the old one.
Two things the reference will not tell you.
| Call | What it does | What you keep |
|---|---|---|
Cache it | The reference shows one exchange. It does not tell you that fetching a token per request will get you throttled and make every call slow. | access_token + expiry |
Send the facility every time | The reference lists the headers. Only this page tells you that leaving them out fails at Consent and the cover check rather than here. | facility headers |
Facility context travels in headers
They never travel in a request body, and you should not assemble them at each call site.
| Call | What it does | What you keep |
|---|---|---|
Authorization: Bearer … | Identifies your system | access_token |
X-Facility-Id | Identifies the facility the call is made from | facility code |
X-Facility-Id-Type | Says which identifier scheme that code is in | id type |
X-Callback-Url | Optional. Where this request's decision should go, if it should not go to your registered endpoint. | the URL you sent |
Two of those three are required on every call. The callback header is the exception, and you send it only when this request's outcome belongs somewhere other than the endpoint you registered.
If a facility identifier appears in a request body anywhere in your codebase, treat it as a bug that will surface on a busy day. The header is the only channel the rail guarantees to honour.
What you keep
| Call | What it does | What you keep |
|---|---|---|
access_token | Sent on every subsequent call, at every stop | In memory, with its expiry |
expires_in | What your refresh timer is set from. Log it, because a 401 is hard to explain if you cannot say when the token was due to run out. | Computed expiry |
Facility code and type | Headers on every call. They scope pricing, empanelment and which consent factors are offered, so they belong to the session rather than to your deployment. | Resolved per session |
callback_id | Proof a delivery endpoint is registered. Keep it even if you also send per-request callbacks, since the registered endpoint is the fallback for everything that does not carry a header. | Your integration record |
What breaks here
Almost nothing breaks at this stop, which is what makes it expensive. The failures surface two or three stops away, and they do not look like authentication problems when they do.
| Where it surfaces | What the desk sees | What actually went wrong |
|---|---|---|
| Every call, suddenly | "Everything returns 401 since this morning" | The token expired and refresh is reactive or absent. Cache with a proactive timer, and log the expiry you computed. |
| Under load | "Calls got slow, then we started getting throttled" | A token fetched per request. One exchange should serve thousands of calls. |
| Consent | "Biometrics is being demanded and we are not set up for it" | Facility context missing or wrong, so the facility's authentication policy resolved to the strict default. |
| Eligibility | "The benefit list is empty for a patient who is definitely covered" | Benefits are filtered by facility empanelment. The wrong facility gives you an empty list, and nothing in the error mentions facilities. |
| Bill | "The price is wrong, and it is wrong consistently" | Tariff variants are facility-scoped. A stale or hard-coded facility code prices every line against the wrong contract. |
| Submit | "The claim will not send and we cannot see why" | No delivery endpoint at all, neither a registered callback nor an X-Callback-Url header on the request. Submission will not proceed without somewhere to send the decision. |
| Three weeks after go-live | "We are live and no money has arrived" | The banking record was never completed. A human reviews it, and it gates every payment regardless of how many claims were accepted. |
One pattern accounts for most of that list. Credentials get treated as setup and are then never looked at again: a token with no logged expiry, a facility code nobody re-reads, a callback registered in one environment. None of the three shows up until a patient is waiting.
Errors
| Code | HTTP | What it means | What to do | fix_stage |
|---|---|---|---|---|
UNAUTHENTICATED | 401 | No token, an expired token, or a token the rail does not recognise. | Refresh proactively on a timer rather than reactively on a 401. | authentication |
FACILITY_CONTEXT_MISSING | 400 | The facility headers were absent, so no facility-scoped rule could be resolved. | Set the facility headers in the HTTP client, not at individual call sites. | authentication |
OUTSIDE_FACILITY_GEOFENCE | 403 | The call originated outside the configured radius of the facility. Checked before any stop-specific gate. | Read distance_m, allowed_radius_m and facility_code from the detail block. Test environments often use a different radius. | authentication |
What carries forward
| Call | What it does | What you keep |
|---|---|---|
access_token | Every stop from 01 to 08 takes it as a header. Nothing on the rail works without it. | Refresh before it dies |
Facility headers | They scope every answer you get. The same call from two facilities gives you two different answers. | Set once in the client |
A place to deliver decisions | Checked at 06 · Preauthorize and 08 · Submit. Register an endpoint here and the check is invisible; override it per request with X-Callback-Url where you need to. | Per environment |
There is no next_action at this stop, because nothing patient-shaped has happened yet. You
are just ready to begin.
Next: 01 · Identify. With a token and a facility, you can resolve who is in front of you.
A complete brief for this step — the calls to make, what to persist, and every failure path to handle. Nothing on this page is assumed.

