Skip to content

Authentication & keys

Railflo has three distinct authentication mechanisms, each for a different caller — they never overlap, by design (a session grants no access on a key-only route, and vice versa).

Every request to /v1/* (outside /v1/auth/* and /v1/console/*) authenticates with an API key:

Authorization: Bearer railflo_sk_test_xxxxxxxxxxxxxxxxxxxxxxxx

Keys are minted from Console (Settings → API keys) — the public POST /v1/api_keys endpoint itself requires an existing key, so your very first key always comes from Console. A key’s secret is shown exactly once, at creation; only its last 4 characters are ever retrievable afterwards.

The _test_ / _live_ segment in every key is permanent for that key’s lifetime — a key is one mode or the other, never both. Test-mode data is completely isolated from live-mode data (separate patient records, separate exchanges), and test-mode usage is never billed. Build and test your integration entirely in test mode before requesting a live key.

Keys carry a coarse set of scopes (patients:read, patients:write, exchanges:read, exchanges:write, webhooks:manage, documents:write, usage:read, and a handful more) — a key created without an explicit scope list gets every scope that exists. Request the narrowest set your integration actually needs.

railflo_dk_... keys are a distinct, narrower kind — issued only through the Bridge desktop agent’s enrolment flow, scoped to documents:write alone. A device key can never read or write patient records, only upload documents on the clinic’s behalf.

The Console authenticates humans, not integrations: email + password + mandatory TOTP two-factor, a __Host--prefixed session cookie, and CSRF protection on every mutating request. Sessions are entirely separate infrastructure from API keys — /v1/console/* never accepts a Bearer token, and /v1/* never accepts a session cookie.

Some Console actions (revealing a masked identifier, creating an API key) require step-up: a fresh password + TOTP re-entry within the last few minutes, on top of an already-valid session. This protects against a stolen, already-open browser tab.

Revoke a key any time from Console or DELETE /v1/api_keys/{id} — revocation is immediate and irreversible; a revoked key’s every subsequent request gets 401 api_key_revoked. There’s no “pause,” only issue-a-new-key-then-revoke-the-old-one.