Phone numbers
Safaricom mobile number checks: who a number is registered to, recent SIM swaps and how long a number has been on the network. Numbers on other networks can't be checked.
Checks with Safaricom whether a Safaricom mobile number is registered to the holder of the given ID. Safaricom answers only yes or no (matched); no subscriber details are returned. Numbers on other networks, or ported away from Safaricom, can't be checked.
Price: set by your bundle; one charge per call. "Not found" answers (result.found: false) are charged. Source failures return 502 and are refunded.
Try it: choose a scenario from the example menu under the code sample and press Test Request. Paste your test key into Authentication in the window that opens (it is remembered); test keys return sandbox sample data, free.
ApiKeyAuthorizationBearer <token>Your API key. sk_test_… keys use the sandbox (sample data, free); sk_live_… keys query the real sources and are charged.
Idempotency-Key?stringMakes retries safe: a repeat with the same key and body returns the original verification without charging again. Up to 255 characters.
length <= 255application/json- body
phoneNumber*stringSafaricom mobile number, in any common form: 0712345678, 254712345678 or +254 712 345 678.
idType?stringKind of document idNumber belongs to.
"NATIONAL_ID""NATIONAL_ID""MILITARY_ID""PASSPORT"idNumber*stringThe ID the number should be registered to.
^[A-Z0-9]{4,20}$Verification completed; see result.
application/json- response
One verification. Returned by every verification API, by GET /v1/verifications/{id}, and in webhooks.
id*stringUnique id; use it to fetch the verification again.
api*stringThe verification API that was called, e.g. identity.national-id.
status*stringCOMPLETED includes "not found" answers; FAILED means the source failed and the charge was refunded.
"PENDING""COMPLETED""FAILED"environment*stringTEST for test keys (sandbox data), LIVE for live keys.
"LIVE""TEST"result*|The answer, specific to each API (see its examples). Always has found: false when the source holds no record.
error*|Set when status is FAILED.
cost*stringAmount charged in KES, as a decimal string. "0" for test keys and failed verifications.
latencyMs?|Time the source took to answer, in milliseconds.
createdAt*stringdate-timecompletedAt?|date-timecurl -X POST 'https://restapi.nilinde.com/v1/verifications/phone.ownership' \ -H 'Idempotency-Key: 6f1c2a90-order-1042' \ -H 'Content-Type: application/json' \ -d '{ "phoneNumber": "0712345678", "idNumber": "12345678"}'{ "id": "cmhd2k7q80001s60h3x9f2a1b", "api": "phone.ownership", "status": "COMPLETED", "environment": "LIVE", "result": { "found": true, "phoneNumberEndsWith": "678", "idType": "NATIONAL_ID", "matched": true }, "error": null, "cost": "50", "latencyMs": 412, "createdAt": "2026-10-30T09:15:02.118Z", "completedAt": "2026-10-30T09:15:02.530Z"}When the SIM behind a Safaricom number was last swapped. Safaricom only looks back about three months: lastSwapDate is null when there was no swap in that window. daysSinceSwap helps flag recent swaps, a common sign of account takeover.
Price: set by your bundle; one charge per call. "Not found" answers (result.found: false) are charged. Source failures return 502 and are refunded.
Try it: choose a scenario from the example menu under the code sample and press Test Request. Paste your test key into Authentication in the window that opens (it is remembered); test keys return sandbox sample data, free.
ApiKeyAuthorizationBearer <token>Your API key. sk_test_… keys use the sandbox (sample data, free); sk_live_… keys query the real sources and are charged.
Idempotency-Key?stringMakes retries safe: a repeat with the same key and body returns the original verification without charging again. Up to 255 characters.
length <= 255application/json- body
phoneNumber*stringSafaricom mobile number, in any common form: 0712345678, 254712345678 or +254 712 345 678.
Verification completed; see result.
application/json- response
One verification. Returned by every verification API, by GET /v1/verifications/{id}, and in webhooks.
id*stringUnique id; use it to fetch the verification again.
api*stringThe verification API that was called, e.g. identity.national-id.
status*stringCOMPLETED includes "not found" answers; FAILED means the source failed and the charge was refunded.
"PENDING""COMPLETED""FAILED"environment*stringTEST for test keys (sandbox data), LIVE for live keys.
"LIVE""TEST"result*|The answer, specific to each API (see its examples). Always has found: false when the source holds no record.
error*|Set when status is FAILED.
cost*stringAmount charged in KES, as a decimal string. "0" for test keys and failed verifications.
latencyMs?|Time the source took to answer, in milliseconds.
createdAt*stringdate-timecompletedAt?|date-timecurl -X POST 'https://restapi.nilinde.com/v1/verifications/phone.sim-swap' \ -H 'Idempotency-Key: 6f1c2a90-order-1042' \ -H 'Content-Type: application/json' \ -d '{ "phoneNumber": "0712345678"}'{ "id": "cmhd2k7q80001s60h3x9f2a1b", "api": "phone.sim-swap", "status": "COMPLETED", "environment": "LIVE", "result": { "found": true, "phoneNumberEndsWith": "678", "lastSwapDate": "2026-10-21", "daysSinceSwap": 12 }, "error": null, "cost": "50", "latencyMs": 412, "createdAt": "2026-10-30T09:15:02.118Z", "completedAt": "2026-10-30T09:15:02.530Z"}When a Safaricom number was registered on the network. Safaricom only looks back so far: registeredOn is null (olderThanLookback: true) for numbers registered before that. A very new number is a common fraud signal.
Price: set by your bundle; one charge per call. "Not found" answers (result.found: false) are charged. Source failures return 502 and are refunded.
Try it: choose a scenario from the example menu under the code sample and press Test Request. Paste your test key into Authentication in the window that opens (it is remembered); test keys return sandbox sample data, free.
ApiKeyAuthorizationBearer <token>Your API key. sk_test_… keys use the sandbox (sample data, free); sk_live_… keys query the real sources and are charged.
Idempotency-Key?stringMakes retries safe: a repeat with the same key and body returns the original verification without charging again. Up to 255 characters.
length <= 255application/json- body
phoneNumber*stringSafaricom mobile number, in any common form: 0712345678, 254712345678 or +254 712 345 678.
Verification completed; see result.
application/json- response
One verification. Returned by every verification API, by GET /v1/verifications/{id}, and in webhooks.
id*stringUnique id; use it to fetch the verification again.
api*stringThe verification API that was called, e.g. identity.national-id.
status*stringCOMPLETED includes "not found" answers; FAILED means the source failed and the charge was refunded.
"PENDING""COMPLETED""FAILED"environment*stringTEST for test keys (sandbox data), LIVE for live keys.
"LIVE""TEST"result*|The answer, specific to each API (see its examples). Always has found: false when the source holds no record.
error*|Set when status is FAILED.
cost*stringAmount charged in KES, as a decimal string. "0" for test keys and failed verifications.
latencyMs?|Time the source took to answer, in milliseconds.
createdAt*stringdate-timecompletedAt?|date-timecurl -X POST 'https://restapi.nilinde.com/v1/verifications/phone.age-on-network' \ -H 'Idempotency-Key: 6f1c2a90-order-1042' \ -H 'Content-Type: application/json' \ -d '{ "phoneNumber": "0712345678"}'{ "id": "cmhd2k7q80001s60h3x9f2a1b", "api": "phone.age-on-network", "status": "COMPLETED", "environment": "LIVE", "result": { "found": true, "phoneNumberEndsWith": "678", "registeredOn": "2016-08-20", "olderThanLookback": false }, "error": null, "cost": "50", "latencyMs": 412, "createdAt": "2026-10-30T09:15:02.118Z", "completedAt": "2026-10-30T09:15:02.530Z"}