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. Registering one endpoint for every call is planned and not implemented yet. Today a preauth outcome goes to the callback_url you send when opening the visit, and a claim outcome goes to the claim endpoint registered for your tenant. Settle both at 00 rather than finding out about it at Submit.
If you only remember one thing: on the v2 calls 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, and it is not implemented yet: no /api/v1/callbacks route is
registered, so it answers 404. 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 | Planned, not implemented yet. Will register the endpoint that preauth, claim and remittance decisions are delivered to. | callback_id |
Open 00 · Authenticate in the Rail API reference to read the
token call, which is the only one you can run today, and the callbacks design. 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 the v2 calls refuse a request without them straight away, with 400 FACILITY_CONTEXT_MISSING, and that a token claim is never used as a fallback. | 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 | Planned, not implemented yet. The service does not read this header today. Where a call takes a callback_url, it goes in the request body. | — |
The token is required on every call. The two facility headers are required on the /api/v2
calls that are scoped to a facility (patients, visits and the stops after them). A /api/v2 call
without them is refused with a 400 FACILITY_CONTEXT_MISSING whose path names the header at
fault. The service never reads the facility from your token instead. The v1 calls
/api/v1/terminology/concepts and /api/v1/professionals do not check them.
X-Facility-Id-Type is one of mfl, license-number, fr-code, registration-number or fid.
The callback header is not implemented yet, so there is nothing to send.
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 | Planned, not implemented yet, because there is no registration call to return one. Once it exists it is the proof that a delivery endpoint is registered, and the fallback for anything that does not carry its own callback_url. | 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 wrong, so the facility's authentication policy resolved against the wrong site. A missing one no longer gets this far, because the v2 calls refuse it with 400 FACILITY_CONTEXT_MISSING. |
| Eligibility | "The benefit list is empty for a patient who is definitely covered" | Benefits are filtered by facility empanelment. A wrong but well-formed facility gives you an empty list, and nothing in the response 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 target for the decision. Registered callbacks and X-Callback-Url are planned and not implemented yet, so today a preauth outcome goes to the callback_url you sent when opening the visit, and a claim outcome goes to the claim endpoint registered for your tenant. |
| 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 URL that only exists in one environment. None of the three shows up until a patient is waiting.
Errors
A bad or expired token is a 401 whose error is the plain text Unauthorized, with no code. A
token that carries no tenant_id claim is refused the same way. A caller the authorisation check
does not allow gets a 403. The facility headers are the one authentication-stage failure that
carries a code: FACILITY_CONTEXT_MISSING, a 400.
| Code | HTTP | What it means | What to do | fix_stage |
|---|---|---|---|---|
FACILITY_CONTEXT_MISSING | 400 | X-Facility-Id or X-Facility-Id-Type was absent or invalid on a v2 call. path names the header at fault. The type must be mfl, license-number, fr-code, registration-number or fid. | Set both facility headers in the HTTP client, not at individual call sites. | 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 | Needed at 06 · Preauthorize and 08 · Submit. Registering one endpoint here is planned and not implemented yet, so for now send a callback_url when you open a visit (preauth outcomes) and have a claim endpoint registered for your tenant (claim outcomes). | 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.

