Dashboard

Integration Guide

Complete guide for integrating VerifyHuman into your application with code examples in multiple languages.

Integration Overview

VerifyHuman integration follows a simple 3-step flow:

  1. User uploads a selfie → Frontend sends to VerifyHuman
  2. VerifyHuman verifies → Returns result with JWT token
  3. Your backend validates → Uses token to confirm verification
┌─────────┐         ┌──────────────┐         ┌─────────────┐
│  User   │────1───>│   Frontend   │────2───>│ VerifyHuman │
│ (Selfie)│         │  (Your App)  │<───3────│     API     │
└─────────┘         └──────┬───────┘         └─────────────┘
                           │
                           4 (Validate Token)
                           │
                           ▼
                    ┌──────────────┐
                    │   Backend    │
                    │  (Your API)  │
                    └──────────────┘

Quick Start Examples

JavaScript / React

import React, { useState } from 'react';

function VerificationComponent() {
    const [status, setStatus] = useState('');
    const [loading, setLoading] = useState(false);

    const handleVerification = async (event) => {
        const file = event.target.files[0];
        if (!file) return;

        setLoading(true);
        const formData = new FormData();
        formData.append('clientKey', process.env.REACT_APP_VERIFYHUMAN_KEY);
        formData.append('file', file);

        try {
            const response = await fetch('https://app.verifyhuman.io/api/verify', {
                method: 'POST',
                body: formData
            });

            const result = await response.json();

            if (result.status === 'PASS') {
                setStatus(`✓ Verified! (${result.confidence}% confidence)`);
                // Send token to your backend for validation
                await validateOnBackend(result.token);
            } else {
                setStatus(`✗ Verification failed: ${result.error}`);
            }
        } catch (error) {
            setStatus(`Error: ${error.message}`);
        } finally {
            setLoading(false);
        }
    };

    const validateOnBackend = async (token) => {
        await fetch('/api/verify-user', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ verificationToken: token })
        });
    };

    return (
        <div>
            <h2>Human Verification</h2>
            <input 
                type="file" 
                accept="image/*"
                capture="user"
                onChange={handleVerification}
                disabled={loading}
            />
            {loading && <p>Verifying...</p>}
            {status && <p>{status}</p>}
        </div>
    );
}

export default VerificationComponent;

Backend validation (Node.js/Express):

const express = require('express');
const fetch = require('node-fetch');

app.post('/api/verify-user', async (req, res) => {
    const { verificationToken } = req.body;

    try {
        const response = await fetch('https://app.verifyhuman.io/api/validate', {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${process.env.VERIFYHUMAN_SECRET}`,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({ token: verificationToken })
        });

        const result = await response.json();

        if (result.valid && result.status === 'PASS') {
            // Mark user as verified in your database
            await db.users.update({ 
                id: req.user.id, 
                verified: true,
                verified_at: new Date()
            });

            res.json({ success: true, message: 'User verified!' });
        } else {
            res.status(401).json({ success: false, message: 'Invalid verification' });
        }
    } catch (error) {
        res.status(500).json({ error: error.message });
    }
});

Python / Flask

from flask import Flask, request, jsonify
import requests
import os

app = Flask(__name__)

@app.route('/verify', methods=['POST'])
def verify_user():
    """Frontend endpoint to submit verification"""
    if 'file' not in request.files:
        return jsonify({'error': 'No file uploaded'}), 400

    file = request.files['file']

    # Send to VerifyHuman API
    files = {'file': (file.filename, file.stream, file.content_type)}
    data = {'clientKey': os.environ.get('VERIFYHUMAN_CLIENT_KEY')}

    response = requests.post(
        'https://app.verifyhuman.io/api/verify',
        files=files,
        data=data
    )

    result = response.json()
    return jsonify(result)


@app.route('/validate-verification', methods=['POST'])
def validate_verification():
    """Backend endpoint to validate verification token"""
    token = request.json.get('token')

    if not token:
        return jsonify({'error': 'Missing token'}), 400

    # Validate with VerifyHuman API
    response = requests.post(
        'https://app.verifyhuman.io/api/validate',
        headers={
            'Authorization': f"Bearer {os.environ.get('VERIFYHUMAN_SECRET')}",
            'Content-Type': 'application/json'
        },
        json={'token': token}
    )

    result = response.json()

    if result.get('valid') and result.get('status') == 'PASS':
        # Mark user as verified
        # db.update_user(user_id, verified=True)
        return jsonify({'success': True, 'message': 'User verified'})
    else:
        return jsonify({'success': False, 'error': result.get('error')}), 401


if __name__ == '__main__':
    app.run(port=5000)

Python / Django

# views.py
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.conf import settings
import requests

@csrf_exempt
def verify_user(request):
    """Handle file upload and verification"""
    if request.method != 'POST':
        return JsonResponse({'error': 'POST required'}, status=405)

    if 'file' not in request.FILES:
        return JsonResponse({'error': 'No file uploaded'}, status=400)

    file = request.FILES['file']

    # Send to VerifyHuman
    files = {'file': file}
    data = {'clientKey': settings.VERIFYHUMAN_CLIENT_KEY}

    response = requests.post(
        'https://app.verifyhuman.io/api/verify',
        files=files,
        data=data
    )

    return JsonResponse(response.json())


@csrf_exempt  
def validate_token(request):
    """Validate verification token on backend"""
    import json
    data = json.loads(request.body)
    token = data.get('token')

    response = requests.post(
        'https://app.verifyhuman.io/api/validate',
        headers={
            'Authorization': f'Bearer {settings.VERIFYHUMAN_SECRET}',
            'Content-Type': 'application/json'
        },
        json={'token': token}
    )

    result = response.json()

    if result.get('valid') and result.get('status') == 'PASS':
        # Update user model
        if request.user.is_authenticated:
            request.user.is_verified = True
            request.user.save()

        return JsonResponse({'success': True})

    return JsonResponse({'success': False}, status=401)

PHP / Laravel

<?php
// routes/web.php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;

Route::post('/verify', function (Request $request) {
    $request->validate([
        'file' => 'required|image|max:5120' // 5MB max
    ]);

    // Send to VerifyHuman API
    $response = Http::attach(
        'file', 
        file_get_contents($request->file('file')->path()),
        $request->file('file')->getClientOriginalName()
    )->post('https://app.verifyhuman.io/api/verify', [
        'clientKey' => env('VERIFYHUMAN_CLIENT_KEY')
    ]);

    return response()->json($response->json());
});

Route::post('/validate-verification', function (Request $request) {
    $token = $request->input('token');

    // Validate with VerifyHuman
    $response = Http::withHeaders([
        'Authorization' => 'Bearer ' . env('VERIFYHUMAN_SECRET')
    ])->post('https://app.verifyhuman.io/api/validate', [
        'token' => $token
    ]);

    $result = $response->json();

    if ($result['valid'] && $result['status'] === 'PASS') {
        // Mark user as verified
        $user = auth()->user();
        $user->verified = true;
        $user->save();

        return response()->json(['success' => true]);
    }

    return response()->json(['success' => false], 401);
});

Ruby / Rails

# app/controllers/verification_controller.rb
class VerificationController < ApplicationController
  def verify
    require 'net/http'
    require 'uri'

    file = params[:file]

    uri = URI.parse('https://app.verifyhuman.io/api/verify')
    request = Net::HTTP::Post.new(uri)

    form_data = [
      ['clientKey', ENV['VERIFYHUMAN_CLIENT_KEY']],
      ['file', file]
    ]
    request.set_form form_data, 'multipart/form-data'

    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end

    render json: JSON.parse(response.body)
  end

  def validate_token
    require 'net/http'
    require 'uri'
    require 'json'

    token = params[:token]

    uri = URI.parse('https://app.verifyhuman.io/api/validate')
    request = Net::HTTP::Post.new(uri)
    request['Authorization'] = "Bearer #{ENV['VERIFYHUMAN_SECRET']}"
    request['Content-Type'] = 'application/json'
    request.body = { token: token }.to_json

    response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
      http.request(request)
    end

    result = JSON.parse(response.body)

    if result['valid'] && result['status'] == 'PASS'
      current_user.update(verified: true)
      render json: { success: true }
    else
      render json: { success: false }, status: :unauthorized
    end
  end
end

Mobile App Integration

React Native

import React, { useState } from 'react';
import { View, Button, Text, Image } from 'react-native';
import * as ImagePicker from 'expo-image-picker';

export default function VerificationScreen() {
    const [status, setStatus] = useState('');

    const pickImageAndVerify = async () => {
        // Request camera permission
        const permission = await ImagePicker.requestCameraPermissionsAsync();
        if (!permission.granted) {
            alert('Camera permission required');
            return;
        }

        // Take photo
        const result = await ImagePicker.launchCameraAsync({
            allowsEditing: false,
            quality: 0.8,
        });

        if (!result.canceled) {
            await verifyImage(result.assets[0].uri);
        }
    };

    const verifyImage = async (imageUri) => {
        const formData = new FormData();
        formData.append('clientKey', 'pk_live_your_key_here');
        formData.append('file', {
            uri: imageUri,
            type: 'image/jpeg',
            name: 'selfie.jpg',
        });

        try {
            const response = await fetch('https://app.verifyhuman.io/api/verify', {
                method: 'POST',
                body: formData,
                headers: {
                    'Content-Type': 'multipart/form-data',
                },
            });

            const result = await response.json();

            if (result.status === 'PASS') {
                setStatus(`✓ Verified (${result.confidence}%)`);
                // Send token to your backend
                await validateOnBackend(result.token);
            } else {
                setStatus(`✗ Failed: ${result.error}`);
            }
        } catch (error) {
            setStatus(`Error: ${error.message}`);
        }
    };

    const validateOnBackend = async (token) => {
        await fetch('https://your-api.com/validate', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ token }),
        });
    };

    return (
        <View style={{ padding: 20 }}>
            <Button title="Verify Your Identity" onPress={pickImageAndVerify} />
            {status && <Text style={{ marginTop: 20 }}>{status}</Text>}
        </View>
    );
}

Flutter

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:io';

class VerificationScreen extends StatefulWidget {
  @override
  _VerificationScreenState createState() => _VerificationScreenState();
}

class _VerificationScreenState extends State<VerificationScreen> {
  String _status = '';
  final ImagePicker _picker = ImagePicker();

  Future<void> _verifyIdentity() async {
    // Take photo
    final XFile? image = await _picker.pickImage(
      source: ImageSource.camera,
      imageQuality: 80,
    );

    if (image == null) return;

    setState(() => _status = 'Verifying...');

    try {
      // Create multipart request
      var request = http.MultipartRequest(
        'POST',
        Uri.parse('https://app.verifyhuman.io/api/verify'),
      );

      request.fields['clientKey'] = 'pk_live_your_key_here';
      request.files.add(await http.MultipartFile.fromPath('file', image.path));

      // Send request
      var response = await request.send();
      var responseData = await response.stream.toBytes();
      var result = json.decode(String.fromCharCodes(responseData));

      if (result['status'] == 'PASS') {
        setState(() => _status = '✓ Verified (${result['confidence']}%)');
        // Validate on backend
        await _validateOnBackend(result['token']);
      } else {
        setState(() => _status = '✗ Failed: ${result['error']}');
      }
    } catch (e) {
      setState(() => _status = 'Error: $e');
    }
  }

  Future<void> _validateOnBackend(String token) async {
    await http.post(
      Uri.parse('https://your-api.com/validate'),
      headers: {'Content-Type': 'application/json'},
      body: json.encode({'token': token}),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Verification')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: _verifyIdentity,
              child: Text('Verify Your Identity'),
            ),
            if (_status.isNotEmpty)
              Padding(
                padding: EdgeInsets.all(20),
                child: Text(_status, style: TextStyle(fontSize: 16)),
              ),
          ],
        ),
      ),
    );
  }
}

Error Handling

Always handle errors gracefully:

async function verifyWithErrorHandling(file) {
    try {
        const formData = new FormData();
        formData.append('clientKey', 'pk_live_your_key');
        formData.append('file', file);

        const response = await fetch('https://app.verifyhuman.io/api/verify', {
            method: 'POST',
            body: formData
        });

        const result = await response.json();

        switch (response.status) {
            case 200:
                if (result.status === 'PASS') {
                    return { success: true, data: result };
                } else {
                    return { success: false, error: result.error };
                }

            case 400:
                return { success: false, error: 'Invalid request: ' + result.error };

            case 401:
                return { success: false, error: 'Authentication failed: ' + result.error };

            case 402:
                return { success: false, error: 'No credits remaining. Please upgrade your plan.' };

            case 429:
                if (result.status === 'throttled') {
                    return { success: false, error: 'Too many attempts. Please try again in 5 minutes.' };
                }
                return { success: false, error: 'Rate limit exceeded' };

            case 500:
                return { success: false, error: 'Server error. Please try again later.' };

            default:
                return { success: false, error: 'Unexpected error occurred' };
        }
    } catch (error) {
        return { success: false, error: 'Network error: ' + error.message };
    }
}

Best Practices

1. Always Validate on Backend

// ✅ GOOD - Validate on backend
const frontendResult = await verifyOnFrontend(file);
const backendValidation = await validateOnBackend(frontendResult.token);

// ❌ BAD - Never trust frontend only
if (frontendResult.status === 'PASS') {
    grantAccess(); // Don't do this!
}

2. Handle Throttling Gracefully

function showUserFriendlyError(result) {
    if (result.status === 'throttled') {
        return 'Too many attempts. Please wait 5 minutes and try again with better lighting.';
    }
    return result.error || 'Verification failed';
}

3. Provide Clear User Instructions

<div class="verification-instructions">
    <h3>Tips for Successful Verification</h3>
    <ul>
        <li>Use good lighting</li>
        <li>Face the camera directly</li>
        <li>Remove glasses or masks</li>
        <li>Ensure only your face is visible</li>
        <li>Hold still while taking the photo</li>
    </ul>
</div>

4. Store Verification Status

// After successful verification
await db.users.update({
    id: userId,
    verified: true,
    verified_at: new Date(),
    verification_id: result.verification_id,
    verification_confidence: result.confidence
});

Widget Integration

For a faster, no-code approach, use our embeddable JavaScript widgets. Widgets handle camera access, image capture, and verification UI automatically.

VerifyHuman Widget

<script src="https://app.verifyhuman.io/widget.js"></script>
<div id="verifyhuman-widget"></div>

<script>
VerifyHuman.init({
  apiKey: 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
  buttonText: 'Verify You\'re Human',
  onSuccess: function(result) {
    console.log('Verified!', result);
  },
  onFailure: function(error) {
    console.error('Failed:', error);
  }
});
</script>

VerifyAge Widget

<script src="https://app.verifyhuman.io/widget-age.js"></script>
<div id="verifyage-widget"></div>

<script>
VerifyAge.init({
  apiKey: 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
  useCase: 'alcohol',
  minAge: 21,
  onSuccess: function(result) {
    console.log('Age verified!', result);
  }
});
</script>

VerifyIdentity Widget

<script src="https://app.verifyhuman.io/widget-identity.js"></script>
<div id="verifyidentity-widget"></div>

<script>
VerifyIdentity.init({
  apiKey: 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
  requireIdBack: false,
  onSuccess: function(result) {
    console.log('Identity verified!', result);
  }
});
</script>

VerifyCompliance Widget

<script src="https://app.verifyhuman.io/widget-compliance.js"></script>
<div id="verifycompliance-widget"></div>

<script>
VerifyCompliance.init({
  apiKey: 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
  onSuccess: function(result) {
    if (result.compliance_screening.total_hits === 0) {
      console.log('Cleared!', result);
    } else {
      console.warn('Compliance hits detected');
    }
  }
});
</script>

Full Widget Documentation: Widget Integration Guide


Hosted Flows (No-Code Integration)

For the fastest implementation without any coding, use our hosted verification pages. Perfect for non-technical teams or quick proof-of-concepts.

How It Works

  1. Log in to your Dashboard
  2. Navigate to Hosted Flows
  3. Click "Create New Flow"
  4. Select your verification product
  5. Configure settings and branding
  6. Generate and share the secure URL

Example Use Cases

Customer Onboarding:

https://verify.verifyhuman.io/flow/ver_kyc_abc123xyz456

Send this link to customers via email. After verification, they're redirected to your success URL.

Age-Gated Content:

https://verify.verifyhuman.io/flow/age_def456ghi789

Display this link or QR code for age verification before content access.

Event Check-In:

https://verify.verifyhuman.io/flow/vh_jkl012mno345

Show QR code at entrance for contactless bot-free check-in.

Customization Options

Full Hosted Flows Documentation: Hosted Flows Guide


Product Selection Guide

Choose the right verification product for your use case:

Product Use Case Credit Cost API Endpoint
VerifyHuman Bot detection, liveness 1 credit /api/verify
VerifyAge Age verification, compliance 10 credits /api/v1/verify-age/*
VerifyIdentity KYC, ID verification 30 credits /api/identity/v1/submit
VerifyCompliance KYC+ with AML/sanctions 50 credits /api/kyc/v1/submit_plus

Multi-Product Integration Example

// Determine which product to use based on business logic
async function verifyUser(userData, requirementLevel) {
  switch(requirementLevel) {
    case 'basic':
      // Just check if real human
      return await verifyHuman(userData.selfie);

    case 'age-restricted':
      // Verify age for age-gated content
      return await verifyAge(userData.selfie, 21);

    case 'kyc':
      // Full identity verification
      return await verifyIdentity(userData.selfie, userData.idFront);

    case 'compliance':
      // KYC + AML/PEP/Sanctions screening
      return await verifyCompliance(userData.selfie, userData.idFront);
  }
}

Product-Specific Guides:


Testing Your Integration

Local Testing

  1. Use your test API keys
  2. Test with sample images
  3. Verify error handling
  4. Check token validation flow

Pre-Production Checklist

Next Steps

Support

Need integration help?