> For the complete documentation index, see [llms.txt](https://docs.voveid.com/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.voveid.com/docs/quick-start.md).

# KYC quick start

Complete a Sandbox KYC integration from session creation to server-side result retrieval.

This guide creates a KYC session on your backend, launches the hosted Sandbox journey, verifies the webhook, and retrieves the authoritative result.

## Before you begin

You need:

* Sandbox dashboard access.
* A Sandbox private API key and public SDK key.
* A webhook signing secret.
* An approved web domain.
* Node.js 18 or newer.
* A KYC flow ID, unless your organization has a default flow.

Keep the private API key and webhook secret on your server.

## 1. Configure Sandbox credentials

```bash
export VOVE_API_KEY='vove_sandbox_replace_me'
export VOVE_PUBLIC_KEY='public_sandbox_replace_me'
export VOVE_WEBHOOK_SECRET='webhook_secret_replace_me'
```

These values are placeholders. Never paste real credentials into source code or documentation.

## 2. Create a session on your backend

Generate and persist a stable `refId` before calling VOVE ID.

```javascript
import crypto from 'node:crypto';

const refId = `sandbox-${crypto.randomUUID()}`;

const response = await fetch('https://api.voveid.net/v2/sessions', {
  method: 'POST',
  headers: {
    'content-type': 'application/json',
    'x-api-key': process.env.VOVE_API_KEY,
  },
  body: JSON.stringify({
    refId,
    flowId: '66f000000000000000000001',
  }),
});

const body = await response.json();

if (!response.ok) {
  throw new Error(`VOVE session creation failed (${response.status})`);
}

const { token } = body;
// Persist refId. Return token only to the intended client.
```

Request:

```http
POST https://api.voveid.net/v2/sessions
x-api-key: vove_sandbox_replace_me
content-type: application/json

{
  "refId": "customer-7f3d",
  "flowId": "66f000000000000000000001"
}
```

Successful response:

```json
{
  "success": true,
  "token": "eyJ...redacted"
}
```

The default token lifetime is 30 minutes. See [Create a verification session](/docs/kyc-api/verification-session.md) for every supported request field.

## 3. Launch the hosted journey

Construct the URL with `URL` and `URLSearchParams` so every value is encoded:

```javascript
const verificationUrl = new URL('/', 'https://web.voveid.net');
verificationUrl.searchParams.set('authToken', token);
verificationUrl.searchParams.set('publicKey', process.env.VOVE_PUBLIC_KEY);
verificationUrl.searchParams.set('environment', 'Sandbox');

window.location.assign(verificationUrl);
```

Only send the session token to the authenticated user for whom it was created. For an embedded experience, choose a client from the [SDK compatibility matrix](/docs/sdks/compatibility.md).

## 4. Receive and verify the webhook

Configure an HTTPS endpoint in the Sandbox dashboard. Verify the `svix-id`, `svix-timestamp`, and `svix-signature` headers against the unmodified request bytes.

```javascript
import express from 'express';
import { Webhook } from 'svix';

const app = express();

app.post('/webhooks/vove', express.raw({ type: 'application/json' }), async (req, res) => {
  let event;

  try {
    event = new Webhook(process.env.VOVE_WEBHOOK_SECRET).verify(req.body, {
      'svix-id': req.header('svix-id'),
      'svix-timestamp': req.header('svix-timestamp'),
      'svix-signature': req.header('svix-signature'),
    });
  } catch {
    return res.sendStatus(400);
  }

  await persistAndEnqueueOnce(req.header('svix-id'), event);
  return res.sendStatus(204);
});
```

Register this route before global JSON parsing middleware. The complete [webhook guide](/docs/kyc-api/webhooks.md) explains idempotency, retries, payloads, and testing.

## 5. Retrieve the result

Treat the webhook as a notification. Retrieve the current server-side result using the same `refId`:

```javascript
const result = await fetch(
  `https://api.voveid.net/v2/users/${encodeURIComponent(refId)}`,
  { headers: { 'x-api-key': process.env.VOVE_API_KEY } },
);

if (!result.ok) {
  throw new Error(`VOVE result retrieval failed (${result.status})`);
}

const verification = await result.json();
console.log(verification.status);
```

Handle every documented [KYC status](/docs/api-fundamentals/statuses.md). Unknown values must remain pending until reviewed.

## Scaling and customization

The same SDK journey can support more complex verification flows as your requirements evolve. Configure the required checks in the dashboard, test the complete journey in Sandbox, and confirm the server-side result before applying a final decision.

<figure><img src="https://4173094968-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F83UoxmShmjD5iX8BJPn0%2Fuploads%2FHDfeC8kmW4LrtJzTI0Cv%2FDiagram%20activities%20vove%20(1).jpg?alt=media&amp;token=caa53725-37dc-4f26-a733-c54a760ec9ef" alt="KYC journey showing document capture, selfie checks, data matching, background checks, and possible outcomes"><figcaption><p>KYC journey and possible verification outcomes.</p></figcaption></figure>

## Overview of steps

The application requests a session token from its backend, starts the VOVE ID SDK with that token, and validates the resulting verification through its backend integration.

![Sequence diagram showing the application, customer backend, VOVE ID SDK, and VOVE ID backend during verification](https://4173094968-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F83UoxmShmjD5iX8BJPn0%2Fuploads%2FIBnF90Ji3ksMpILWOB5L%2Fvove_diagram.jpg?alt=media\&token=27b20b6f-26f9-48a8-91cd-05c305875673)

## Troubleshooting

| Symptom                                   | Check                                                                             |
| ----------------------------------------- | --------------------------------------------------------------------------------- |
| `401` or `403`                            | API key, environment, product access, and server-only use                         |
| Hosted page does not start                | Token age, public key, environment, and domain allowlist                          |
| No webhook arrives                        | Endpoint URL, event subscription, signing secret, delivery log, and response time |
| Duplicate processing                      | Add a unique constraint on `svix-id`                                              |
| Client says complete but backend does not | Retrieve `GET /v2/users/{refId}` and keep the decision pending                    |

## Next steps

* Read the complete [session API reference](/docs/kyc-api/verification-session.md).
* Choose and configure a [client SDK](/docs/sdks/compatibility.md).
* Implement production-grade [webhook handling](/docs/kyc-api/webhooks.md).
* Complete the [production checklist](/docs/production-readiness.md).
