Skip to main content
Real API documentation

Build with the AgeCheck API

Create age-check sessions, route users to hosted verification, accept wallet credential presentations, and store only the minimal age-gate result your product needs.

X-API-Key authentication
No identity document storage
HMAC-signed webhooks
REST and TypeScript SDK

Quickstart

Create your first age-check session

Use the API key for one environment to create a session. AgeCheckAPI returns a hosted verification URL plus the minimal result object in its current state.

Create a session
bash
export API=http://localhost:3001
export AGE_KEY=ack_test_your_key.your_secret

curl -X POST "$API/v1/age-check/sessions" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $AGE_KEY" \
  -H "Idempotency-Key: order-123" \
  -d '{
    "age_policy": "over_18",
    "use_case": "general_b2b",
    "redirect_url": "https://merchant.example/age-result",
    "external_reference": "order_123"
  }'
Response
json
{
  "session_id": "clx_session_id",
  "status": "provider_redirected",
  "age_policy": "over_18",
  "verified": false,
  "result": "unknown",
  "reason_code": "provider_request_created",
  "verified_at": null,
  "assurance_level": "low",
  "provider_reference": "mock_provider_reference",
  "verification_url": "http://localhost:3000/verify?...",
  "expires_at": "2026-07-03T13:15:00.000Z"
}

What to do next

Send the user to verification_url, open it inside the widget, or collect a verifiable presentation from a wallet/provider bridge and submit it to the session presentation endpoint.

Authentication

API keys are scoped to environments

Session APIs use X-API-Key. Bootstrap/admin APIs use X-Admin-Token and should be protected by dashboard auth, SSO and RBAC before production.

Base URLs

Local development uses http://localhost:3001. Production clients should target https://api.agecheckapi.com when provisioned.

Idempotency

Pass Idempotency-Key when creating sessions. The backend stores a scoped hash and returns the existing session for repeated keys.

Secrets

API key secrets are returned once, then stored hashed. Webhook secrets are encrypted and used for HMAC signatures.

Bootstrap an organization and API key
bash
export API=http://localhost:3001
export ADMIN_TOKEN=replace-with-admin-bootstrap-token

curl -X POST "$API/v1/admin/organizations" \
  -H "Content-Type: application/json" \
  -H "X-Admin-Token: $ADMIN_TOKEN" \
  -d '{"slug":"acme","display_name":"Acme Media"}'

curl -X POST "$API/v1/admin/projects" \
  -H "Content-Type: application/json" \
  -H "X-Admin-Token: $ADMIN_TOKEN" \
  -d '{"organization_id":"ORG_ID","slug":"main","display_name":"Main","use_case":"general_b2b"}'

curl -X POST "$API/v1/admin/environments" \
  -H "Content-Type: application/json" \
  -H "X-Admin-Token: $ADMIN_TOKEN" \
  -d '{"project_id":"PROJECT_ID","kind":"sandbox","display_name":"Sandbox"}'

curl -X POST "$API/v1/admin/api-keys" \
  -H "Content-Type: application/json" \
  -H "X-Admin-Token: $ADMIN_TOKEN" \
  -d '{"environment_id":"ENVIRONMENT_ID"}'

API surface

Implemented REST endpoints

These endpoints mirror the real NestJS controllers in the backend project. The static OpenAPI file documents the public core subset, while admin and compliance operations are listed here from the implementation.

Health

GET
/health

Service health check. This route is intentionally not prefixed with /v1.

Age-check sessions

POST
/v1/age-check/sessions

Create a session and receive a hosted verification URL. Requires X-API-Key.

GET
/v1/age-check/sessions/{session_id}

Read the minimal result for one session. Requires X-API-Key.

POST
/v1/age-check/sessions/{session_id}/cancel

Cancel a session. Requires X-API-Key.

Verification inputs

POST
/v1/age-check/sessions/{session_id}/presentations

Verify an Ed25519 compact JWS presentation. Public, but bound by session nonce and audience.

POST
/v1/provider-callbacks/{provider_id}

Provider callback endpoint. The built-in sandbox provider id is mock-wallet.

Admin setup

POST
/v1/admin/organizations

Bootstrap a B2B organization. Requires X-Admin-Token.

POST
/v1/admin/projects

Create a project under an organization. Requires X-Admin-Token.

POST
/v1/admin/environments

Create a sandbox or production environment. Requires X-Admin-Token.

POST
/v1/admin/api-keys

Create an API key. The secret is returned once and stored hashed.

POST
/v1/admin/api-keys/{api_key_id}/rotate

Revoke an API key and return a replacement secret once. Requires X-Admin-Token.

POST
/v1/admin/webhook-endpoints

Create a webhook endpoint and encrypted signing secret. Requires X-Admin-Token.

GET
/v1/admin/environments/{environment_id}/sessions

List the latest sessions for an environment. Requires X-Admin-Token.

GET
/v1/admin/organizations/{organization_id}/usage

List recent usage records for an organization. Requires X-Admin-Token.

Compliance and webhooks

GET
/v1/compliance/{organization_id}/ropa

Export ROPA-style processing records.

GET
/v1/compliance/{organization_id}/dpia

Export a DPIA draft for the selected policy.

GET
/v1/compliance/{organization_id}/dpa-annex

Export a processor-first DPA annex.

GET
/v1/compliance/{organization_id}/audit-evidence

Export append-only audit hash-chain evidence.

POST
/v1/compliance/{organization_id}/breach-incidents

Register a breach incident and append an audit event.

GET
/v1/compliance/policy-report

Export the EU policy registry mapping.

POST
/v1/webhooks/{endpoint_id}/test

Create a signed webhook test delivery.

Wallet proof

Submit a verifiable age presentation

A wallet, issuer or provider bridge can submit an Ed25519 compact JWS. AgeCheckAPI verifies the signature, trusted issuer, audience, session nonce, expiration and age evidence before computing the final pass/fail result.

Presentation endpoint
bash
curl -X POST "$API/v1/age-check/sessions/SESSION_ID/presentations" \
  -H "Content-Type: application/json" \
  -d '{"presentation_jws":"COMPACT_ED25519_JWS"}'
Expected JWS payload claims
json
{
  "iss": "https://issuer.example.com",
  "aud": "agecheckapi:ENVIRONMENT_ID",
  "nonce": "SESSION_ID",
  "vc": {
    "type": ["VerifiableCredential", "AgeCredential"],
    "credentialSubject": {
      "age_over_18": true
    }
  },
  "assurance_level": "substantial",
  "iat": 1783079100,
  "exp": 1783079400
}

Nonce and audience are mandatory

The presentation aud must equal agecheckapi:ENVIRONMENT_ID, and nonce must equal the AgeCheckAPI session id. This prevents replay across sessions or relying parties.

Sandbox

Mock wallet callback scenarios

The built-in sandbox provider is mock-wallet. Use it to exercise pass, fail, consent-declined, provider-unavailable and expired-session paths without real credentials.

Trigger a sandbox callback
bash
curl -X POST "$API/v1/provider-callbacks/mock-wallet" \
  -H "Content-Type: application/json" \
  -d '{
    "provider_reference": "mock_reference_from_session",
    "state": "SESSION_ID",
    "scenario": "user_over_18"
  }'

Supported scenarios

user_over_18user_under_18provider_unavailableconsent_declinedexpired_session

Webhooks

Verify signed delivery attempts

Webhook payloads are signed with an AgeCheckAPI-Signature header. Verify the timestamp and HMAC before trusting a delivery.

Signature scheme
text
AgeCheckAPI-Signature: t=1783079100,v1=hex_hmac_sha256

signed_payload = timestamp + "." + raw_json_body
signature = HMAC_SHA256(webhook_secret, signed_payload)

Delivery behavior

  • Worker retries failed deliveries with exponential backoff.
  • Payloads contain session id and payload hash, not raw identity data.
  • Default event set: age_check.completed, age_check.failed, age_check.expired.

Data model

Persist only the minimal age-gate result

The public result allowlist contains only session status, policy, boolean verification result, reason code, assurance level, timestamp and a non-identifying provider reference.

Minimal result object
json
{
  "session_id": "SESSION_ID",
  "status": "verified",
  "age_policy": "over_18",
  "verified": true,
  "result": "pass",
  "reason_code": "age_threshold_met_by_agecheckapi",
  "verified_at": "2026-07-03T13:15:00.000Z",
  "assurance_level": "substantial",
  "provider_reference": "vp_non_identifying_reference"
}

Session statuses

provider_redirected

Session is ready and the user should complete the hosted or provider flow.

verified

AgeCheckAPI verified the proof and the age threshold passed.

failed

The proof was valid but the user did not meet the age threshold, or the provider result failed.

expired

The session or presentation expired.

cancelled

The relying party cancelled the session or the user declined consent.

Age policies and use cases

Current behavior is policy-registry driven. For a threshold such as 21, use age_policy: "custom_min_age" with custom_min_age: 21 until a dedicated over-21 policy profile is configured.

PolicyMinimum ageTypical use
over_1616Resolved by the current policy registry for social_media.
over_1818Resolved by the current policy registry for general_b2b, adult_content, gambling, alcohol and video_sharing.
custom_min_age13-25Requires custom_min_age in the create-session body.
Integration checklist

Ready to wire this into your product?

Start with sandbox sessions, implement idempotency, verify webhook signatures, and make access decisions only from the minimal result object.

TypeScript SDK

Use the SDK when running inside Node.js

The SDK wraps session creation, lookup and verifiable presentation submission while preserving the same REST payloads.

SDK example
ts
import { AgeCheckClient } from "@agecheck/sdk";

const agecheck = new AgeCheckClient({
  apiKey: process.env.AGECHECK_API_KEY,
  baseUrl: "http://localhost:3001"
});

const session = await agecheck.createAgeCheckSession({
  age_policy: "over_18",
  use_case: "general_b2b",
  redirect_url: "https://merchant.example/age-result",
  external_reference: "user_or_order_reference",
  idempotency_key: "order-123"
});

console.log(session.verification_url);