# Verification Hub Integration Guide

**Version:** 1.0.0
**Last Updated:** 2026-06-23

The Verification Hub provides a highly secure, flexible, and comprehensive multi-channel identity verification system (WhatsApp & Email). This document outlines the best practices for integrating the Verification Hub into your own frontend applications, flow builders, and backend services.

---

## Overview

Integrating verification involves a standard 3-step process:

1. **Request Verification**: Your app requests the API to start a verification flow for an `identifier` (e.g. phone number or email).
2. **Handle User Input (OTP / Magic Link)**: The user receives a message and either enters an OTP code into your frontend or clicks a Magic Link.
3. **Verify and Proceed**: Your app sends the OTP code to the Verification API, or the Magic Link validates automatically. If successful, you proceed with the user's intended action (e.g., creating an account, allowing a login).

---

## Authentication

All API requests require authentication using API keys. You can obtain API keys from the Verification Hub Dashboard.

### Required Headers

| Header | Description |
|--------|-------------|
| `X-Public-Key` | Your public API key (required) |
| `X-Timestamp` | Current Unix timestamp (required for signed requests) |
| `X-Signature` | HMAC-SHA256 signature (optional but recommended) |

### Example Authentication

```php
// PHP Example
$publicKey = 'vpub_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
$secretKey = 'vsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

// Generate timestamp and signature
$timestamp = time();
$body = json_encode(['profile_id' => 'xxx', 'identifier' => '+1234567890', ...]);
$payload = $timestamp . '.' . 'POST' . '.' . '/api/v1/verification/request' . '.' . $body;
$signature = base64_encode(hash_hmac('sha256', $payload, $secretKey, true));

$response = Http::withHeaders([
    'X-Public-Key' => $publicKey,
    'X-Timestamp' => (string) $timestamp,
    'X-Signature' => $signature,
    'Content-Type' => 'application/json',
])->post('https://your-domain.com/api/v1/verification/request', $data);
```

### Signature Generation

The signature is computed as:

```
base64_encode(HMAC-SHA256(timestamp + '.' + method + '.' + path + '.' + body, secret_key))
```

**Security Notes:**
- Signatures older than 5 minutes are rejected (replay attack protection)
- Use HTTPS for all API requests
- Never expose your secret key in client-side code

---

## Creating a Verification Profile

Before any verification can happen, you need a **Verification Profile**.
Profiles define the rules for a specific verification flow, such as:
- Which channel to use (`whatsapp`, `email`)
- OTP length and expiry time
- Allowed IP whitelists and Country Codes
- Captcha enforcement rules (`disabled`, `always`, `risk_based`, `after_x_attempts`)

**Best Practice:** Create separate profiles for different use cases. For example, have a `Login Profile` and a `Checkout Profile` with different security strictness.

---

## API Endpoints

### Base URL

```
https://your-domain.com/api/v1/verification
```

---

### Request Verification

Initiates a verification request and dispatches an OTP or Magic Link to the user.

**Endpoint:** `POST /api/v1/verification/request`

**Headers:**
```
X-Public-Key: vpub_your_public_key
X-Timestamp: 1719123456
X-Signature: base64_signature (optional)
```

**Request Body:**

```json
{
    "profile_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "identifier": "+1234567890",
    "channel": "whatsapp",
    "purpose": "login",
    "ip_address": "203.0.113.42",
    "user_agent": "Mozilla/5.0...",
    "captcha_token": "03AFcWeA4...",
    "silent": false
}
```

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `profile_id` | string (UUID) | Yes | Your Verification Profile UUID |
| `identifier` | string | Yes | Phone number or email address |
| `channel` | string | Yes | `whatsapp` or `email` |
| `purpose` | string | Yes | Purpose of verification (e.g., `login`, `register`, `payment`) |
| `ip_address` | string | No | Client IP address for fraud detection |
| `user_agent` | string | No | Client user agent string |
| `captcha_token` | string | No | Google reCAPTCHA token (if enabled in profile) |
| `silent` | boolean | No | If `true`, OTP message is NOT sent (for testing) |

**Response (Success):**

```json
{
    "success": true,
    "request_id": "550e8400-e29b-41d4-a716-446655440000",
    "cached": false,
    "reused": false
}
```

**Response (Cached - Skip Verification):**

```json
{
    "success": true,
    "cached": true,
    "verified": true
}
```

---

### Validate OTP Code

Validates an OTP submitted by the user.

**Endpoint:** `POST /api/v1/verification/verify`

**Request Body:**

```json
{
    "request_id": "550e8400-e29b-41d4-a716-446655440000",
    "code": "123456"
}
```

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `request_id` | string (UUID) | Yes | The request ID from the `/request` endpoint |
| `code` | string | Yes | The OTP code entered by the user |

**Response (Success):**

```json
{
    "verified": true
}
```

**Response (Failed):**

```json
{
    "verified": false
}
```

**Response (Error - e.g., expired, blocked):**

```json
{
    "error": "Maximum verification attempts reached. Try again in 30 minute(s)."
}
```

---

### Check Verification Status

Retrieves the current status of a verification request.

**Endpoint:** `GET /api/v1/verification/status/{request_id}`

**Response:**

```json
{
    "status": "verified",
    "trust_key": "trust_abc123...",
    "identifier": "+1234567890",
    "channel": "whatsapp",
    "verified_at": "2026-06-23T10:30:00Z"
}
```

Possible statuses: `pending`, `verified`, `expired`, `failed`, `blocked`, `rate_limited`

---

### Resend OTP

Initiates a resend of the OTP (if the original hasn't expired).

**Endpoint:** `POST /api/v1/verification/resend`

**Request Body:**

```json
{
    "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

**Response:**

```json
{
    "success": true,
    "message": "Resend initiated"
}
```

---

### Magic Link Verification (Public)

Opens the user's browser when they click a magic link from the verification message.

**Endpoint:** `GET /api/v1/verification/magic/{request_id}/{token}`

**Rate Limit:** 10 requests per minute per IP

**Response (Success):**
HTML page indicating successful verification.

**Response (Failed):**
HTML page indicating the link is invalid or expired.

---

## Webhook Integration

Instead of polling the API, you can configure webhooks to receive real-time notifications.

### Configuring Webhooks

1. Go to your Verification Profile settings
2. Add a webhook URL
3. Select which events to receive:
   - `verification.requested`
   - `verification.successful`
   - `verification.failed`

### Webhook Payload

```json
{
    "event": "verification.successful",
    "data": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "identifier": "+1234567890"
    },
    "timestamp": "2026-06-23T10:30:00Z"
}
```

### Webhook Headers

| Header | Description |
|--------|-------------|
| `X-Webhook-Event` | The event type (e.g., `verification.successful`) |
| `X-Webhook-Timestamp` | Unix timestamp when the webhook was sent |

### Best Practices

- Always return HTTP 200 within 10 seconds to acknowledge receipt
- Process webhooks asynchronously (queue them for processing)
- Verify webhook authenticity using the event timestamp (reject if too old)
- Implement idempotency using the `request_id`

---

## Fraud Prevention Features

The Verification Hub includes built-in fraud prevention:

### OTP Bombing Protection
Blocks an identifier after too many requests within a time window.

### IP Velocity Limiting
Limits the number of unique identifiers that can be verified from a single IP.

### Disposable Email Blocking
Prevents common disposable email domains (mailinator.com, 10minutemail.com, etc.)

### reCAPTCHA Integration
Optionally require Google reCAPTCHA verification:
- `disabled` - No captcha required
- `always` - Always required
- `risk_based` - Required based on risk score
- `after_x_attempts` - Required after failed verification attempts

### IP/Country Whitelisting
Restrict verification to specific IPs, domains, or countries.

---

## Rate Limiting

| Endpoint | Limit |
|----------|-------|
| All authenticated endpoints | 30 requests/minute |
| Magic link verification | 10 requests/minute |

Rate limit headers are included in responses:
- `X-RateLimit-Limit`: Maximum requests allowed
- `X-RateLimit-Remaining`: Remaining requests in current window
- `X-RateLimit-Reset`: Unix timestamp when the limit resets

---

## Error Codes

| HTTP Status | Error | Description |
|-------------|-------|-------------|
| 400 | Bad Request | Invalid request parameters |
| 401 | Unauthorized | Missing or invalid API key |
| 401 | Invalid signature | HMAC signature validation failed |
| 404 | Not found | Verification request not found |
| 422 | Validation failed | Request validation errors |
| 429 | Too Many Requests | Rate limit exceeded |
| 429 | OTP Bombing protection triggered | Too many requests to this identifier |
| 429 | Velocity protection triggered | Too many unique identifiers from this IP |

---

## SDKs and Libraries

Official SDKs are available for:
- PHP (Laravel)
- JavaScript/Node.js
- Python
- Ruby

Coming soon.

---

## Support

For technical support, contact:
- Email: support@your-domain.com
- Documentation: https://docs.your-domain.com/verification
