Search by

uverify / uverify-php

elasto

Official PHP library for the Bytid API (formerly UVerify): BVN, NIN and ID checks, liveness, face match, ID documents and AML screening for Nigeria.

v0.2.2 2026-10-12 18:50 UTC

This package is auto-updated.

Last update: 2026-10-12 18:59:37 UTC


README

Bytid was called UVerify (and, briefly, ByteID). Package names are unchanged, and UVerify and ByteID still work as aliases of Bytid.

The official PHP library for Bytid: BVN, NIN, driver’s licence and voter’s card checks, liveness and face match, ID documents, AML screening and CAC, for Nigerian businesses.

composer require uverify/uverify-php

PHP 8.1 or later, with the standard curl and json extensions. No other dependencies.

Quick start

$bytid = new \UVerify\Bytid('uvk_test_...'); // or set BYTID_API_KEY; uvk_test_ is the free sandbox

$v = $bytid->identity->nin(['id_number' => '12345678901', 'first_name' => 'Adaeze', 'last_name' => 'Okafor']);
if ($v['status'] === 'verified') {
    print_r($v['data']);
}

In the sandbox the last two digits of the ID number choose the result: 00 not found, 99 registry error, 98 face mismatch, anything else verified.

A live customer, end to end

$session = $bytid->liveness->createSession(['redirect_url' => 'https://yourapp.com/kyc/done']);
// send the person to $session['url']; when they come back:
$v = $bytid->identity->bvnFaceMatch([
    'id_number' => '22212345678', 'first_name' => 'Adaeze', 'last_name' => 'Okafor',
    'liveness_session_id' => $session['id'],
    'aml_screening' => true,
]);

Everything else

$bytid->identity->bvn([...]);                 // also driversLicense, votersCard, tin, and the *FaceMatch variants
$bytid->business->cac(['id_number' => 'RC123456', 'aml_screening' => true]);
$bytid->documents->verify(['front_image' => new \SplFileInfo('nin.jpg'), 'document_type' => 'nin_card']);
$bytid->aml->screen(['name' => 'Adaeze Okafor', 'date_of_birth' => '1990-01-15']);
$bytid->aml->monitors->create(['name' => 'Adaeze Okafor']);
$bytid->address->verify(['address' => '12 Admiralty Way, Lekki Phase 1', 'lga' => 'Eti-Osa', 'state' => 'Lagos']);
$home = $bytid->address->createLink(['address' => '12 Admiralty Way', 'state' => 'Lagos', 'customer_name' => 'Ada']); // send $home['url']
$bytid->address->verifyDocument(['front_image' => Bytid::imageFile('bill.jpg'), 'address' => '12 Admiralty Way', 'state' => 'Lagos', 'name' => 'Adaeze Okafor']);
$link = $bytid->kyc->createLink(['customer_name' => 'Ada', 'require_document' => true]); // send $link['url']
$bytid->verifications->list(['status' => 'verified']);
$bytid->account->balance();

Image fields take base64, or a \SplFileInfo for a file (Bytid::imageFile($path) also gives base64).

Errors

try {
    $bytid->identity->nin(['id_number' => $id]);
} catch (\UVerify\UVerifyError $e) {
    if ($e->errorCode === 'insufficient_balance') { /* top up */ }
    echo $e->errorCode, $e->getMessage(), $e->requestId;
}

A check that finds nothing isn’t an error: it returns status => 'not_found'.

Retries

Timeouts, connection errors, 5xx and rate limits are retried twice with backoff (['max_retries' => 2, 'timeout' => 60]). Every check carries a reference, so a retry never charges twice.

Webhooks

try {
    $event = \UVerify\Webhook::constructEvent(file_get_contents('php://input'), $_SERVER['HTTP_UVERIFY_SIGNATURE'] ?? null, getenv('UVERIFY_WEBHOOK_SECRET'));
} catch (\UVerify\UVerifySignatureError $e) {
    http_response_code(400);
    exit;
}
if ($event['type'] === 'verification.completed') { /* ... */ }

Deliveries can repeat: dedupe on $event['id'].

MIT licence. API reference: https://www.bytid.com/docs