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

# Quickstart

> Mint a session token, mount the flow, and read the decision

The verification flow mounts into an element you provide, runs the capture screens your dashboard defines, and calls you back once the server has decided.

## 1. Mint a session token on your backend

Your API key stays on your server. Exchange it for a short-lived session token and return that to your frontend.

<Warning>
  Never ship an API key to the browser, and never embed one in your frontend bundle or in a public repository. The SDK is designed so it never needs one — it only ever sees the short-lived session token.
</Warning>

## 2. Mount the flow

```ts theme={null}
import { createVerification } from "idesify/verification";

const controller = createVerification({
  token,                                   // session token from your backend
  container: document.getElementById("idv")!,
  language: navigator.language,
  callbacks: {
    onStep:     ({ step, index, total }) => console.log("step", step, index + 1, "/", total),
    onProgress: (e) => console.log("progress", e.event),
    onComplete: (r) => console.log("decision", r.decision, r.reason),
    onError:    ({ error, fatal }) => console.error(error, { fatal }),
    onExpire:   async () => controller.resume(await mintNewToken()),
  },
});

await controller.start();   // shows the intro screen, then runs the flow
```

When you are done, tear it down. This stops the camera, clears frame buffers, removes the UI, and drops listeners:

```ts theme={null}
controller.destroy();
```

## 3. Handle the decision

`onComplete` fires once, with the server's authoritative result:

```ts theme={null}
callbacks: {
  onComplete: ({ decision, reason, caseId }) => {
    if (decision === "approved") continueOnboarding();
    else showPendingState(decision, reason);
  },
}
```

See [Results and errors](/sdk/verification/results) for every decision value and what to do with it.

## Handling token expiry

Session tokens are short-lived by design. When one expires the SDK fires `onExpire` rather than failing the flow — mint a fresh token and hand it back:

```ts theme={null}
onExpire: async () => {
  const newToken = await fetch("/my-backend/idesify-token").then((r) => r.json());
  controller.resume(newToken.token);
},
```

The user keeps their place. Nothing already captured is lost.

## What the dashboard controls

The flow renders **strictly** from your dashboard configuration: which screens appear, which documents are offered, whether each is captured front-only or front-and-back, and the theme.

Change it in the dashboard, not in your code. No redeploy is required.

<Note>
  The intro screen shows the end user a language picker and a light/dark toggle. Both switch live and drive every subsequent screen. Your `language` and `colorScheme` options set the starting values.
</Note>

## Before you go live

<Columns cols={2}>
  <Card title="Embedding requirements" icon="lock" href="/sdk/embedding">
    The camera and CSP headers your page must allow. The most common launch blocker.
  </Card>

  <Card title="Configuration reference" icon="sliders" href="/sdk/verification/configuration">
    Every option and every controller method.
  </Card>
</Columns>
