Proof Developer Reference

Integrate identity verification into your product in minutes. Proof is a multi-tenant REST API — bring your own camera, we handle the biometrics.

API Key Auth

x-api-key: prf_live_…

Used for /api/verify and /api/enroll

Service Token Auth

Authorization: Bearer …

Used for /api/presence/* endpoints

Authentication

Proof uses two token types depending on the endpoint:

Token TypeHeaderUsed for
API Keyx-api-key: prf_live_…Verify, Enroll
Service TokenAuthorization: Bearer …Presence sessions, MCP server

Create API keys and service tokens in Admin → API Keys.

Admin Authentication & 2FA

Admin accounts support two-factor authentication via passkey (WebAuthn) or Proof 2FA (biometric verification with consent). New admins must enroll at least one 2FA method within 7 days of account creation. After the deadline, login is blocked until enrollment is complete.

Passkey (WebAuthn)

  • Hardware security keys (YubiKey, Titan) and platform authenticators (Touch ID, Windows Hello)
  • Phishing-resistant — origin-bound credentials
  • Multiple passkeys per admin account
  • Managed in Admin → Security → Passkeys

Proof 2FA

  • Live identity scan with blink detection
  • Requires explicit biometric consent (BIPA/GDPR compliant)
  • Uses the same liveness pipeline as user verification
  • Can be used alongside or as an alternative to passkeys

Login API response changes

When 2FA is enabled, the POST /api/auth/login response includes a requires_2fa field with available methods:

// POST /api/auth/login — 2FA required response
{
  "requires_2fa": true,
  "methods": {
    "passkey": true,
    "face": true
  },
  "sessionToken": "tmp_sess_...",
  "message": "Two-factor authentication required"
}

The client should present the user with their available 2FA options. Complete the challenge via POST /api/auth/2fa/passkey/authenticate or POST /api/auth/2fa/face, passing the sessionToken from the login response.

Enrollment deadline: Admins have 7 days from account creation to enroll in at least one 2FA method (passkey or face). After the deadline, POST /api/auth/login returns 403 with "error": "2FA enrollment required" until enrollment is completed.

Identity Verification

Match a probe image against your org's enrolled users. Returns a verified flag, matched identity, and per-check pipeline breakdown.

POST/api/verify

Request

{
  "image": "data:image/jpeg;base64,/9j/...",
  "profile": "strict-finance",           // optional: profile ID or slug
  "deviceInfo": {                        // optional: improves device check score
    "userAgent": "Mozilla/5.0...",
    "cameraWidth": 1280,
    "cameraHeight": 720,
    "screenWidth": 1920,
    "screenHeight": 1080
  }
}

Response — verified

{
  "verified": true,
  "userId": "clx1a2b3c4d5e6f",
  "email": "alice@example.com",
  "confidence": 0.94,
  "compositeScore": 0.87,
  "checkResults": [
    { "check": "liveness",          "pass": true, "score": 0.92, "weight": 1.5 },
    { "check": "frameConsistency", "pass": true, "score": 1.00, "weight": 1.0 },
    { "check": "impossibleTravel", "pass": true, "score": 1.00, "weight": 1.2 },
    { "check": "deviceConsistency","pass": true, "score": 0.75, "weight": 0.8 }
  ]
}

Response — not verified

{ "verified": false, "reason": "Identity not recognised" }

User Enrollment

Register an identity template for a user. The user will be matchable by subsequent verify calls. Typically triggered from your registration flow or via the admin portal.

POST/api/enroll

Request

{
  "image": "data:image/jpeg;base64,/9j/...",
  "email": "alice@example.com"
}

Response

{ "enrolled": true, "userId": "clx1a2b3c4d5e6f" }

Passkey API (WebAuthn)

Manage passkey credentials for admin 2FA. Passkeys provide phishing-resistant authentication using platform authenticators (Touch ID, Windows Hello) or hardware security keys (YubiKey, Titan).

POST/api/auth/2fa/passkey/register-options

Generate WebAuthn registration options for the current admin session.

// Response
{
  "options": {
    "challenge": "base64url-encoded-challenge",
    "rp": { "name": "Proof", "id": "webel.ai" },
    "user": { "id": "...", "name": "admin@example.com", "displayName": "Admin" },
    "pubKeyCredParams": [
      { "alg": -7, "type": "public-key" },
      { "alg": -257, "type": "public-key" }
    ],
    "authenticatorSelection": {
      "residentKey": "preferred",
      "userVerification": "required"
    }
  }
}
POST/api/auth/2fa/passkey/register

Complete passkey registration with the authenticator response.

// Request
{
  "credential": { /* PublicKeyCredential JSON from navigator.credentials.create() */ },
  "name": "MacBook Touch ID"   // optional: friendly name for this passkey
}

// Response
{
  "success": true,
  "credentialId": "cred_...",
  "name": "MacBook Touch ID",
  "createdAt": "2026-04-07T10:00:00.000Z"
}
POST/api/auth/2fa/passkey/authenticate-options

Generate WebAuthn authentication options during login. Requires the sessionToken from the login response.

// Request
{ "sessionToken": "tmp_sess_..." }

// Response
{
  "options": {
    "challenge": "base64url-encoded-challenge",
    "rpId": "webel.ai",
    "allowCredentials": [
      { "id": "cred_...", "type": "public-key" }
    ],
    "userVerification": "required"
  }
}
POST/api/auth/2fa/passkey/authenticate

Complete passkey authentication to finish login.

// Request
{
  "sessionToken": "tmp_sess_...",
  "credential": { /* PublicKeyCredential JSON from navigator.credentials.get() */ }
}

// Response
{
  "success": true,
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "admin": {
    "id": "adm_...",
    "email": "admin@example.com",
    "orgId": "clx_org_..."
  }
}
GET/api/auth/2fa/passkey/credentials

List all registered passkeys for the current admin.

// Response
{
  "credentials": [
    {
      "credentialId": "cred_...",
      "name": "MacBook Touch ID",
      "createdAt": "2026-04-07T10:00:00.000Z",
      "lastUsedAt": "2026-04-07T14:30:00.000Z"
    }
  ]
}
DELETE/api/auth/2fa/passkey/credentials/:id

Remove a registered passkey. At least one 2FA method (passkey or face) must remain active.

// Response
{ "success": true, "message": "Passkey removed" }

Verification Profiles

Profiles are named check configurations created in the admin portal. Reference them by ID or slug to apply different security postures per call.

POST /api/verify
{ "image": "...", "profile": "high-security" }
CheckDescription
livenessDetects photo/video replay via passive DCT analysis
frameConsistencyValidates inter-frame variance to catch spliced video
impossibleTravelFlags logins faster than 900 km/h from last location
embeddingHistoryClusters past identity templates; flags statistical outliers
deviceConsistencyFingerprints camera + UA; penalises unrecognised devices
geoFenceRestricts verifications to an allowed country list
timeRestrictionLimits verifications to configured hours and days

Human Presence Tokens

AI agents can request cryptographic proof that a specific human was present at a specific moment. The result is a short-lived signed JWT — a Human Presence Token (HPT).

1

Agent creates a session

Receives a one-time verifyUrl to send to the human

2

Human visits the URL

Completes a live identity scan in their browser

3

Agent polls for completion

GET /api/presence/sessions/:id until VERIFIED

4

Agent retrieves the HPT

GET /api/presence/sessions/:id/token

5

Agent validates claims

POST /api/presence/verify-token — confirms email, nonce, org

POST/api/presence/sessions

Auth: Authorization: Bearer <service-token>

// Request
{
  "orgId": "clx_org_...",
  "purpose": "Authorize production deployment",
  "email": "alice@example.com",    // optional: lock to specific user
  "nonce": "8f3a...",              // optional: bind to HPT for replay prevention
  "ttlSeconds": 300                // optional: HPT lifetime (max 3600, default 300)
}

// Response
{
  "sessionId": "clx_sess_...",
  "verifyUrl": "https://id.example.com/verify-presence/abc123...",
  "expiresAt": "2026-04-06T15:00:00.000Z"
}
GET/api/presence/sessions/:id
// Response
{
  "sessionId": "clx_sess_...",
  "status": "VERIFIED",          // PENDING | VERIFIED | EXPIRED | CANCELLED
  "verifiedEmail": "alice@example.com",
  "verifiedAt": "2026-04-06T14:52:10.000Z",
  "expiresAt": "2026-04-06T15:00:00.000Z"
}
GET/api/presence/sessions/:id/token
// Response
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "jti": "a1b2c3d4-...",
  "verifiedEmail": "alice@example.com",
  "verifiedAt": "2026-04-06T14:52:10.000Z"
}
POST/api/presence/verify-token
// Request
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expectedOrgId": "clx_org_...",
  "expectedEmail": "alice@example.com",   // optional
  "expectedNonce": "8f3a..."              // optional
}

// Response
{
  "valid": true,
  "sub": "alice@example.com",
  "orgId": "clx_org_...",
  "userId": "clx_usr_...",
  "sessionId": "clx_sess_...",
  "purpose": "Authorize production deployment",
  "checks": { "compositeScore": 0.87, "liveness": 0.92 },
  "issuedAt": "2026-04-06T14:52:10.000Z",
  "expiresAt": "2026-04-06T14:57:10.000Z"
}

MCP Server

Connect Proof to Claude, Cursor, or any MCP-compatible AI agent. The server exposes three tools over stdio (local) or HTTP+SSE (hosted).

Claude Desktop / Cursor config:

{
  "mcpServers": {
    "proof": {
      "command": "node",
      "args": ["/path/to/mcp-server/dist/index.js"],
      "env": {
        "PROOF_BASE_URL": "https://id.example.com",
        "PROOF_SERVICE_TOKEN": "your-service-token"
      }
    }
  }
}
ToolDescription
request_human_presenceCreate a presence session; returns a verifyUrl to send to the human
get_presence_tokenPoll for completion and retrieve the signed HPT
verify_presence_tokenValidate an HPT and return decoded claims

TypeScript SDK

The official SDK wraps the REST API with full TypeScript types. Works in Node.js, browsers, and React Native.

npm install @webel/sdk

Verify an identity

import { ProofClient } from "@webel/sdk";

const client = new ProofClient({
  baseUrl: "https://id.example.com",
  apiKey: "prf_live_...",
});

const result = await client.verify({ image: base64Image });
if (result.verified) {
  console.log(`Verified: ${result.email} (score: ${result.compositeScore})`);
}

Full HPT flow

// 1. Create a presence session
const session = await client.createPresenceSession({
  orgId: "clx_org_...",
  purpose: "Authorize production deployment",
  nonce: crypto.randomUUID(),
});

// 2. Send session.verifyUrl to the human (email, Slack, etc.)
console.log("Ask the human to visit:", session.verifyUrl);

// 3. Wait until verified (polls every 2s, times out after 5min)
await client.waitForPresence(session.sessionId);

// 4. Retrieve the HPT
const { token } = await client.getPresenceToken(session.sessionId);

// 5. Validate
const claims = await client.verifyPresenceToken({ token });
console.log("Verified by:", claims.sub);   // alice@example.com

Webhooks

Proof fires webhooks to your configured endpoints for key events. Configure in Admin → Webhooks.

EventFired when
verification.successAn identity is successfully matched
verification.failureA verification attempt fails
user.enrolledA user completes identity enrollment
alert.triggeredAn alert rule threshold is breached
{
  "event": "verification.success",
  "orgId": "clx_org_...",
  "timestamp": "2026-04-06T14:52:10.000Z",
  "data": { ... }
}

Each delivery includes an x-proof-signature header — HMAC-SHA256 of the raw body signed with your webhook secret. Verify it to confirm the request originated from Proof.

Error Reference

All errors return JSON with an error field.

StatusMeaning
400Bad Request — missing or invalid fields
401Unauthorized — missing or invalid API key / service token
403Forbidden — session key mismatch or email constraint violated
409Conflict — session not in the expected state
410Gone — session has expired
422Unprocessable — identity not recognised, liveness failed, or pipeline hard-fail
429Too Many Requests — rate limit exceeded
{ "error": "Identity not recognised" }