AllowID developers

Work in progress. The API and SDKs work today, but AllowID is still being built: details may change before a first stable release.

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"}'
codestring, ≤ 512The 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
resultresolved · unknown · invalid · replayed. See the answer.
subjectWhen resolved. sub_ + 24 characters, stable for this person at your company only.
linkedWhen resolved. The person has signed in to your company with the app.
claimsWhen linked: email and the attributes they approved. Otherwise null.
repeattrue when this is the same code again within a minute (not billed).
usageWhen 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"]}'
purposestring, ≤ 200Shown to the person in the app.
attributesarray, ≤ 10Optional: 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.