CAIRLDocs
Integration

API Reference

Public endpoint and webhook contract for CAIRL hosted verification integrations.

API Reference

This page is the human-readable companion to the machine-readable OpenAPI contract.

Use the reference when you need exact endpoint names, request bodies, response shapes, webhook event schemas, or auth requirements. Use the quickstart when you want a copy-paste path to a working OAuth + PKCE integration.

Machine-readable contract

  • OpenAPI JSON: /openapi.json
  • Production server: https://cairl.app
  • Staging server: https://staging.cairl.app

The contract covers these public integration surfaces:

AreaEndpoint or surfacePurpose
Hosted verificationGET /verify/startRedirect the user into a fresh CAIRL verification for your site, with PKCE.
OAuth providerPOST /api/oauth/tokenExchange an authorization code for a bearer access token.
OAuth providerGET /api/oauth/userinfoRead the issuance-time verified claims snapshot.
OAuth providerPOST /api/oauth/revokeRevoke an access token under RFC 7009 semantics.
Verification sessionsGET /api/verify/hvf-session/{session_id}Poll hosted verification session status.
Shopify integrationPOST /api/integrations/shopify/verify/exchangeExchange a Shopify-hosted verification code for claims.
WebhooksYour configured HTTPS callbackReceive signed outbound lifecycle and billing events.

Also available, not yet described in the OpenAPI file:

EndpointPurpose
GET /oauth/authorizeConventional OAuth authorization endpoint, in verification mode: same parameters as /verify/start plus the required response_type=code. Unlike /verify/start, it honours an existing verification that meets the key's depth and falls inside its time-based freshness window (daily, 3day, weekly, biweekly, monthly) and goes straight to consent. The event-driven policies, session and transaction, are not enforced here. This is not the sign-in flow — see the OIDC row below.
GET /oauth/authorizeThe same endpoint in OIDC sign-in mode: the openid scope alone, on a login-enabled credential, returns an ID token. Verification scopes and openid are different contracts — mixing them up is the most common integration mistake. See Log in with CAIRL.
GET /.well-known/jwks.jsonPublic signing keys for the access-token JWT.

Not published: refresh tokens. ID tokens are issued only on the OIDC sign-in path above (openid alone, login-enabled credential) — never on a verification-scope exchange. Configure endpoint URLs explicitly in your OAuth library.

Authentication summary

SurfaceAuth model
/verify/startPublic redirect with registered client_id, redirect_uri, state, and PKCE challenge.
/api/oauth/tokenServer-to-server client_id plus client_secret; grant_type=authorization_code only, with code, redirect_uri, and PKCE code_verifier required.
/api/oauth/userinfoAuthorization: Bearer ACCESS_TOKEN.
/api/oauth/revokeServer-to-server client_id plus client_secret.
/api/verify/hvf-session/{session_id}Authorization: Bearer YOUR_API_KEY.
Shopify exchangeHMAC headers: X-CAIRL-Integration-Id, X-CAIRL-Timestamp, and X-CAIRL-Signature.
WebhooksX-CAIRL-Signature: sha256=<hex> over the raw body.

Userinfo response shape

GET /api/oauth/userinfo returns a snapshot of the claims evaluated when the token was issued. It does not re-evaluate claims live on every request.

{
  "sub": "pws_v1_<pairwise>",
  "evaluated_at": "2026-05-03T10:00:00.000Z",
  "mode": "live",
  "claims": {
    "age_18_plus": true,
    "identity_verified": true
  },
  "meta": {
    "claims_requested": ["age_18_plus", "identity_verified"],
    "claims_resolved": ["age_18_plus", "identity_verified"],
    "claims_null": [],
    "claims_ignored": []
  }
}

Read the claim value from response.claims.age_18_plus, not from a top-level age_18_plus field. The scope that produces it is age:18+; scopes and claim names are spelled differently by design (see the claims reference).

Webhook event schemas

The OpenAPI webhooks.cairlEvents section defines the signed callback payloads CAIRL can send to your endpoint:

  • verification.session.completed
  • verification.session.failed
  • enrollment.created
  • vae.resolved

All events include an event_id for idempotency. Store seen event IDs and acknowledge quickly with a 2xx response before doing slow work.

Compatibility rules

  • Unknown response fields are additive and should be ignored by clients.
  • Unknown webhook event types should be ignored and logged.
  • New required request fields are compatibility-sensitive and will be recorded in the versioning changelog.
  • CAIRL returns verified claims. It does not return raw identity documents or default raw PII through the public OAuth userinfo endpoint.

On this page