HTTP API
HTTPS and JSON. Base URL https://api.allowid.eu. The SDKs are thin wrappers
around exactly these calls.
Authentication§
Authorization: Bearer aidk_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Keyed endpoints send no CORS headers, so browsers cannot call them: call them from your server.
Only /v1/health and /v1/sessions/{id}/status may be called from a web page.
Every response carries X-Request-Id (yours if you sent one, ours otherwise; quote it
when asking for help). When usage is known it also carries X-AllowID-Usage: used/included.
POST /v1/scans§
Resolve what a QR reader read from the AllowID app. Billed once when the result is resolved.
curl https://api.allowid.eu/v1/scans \
-H "Authorization: Bearer $ALLOWID_API_KEY" \
-H "Content-Type: application/json" \
-d '{"code": "PIMDH42NFG2E"}'
code | string, ≤ 512 | The text as read. Case and surrounding whitespace don't matter; the signed form PI…:1:… is accepted. |
{
"result": "resolved",
"subject": "sub_3x2yqgcm35ruenvjhokobojd",
"linked": true,
"claims": { "email": "person@example.com", "profession": "Architect" },
"usage": { "month": "2026-10-01", "used": 213, "included": 1000, "hard_limit": 1200, "licensed": false }
}
| Field | |
|---|---|
result | resolved · unknown · invalid · replayed. See the answer. |
subject | When resolved. sub_ + 24 characters, stable for this person at your company only. |
linked | When resolved. The person has signed in to your company with the app. |
claims | When linked: email and the attributes they approved. Otherwise null. |
repeat | true when this is the same code again within a minute (not billed). |
usage | When resolved: your month so far. |
POST /v1/sessions§
Start a website sign-in. Free. Answers 201.
curl https://api.allowid.eu/v1/sessions \
-H "Authorization: Bearer $ALLOWID_API_KEY" \
-H "Content-Type: application/json" \
-d '{"purpose": "Sign in to Example Co", "attributes": ["profession"]}'
purpose | string, ≤ 200 | Shown to the person in the app. |
attributes | array, ≤ 10 | Optional: profession, company, address, age_band, nationality. |
{
"session_id": "23a8514f-c80b-4c42-abdf-d318e32bc38e",
"qr_payload": "{\"v\":1,\"t\":\"login\",\"sid\":\"23a8514f-…\",\"chal\":\"-D6PVq5oxC5OqMTIw3PH4qYC\"}",
"browser_token": "bt_a662e14c22cfcdf72c4216f63201ead076818bd7c612a15a",
"expires_at": "2026-10-11T14:40:47.530427+00:00"
}
GET /v1/sessions/{id}§
Collect the outcome, from your server. Billed once, the first time the state is
authenticated. Collectable until ten minutes after expires_at.
{
"state": "authenticated",
"subject": "sub_3x2yqgcm35ruenvjhokobojd",
"claims": { "email": "person@example.com", "profession": "Architect" },
"usage": { "month": "2026-10-01", "used": 214, "included": 1000, "hard_limit": 1200, "licensed": false }
}
state: pending · authenticated · denied · expired. Only
authenticated carries subject and claims. A session made by another company is
404.
GET /v1/sessions/{id}/status§
The state only, for the browser. Free. Authenticated by the browser token, not the key; callable from any origin.
curl https://api.allowid.eu/v1/sessions/23a8514f-c80b-4c42-abdf-d318e32bc38e/status \
-H "X-AllowID-Browser-Token: bt_a662e14c22cfcdf72c4216f63201ead076818bd7c612a15a"
{ "state": "pending" }
GET /v1/usage§
This month's billed answers against your allowance. Free.
{ "month": "2026-10-01", "used": 214, "included": 1000, "hard_limit": 1200, "licensed": false }
GET /v1/health§
No key. {"ok": true, "api": "allowid", "version": "1.0.0"}
Errors§
A refusal is a non-2xx status with a JSON body:
{ "error": "quota_exceeded", "detail": "This month's allowance and its 20 % grace are used up. …", "usage": { … } }
The codes are listed in Pricing, limits, errors. A code that does
not resolve is not an error: POST /v1/scans answers 200 with
"result": "unknown".
OpenAPI§
The same contract, machine-readable: openapi.yaml.