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

# Generate KYC Verification Session

> Generate a Veriff verification session URL for identity verification during registration

## Overview

Generate a time-limited verification session URL for identity verification (KYC) during the registration flow. This endpoint creates a Veriff session that users complete to verify their identity before proceeding with personal details and address information.

**When to use:**

* After phone verification is complete
* Before collecting personal details and address
* User has not yet received an access token

This endpoint is **unauthenticated** and uses the `onboardingId` for session validation instead of a bearer token.

<Note>
  This endpoint is part of the registration flow and should be called **before** personal details submission. It does not require authentication.
</Note>

## Authentication

<ParamField header="x-client-key" type="string" required>
  Your client public key for API authentication
</ParamField>

<ParamField header="x-us-env" type="boolean" default="false">
  Set to `true` to route requests to the US backend environment (if available for your client)
</ParamField>

<Note>
  **No Bearer Token Required**: This endpoint is unauthenticated. Do not include an `Authorization` header.
</Note>

## Request

### Body

<ParamField body="onboardingId" type="string" required>
  Onboarding ID from email verification step

  **Example**: `100a99cf-f4d3-4fa1-9be9-2e9828b20ebb`
</ParamField>

## Response

<ResponseField name="sessionUrl" type="string">
  Time-limited Veriff session URL. Direct the user to this URL to complete identity verification. The URL typically expires after 7 days and can be used multiple times until verification is complete.
</ResponseField>

## Code Examples

<CodeGroup>
  ```javascript JavaScript theme={null}
  const response = await fetch('https://dev.api.baanx.com/v1/auth/register/verification', {
    method: 'POST',
    headers: {
      'x-client-key': 'your-client-key',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      onboardingId: sessionStorage.getItem('onboardingId')
    })
  });

  const { sessionUrl } = await response.json();

  // Redirect user to Veriff
  window.location.href = sessionUrl;
  ```

  ```typescript TypeScript theme={null}
  interface VerificationSession {
    sessionUrl: string;
  }

  async function generateKYCSession(onboardingId: string): Promise<string> {
    const response = await fetch('https://dev.api.baanx.com/v1/auth/register/verification', {
      method: 'POST',
      headers: {
        'x-client-key': process.env.NEXT_PUBLIC_CLIENT_KEY!,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ onboardingId })
    });

    if (!response.ok) {
      throw new Error('Failed to generate verification session');
    }

    const data: VerificationSession = await response.json();
    return data.sessionUrl;
  }

  // Usage
  const sessionUrl = await generateKYCSession(onboardingId);
  window.location.href = sessionUrl;
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      'https://dev.api.baanx.com/v1/auth/register/verification',
      headers={
          'x-client-key': 'your-client-key',
          'Content-Type': 'application/json'
      },
      json={
          'onboardingId': onboarding_id
      }
  )

  data = response.json()
  session_url = data['sessionUrl']

  print(f"Direct user to: {session_url}")
  ```

  ```bash cURL theme={null}
  curl -X POST https://dev.api.baanx.com/v1/auth/register/verification \
    -H "x-client-key: your-client-key" \
    -H "Content-Type: application/json" \
    -d '{
      "onboardingId": "100a99cf-f4d3-4fa1-9be9-2e9828b20ebb"
    }'
  ```
</CodeGroup>

### Response Example

```json theme={null}
{
  "sessionUrl": "https://magic.veriff.me/v/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```

## Error Responses

<ResponseExample>
  ```json 400 Bad Request theme={null}
  {
    "message": "Invalid onboarding ID"
  }
  ```

  ```json 404 Not Found theme={null}
  {
    "message": "Onboarding session not found"
  }
  ```

  ```json 498 Invalid Token theme={null}
  {
    "message": "Invalid API key"
  }
  ```

  ```json 500 Internal Server Error theme={null}
  {
    "message": "Internal server error"
  }
  ```
</ResponseExample>

<Accordion title="Error Response Details">
  ### 400 Bad Request

  The onboarding ID is invalid, expired, or malformed. You need to:

  * Verify the onboardingId is a valid UUID
  * Ensure the onboarding session hasn't expired (typically 30-60 minutes)
  * Restart registration from Step 1 if expired

  ### 404 Not Found

  The onboarding session with this ID doesn't exist:

  * The ID may be incorrect
  * The session may have already been completed
  * Restart registration if the session is lost

  ### 498 Invalid Token

  The x-client-key header is invalid:

  * Verify your client key is correct
  * Ensure the key is active and not revoked
  * Contact support if you believe this is an error

  ### 500 Internal Server Error

  An unexpected error occurred:

  * The verification provider may be unavailable
  * Retry the request after a brief delay
  * Contact support if the issue persists
</Accordion>

## Implementation Guide

### Web Application Flow

```typescript theme={null}
import { useRouter } from 'next/navigation';

async function handleKYCVerification(onboardingId: string) {
  try {
    const response = await fetch('https://dev.api.baanx.com/v1/auth/register/verification', {
      method: 'POST',
      headers: {
        'x-client-key': process.env.NEXT_PUBLIC_CLIENT_KEY!,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ onboardingId })
    });

    if (!response.ok) {
      throw new Error('Failed to generate verification session');
    }

    const { sessionUrl } = await response.json();

    // Redirect to Veriff
    window.location.href = sessionUrl;
  } catch (error) {
    console.error('KYC verification error:', error);
    showErrorToast('Unable to start verification. Please try again.');
  }
}
```

### Mobile Application Flow (React Native)

```typescript theme={null}
import { Linking } from 'react-native';
import { InAppBrowser } from 'react-native-inappbrowser-reborn';

async function startKYCVerification(onboardingId: string) {
  try {
    const response = await fetch('https://dev.api.baanx.com/v1/auth/register/verification', {
      method: 'POST',
      headers: {
        'x-client-key': YOUR_CLIENT_KEY,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ onboardingId })
    });

    const { sessionUrl } = await response.json();

    // Open in in-app browser for better UX
    if (await InAppBrowser.isAvailable()) {
      await InAppBrowser.open(sessionUrl, {
        dismissButtonStyle: 'cancel',
        preferredBarTintColor: '#16A34A',
        preferredControlTintColor: 'white',
        readerMode: false,
        animated: true,
        modalEnabled: true,
        enableBarCollapsing: false
      });
    } else {
      // Fallback to external browser
      await Linking.openURL(sessionUrl);
    }
  } catch (error) {
    console.error('Failed to start KYC:', error);
  }
}
```

### Handling Verification Completion

After the user completes Veriff verification, they will be redirected back to your application. The verification status is updated on the backend, but you should poll the onboarding status to detect completion:

```typescript theme={null}
async function pollVerificationStatus(onboardingId: string): Promise<void> {
  const maxAttempts = 60; // 5 minutes with 5-second intervals
  let attempts = 0;

  return new Promise((resolve, reject) => {
    const poll = setInterval(async () => {
      try {
        const response = await fetch(
          `https://dev.api.baanx.com/v1/auth/register?onboardingId=${onboardingId}`,
          {
            headers: {
              'x-client-key': process.env.NEXT_PUBLIC_CLIENT_KEY!
            }
          }
        );

        const user = await response.json();

        // Check if verification state has changed
        if (user.verificationState === 'VERIFIED' || user.verificationState === 'PENDING') {
          clearInterval(poll);
          resolve();
        } else if (user.verificationState === 'REJECTED') {
          clearInterval(poll);
          reject(new Error('Verification was rejected'));
        }

        attempts++;
        if (attempts >= maxAttempts) {
          clearInterval(poll);
          reject(new Error('Verification polling timeout'));
        }
      } catch (error) {
        clearInterval(poll);
        reject(error);
      }
    }, 5000); // Poll every 5 seconds
  });
}

// Usage
try {
  await pollVerificationStatus(onboardingId);
  showSuccessMessage('Verification complete! Proceeding to personal details.');
  // Navigate to personal details step
} catch (error) {
  showErrorMessage('Verification incomplete. Please try again.');
}
```

## Verification Process Details

### Required Documents

Users will need to provide:

<AccordionGroup>
  <Accordion title="Government-Issued ID">
    One of the following:

    * Passport
    * Driver's license
    * National ID card
    * Residence permit

    Requirements:

    * Must be valid (not expired)
    * Clear, readable photo of the document
    * All corners visible in the image
  </Accordion>

  <Accordion title="Selfie Verification">
    * Live selfie or video recording
    * Used for biometric matching with ID photo
    * Ensures the person presenting the ID is the actual holder
  </Accordion>

  <Accordion title="Proof of Address (May Be Required)">
    Document showing current residential address (dated within last 3 months):

    * Utility bill (electricity, water, gas)
    * Bank statement
    * Government correspondence
    * Rental agreement

    Note: This is typically collected via the address endpoints later in the registration flow
  </Accordion>
</AccordionGroup>

### Verification Timeline

<Steps>
  <Step title="Immediate (0-2 minutes)">
    User uploads documents and completes selfie verification in Veriff
  </Step>

  <Step title="Quick Review (5-15 minutes)">
    Automated checks: Document authenticity, facial recognition, data extraction
  </Step>

  <Step title="Manual Review (15-60 minutes)">
    If automated checks are inconclusive, manual review by compliance team
  </Step>

  <Step title="Extended Review (1-24 hours)">
    Complex cases requiring additional verification or document requests (rare)
  </Step>
</Steps>

## Verification States

The user's verification state will be updated based on the verification outcome:

* **UNVERIFIED**: Initial state before verification
* **PENDING**: Verification submitted and under review
* **VERIFIED**: Verification approved
* **REJECTED**: Verification rejected (user can retry)

## Important Notes

<Warning>
  **Session Expiry**: The verification session URL typically expires after 7 days. However, users can use the same URL multiple times during this period if they need to restart the process.
</Warning>

<Note>
  **Multiple Attempts**: If a user closes the Veriff session without completing it, they can use the same URL to resume. No need to generate a new session unless it has expired.
</Note>

<Tip>
  **User Experience**: For the best user experience:

  * Display a clear message explaining why verification is needed
  * Show what documents will be required (government ID)
  * Inform users about the typical processing time (5-30 minutes)
  * Provide a way to check verification status after completion
  * Consider opening Veriff in a modal or in-app browser rather than redirecting
</Tip>

## Common Issues

### Verification Rejected

If verification is rejected, common reasons include:

<AccordionGroup>
  <Accordion title="Document Issues">
    * Expired documents
    * Poor image quality (blurry, dark, cut-off)
    * Documents not accepted in user's region
    * Mismatched document information
  </Accordion>

  <Accordion title="Identity Mismatch">
    * Selfie doesn't match ID photo
    * Name on documents doesn't match registration
    * Age doesn't meet minimum requirements (typically 18+)
  </Accordion>

  <Accordion title="Fraud Detection">
    * Document appears altered or fake
    * User on sanctions or watchlist
    * Previous account with same credentials
    * Suspicious behavior patterns
  </Accordion>
</AccordionGroup>

### Retry After Rejection

When a user is rejected, they can proceed with registration and retry verification later using the authenticated endpoint:

1. Complete registration to get access token
2. Use `GET /v1/user/verification` (authenticated) to generate a new session
3. Ensure documents meet all requirements
4. Submit with corrected/additional documents

## Registration Flow Context

This endpoint is **Step 3** in the registration process:

1. Email verification → get `onboardingId`
2. Phone verification → use `onboardingId`
3. **→ KYC verification** → use `onboardingId` (this endpoint) ← You are here
4. Personal details → use `onboardingId`
5. Physical address → use `onboardingId`, may get `accessToken`
6. Mailing address (US only) → use `onboardingId`, get `accessToken`

<Note>
  **No Bearer Token**: This endpoint is unauthenticated because the user doesn't have an access token yet. The access token is only issued after the address step completes.
</Note>

## Comparison with Post-Registration Verification

There are two verification endpoints:

| Endpoint                              | When to Use         | Authentication                   | Purpose                                            |
| ------------------------------------- | ------------------- | -------------------------------- | -------------------------------------------------- |
| `POST /v1/auth/register/verification` | During registration | `onboardingId` (no bearer token) | Initial KYC for new users                          |
| `GET /v1/user/verification`           | After registration  | Bearer token required            | Re-verification or verification for existing users |

## Related Endpoints

<CardGroup cols={2}>
  <Card title="Get Onboarding Status" href="/api-reference/auth/register">
    Check verification status during registration
  </Card>

  <Card title="Update Personal Details" href="/api-reference/auth/register-personal-details">
    Next step after verification
  </Card>

  <Card title="Post-Registration Verification" href="/api-reference/user/verification">
    For verified users who need to re-verify
  </Card>

  <Card title="Registration Guide" href="/guides/user/registration">
    Complete registration flow documentation
  </Card>
</CardGroup>

## Best Practices

<AccordionGroup>
  <Accordion title="User Guidance">
    Before redirecting users to verification:

    * Explain why verification is required (regulatory compliance, security)
    * List required documents (government ID, selfie)
    * Estimate processing time (5-30 minutes)
    * Provide preparation tips (good lighting, clear images, remove glasses)
  </Accordion>

  <Accordion title="Error Handling">
    Implement robust error handling:

    * Network failures during session generation
    * User closing verification window prematurely
    * Session expiry (allow regeneration)
    * Verification rejection (provide clear next steps)
  </Accordion>

  <Accordion title="Status Monitoring">
    After verification:

    * Poll onboarding status periodically (every 5 seconds)
    * Show loading state while verification processes
    * Display clear success/failure messages
    * Provide next steps based on outcome
  </Accordion>

  <Accordion title="Security">
    * Never store or log verification session URLs (they contain sensitive tokens)
    * Implement CSRF protection on your redirect endpoints
    * Validate the user's onboarding session before generating verification URL
    * Use HTTPS for all communications
  </Accordion>
</AccordionGroup>
