Skip to content

Conventions

This page collects the cross-cutting rules every endpoint follows. Skim it once so the rest of the docs feel familiar.

  • Verification endpoints accept and return application/json.
  • POST /login accepts application/x-www-form-urlencoded (OAuth2 password flow). Every other endpoint is JSON.
  • Responses always include a Content-Type: application/json; charset=utf-8 header.
CodeMeaning
200The request succeeded. The body contains a data envelope for verification calls, or a top-level resource for other calls.
400Validation failed — your request body is missing a required field or contains an invalid value. The detail field names the problem.
401Token is missing, expired, or invalid. Re-authenticate.
402Insufficient units. Top up your wallet before retrying.
403Token is valid, but the user lacks permission for this action.
404The referenced resource does not exist. Most common on /verify-nin/requery with an unknown reference_id.
422Pydantic validation error — typically a malformed payload (wrong type, missing field).
429Rate-limited — slow down and retry with backoff.
5xxRandaVerify is having a bad day. Retry with exponential backoff; if it persists, contact support with your reference_id.

The error body shape is consistent:

{ "detail": "Insufficient units in organisation wallet" }

Verification responses use camelCase for NIMC-sourced fields (e.g. dateOfBirth, firstname, residenceAddressLine1) but RandaVerify normalises them to a consistent snake-friendly schema before returning. You always receive:

FieldSource aliases
ninnin, NIN, identityNumber
fnamefirstname, firstName, fname
mnamemiddlename, middleName, mname
lnamesurname, lastName, lname
dobdateOfBirth, birthdate, dob
phonetelephoneno, mobile, phone, phone1
residenceAdressresidence_AdressLine1, address (note original NIMC mis-spelling preserved)
residenceTowntown, city
residenceLgaresidence_lga, lga
residenceStatestate
stateOfOriginself_origin_state, birthState
lgaOfOriginself_origin_lga, birthLga
imagephoto, base64 JPEG

This way you do not need to know which key NIMC happened to use — RandaVerify returns the same shape every time.

Every verification produces a reference_id of the form REF-XXXXXXXXXXXX. Persist it. You can:

  • Look the record up again later with /verify-nin/requery (no unit charged).
  • Quote it to support when reporting an issue.
  • Use it as your idempotency key for retry-safe persistence on your side.
  • Phone numbers are Nigerian 11-digit format beginning with 0 (e.g. 08012345678).
  • Dates of birth are dd-mm-yyyy (e.g. 03-09-1999) on the demography request side. The dob returned in responses uses the same format.

NIMC validates every verification against a fixed list of allowed reasons. Always fetch the current list from GET /nimc-reasons and pass the key (not the human label) in your request:

Terminal window
curl https://api.randaverify.com/v1/nimc-reasons -H "Authorization: Bearer $TOKEN"
{
"data": [
{ "key": "corporate", "label": "Corporate", "description": "..." },
{ "key": "nyscCheck", "label": "NYSC Check", "description": "..." },
{ "key": "telecommunicationSimReg", "label": "Telecom SIM Reg", "description": "..." }
]
}
  • Every successful verification debits one unit from your org wallet.
  • A failed verification does not debit your wallet (you only pay for results).
  • A re-query does not debit your wallet (idempotent retrieval).
  • You can check your current balance via GET /v1/meorganisation (the unit count is available in admin contexts; for the standard officer flow, see your wallet via the portal).

The single most important rule: do not blindly retry a POST /v1/verify-nin* request on transient errors. Verification POSTs are not idempotent — every successful call mints a new transaction and debits a unit. A naive retry on a network blip will charge your wallet twice.

The right pattern:

OutcomeDid a unit get charged?What to do
HTTP 2xx received with a reference_idYesYou’re done. Persist the reference_id. To “retry” (e.g. user pressed back and re-submitted), use POST /v1/verify-nin/requery with the same reference — it’s free and idempotent.
HTTP 4xx (validation, 402, 403, 404)NoThe request never reached NIMC. Fix the client input and retry safely.
HTTP 5xx or network failure / timeoutMaybe — the request may or may not have completed upstreamDo not retry blindly. Wait 30 seconds, then call /v1/verify-nin/requery with the reference you would have used. If your client never saw a reference, you can also list your recent transactions in the admin portal to confirm whether a charge landed.

Re-queries (POST /v1/verify-nin/requery) and reads (GET /v1/me, GET /v1/nimc-reasons) are idempotent and safe to retry freely.

The RandaVerify API is meant to be called server-to-server, not directly from a customer’s browser. The CORS allow-list on api.randaverify.com is locked to the official RandaVerify domains; any Origin header from partner.com.ng (or any other domain) will be rejected by the preflight.

In practice:

  • ✅ Your backend code (Node, Python, Go, PHP, whatever) calls our API directly. Bearer tokens stay server-side.
  • ❌ Your frontend JavaScript should not call api.randaverify.com directly. CORS will block it, and even if it didn’t, you would be leaking your bearer token to every visitor’s browser.
  • The right pattern: your frontend calls your backend, your backend calls ours. This also lets you cache, rate-limit, log, and apply your own business rules between the two.

If your customer-facing UI needs to surface verification results, fetch them on your backend, store the reference_id, and re-query from your backend later if the user revisits.