---
title: "Poll an age check"
method: GET
path: "/v1/age-checks/{id}"
tags: ["Age Verification"]
---

# Poll an age check

`GET /v1/age-checks/{id}`

## Request

- Base URL: `https://api.tessio.eu`
- URL: `https://api.tessio.eu/v1/age-checks/{id}`
- Auth: HTTP bearer

Scoped to a project: a key can only read checks it created. `result` stays null until the check completes.

## Response `200`

OK

- AgeCheck
  - `id` string, uuid
  - `status` 'pending' | 'completed' | 'expired' | 'failed'
  - `result` AgeCheckResult
    - `minAge` integer
    - `meetsMinAge` boolean: True if the user proved they meet the age threshold
    - `method` 'demo' | 'simulated' | 'eudiw' | 'av': What answered the check. 'demo' is a sandbox completion and 'simulated' is the public demo's explicit simulate call, neither of which involves a wallet. 'eudiw' and 'av' name the profile a real wallet presented under.
    - `transport` 'openid4vp' | 'dcapi' | 'null', nullable: How a real wallet's answer travelled: `openid4vp` for the deeplink flow, `dcapi` for the W3C Digital Credentials API. Null when no wallet was involved, so a sandbox completion stays distinguishable on this field too.
  - `reference` string, nullable: Your correlation id from create, echoed back
  - `mode` 'test' | 'live': The mode of the project that created this check, fixed when the project was created. `test` is a sandbox: the check completes on its own after a couple of seconds and its result is simulated, so `meetsMinAge` proves nothing about anyone. `live` means only a wallet presentation completes the check. Read this before acting on `meetsMinAge`.
  - `failedAttempts` integer: How many presentations failed verification, or wallet error responses arrived, while the check stayed pending, on either transport. Neither ends the check, so a pending or expired check with a count above zero means a response was posted and refused, or a wallet said it could not answer. It counts every refused response for the check, not only the holder's, so read it as a signal rather than as the person's own attempts.
  - `lastFailureCodes` string[], nullable: The error codes of the most recent failed attempt, such as `issuer_untrusted` or `signature_invalid`. A code beginning `wallet_` is the wallet's own error response, for example `wallet_access_denied` when the holder declined, the wallet held no matching credential or it could not authenticate the holder (OpenID4VP 1.0 section 8.5 gives one code for all three): it is the wallet's claim and nothing was verified. `session_mismatch` is a same device presentation whose redirect came back to a different browser from the one that opened the wallet, rejected under HAIP 1.0 section 5.1. Null when there has been none. Kept after the check completes.

## Other responses

- `401`: Missing / invalid / revoked key
- `403`: insufficient_scope. The key is valid but may only read stats (`stats:read`), so it cannot call this route. Use a project's key with scope `full`.
- `404`: Unknown check / not this project's

---

[API](https://skmtc.dev/tessio/apis/tessio-cloud-api.md) · [All operations](https://skmtc.dev/tessio/apis/tessio-cloud-api/llms.txt) · [OpenAPI document](https://skmtc.dev/tessio/apis/tessio-cloud-api/revisions/536b3f4769fb?raw)
