> ## 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.

# Start User Verification

> Generates a verification session URL for identity verification

## Overview

This endpoint generates a time-limited, single-use verification session URL that you direct your users to for completing identity verification. The verification process is handled by Baanx's integrated identity verification provider.

Use this endpoint when:

* A user registers and needs to complete identity verification
* A user's verification was rejected and they need to retry
* You want to upgrade an unverified user to verified status

## How It Works

<Steps>
  <Step title="Generate Session URL">
    Call this endpoint to receive a unique verification session URL
  </Step>

  <Step title="Redirect User">
    Direct the user to the session URL (web redirect or open in webview/browser)
  </Step>

  <Step title="User Completes Verification">
    User uploads documents and completes identity checks on the verification provider's page
  </Step>

  <Step title="Verification Processing">
    The provider processes the submission (typically 5-30 minutes)
  </Step>

  <Step title="Status Update">
    User's `verificationState` is updated to either `PENDING`, `VERIFIED`, or `REJECTED`
  </Step>

  <Step title="Verification Complete">
    Check the user's verification status via [GET /v1/user](/api-reference/user/get-user)
  </Step>
</Steps>

## Authentication

This endpoint requires both client authentication and user authentication:

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

<ParamField header="Authorization" type="string" required>
  Bearer token obtained from OAuth flow or login endpoint
</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). Defaults to international environment.
</ParamField>

## Response

<ResponseField name="sessionUrl" type="string">
  Time-limited verification session URL. Direct the user to this URL to complete identity verification. The URL typically expires after 24 hours and is single-use only.
</ResponseField>

## Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl --request GET \
    --url https://dev.api.baanx.com/v1/user/verification \
    --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
    --header 'x-client-key: YOUR_CLIENT_KEY'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://dev.api.baanx.com/v1/user/verification', {
    method: 'GET',
    headers: {
      'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
      'x-client-key': 'YOUR_CLIENT_KEY'
    }
  });

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

  window.location.href = sessionUrl;
  ```

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

  async function startVerification(accessToken: string): Promise<string> {
    const response = await fetch('https://dev.api.baanx.com/v1/user/verification', {
      method: 'GET',
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'x-client-key': 'YOUR_CLIENT_KEY'
      }
    });

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

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

  const sessionUrl = await startVerification(accessToken);
  window.location.href = sessionUrl;
  ```

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

  url = "https://dev.api.baanx.com/v1/user/verification"
  headers = {
      "Authorization": "Bearer YOUR_ACCESS_TOKEN",
      "x-client-key": "YOUR_CLIENT_KEY"
  }

  response = requests.get(url, headers=headers)
  data = response.json()
  session_url = data['sessionUrl']

  print(f"Redirect user to: {session_url}")
  ```
</CodeGroup>

### Response Example

```json theme={null}
{
  "sessionUrl": "https://example.com?sessionId=12345-12345-12345b"
}
```

## Error Responses

<ResponseExample>
  ```json 401 Unauthorized theme={null}
  {
    "message": "Not authenticated"
  }
  ```

  ```json 403 Forbidden theme={null}
  {
    "message": "Not authorized"
  }
  ```

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

<Accordion title="Error Response Details">
  ### 401 Unauthorized

  The access token is missing, invalid, or expired. You need to:

  * Ensure the Authorization header is present and properly formatted
  * Verify the access token hasn't expired (6-hour lifetime)
  * Obtain a new access token using the refresh token if expired

  ### 403 Forbidden

  The access token is valid but doesn't have permission to access this resource. This may occur if:

  * The token doesn't belong to a valid user
  * The client key doesn't match the user's associated client
  * The user account has been suspended or disabled

  ### 500 Internal Server Error

  An unexpected error occurred on the server. If this persists:

  * Check the API status page
  * Contact support with the request timestamp
  * Implement retry logic with exponential backoff
</Accordion>

## Implementation Examples

### Web Application Flow

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

async function handleStartVerification() {
  try {
    const response = await fetch('https://dev.api.baanx.com/v1/user/verification', {
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'x-client-key': process.env.NEXT_PUBLIC_CLIENT_KEY
      }
    });

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

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

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

### Mobile Application Flow (React Native)

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

async function startVerificationMobile(accessToken: string) {
  try {
    const response = await fetch('https://dev.api.baanx.com/v1/user/verification', {
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'x-client-key': YOUR_CLIENT_KEY
      }
    });

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

    const canOpen = await Linking.canOpenURL(sessionUrl);
    if (canOpen) {
      await Linking.openURL(sessionUrl);
    }
  } catch (error) {
    console.error('Failed to open verification:', error);
  }
}
```

### In-App Browser Flow

For better UX, open the verification URL in an in-app browser:

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

async function startVerificationInApp(accessToken: string) {
  try {
    const response = await fetch('https://dev.api.baanx.com/v1/user/verification', {
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'x-client-key': YOUR_CLIENT_KEY
      }
    });

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

    if (await InAppBrowser.isAvailable()) {
      await InAppBrowser.open(sessionUrl, {
        dismissButtonStyle: 'cancel',
        preferredBarTintColor: '#16A34A',
        preferredControlTintColor: 'white',
        readerMode: false,
        animated: true,
        modalEnabled: true,
        enableBarCollapsing: false
      });
    }
  } catch (error) {
    console.error('Failed to open verification:', error);
  }
}
```

### Polling for Verification Completion

After redirecting the user, implement polling to detect when verification is complete:

```typescript theme={null}
async function pollVerificationStatus(
  accessToken: string,
  onComplete: (verified: boolean) => void
) {
  const maxAttempts = 60; // 5 minutes with 5-second intervals
  let attempts = 0;

  const poll = setInterval(async () => {
    try {
      const response = await fetch('https://dev.api.baanx.com/v1/user', {
        headers: {
          'Authorization': `Bearer ${accessToken}`,
          'x-client-key': YOUR_CLIENT_KEY
        }
      });

      const user = await response.json();

      if (user.verificationState === 'VERIFIED') {
        clearInterval(poll);
        onComplete(true);
      } else if (user.verificationState === 'REJECTED') {
        clearInterval(poll);
        onComplete(false);
      }

      attempts++;
      if (attempts >= maxAttempts) {
        clearInterval(poll);
        console.log('Verification still pending after 5 minutes');
      }
    } catch (error) {
      console.error('Polling error:', error);
    }
  }, 5000); // Poll every 5 seconds

  return () => clearInterval(poll);
}

const stopPolling = pollVerificationStatus(accessToken, (verified) => {
  if (verified) {
    showSuccessMessage('Verification complete! You can now order a card.');
  } else {
    showErrorMessage('Verification was rejected. Please contact support.');
  }
});
```

## Important Notes

<Warning>
  **Session Expiry**: The verification session URL typically expires after 24 hours. If a user doesn't complete verification within this time, you'll need to generate a new session URL by calling this endpoint again.
</Warning>

<Note>
  **Single Use**: Each session URL is single-use. Once the user completes (or abandons) the verification session, the URL becomes invalid. Generate a new URL for retry attempts.
</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, proof of address)
  * Inform users about the typical processing time (5-30 minutes)
  * Provide a way to check verification status after completion
</Tip>

## Verification Process Details

### Required Documents

Users will typically 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 (Region Dependent)">
    Document showing current residential address (dated within last 3 months):

    * Utility bill (electricity, water, gas)
    * Bank statement
    * Government correspondence
    * Rental agreement
  </Accordion>
</AccordionGroup>

### Verification Timeline

<Steps>
  <Step title="Immediate (0-2 minutes)">
    Automated checks: Document authenticity, facial recognition, data extraction
  </Step>

  <Step title="Quick Review (5-15 minutes)">
    Most verifications complete automatically within this timeframe
  </Step>

  <Step title="Manual Review (15-30 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
  </Step>
</Steps>

## Edge Cases & Limitations

### Already Verified Users

If a user is already verified and calls this endpoint:

* A new verification session is still generated
* The existing verification status remains until the new session completes
* This allows users to update their verification documents if needed

### Verification Rejection

If verification is rejected, the user's `verificationState` becomes `REJECTED`. Common rejection reasons:

<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>

  <Accordion title="Address Verification">
    * Proof of address doesn't match registered address
    * Document too old (must be within 3 months)
    * Address in restricted region
  </Accordion>
</AccordionGroup>

### Retry After Rejection

When a user is rejected:

1. Check rejection reason (contact support if not clear)
2. Wait 24 hours before retry (cooldown period)
3. Generate new verification session
4. Ensure documents meet all requirements
5. Submit with corrected/additional documents

```typescript theme={null}
async function retryVerification(accessToken: string) {
  const userResponse = await fetch('https://dev.api.baanx.com/v1/user', {
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'x-client-key': YOUR_CLIENT_KEY
    }
  });

  const user = await userResponse.json();

  if (user.verificationState === 'REJECTED') {
    // Show guidance on what went wrong
    showRejectionGuidance();

    // Generate new session after user confirms they're ready
    const verificationResponse = await fetch(
      'https://dev.api.baanx.com/v1/user/verification',
      {
        headers: {
          'Authorization': `Bearer ${accessToken}`,
          'x-client-key': YOUR_CLIENT_KEY
        }
      }
    );

    const { sessionUrl } = await verificationResponse.json();
    window.location.href = sessionUrl;
  }
}
```

### Regional Differences

**International Environment**:

* Standard KYC requirements
* Typical processing: 5-30 minutes
* Document requirements vary by country

**US Environment** (x-us-env: true):

* Enhanced KYC requirements
* SSN verification
* Additional compliance checks
* May require proof of address
* Typical processing: 15-60 minutes

### Session Abandonment

If a user starts verification but doesn't complete it:

* The session URL remains valid until expiry (24 hours)
* User's `verificationState` stays at current value
* No partial progress is saved
* User can restart by generating a new session URL

### Rate Limiting

* Maximum 10 verification sessions per user per day
* Maximum 3 concurrent active sessions per user
* Cooldown period of 1 hour after 3 consecutive failures

If limits are exceeded, you'll receive a 429 Too Many Requests response with details:

```json theme={null}
{
  "message": "Rate limit exceeded",
  "retryAfter": 3600,
  "limit": "3_per_hour"
}
```

## Webhook Notifications

<Note>
  While this endpoint doesn't directly support webhooks, you can configure verification status webhooks in your client dashboard to receive real-time notifications when a user's verification status changes.
</Note>

Webhook payload example:

```json theme={null}
{
  "event": "user.verification.completed",
  "userId": "100a99cf-f4d3-4fa1-9be9-2e9828b20ebb",
  "verificationState": "VERIFIED",
  "timestamp": "2024-01-15T10:30:00Z"
}
```

## Testing

### Sandbox Environment

In sandbox/test environments, you can use test documents to simulate different verification outcomes:

```typescript theme={null}
// Test user - will auto-approve
const testApprovedUser = {
  firstName: "Test",
  lastName: "Approved"
};

// Test user - will auto-reject
const testRejectedUser = {
  firstName: "Test",
  lastName: "Rejected"
};

// Test user - will remain pending
const testPendingUser = {
  firstName: "Test",
  lastName: "Pending"
};
```

Contact Baanx support for access to sandbox environment and test credentials.

## Related Endpoints

* [Get User Details](/api-reference/user/get-user) - Check current verification status
* [Order Card](/api-reference/card/order) - Requires VERIFIED status
* [Register User](/api-reference/auth/register) - Initial user registration
* [Get External Wallets](/api-reference/wallet/external) - View wallet balances (some features require verification)

## Best Practices

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

    * Explain why verification is required
    * List required documents
    * Estimate processing time
    * Provide preparation tips (good lighting, clear images)
  </Accordion>

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

    * Network failures during session generation
    * User closing verification window prematurely
    * Session expiry
    * Verification rejection
  </Accordion>

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

    * Poll user status periodically
    * 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
    * Implement CSRF protection on your redirect endpoints
    * Validate the user's session before generating verification URL
    * Use HTTPS for all communications
  </Accordion>
</AccordionGroup>
