Authentication Guide
Last Updated: November 30, 2025
Learn how to authenticate with VerifyHuman API using unified API keys with product scopes.
๐ Table of Contents
- Unified API Keys
- Product Scopes
- Getting Your API Keys
- Authentication Methods
- Plan-Based Product Access
- Security Best Practices
- Environment Configuration
- Key Rotation
- Rate Limiting
- Testing Authentication
- Troubleshooting
๐ Unified API Keys
VerifyHuman uses a unified API key system with product scopes. A single API key can access multiple verification products based on the scopes you enable when creating it.
Key Format
All API keys use the unified vhk- prefix:
| Type | Format | Example |
|---|---|---|
| API Key | vhk-{32chars} |
vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 |
| API Secret | vhsk-{48chars} |
vhsk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4 |
Key Components
- API Key (Public): Used in API requests via
X-API-Keyheader or form data - API Secret (Private): Used for server-to-server token validation (keep secret!)
๐ฏ Product Scopes
When creating an API key, you select which products the key can access:
| Scope | Product | Purpose | Plan Required |
|---|---|---|---|
verifyhuman |
VerifyHuman | Liveness & bot detection | All plans |
verifyage |
VerifyAge | Age verification | All plans |
verifyidentity |
VerifyIdentity | KYC with ID verification | All plans |
verifycompliance |
VerifyCompliance | KYC+ with AML/sanctions | Pro & Enterprise only |
A single key can have multiple scopes. For example, one key with verifyhuman + verifyage scopes can be used for both products.
๐ Getting Your API Keys
Step-by-Step
- Log in to your Dashboard
- Navigate to API Keys in the sidebar
- Click "Create New API Key"
- Name your key (e.g., "Production", "Staging")
- Select scopes - choose which products this key can access:
- VerifyHuman (Liveness & bot detection)
- VerifyAge (Age verification)
- VerifyIdentity (KYC)
- VerifyCompliance (KYC+) - Pro/Enterprise plans only
- Click "Generate API Key"
- Copy both your API Key and API Secret - they're shown only once!
- Store securely in your environment variables
Managing Multiple Keys
Create separate keys for different environments:
| Environment | Purpose | Key Naming Example |
|---|---|---|
| Development | Local testing | "Development - VerifyHuman" |
| Staging | Pre-production testing | "Staging - VerifyHuman" |
| Production | Live application | "Production - VerifyHuman" |
๐ก Authentication Methods
Method 1: Header Authentication (Recommended)
Use the X-API-Key header for all API requests. The same unified key works for all products based on its scopes:
// All endpoints use the same unified API key format
const API_KEY = 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6';
// VerifyHuman endpoint (requires 'verifyhuman' scope)
const response = await fetch('https://app.verifyhuman.io/api/verify', {
method: 'POST',
headers: {
'X-API-Key': API_KEY
},
body: formData
});
// VerifyAge endpoint (requires 'verifyage' scope)
const response = await fetch('https://app.verifyhuman.io/api/v1/verify-age/verify', {
method: 'POST',
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
// VerifyIdentity endpoint (requires 'verifyidentity' scope)
const response = await fetch('https://app.verifyhuman.io/api/identity/v1/submit', {
method: 'POST',
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
// VerifyCompliance endpoint (requires 'verifycompliance' scope, Pro/Enterprise only)
const response = await fetch('https://app.verifyhuman.io/api/kyc/v1/submit_plus', {
method: 'POST',
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
Method 2: Form Data Authentication
For VerifyHuman specifically, you can include the key in form data:
const formData = new FormData();
formData.append('clientKey', 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6');
formData.append('file', imageFile);
const response = await fetch('https://app.verifyhuman.io/api/verify', {
method: 'POST',
body: formData
});
Method 3: Widget Initialization
For embeddable widgets, pass the key during initialization:
<script src="https://app.verifyhuman.io/widget.js"></script>
<script>
VerifyHuman.init({
apiKey: 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
onSuccess: function(result) {
console.log('Verified!', result);
},
onFailure: function(error) {
console.error('Failed:', error);
}
});
</script>
๐ Plan-Based Product Access
API keys are scoped to specific products based on your subscription plan:
Plan Access Matrix
| Plan | VerifyHuman | VerifyAge | VerifyIdentity | VerifyCompliance |
|---|---|---|---|---|
| Free | โ | โ | โ | โ |
| Starter | โ | โ | โ | โ |
| Growth | โ | โ | โ | โ |
| Pro | โ | โ | โ | โ |
| Enterprise | โ | โ | โ | โ |
Plan Restriction Errors
Attempting to use a product not available in your plan returns:
{
"error": "VerifyCompliance requires Pro or Enterprise plan",
"status": "ERROR",
"upgrade_url": "https://app.verifyhuman.io/dashboard/billing"
}
Wrong Key Scope Errors
Using the wrong key type for an endpoint returns:
{
"error": "Invalid API key or wrong product scope",
"status": "ERROR",
"hint": "This endpoint requires a unified API key with verifyage scope (vhk-...)"
}
๐ก๏ธ Security Best Practices
โ DO:
Store keys in environment variables
# .env file (never commit to Git) VERIFYHUMAN_KEY=vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6... VERIFYAGE_KEY=vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6... VERIFYIDENTITY_KEY=vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6... VERIFYCOMPLIANCE_KEY=vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6...Use separate keys for each environment
- Development key for local testing
- Staging key for pre-production
- Production key for live apps
Rotate keys periodically
- Generate new keys every 90 days
- Update environment variables
- Delete old keys after transition
Validate verification results server-side
// Don't trust client-side verification alone async function validateVerification(verificationId) { const response = await fetch( `https://app.verifyhuman.io/api/status/${verificationId}`, { headers: { 'X-API-Key': process.env.VERIFYHUMAN_KEY } } ); return await response.json(); }
โ DON'T:
Never hardcode keys in source code
// โ BAD - Don't do this! const API_KEY = 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6...';Never commit keys to Git
# Add to .gitignore .env .env.local .env.productionNever expose keys in client-side error messages
Never share keys in support tickets, forums, or screenshots
โ๏ธ Environment Configuration
Node.js / JavaScript
// config.js
module.exports = {
verifyHuman: process.env.VERIFYHUMAN_KEY,
verifyAge: process.env.VERIFYAGE_KEY,
verifyIdentity: process.env.VERIFYIDENTITY_KEY,
verifyCompliance: process.env.VERIFYCOMPLIANCE_KEY,
apiUrl: 'https://app.verifyhuman.io'
};
Python
# config.py
import os
VERIFYHUMAN_CONFIG = {
'verify_human_key': os.environ.get('VERIFYHUMAN_KEY'),
'verify_age_key': os.environ.get('VERIFYAGE_KEY'),
'verify_identity_key': os.environ.get('VERIFYIDENTITY_KEY'),
'verify_compliance_key': os.environ.get('VERIFYCOMPLIANCE_KEY'),
'api_url': 'https://app.verifyhuman.io'
}
React / Next.js
// .env.local (not committed to Git)
NEXT_PUBLIC_VERIFYHUMAN_KEY=vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
// In your component
const apiKey = process.env.NEXT_PUBLIC_VERIFYHUMAN_KEY;
PHP
// config.php
<?php
$verifyhuman_config = [
'verify_human_key' => getenv('VERIFYHUMAN_KEY'),
'verify_age_key' => getenv('VERIFYAGE_KEY'),
'verify_identity_key' => getenv('VERIFYIDENTITY_KEY'),
'api_url' => 'https://app.verifyhuman.io'
];
๐ Key Rotation
Rotation Process
- Generate new key in your dashboard
- Add new key to environment variables alongside old key
- Deploy changes to all environments
- Monitor for errors for 24-48 hours
- Remove old key from environment
- Delete old key in dashboard
Zero-Downtime Rotation
// Support both keys during transition
const PRIMARY_KEY = process.env.VERIFYHUMAN_KEY_NEW;
const FALLBACK_KEY = process.env.VERIFYHUMAN_KEY_OLD;
async function verifyWithFallback(formData) {
try {
return await callApi(formData, PRIMARY_KEY);
} catch (error) {
if (error.status === 401) {
console.warn('Primary key failed, trying fallback');
return await callApi(formData, FALLBACK_KEY);
}
throw error;
}
}
๐ Rate Limiting
Limits by Plan
| Plan | Requests/Minute | Monthly Credits |
|---|---|---|
| Free | 10 | 50 trial credits |
| Starter | 60 | 1,000 credits |
| Growth | 300 | 5,000 credits |
| Pro | 600 | 20,000 credits |
| Enterprise | 1,000+ | Custom |
Rate Limit Response (429)
{
"error": "Rate limit exceeded",
"status": "ERROR",
"retry_after": 60,
"limit": "60 requests/minute"
}
Rate Limit Headers
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1700000000
Handling Rate Limits
async function verifyWithRetry(formData, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch('https://app.verifyhuman.io/api/verify', {
method: 'POST',
headers: { 'X-API-Key': process.env.VERIFYHUMAN_KEY },
body: formData
});
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
console.log(`Rate limited. Retrying in ${retryAfter}s...`);
await new Promise(r => setTimeout(r, retryAfter * 1000));
continue;
}
return await response.json();
}
throw new Error('Max retries exceeded');
}
๐งช Testing Authentication
Demo Keys (No Credits Consumed)
Use demo keys for development testing:
vhk-demo_test123456789abcdefghijklm # Demo key for all products
All products use the unified key format with product-specific scopes.
Demo mode:
- Always returns successful verification
- Simulates realistic processing delay (1-3 seconds)
- No credit consumption
- Valid response structures
Test Your Key
# Test VerifyHuman key
curl -X POST https://app.verifyhuman.io/api/verify \
-H "X-API-Key: vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" \
-F "file=@test_selfie.jpg"
# Test VerifyAge key
curl -X POST https://app.verifyhuman.io/api/v1/verify-age/init \
-H "X-API-Key: vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" \
-H "Content-Type: application/json" \
-d '{"use_case": "alcohol", "min_age": 21}'
โ Troubleshooting
Common Errors
| Error | Cause | Solution |
|---|---|---|
| "Invalid API key" | Key is incorrect or inactive | Check key in dashboard, ensure correct format |
| "Wrong product scope" | Using wrong key type for endpoint | Use correct key prefix for the endpoint |
| "Product not available in plan" | Plan doesn't include product | Upgrade plan or use available products |
| "Rate limit exceeded" | Too many requests | Implement exponential backoff |
| "Account not verified" | Email not verified | Check email for verification link |
Debugging Checklist
- โ Correct key prefix for the endpoint?
- โ Key is active in dashboard?
- โ No extra spaces or line breaks?
- โ
Using correct header format (
X-API-Key)? - โ Plan includes the product you're trying to use?
๐ Next Steps
- API Reference - Complete API documentation
- Widget Integration - Embed verification widgets
- Hosted Flows - No-code verification pages
- Integration Guide - Full implementation guide
๐ Support
Need help with authentication?
- Email: support@verifyhuman.io
- Dashboard: Live chat available
- Documentation: docs.verifyhuman.io