Sandbox

Verification playground

The whole integration in three steps, running live against the sandbox with nothing mocked. Create a session, run the real flow, then compare what the browser told your page with what the server says happened.

Create a session

You are here

A session is one verification for one person, valid once. Your backend mints it with your secret key and hands the browser only the URL that comes back.

A sandbox flow Auvral hosts, so you can run the whole thing without an account. Its key lives in this app's server environment and is resolved inside /api/session, so there is nothing here for you to fill in.

Waiting for the SDK bundle to load…
The server-side call, in your language
bash
curl -X POST https://api.dev.auvral.com/v1/sessions \
  -H "x-api-key: $AUVRAL_API_KEY" \
  -H "content-type: application/json" \
  -d '{"flowId":"<your-flow-id>","referenceId":"user_8842","allowedOrigins":["https://yourapp.com"],"locale":"en"}'

Run the verification

The SDK opens the hosted flow over your page in an iframe it owns. Photograph a document, take a selfie, reach a verdict, exactly as your user would.

SDK bundleloading

Nothing running yet

Create a session in step 1 and the verification flow opens here, in a fullscreen overlay drawn by the SDK on top of this page, exactly as it would on yours.

The browser-side call, one script tag and one init
html
<script src="https://sdk.dev.auvral.com/v1/verification.js"></script>

<button id="verify">Verify identity</button>

<script>
  document.getElementById("verify").addEventListener("click", () => {
    const frame = new AuvralVerification().init({
      url: "https://verify.example.com/c/<code>",

      onResult: ({ status, verificationId, sessionId }) => {
        // UI only. Show a spinner, enable a button, update copy.
        // Do NOT unlock anything here; wait for the webhook.
        console.log("result", status, verificationId, sessionId);
      },

      onClose: ({ reason }) => {
        // "completed" | "user_dismissed" | "programmatic"
        console.log("closed", reason);
      },

      onError: ({ code, message }) => {
        // "missing_url" | "already_open"
        console.error(code, message);
      },
    });

    // frame.close() closes it from your side. It is idempotent.
  });
</script>

See what happened

The browser tells you what to render. The server tells you what is true. Both are here, on one timeline, so you can see which arrives first and which one you are allowed to believe.

What the browser said

no result yet

postMessage and onResult. Move your UI on this. Trust it with nothing.

What the server said

no server confirmation yet

GET /v1/sessions/{sessionId} asked with your API key, or a signed webhook. This is what may change your database.

Offsets are relative to the first line. Server rows are stamped by the server clock, every other row by yours.

Nothing yet. Create a session and run the flow.

The webhook, which is the part that may change your database
http
POST /your/webhook/endpoint

user-agent:            Auvral-Webhooks/2
content-type:          application/json
x-auvral-event-id:     3f1c9a54-8e2b-4d77-9f10-6a2c5b8e1d43
x-auvral-event-type:   VERIFICATION_SUCCEEDED
x-auvral-delivery-id:  b7e21a09-4c6d-42f1-83aa-19d0c7f5e2b8
x-auvral-attempt:      1
x-auvral-timestamp:    1787712835
x-auvral-signature:    v1=9c5b1e0d7a3f48c26b91ad5e7f30c8241b6de9a07c45f2318ed6b0a94c7f52d1

{
  "id": "3f1c9a54-8e2b-4d77-9f10-6a2c5b8e1d43",
  "type": "verification.succeeded",
  "createdAt": "2026-08-27T21:33:55.284Z",
  "data": {
    "verification": {
      "id": "0198f2c1-5a7b-7d3e-9f42-c8b06a1e94d7",
      "status": "VERIFIED",
      "flowId": "01a02fdf-4e4b-7b4b-956b-7d6de62fbe38",
      "flowName": "Verificación QR",
      "sessionId": "0f8d7260-d083-4ed4-b38b-c3bd3f5db31f",
      "referenceId": "user_8842",
      "metadata": { "orderId": "order-1234" },
      "startedAt": "2026-08-27T21:33:12.006Z",
      "endedAt": "2026-08-27T21:33:55.101Z",
      "steps": [
        { "name": "document_verification", "status": "VERIFIED" },
        { "name": "biometric_verification", "status": "VERIFIED" }
      ]
    }
  }
}

A sample of what Auvral POSTs to the endpoint you register per flow in the dashboard. The playground does not receive these. Note x-auvral-event-id: it is stable across all six delivery attempts, so it is your deduplication key.