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

# Hosted link

> Verify an individual user through a Bridge-hosted KYC flow

Privy verifies an individual user with Bridge. Privy creates the [Bridge customer](https://apidocs.bridge.xyz/platform/customers/customers/api) on the first request and links it to the Privy user, so your app only ever references the Privy user ID.

Before creating a KYC link, see [hosted terms of service](/kyc-kyb/kyc-tos) or, if Bridge has approved your app, [terms of service reliance](/kyc-kyb/kyc-tos-reliance) for how to collect the user's acceptance. The user then submits their identity information through a hosted verification flow. To collect that data in your own interface instead, see [headless KYC](/kyc-kyb/kyc-headless).

Before verifying users, [register a Bridge API key with Privy](/kyc-kyb/setup).

## Create a KYC link

<View title="NodeJS" icon="node-js">
  Use the `initiateLinks` method from the `kyc` resource on `users()`.

  ```ts theme={"system"}
  import {PrivyClient} from '@privy-io/node';

  const privy = new PrivyClient({
    appId: process.env.PRIVY_APP_ID!,
    appSecret: process.env.PRIVY_APP_SECRET!
  });

  const status = await privy.users().kyc.initiateLinks('did:privy:xxxxx', {
    provider: 'bridge',
    environment: 'sandbox',
    email: 'user@example.com',
    endorsements: ['base'],
    redirect_uri: 'https://your-app.com/kyc/complete'
  });

  // status.kyc.link is the hosted KYC link to pass to your frontend
  ```
</View>

<View title="Python" icon="python">
  Use `initiate_links` to create a hosted KYC link.

  ```python theme={"system"}
  status = client.users.kyc.initiate_links(
      "did:privy:xxxxx",
      provider="bridge",
      environment="sandbox",
      email="user@example.com",
      endorsements=["base"],
      redirect_uri="https://your-app.com/kyc/complete",
  )

  # Pass status.kyc.link to your frontend.
  ```
</View>

<View title="REST API" icon="terminal">
  To generate a hosted KYC link for a user, make a `POST` request to:

  ```bash theme={"system"}
  https://api.privy.io/v1/users/{user_id}/kyc/links
  ```

  See the [API reference](/api-reference/fiat/kyc-server/links) for the full request and response schema.

  In the body of the request, include the following fields:

  <ParamField body="provider" type="'bridge'" required>
    Provider to verify the user with.
  </ParamField>

  <ParamField body="environment" type="'production' | 'sandbox'">
    Bridge environment to use. Defaults to `production`.
  </ParamField>

  <ParamField body="email" type="string">
    Email address for the Bridge customer. Falls back to the user's linked email account. Required if
    the user has no linked email.
  </ParamField>

  <ParamField body="endorsements" type="string[]">
    [Endorsements](https://apidocs.bridge.xyz/platform/customers/customers/endorsements) to request
    from Bridge. Each endorsement unlocks a set of rails and regions. Defaults to `['base']`.
  </ParamField>

  <ParamField body="redirect_uri" type="string">
    URI the user is redirected to after completing the hosted flow.
  </ParamField>

  <ParamField body="client_agreement_id" type="string">
    Identifier resolving to your app's stored record of the user's terms of service acceptance. Only
    applicable if Bridge has approved the app for [terms of service
    reliance](/kyc-kyb/kyc-tos-reliance).
  </ParamField>

  Below is a sample cURL command for this request:

  ```bash theme={"system"}
  curl --request POST https://api.privy.io/v1/users/did:privy:xxxxx/kyc/links \
    -u "<your-privy-app-id>:<your-privy-app-secret>" \
    -H "privy-app-id: <your-privy-app-id>" \
    -H 'Content-Type: application/json' \
    -d '{
      "provider": "bridge",
      "environment": "sandbox",
      "email": "user@example.com",
      "endorsements": ["base"],
      "redirect_uri": "https://your-app.com/kyc/complete"
    }'
  ```

  The response is the user's full KYC status, including the link to complete verification. See [Track
  KYC status](#track-kyc-status) for the complete set of fields.

  ```json theme={"system"}
  {
    "provider": "bridge",
    "environment": "sandbox",
    "status": "not_started",
    "tos": {
      "status": "approved"
    },
    "kyc": {
      "status": "not_started",
      "link": "https://bridge.withpersona.com/verify?..."
    },
    "endorsements": [
      {
        "name": "base",
        "status": "incomplete",
        "missing": ["government_id_verification"]
      }
    ],
    "capabilities": {
      "payin_crypto": "pending",
      "payout_crypto": "pending",
      "payin_fiat": "pending",
      "payout_fiat": "pending"
    },
    "requirements_due": [],
    "future_requirements_due": []
  }
  ```
</View>

Pass `kyc.link` to your app's frontend so the user can complete verification. The request is idempotent: calling it again for the same user returns the existing link.

## Track KYC status

Verification is asynchronous. Bridge reviews the submission after the user completes the hosted flow, and can revoke an endorsement later. See [track KYC status](/kyc-kyb/kyc-status) to poll a user's status or subscribe to webhooks.

## Next steps

<CardGroup cols={2}>
  <Card title="Track KYC status" icon="magnifying-glass" href="/kyc-kyb/kyc-status">
    Poll a user's verification status or subscribe to webhooks
  </Card>

  <Card title="Headless KYC" icon="code" href="/kyc-kyb/kyc-headless">
    Submit a user's verification data from your server
  </Card>

  <Card title="KYB" icon="building" href="/kyc-kyb/kyb">
    Verify an organization
  </Card>

  <Card title="Handling webhook events" icon="webhook" href="/user-management/users/webhooks/handling-events">
    Configure an endpoint to receive Privy webhook events
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.