Skip to main content
POST
https://dev.api.baanx.com
/
v1
/
auth
/
register
/
verification
Generate KYC Verification Session
curl --request POST \
  --url https://dev.api.baanx.com/v1/auth/register/verification \
  --header 'Content-Type: application/json' \
  --header 'x-client-key: <x-client-key>' \
  --data '
{
  "onboardingId": "<string>"
}
'
{
  "message": "Invalid onboarding ID"
}

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.
This endpoint is part of the registration flow and should be called before personal details submission. It does not require authentication.

Authentication

x-client-key
string
required
Your client public key for API authentication
x-us-env
boolean
default:"false"
Set to true to route requests to the US backend environment (if available for your client)
No Bearer Token Required: This endpoint is unauthenticated. Do not include an Authorization header.

Request

Body

onboardingId
string
required
Onboarding ID from email verification stepExample: 100a99cf-f4d3-4fa1-9be9-2e9828b20ebb

Response

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

Code Examples

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;

Response Example

{
  "sessionUrl": "https://magic.veriff.me/v/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Error Responses

{
  "message": "Invalid onboarding ID"
}

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

Implementation Guide

Web Application Flow

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)

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:
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:
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
  • Live selfie or video recording
  • Used for biometric matching with ID photo
  • Ensures the person presenting the ID is the actual holder
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

Verification Timeline

1

Immediate (0-2 minutes)

User uploads documents and completes selfie verification in Veriff
2

Quick Review (5-15 minutes)

Automated checks: Document authenticity, facial recognition, data extraction
3

Manual Review (15-60 minutes)

If automated checks are inconclusive, manual review by compliance team
4

Extended Review (1-24 hours)

Complex cases requiring additional verification or document requests (rare)

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

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

Common Issues

Verification Rejected

If verification is rejected, common reasons include:
  • Expired documents
  • Poor image quality (blurry, dark, cut-off)
  • Documents not accepted in user’s region
  • Mismatched document information
  • Selfie doesn’t match ID photo
  • Name on documents doesn’t match registration
  • Age doesn’t meet minimum requirements (typically 18+)
  • Document appears altered or fake
  • User on sanctions or watchlist
  • Previous account with same credentials
  • Suspicious behavior patterns

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

Comparison with Post-Registration Verification

There are two verification endpoints:
EndpointWhen to UseAuthenticationPurpose
POST /v1/auth/register/verificationDuring registrationonboardingId (no bearer token)Initial KYC for new users
GET /v1/user/verificationAfter registrationBearer token requiredRe-verification or verification for existing users

Best Practices

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)
Implement robust error handling:
  • Network failures during session generation
  • User closing verification window prematurely
  • Session expiry (allow regeneration)
  • Verification rejection (provide clear next steps)
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
  • 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