Integrate AdresX
Add address verification to your bank or fintech app: call the API, send a link by SMS, or open the check inside your own app with a few lines of code.
Status: AdresX is in closed beta. The API, the SMS link and the web widget below are live today. Packaged mobile SDKs are not released yet; the table shows which are planned.
Ways to integrate
| Option | Status | Best for |
| REST API and signed webhooks | Live | Teams with a backend |
| Verification link by SMS | Live | No change to your app at all |
Web widget (embed.js, v0.1.0) | Live | Web apps and in-app WebViews |
| Android SDK | Planned, next | Native Android apps |
| Flutter and React Native | Roadmap | Cross-platform apps |
| iOS SDK | Roadmap | Native iOS apps |
Embed the check in your app
- Create a verification on your serverOne API call with your key. Keep the key on your server, never in the app. The response holds a one-time link.
- Open the link with the widgetPass that link to
AdresX.verify. The customer confirms their location inside your app and never leaves it.
- Receive the resultYour
onComplete function gets the level, score and certificate when the customer finishes. Your server can also read it later, or receive a signed webhook.
On your server:
curl -X POST https://adresx.org/v1/verifications \
-H "X-API-Key: YOUR_KEY" -H "Content-Type: application/json" \
-d '{"country":"NG","reference":"cust-1042"}'
Optional: add the customer's national postcode
If you already hold the customer's national postcode, send it as nipost_code in the same call. Any common style is accepted: la 11 w06 tc 10 is returned as LA-11-W06-TC-10. A value that is not shaped like a postcode is refused with a 400.
{"country":"NG","reference":"cust-1042","nipost_code":"EK-01-A03-FK-01"}
The response then carries a nipost block:
{"id":"ver_...","url":"https://adresx.org/v/...","expires_at":"...","sms_queued":false,
"nipost":{"code":"EK-01-A03-FK-01","source":"NIPOST","status":"unchecked","note":"..."}}
status | Meaning |
valid | The national registry lists this postcode. |
not_found | The registry did not list it. The national rollout is still partial, so this is not proof that the code is wrong. |
unavailable | The registry could not be reached, so there is no conclusion. |
unchecked | The registry check is not switched on for this server. This is the status today. |
The registry check is being tested against NIPOST's test environment and is not live. Only the postcode is sent to NIPOST, never a name, phone number or location.
In your web app, using the url from that response:
<script src="https://adresx.org/embed.js"></script>
<script>
AdresX.verify({
url: linkFromYourServer,
onComplete: function (r) {
// r.level, r.level_name, r.score, r.cell_code, r.certificate_id
}
});
</script>
By default the check opens in a modal. Pass container: "#box" to show it inline instead, and onClose or onError to react to closing or errors. The result your code receives looks like this:
{"source":"adresx","type":"verification.completed","level":0,"level_name":"Declared",
"score":7,"cell_code":"NG 0648 4489 7502","certificate_id":null}
certificate_id is empty until a result reaches a level that issues one. Desktop browsers usually report location worse than 100 m, so results from a desktop stay at Level 0; phone GPS and the AdresX app can reach higher levels.
Identity checks (optional)
Alongside the address check, a partner can ask AdresX whether an identity record exists for a BVN, a NIN or a phone number, and whether the name, date of birth and phone number it holds are consistent with that record. The answer is a set of flags. AdresX never returns a name, date of birth, phone number, address or photo, never stores the number or the details you send, and never lets an identity match change an address level.
It needs an API key with the identity scope, which is issued separately and is off by default. Every request must carry "consent": true, which states that the person agreed to the check.
NIN and phone number: one call
curl -X POST https://adresx.org/v1/identity/check \
-H "X-API-Key: YOUR_KEY" -H "Content-Type: application/json" \
-d '{"kind":"nin","number":"THE_NIN","name":"Full Name","dob":"1990-01-31","consent":true,"reference":"cust-1042"}'
{"check_id":"idc_...","kind":"nin","status":"found","provider":"mono",
"name_match":"full","dob_match":true,"phone_match":null,"checked_at":"...","note":"..."}
kind is nin or phone. The optional name, dob and phone are compared with the record.
BVN: three calls, with the person's one-time code
- StartPOST /v1/identity/check with kind bvn and the number. The reply carries a session and the channels a code can go to (phone, phone_1 or email), never the contact details themselves.
- Send the codePOST /v1/identity/check/SESSION/otp with the channel the person chooses. The national consent service sends them a one-time code.
- ConfirmPOST /v1/identity/check/SESSION/confirm with the code, plus the name, dob and phone you want compared. The reply carries the flags only.
A code can only go to a channel registered on the BVN, so that the code is the person's own consent. A session lasts ten minutes, belongs to the key that started it, allows three code requests and three attempts, and can be used once.
What comes back
status | Meaning |
found | A record exists. The flags say whether the details you sent matched it. |
not_found | The provider says there is no such record. |
unavailable | No conclusion: a provider problem, a missing balance or a rejected credential. It is never read as not found. |
otp_required, otp_sent | BVN steps one and two: the person must give you the code they received. |
otp_invalid | The code was not accepted. The person can try again, up to three times. |
session_expired, limit | Start again. |
name_match is full, partial or none, or null when there is too little to judge (a single name part is not enough). dob_match and phone_match are true, false or null when you did not send the detail or the record has none.
For phone numbers, a match shows only that a record exists for the number. Some registry records carry placeholder numbers, so rely on the name and date of birth flags. Each key has a per-minute limit and a daily limit on checks, set by agreement. Contact us to enable identity checks for a key.
Native apps
Today: open the link in a WebView
The verification page already reports its result to a native app. On Android, expose a JavaScript interface named AdresXBridge with an onResult(String) method. On iOS, add a script message handler named adresx. This is built into the page but is not yet packaged or tested as an SDK.
Next: packaged SDKs
The Android SDK comes first, then Flutter and React Native wrappers, then iOS. Each will wrap the same flow, so a bank's integration code stays small. Tell us which you need first.
Security and limits
Approved sites only
Only websites on an approved list can embed the check, so another site cannot frame it. Send us your site's origin, for example https://app.yourbank.com, and we add it. Native apps are not affected by this list.
Limits per link
Each link caps capture attempts, check-ins and total uses, so a stray link cannot be abused. A new link is one API call. Webhooks are signed so you can check they came from us.
Start a pilot
Write to enterprise@agxii.org.ng, or see all contact details. Access keys are issued under an agreement, and our terms of service apply. See also address verification for banks and how it works.