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

# POST /v3/initialize

> Mint a verification session and get back a hosted URL to send the user to.

`POST /v3/initialize` starts a verification and returns the hosted URL to send the user to. It is the server-side counterpart to the SDK's [`vycheck()`](/v3/sdk/vycheck). Reach for it when you want to mint the session from trusted code, for example to [link a known user](/v3/advanced/account-linking) or bind an identity before the user verifies.

```http theme={null}
POST https://trust.verifyyou.com/v3/initialize
Authorization: Bearer <key>
Content-Type: application/json
```

```ts theme={null}
type InitializeResponse = {
  url: string;        // redirect the user here, or
  session_id: string; // hand to the SDK's vycheck({ session }) to embed the flow
};
```

<Tip>
  This page is the guided walkthrough. To see every endpoint and **try it out**
  against the live API, use the [API Reference](/api-reference). It is generated
  from the same spec, so it never drifts.
</Tip>

## Authentication

Accepts a **publishable key** (`pk_…`) or a **secret key** (`sk_…`). A handful of parameters attach an identity or target a verification directly and therefore require a secret key. They are marked **secret key only** below; sending them with a publishable key returns `400`.

Keys come in matched test and live pairs. A session started with a test key mints tokens only the test secret key can confirm, and the same goes for live. Use the test pair while you build, then swap both keys together.

<CardGroup cols={2}>
  <Card title="Publishable key" icon="globe">
    From the browser. The SDK uses this. Can pass `origin`, `return_path`,
    `start_path`, `external_tracker`, and `pass_params`.
  </Card>

  <Card title="Secret key" icon="lock">
    From your server. Can pass everything, including the identity and
    target parameters below.
  </Card>
</CardGroup>

## Body parameters

<ParamField body="origin" type="string" optional>
  The domain you start the verification from (e.g. `https://yourapp.com`). Used to look up which of your verifications to run when `verification_id` isn't given, and as the return destination when the verification has no saved redirect URL.
</ParamField>

<ParamField body="return_path" type="string" optional>
  Path on `origin` the user is redirected back to after verifying (e.g. `/verified`). We append the result as `?vyt=<token>&vyc=<0|1>`. The redirect URL saved on the verification takes precedence when set.
</ParamField>

<ParamField body="start_path" type="string" optional>
  Path on `origin` the user is coming from. Lets one domain host several verification flows. Requires an `origin`.
</ParamField>

<ParamField body="verification_id" type="string" optional>
  **Secret key only.** Target a verification directly instead of running your default one.
</ParamField>

<ParamField body="verification_external_id" type="string" optional>
  **Secret key only.** Target a verification by your own external id for it (set when the verification was created), as an alternative to `verification_id`.
</ParamField>

<ParamField body="email" type="string" optional>
  **Secret key only.** Attach a verified identity to the person (makes them a [member](/v3/concepts/members-vs-guests)). Fails if that identity is already claimed.
</ParamField>

<ParamField body="phone" type="string" optional>
  **Secret key only.** Attach a stable identity to the verification. Fails if that identity is already in use.
</ParamField>

<ParamField body="external_id" type="string" optional>
  **Secret key only.** Link this verification to your own user or record id. See [Account linking](/v3/advanced/account-linking).
</ParamField>

<ParamField body="external_tracker" type="string" optional>
  A non-PII label carried on the session. Use it to correlate sessions with your own analytics.
</ParamField>

<ParamField body="pass_params" type="object" optional>
  Extra query parameters to carry through the flow and re-append to the return URL. Reserved `vy*` keys are ignored.
</ParamField>

## Response

<ResponseField name="url" type="string">
  The hosted verification link with a queued-up session. Redirect the user here.
</ResponseField>

<ResponseField name="session_id" type="string | null">
  The minted session id. Pass it to the SDK's [`vycheck({ session })`](/v3/sdk/vycheck)
  to run the flow in a drawer or inline embed instead of redirecting to `url`.
</ResponseField>

```json theme={null}
{
  "url": "https://app.verifyyou.com/v/abc123",
  "session_id": "sess_abc123"
}
```

## Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://trust.verifyyou.com/v3/initialize \
    -H "Authorization: Bearer sk_test_…" \
    -H "Content-Type: application/json" \
    -d '{ "external_id": "user_123" }'
  # => { "url": "https://app.verifyyou.com/v/abc123" }
  ```

  ```ts Node theme={null}
  const res = await fetch("https://trust.verifyyou.com/v3/initialize", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.VY_SK}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      external_id: "user_123", // secret key only; links the session to your user
    }),
  });
  const { url } = await res.json();
  // Redirect the user to `url`.
  ```
</CodeGroup>

## Errors

Errors return the matching HTTP status and a JSON body with a `detail` code:

```json theme={null}
{ "detail": "identifiers_require_secret_key" }
```

| Status | `detail`                         | Cause                                                                                                                                |
| ------ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `400`  | `identifiers_require_secret_key` | `external_id`, `email`, `phone`, `verification_id`, or `verification_external_id` was sent with a publishable key. Use a secret key. |
| `401`  | `invalid_key_type`               | The `Authorization` key isn't a recognized publishable or secret key.                                                                |
| `401`  | `invalid_or_revoked_key`         | The key is unknown or has been revoked.                                                                                              |
| `403`  | `config_requires_test_key`       | A `config` override was sent with a live key. Inline config is test-only.                                                            |
| `404`  | `no_matching_verification`       | Couldn't resolve which verification to run. Pass `verification_id`.                                                                  |
| `409`  | `external_id_already_exists`     | The `external_id` is already bound to a verification.                                                                                |
| `422`  | `config_incomplete: missing …`   | The `config` declares options that aren't built yet; the message lists them.                                                         |
| `422`  | validation error                 | The request body failed schema validation.                                                                                           |

## Client-side: `init()` + `vycheck()`

You don't have to call this endpoint by hand. In the browser, configure the SDK once with [`init()`](/v3/sdk/init) and let [`vycheck()`](/v3/sdk/vycheck) call `initialize` and run the flow for you, as a redirect, a drawer, or an inline embed:

```ts theme={null}
import { init, vycheck } from "@verifyyou-sdk/client";

init({ publishableKey: "pk_test_…" });
verifyButton.addEventListener("click", () => vycheck());
```

`init()` takes the publishable key only. The secret key never belongs in the browser; parameters that need it, like `external_id` and `email`, are the reason this server-side endpoint exists.

<Note>
  After the user returns, [confirm the token](/v3/api/confirmations) on your
  backend. Initializing a session doesn't verify anyone on its own.
</Note>
