> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kayle.id/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Create your first verification session, redirect a user to it, and receive the result over a webhook.

This guide takes you from zero to a working verification in about ten minutes. You'll create an organization, mint an API key, create a session via the API, send a user through the verify flow, and inspect the resulting webhook event.

## Prerequisites

* A Kayle ID account at [kayle.id](https://kayle.id), or a self-hosted instance running the platform app
* A way to expose a local HTTPS endpoint to the internet for webhook testing — [ngrok](https://ngrok.com) or [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) both work
* `curl` and `jq` for poking at the API

<Steps>
  <Step title="Create an organization">
    Sign in to the dashboard, follow the onboarding flow, and create an organization. The slug you choose becomes part of the dashboard URL (`/organizations/<slug>`) and is used by the demo flow if you wire it up later.
  </Step>

  <Step title="Mint an API key">
    Go to **API keys**, click **Create API key**, give it a name, and select the scopes you need. For this quickstart you need `sessions:write` (to create sessions) and `webhooks:write` (to register an endpoint). Copy the key — it's shown once and starts with `kk_`.

    <Warning>
      The key is only displayed at creation. If you lose it, delete the key and create a new one.
    </Warning>
  </Step>

  <Step title="Register a webhook endpoint">
    Either through the dashboard or with the API:

    ```bash theme={null}
    curl -X POST https://api.kayle.id/v1/webhooks/endpoints \
      -H "Authorization: Bearer kk_..." \
      -H "Content-Type: application/json" \
      -d '{
        "url": "https://example.ngrok.app/webhooks/kayle",
        "subscribed_event_types": [
          "verification.session.succeeded",
          "verification.session.failed",
          "verification.session.expired",
          "verification.session.cancelled"
        ]
      }'
    ```

    The response includes the endpoint ID and `signing_secret`. Save the secret — it's also shown only once. You'll use it to verify incoming webhook signatures. See [Verifying signatures](/webhooks/verifying-signatures).
  </Step>

  <Step title="Register an encryption key">
    Webhook payloads are always JWE-encrypted. The endpoint cannot receive deliveries until an active encryption key is attached.

    Generate an RSA key pair, export the public key as a JWK, then register it:

    ```bash theme={null}
    curl -X POST https://api.kayle.id/v1/webhooks/endpoints/whe_.../keys \
      -H "Authorization: Bearer kk_..." \
      -H "Content-Type: application/json" \
      -d '{
        "key_id": "k1",
        "algorithm": "RSA-OAEP-256",
        "key_type": "RSA",
        "jwk": { "kty": "RSA", "n": "...", "e": "AQAB", "alg": "RSA-OAEP-256", "use": "enc", "kid": "k1" }
      }'
    ```

    Store the matching private key in your secret manager. Your server uses it to decrypt incoming JWE bodies. See [Encrypted payloads](/webhooks/encryption) for key generation and decryption code.
  </Step>

  <Step title="Create a verification session">
    A session represents one Kayle check you want to run. You can request specific [share fields](/verifications/share-fields) — claims the user must consent to share before completing the flow.

    ```bash theme={null}
    curl -X POST https://api.kayle.id/v1/sessions \
      -H "Authorization: Bearer kk_..." \
      -H "Content-Type: application/json" \
      -d '{
        "redirect_url": "https://yourapp.com/verification/done",
        "share_fields": {
          "date_of_birth": { "required": true,  "reason": "Check age eligibility" },
          "family_name":   { "required": true,  "reason": "Match account name" },
          "given_names":   { "required": true,  "reason": "Match account name" }
        }
      }'
    ```

    The response includes a `verification_url` (where to send the user) and a one-shot `cancel_token` (in case you need to cancel from the browser):

    ```json theme={null}
    {
      "data": {
        "id": "vs_mza7vecksrtyfw193ekcvl5vnws3bt1lz96buu3iw7zidckf8dga2zx2echb3t16",
        "status": "created",
        "verification_url": "https://verify.kayle.id/vs_...?cancel_token=...",
        "cancel_token": "...",
        "expires_at": "2026-05-05T12:00:00Z"
      },
      "error": null
    }
    ```
  </Step>

  <Step title="Send the user through the flow">
    Redirect the user to `verification_url`. They'll land on `verify.kayle.id`, see the consent screen for the share fields you requested, and complete the flow on their phone (NFC chip read of their document plus a selfie).

    Sessions expire after 60 minutes. The user gets up to three attempts within that window.
  </Step>

  <Step title="Receive the webhook">
    When the user finishes, your webhook endpoint receives a POST with `Content-Type: application/jose`. The body is a compact JWE. Verify `X-Kayle-Signature` against the JWE string, decrypt with your private key, and the cleartext is the event JSON. For a confirmed Kayle check:

    ```json theme={null}
    {
      "type": "verification.session.succeeded",
      "metadata": {
        "contract_version": 1,
        "event_id": "evt_...",

        "verification_session_id": "vs_..."
      },
      "data": {
        "claims": {
          "date_of_birth": "1995-04-12",
          "family_name": "Curie",
          "given_names": "Marie"
        },
        "selected_field_keys": ["date_of_birth", "family_name", "given_names"]
      }
    }
    ```

    See [Verifying signatures](/webhooks/verifying-signatures) and [Encrypted payloads](/webhooks/encryption) for full code samples.
  </Step>

  <Step title="Pick up the redirect">
    After the Kayle check finishes, the user is sent to `redirect_url` if you supplied one. The redirect carries the session ID so you can match the browser back to the result you received over the webhook. Kayle's result is not your final access, onboarding, or eligibility decision.

    <Note>
      If you don't supply a redirect URL, the user will be shown a button that closes the page.
    </Note>
  </Step>
</Steps>

## Next

<Columns cols={2}>
  <Card title="Verification sessions" icon="id-card" href="/verifications/sessions">
    Statuses, attempts, expiry, and cancellation.
  </Card>

  <Card title="Failure codes" icon="triangle-exclamation" href="/verifications/document-checks#failure-codes">
    What each `failure_code` means and what to do about it.
  </Card>

  <Card title="Webhook deliveries" icon="paper-plane" href="/webhooks/deliveries">
    Retry semantics, delivery inspection, manual replays.
  </Card>

  <Card title="API reference" icon="code" href="/api-reference/introduction">
    Full endpoint reference, error codes, pagination.
  </Card>
</Columns>
