Testing with fixture NINs
RandaVerify runs a single production environment at https://api.randaverify.com/v1. Customers integrate and test against the same endpoints they’ll use in live traffic — there is no separate staging URL.
What makes safe integration testing possible is fixture NINs: a small reserved set of 11-digit values that short-circuit upstream NIMC. They return deterministic mock records (or a deterministic 404), do not consume a wallet unit, do not require an active subscription, and do not store anything against your billable usage. Same code path, same response shape, same error semantics — just no real NIMC call and no charge.
Fixture catalogue
Section titled “Fixture catalogue”| NIN | Scenario | What it tests |
|---|---|---|
12345678901 | Happy path — full bio | Your UI binds every field correctly; your success branch debits the right amount of units in your local mirror; your slip render fills every cell. |
12345678902 | Sparse bio — name + DOB + gender only | Your UI handles missing phone, missing address, missing image, missing maiden name gracefully. (Common in production for older NIN registrations.) |
99999999999 | Not found — HTTP 404 | Your error handling for invalid / non-existent NINs. Returns the same 404 NIN not found shape NIMC sends in production. |
Happy path
Section titled “Happy path”curl -X POST https://api.randaverify.com/v1/verify-nin \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"nin": "12345678901", "reason": "corporate"}'Expected response:
{ "data": { "transaction_id": "430000000000000000001", "nin": "12345678901", "fname": "SUMAILA", "mname": "MEMUNAT", "lname": "AKOWE", "dob": "19 AUG 1989", "gender": "F", "phone": "08012345678", "residenceAdress": "123 SAMPLE STREET", "residenceTown": "LAGOS", "residenceState": "LAGOS", "stateOfOrigin": "KOGI", "lgaOfOrigin": "ANKPA", "image": "<base64 JPEG — small grey placeholder; decodes cleanly>" }}The image field returns a valid base64-encoded JPEG (a “FIXTURE NIN” placeholder, not a real photo) so your decode + slip-rendering code can be exercised end-to-end. The transaction_id is stable per fixture, so a CI smoke test can pin it.
Sparse-bio path
Section titled “Sparse-bio path”curl -X POST https://api.randaverify.com/v1/verify-nin \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"nin": "12345678902", "reason": "corporate"}'Expected response — note empty strings for the fields NIMC didn’t return. transaction_id is still present because NIMC always emits one regardless of how much bio is available, but image is empty (sparse-bio records often have no photo):
{ "data": { "transaction_id": "430000000000000000002", "nin": "12345678902", "fname": "ADAEZE", "mname": "", "lname": "NWOSU", "dob": "03 MAR 1995", "gender": "F", "phone": "", "residenceAdress": "", "residenceTown": "", "residenceState": "", "image": "" }}Not-found path
Section titled “Not-found path”curl -i -X POST https://api.randaverify.com/v1/verify-nin \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"nin": "99999999999", "reason": "corporate"}'Expected response:
HTTP/1.1 404 Not FoundContent-Type: application/json
{"detail": "NIN not found"}Use this fixture to confirm your portal surfaces a sensible error message to the end user rather than crashing or showing a blank slip.
Behaviour that’s identical between test mode and live mode
Section titled “Behaviour that’s identical between test mode and live mode”- Authentication flow, password rotation, and token lifetime (60 min)
- Reason validation (
/v1/nimc-reasonsreturns the same NIMC list) - Error code structure, status codes, and
detailstrings - Rate-limit thresholds and 429 responses
- Response shape — your binding code does not need a separate code path for test mode
Behaviour that differs
Section titled “Behaviour that differs”| Aspect | Live (real NIN) | Test (fixture NIN) |
|---|---|---|
| Upstream NIMC | Real NIMC call | Bypassed entirely |
| Unit debit | 1 unit deducted on 200 | 0 units deducted, ever |
| Subscription gate | Required (your org must be active) | Bypassed |
| Storage | Recorded in your org’s transaction history | Recorded with amount: 0 and a fixture: true flag in details |
Wallet units_before / units_after | Visibly decrement | Unchanged |
Wiring fixture NINs into your CI
Section titled “Wiring fixture NINs into your CI”A reasonable pattern: have a smoke-test job in your CI that hits production with a fixture NIN on every deploy of your own service. It costs you nothing and catches regressions in your integration before customers do.
# LoginTOKEN=$(curl -sS -X POST https://api.randaverify.com/v1/login \ -d "username=$RANDAVERIFY_USER&password=$RANDAVERIFY_PASS" \ | jq -r .access_token)
# Happy pathRESULT=$(curl -sS -X POST https://api.randaverify.com/v1/verify-nin \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"nin": "12345678901", "reason": "corporate"}')
echo "$RESULT" | jq -e '.data.lname == "AKOWE"' > /dev/null \ && echo "happy-path smoke passed" \ || { echo "happy-path smoke failed: $RESULT"; exit 1; }
# Not-found pathSTATUS=$(curl -sS -o /dev/null -w "%{http_code}" -X POST https://api.randaverify.com/v1/verify-nin \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"nin": "99999999999", "reason": "corporate"}')
[ "$STATUS" = "404" ] \ && echo "not-found smoke passed" \ || { echo "expected 404, got $STATUS"; exit 1; }Run as a non-blocking check or a hard deploy gate — your call.