Skip to content
VerathYour digital identity. Reimagined.

Developers · API Resources

API reference

A small REST API over HTTPS with JSON bodies, mutual TLS and signed requests. Base URLs are issued with your sandbox credentials.

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.

Authentication

Every request must carry all three of the following. Requests failing any check are rejected with 401.

Mutual TLS

Present the client certificate issued to your partner account.

Authorization

Bearer token: your VERATH_API_KEY.

Verath-Signature

t=<unix seconds>,v1=<hex HMAC-SHA256 of “t.body” with your signing secret>

Endpoints

POST/v1/eventsPreview

Report an identity check

Send one signed event each time you verify or use a NIN or BVN. The response never reveals whether the identity is enrolled with Verath. Duplicate partner_ref values are de-duplicated.

request body
{
  "id_type": "NIN" | "BVN",
  "identity_hash": "<hex HMAC-SHA256>",
  "hash_key_version": 1,
  "institution": { "name": "string", "category": "bank | fintech | digital_lender | telco | other" },
  "purpose": "kyc_check | account_opening | loan_application | …",
  "purpose_detail": "optional string",
  "occurred_at": "ISO 8601 timestamp",
  "partner_ref": "your unique reference"
}
response
202 Accepted
{ "event_id": "evt_8f21c0a9", "status": "accepted" }
POST/v1/events/batchPreview

Import historical checks

Upload up to 1,000 past events per request so newly enrolled owners can see their history.

request body
{ "events": [ { …event }, { …event } ] }
response
202 Accepted
{ "accepted": 998, "rejected": [ { "index": 4, "error": "invalid_purpose" } ] }
GET/v1/events/{event_id}Preview

Get event status

Retrieve an event you reported and any owner response linked to it.

response
200 OK
{
  "event_id": "evt_8f21c0a9",
  "partner_ref": "kyc-2026-10-07-55102",
  "owner_response": "not_me" | "confirmed" | null,
  "dispute_id": "dsp_4c7e19",
  "dispute_status": "sent" | "acknowledged" | "investigating" | … | null
}
PATCH/v1/disputes/{dispute_id}Preview

Update a dispute

Tell the owner how their “Not me” report is progressing. Only disputes on events you reported can be updated.

request body
{ "status": "acknowledged | investigating | account_closed | resolved | rejected", "case_ref": "optional", "note": "optional" }
response
200 OK
{ "dispute_id": "dsp_4c7e19", "status": "account_closed" }
POST/v1/lock-checksPlanned

Check identity lock

Ask whether an identity is locked before opening an account. Designed to fail open: if Verath is unavailable, proceed with your normal controls and flag the account.

request body
{ "id_type": "BVN", "identity_hash": "…", "hash_key_version": 1, "purpose": "account_opening" }
response
200 OK
{ "locked": true, "action": "require_owner_approval", "check_id": "lck_2b81" }

Webhooks

Verath POSTs JSON to the HTTPS endpoint you register, signed with the same Verath-Signature scheme. Respond 2xx within 10 seconds; failed deliveries are retried with backoff.

EventStatus
dispute.created

The owner tapped “Not me” on an event you reported.

Preview
event.confirmed

The owner confirmed an event (“This was me”).

Preview
dispute.updated

A dispute’s status changed.

Planned
lock.approval_granted

The owner approved a one-time unlock for your institution.

Planned
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);
}

Errors

Errors return JSON: { "error": { "code": "…", "message": "…" } }

HTTPCode
400invalid_payload

A field is missing or malformed.

401invalid_signature

Signature, timestamp or certificate could not be verified.

403key_version_retired

The hash_key_version has been rotated out.

409duplicate_event

An event with this partner_ref was already accepted.

429rate_limited

Too many requests. Retry with exponential backoff.

5xxserver_error

Retry with backoff. Events are idempotent by partner_ref.

Rate limits & retries

  • Limits are set per partner and shared with your credentials. Exceeding them returns 429 with a Retry-After header.
  • Retry 429 and 5xx responses with exponential backoff and jitter, reusing the same partner_ref.
  • Never block a customer journey on a Verath call. Queue events and send them asynchronously.
  • Hash keys are versioned. During rotation, send the new hash_key_version as soon as you receive it.