API preview. The Verath API is in development. Endpoints, fields and behaviour shown here illustrate the planned design and may change before general availability. Sandbox credentials are issued to early partners on request.
Request access
Verath is onboarding early partners. Tell us about your organisation and use case and we’ll set up a sandbox account and a partner agreement.
Store your credentials
You’ll receive four things. Keep them in a secrets manager, never in source control or client-side code.
VERATH_API_KEYIdentifies your partner account
VERATH_SIGNING_SECRETSigns requests and verifies webhooks
VERATH_HASH_KEYHashes identity numbers (versioned)
partner.crt / .keyClient certificate for mutual TLS
Hash the identity number
At the moment you verify a NIN or BVN, compute an HMAC-SHA256 of the 11-digit number using your hash key. Send only the hash. The raw number never leaves your systems.
import { createHmac } from "node:crypto";
// hashKey is issued to you by Verath (one per key version).
export function identityHash(idNumber, hashKey) {
const normalized = idNumber.replace(/\D/g, ""); // 11 digits, no spaces
return createHmac("sha256", hashKey).update(normalized).digest("hex");
}Send your first event
POST the event to /v1/events. Sign the request with a timestamp and HMAC of the body, and use your own reference as the idempotency key so retries are safe. Sending events should never block your customer flow; queue and retry in the background.
BODY='{
"id_type": "BVN",
"identity_hash": "3f9a…c21e",
"hash_key_version": 1,
"institution": { "name": "QuickLoan", "category": "digital_lender" },
"purpose": "loan_application",
"occurred_at": "2026-10-07T14:02:00+01:00",
"partner_ref": "kyc-2026-10-07-55102"
}'
TS=$(date +%s)
SIG=$(printf "%s.%s" "$TS" "$BODY" | openssl dgst -sha256 -hmac "$VERATH_SIGNING_SECRET" | cut -d' ' -f2)
curl -X POST "$VERATH_BASE_URL/v1/events" \
--cert partner.crt --key partner.key \
-H "Authorization: Bearer $VERATH_API_KEY" \
-H "Verath-Signature: t=$TS,v1=$SIG" \
-H "Idempotency-Key: kyc-2026-10-07-55102" \
-H "Content-Type: application/json" \
-d "$BODY"| purpose | When to use |
|---|---|
| kyc_check | Routine identity verification |
| account_opening | A new account is being opened |
| loan_application | Loan or credit application |
| credit_inquiry | Credit bureau inquiry |
| sim_registration | SIM registration or NIN-SIM link |
| account_update | Change to an existing account |
| other | Anything else (describe in purpose_detail) |
Handle webhooks
Register an HTTPS endpoint for owner responses. Always verify the Verath-Signature header against the raw request body before acting, and respond with 2xx quickly. Process the work asynchronously.
{
"id": "whk_01J9X…",
"type": "dispute.created",
"created_at": "2026-10-07T14:03:11+01:00",
"data": {
"event_id": "evt_8f21c0a9",
"partner_ref": "kyc-2026-10-07-55102",
"id_type": "BVN",
"purpose": "loan_application",
"owner_response": "not_me",
"dispute_id": "dsp_4c7e19"
}
}import { createHmac, timingSafeEqual } from "node:crypto";
// Verify a Verath webhook before trusting it.
export function verifyVerathWebhook(rawBody, header, secret, toleranceSec = 300) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false; // replay protection
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest();
const given = Buffer.from(parts.v1 ?? "", "hex");
return given.length === expected.length && timingSafeEqual(given, expected);
}Test and go live
Use the browser sandbox to see the full flow, then send test events from your sandbox account. When you’re ready, we’ll review your integration together and issue production credentials.
- Events are sent for every NIN/BVN verification, including failures you choose to report
- Retries use exponential backoff and the same partner_ref
- Webhook signatures and timestamps are verified
- Your fraud team knows how to act on dispute.created
