# Verify a business address Source: https://docs.dojah.io/api-reference/address-verification/business-address Submit and retrieve a Nigerian business address verification — an async POST that returns a reference_id you poll for the result.
POST /api/v1/kyc/address/business
Submit a business name, its contact and the owner’s details for physical verification of the company address in Nigeria. Like the individual check, it’s asynchronous — submit returns a reference\_id you poll for the result. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | ----------------- | ------ | -------- | --------------------------------------------- | | `business_name` | string | Yes | Name of the business. | | `business_mobile` | string | Yes | Office mobile number of the business. | | `first_name` | string | Yes | First name of the business owner. | | `last_name` | string | Yes | Last name of the business owner. | | `mobile` | string | Yes | Mobile number of the business owner. | | `street` | string | Yes | House number and street name of the business. | | `landmark` | string | No | Closest landmark to the location. | | `lga` | string | Yes | Local Government Area. | | `city` | string | Yes | City. | | `state` | string | Yes | State. | ## Response The submit call returns an `entity` with `status: "pending"` and a `reference_id`. Keep the `reference_id` to retrieve the result. ## Fetch verification results Business submissions are polled the same way as individual ones — call `GET /api/v1/kyc/address` with the `reference_id` returned above. The result `entity` carries the same shape (applicant/contact, captured `location` and `photos`, a neighbour reference and agent `comments`); see [Individual Address → Fetch verification results](/api-reference/address-verification/individual-address#fetch-verification-results) for the full response. ```http GET /api/v1/kyc/address theme={null} curl "https://api.dojah.io/api/v1/kyc/address?reference_id=69e10264-4b90-64fe-b4b7-c9dddafd0241" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required field is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/kyc/address/business" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "business_name": "Acme Stores Ltd", "business_mobile": "08011112222", "first_name": "John", "last_name": "Musa", "mobile": "08012345678", "street": "270 Murtala Muhammed Way, Yaba", "lga": "Lagos Mainland", "city": "Lagos", "state": "Lagos" }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/kyc/address/business", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ business_name: "Acme Stores Ltd", business_mobile: "08011112222", first_name: "John", last_name: "Musa", mobile: "08012345678", street: "270 Murtala Muhammed Way, Yaba", lga: "Lagos Mainland", city: "Lagos", state: "Lagos" }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/kyc/address/business", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={ "business_name": "Acme Stores Ltd", "business_mobile": "08011112222", "first_name": "John", "last_name": "Musa", "mobile": "08012345678", "street": "270 Murtala Muhammed Way, Yaba", "lga": "Lagos Mainland", "city": "Lagos", "state": "Lagos" }, ) data = res.json() ``` ```json POST /api/v1/kyc/address/business theme={null} { "entity": { "status": "pending", "reference_id": "69e10264-4b90-64fe-b4b7-c9dddafd0241" } } ``` # Fetch address verification data Source: https://docs.dojah.io/api-reference/address-verification/fetch-address-verification-data Fetch the result of a submitted address verification using its reference ID.
GET /api/v1/kyc/address
Address verifications run asynchronously — after submitting one you receive a reference\_id. Use this endpoint to fetch the verification’s status and collected data by that reference. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | -------------- | ------ | -------- | -------------------------------------------------------------------------- | | `reference_id` | string | Yes | The unique reference returned when the address verification was submitted. | ## Response Returns an `entity` with the verification `status`, the `reference_id`, and a `data` object holding the applicant, location, neighbour and address details collected. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/kyc/address?reference_id=69e10264-4b90-64fe-b4b7-c9dddafd0241" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "reference_id": "69e10264-4b90-64fe-b4b7-c9dddafd0241", }); const url = "https://api.dojah.io/api/v1/kyc/address?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/kyc/address", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "reference_id": "69e10264-4b90-64fe-b4b7-c9dddafd0241" }, ) data = res.json() ``` ```json GET /api/v1/kyc/address theme={null} { "entity": { "status": "pending", "reference_id": "69e10264-4b90-64fe-b4b7-c9dddafd0241", "data": { "applicant": { "first_name": "John", "last_name": "Musa", "phone": "08012345678", "middle_name": "Doe", "photo": "", "gender": "Male", "dob": "17/01/1988" }, "location": "7.081273, 8.232523", "photos": [""], "neighbor": { "name": "Musa Garba", "comment": "Very friendly", "phone": "080987654321" }, "city": "oshodi", "street": "270 Murtala Muhammed Way, Alagomeji. Yaba", "lga": "lagos mainland", "state": "Lagos", "country": "Nigeria", "comments": "" } } } ``` # Verify an individual's address Source: https://docs.dojah.io/api-reference/address-verification/individual-address Submit and retrieve a Nigerian individual address verification — an async POST that returns a reference_id you poll for the agent-visited result.
POST /api/v1/kyc/address
Submit a person’s name, phone and address for physical verification in Nigeria. The call is asynchronous — it returns a reference\_id you poll to collect the result once an agent has visited the address. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | ------------- | ------ | -------- | --------------------------------------- | | `first_name` | string | Yes | First name of the individual. | | `last_name` | string | Yes | Last name of the individual. | | `middle_name` | string | No | Middle name of the individual. | | `dob` | string | No | Date of birth, `yyyy-mm-dd`. | | `gender` | string | No | Gender of the individual. | | `mobile` | string | Yes | Active mobile number of the individual. | | `street` | string | Yes | House number and street name. | | `landmark` | string | No | Closest landmark to the street. | | `lga` | string | Yes | Local Government Area. | | `state` | string | Yes | State. | ## Response The submit call returns an `entity` with `status: "pending"` and a `reference_id`. Store the `reference_id` — it’s how you retrieve the result. ## Fetch verification results Poll `GET /api/v1/kyc/address` with the `reference_id` from the submit call. While the visit is outstanding the `status` stays `pending`; once complete, `data` carries the applicant details, captured location and photos, a neighbour reference and any agent comments. | Query | Type | Required | Description | | -------------- | ------ | -------- | ----------------------------------------------- | | `reference_id` | string | Yes | The `reference_id` returned by the submit call. | ```http GET /api/v1/kyc/address theme={null} curl "https://api.dojah.io/api/v1/kyc/address?reference_id=69e10264-4b90-64fe-b4b7-c9dddafd0241" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```json 200 — result ready theme={null} { "entity": { "status": "pending", "reference_id": "69e10264-4b90-64fe-b4b7-c9dddafd0241", "data": { "applicant": { "first_name": "John", "last_name": "Musa", "middle_name": "Doe", "phone": "08012345678", "gender": "Male", "dob": "17/01/1988", "photo": "" }, "location": "7.081273, 8.232523", "photos": [""], "neighbor": { "name": "Musa Garba", "comment": "Very friendly", "phone": "080987654321" }, "street": "270 Murtala Muhammed Way, Alagomeji. Yaba", "city": "oshodi", "lga": "lagos mainland", "state": "Lagos", "country": "Nigeria", "comments": "" } } } ``` ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required field is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/kyc/address" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "first_name": "John", "last_name": "Musa", "mobile": "08012345678", "street": "270 Murtala Muhammed Way, Yaba", "lga": "Lagos Mainland", "state": "Lagos" }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/kyc/address", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ first_name: "John", last_name: "Musa", mobile: "08012345678", street: "270 Murtala Muhammed Way, Yaba", lga: "Lagos Mainland", state: "Lagos" }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/kyc/address", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={ "first_name": "John", "last_name": "Musa", "mobile": "08012345678", "street": "270 Murtala Muhammed Way, Yaba", "lga": "Lagos Mainland", "state": "Lagos" }, ) data = res.json() ``` ```json POST /api/v1/kyc/address theme={null} { "entity": { "status": "pending", "reference_id": "69e10264-4b90-64fe-b4b7-c9dddafd0241" } } ``` # Location reverse geocoding Source: https://docs.dojah.io/api-reference/address-verification/location-reverse-geocoding Convert a latitude and longitude coordinate into a structured street address.
GET /api/v1/kyc/address/reverse\_geocode
Turn a GPS coordinate into a structured, human-readable address — street, locality, administrative areas, postal code and country — plus a formatted address string. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | ----------- | ------ | -------- | ------------------------------ | | `latitude` | string | Yes | The latitude of the location. | | `longitude` | string | Yes | The longitude of the location. | ## Response Returns an `entity` with an `address_components` object (street, locality, administrative areas, postal code, country, neighbourhood) and a `formatted_address` string. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/kyc/address/reverse_geocode?latitude=37.7749&longitude=-122.4194" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "latitude": "37.7749", "longitude": "-122.4194", }); const url = "https://api.dojah.io/api/v1/kyc/address/reverse_geocode?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/kyc/address/reverse_geocode", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "latitude": "37.7749", "longitude": "-122.4194", }, ) data = res.json() ``` ```json GET /api/v1/kyc/address/reverse_geocode theme={null} { "entity": { "address_components": { "plus_code": "", "premise": "", "street_number": "2647", "route": "21st Street", "locality": "San Francisco", "postal_town": "", "administrative_area_level_2": "San Francisco County", "administrative_area_level_1": "California", "country": "United States", "postal_code": "94110", "neighborhood": "Mission District" }, "formatted_address": "2647 21st St, San Francisco, CA 94110, USA" } } ``` # Buy Airtime Source: https://docs.dojah.io/api-reference/airtime-data/buy-airtime Send airtime to any mobile number across all major networks in a single Dojah API call.
POST /api/v1/purchase/airtime
Send airtime to any mobile number across all major networks in a single API call. The cost is charged to your Dojah wallet. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | ------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------ | | `amount` | number | Yes | The amount of airtime to send. | | `destination` | array | Yes | The number(s) to receive the airtime, e.g. `2348012345678`. Pass an array to top up several numbers at once. | ## Response Returns an `entity` describing the airtime purchase — its `status`, the `mobile` number topped up, and the `amount` sent (with currency). ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required field is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/purchase/airtime" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "amount": 200, "destination": ["2348012345678"] }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/purchase/airtime", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ amount: 200, destination: ["2348012345678"], }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/purchase/airtime", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={ "amount": 200, "destination": ["2348012345678"], }, ) data = res.json() ``` ```json POST /api/v1/purchase/airtime theme={null} { "entity": { "status": "Sent", "mobile": "+2348102152847", "amount": "NGN 200.0000" } } ``` # Buy Data Source: https://docs.dojah.io/api-reference/airtime-data/buy-data Purchase a mobile data bundle for any number using a plan code from the Data Plans endpoint.
POST /api/v1/purchase/data
Purchase a mobile data bundle for any number. Pick a bundle with its plan code from the Data Plans endpoint, then pass that code here. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | ------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------ | | `plan` | string | Yes | The bundle's plan code, e.g. `9MOBILE_1.5GB`. Get valid codes from [Data Plans](/api-reference/airtime-data/data-plans). | | `destination` | number | Yes | The mobile number to receive the data, e.g. `2348012345678`. | ## Response Returns an `entity` with the `phone_number` credited, the `amount` charged, the `network` and bundle description, and a `reference_id` for the transaction. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required field is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/purchase/data" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "plan": "9MOBILE_1.5GB", "destination": 2348012345678 }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/purchase/data", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ plan: "9MOBILE_1.5GB", destination: 2348012345678, }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/purchase/data", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={ "plan": "9MOBILE_1.5GB", "destination": 2348012345678, }, ) data = res.json() ``` ```json POST /api/v1/purchase/data theme={null} { "entity": { "phone_number": "2348012345678", "amount": 200, "network": "MTN 200 MB DATA BUNDLE", "reference_id": "dj_e076726b-b136-4e18-b63d-3eabc77d56c1" } } ``` # Data Plans Source: https://docs.dojah.io/api-reference/airtime-data/data-plans Fetch the list of available data bundles, each with its amount, description, and plan code to buy with.
GET /api/v1/purchase/data/plans
List every data bundle you can buy — each with its amount, a human-readable description, and the plan code to pass to Buy Data. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters None — this endpoint takes no query parameters. Authenticate with your `AppId` and secret key. ## Response Returns an `entity` array. Each item is a bundle with its `amount` (in NGN), a `description`, and the `plan` code you pass to [Buy Data](/api-reference/airtime-data/buy-data). ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------- | | `400` | Bad request — a required field is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/purchase/data/plans" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/purchase/data/plans", { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/purchase/data/plans", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, ) data = res.json() ``` ```json GET /api/v1/purchase/data/plans theme={null} { "entity": [ { "amount": 1000, "description": "9MOBILE 1.5GB data bundle", "plan": "9MOBILE_1.5GB" }, { "amount": 2000, "description": "9MOBILE 4.5GB data bundle", "plan": "9MOBILE_4.5GB" } ] } ``` # AML screening Source: https://docs.dojah.io/api-reference/aml-background/aml-screening Screen an individual or organization against global PEP, sanctions, warning and adverse-media lists, and read every match in one call.
POST /api/v1/aml/v2/screening
Screen an individual or organization against global PEP, sanctions, warning and adverse-media lists — across 200+ countries and 40,000+ databases — and get back every match in one call. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | --------------------------------------- | ------- | -------- | ------------------------------------------------------------------- | | `schema` | string | Yes | What you're screening — `"individual"` or `"organization"`. | | `unique_reference` | string | No | Your own reference for the request, echoed back for reconciliation. | | `properties.names` | string | Yes | The full name to screen (e.g. `"John Doe"`). | | `properties.gender` | string | No | e.g. `"male"` — narrows the candidate set. | | `properties.date_of_birth` | string | No | `YYYY-MM-DD`. Strengthens match scoring. | | `properties.nationality` | string | No | The subject's nationality. | | `properties.id_number` | string | No | A government-issued ID number. | | `properties.registration_number` | array | No | Business registration numbers — `organization` schema only. | | `properties.country_of_incorporation` | array | No | Country codes — `organization` schema only. | | `screening_options.pep_check` | boolean | No | Screen against politically-exposed-person registries. | | `screening_options.sanction` | boolean | No | Screen against sanctions lists. | | `screening_options.adverse_media_check` | boolean | No | Screen against adverse media. | | `screening_options.watchlists` | array | No | Restrict to specific watchlists, or omit/leave empty to search all. | | `screening_options.match_threshold` | number | No | Minimum match score to return, `0`–`1` (e.g. `0.85`). | | `properties` | | No | | | `screening_options` | | No | | ## What gets screened Every result carries a `source_type` identifying which kind of list it came from: | Category | What it covers | | --------------- | ---------------------------------------------------------------------------------------------------------- | | `PEP` | Politically exposed persons — current and former office-holders and their close associates. | | `Sanctions` | Global and regional sanctions and embargo lists (OFAC, UN, EU and more). | | `Adverse Media` | Negative news — categorised (e.g. `violent_crime`, `terrorism`, `political`) with the underlying articles. | | `Warning` | Regulatory and law-enforcement warning lists. | The overall record is graded with a `risk_level` (e.g. Low / Medium / High) and a `match_status` — one of **No Match**, **Partially Matched**, **Potential Match** or **Confirmed Match**. ## Response Returns an `entity` with the `search_query`, `total_results` / `total_articles` counts, an overall `risk_level` and `match_status`, and a `results` array. Each result is either a **profile match** (`source_type` such as `"PEP"`, with names, aliases, positions, country and dates of birth, and `match: true`) or an **adverse-media group** (`source_type: "ADVERSE_MEDIA"` with a `media_category` and an `articles` array). The response opposite is trimmed for readability. ## Fetch match details An individual screen returns its matches inline. To pull the full, normalised detail for a single profile — or to retrieve results from a [business screen](/api-reference/aml-background/business-screening), which returns only lightweight candidates — call `GET /api/v2/aml/screening/info` with the `profile_id` from the screen as a query parameter. ```bash cURL theme={null} curl "https://api.dojah.io/api/v2/aml/screening/info?profile_id=57994afb-357b-4288-bc5d-9f3954d037e3" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` The result `entity.result` exposes a numeric `match_score` (`0`–`1`), an `entryCategory` (`"PEP"`, `"sanction"`, `"adverse-media"` or `"warning"`), a `watch` flag, the subject’s `aliases`, `dob` and `countryName`, and — for adverse media — a `media` array of `title` / `snippet` / `url` / `date`. Trimmed below. ```json 200 — /api/v2/aml/screening/info theme={null} { "entity": { "result": { "name": "John Doe Musa", "aliases": [ { "name": "John D. Musa" } ], "firstName": "John", "lastName": "Musa", "dob": "1985", "countryName": "Nigeria", "entryCategory": "adverse-media", "watch": false, "media": [ { "date": "2022-12-22T00:00:00Z", "title": "2022 in Review: Key Financial Crime Moments", "snippet": "… found guilty of laundering money from various online crimes …", "url": "https://complyadvantage.com/insights/…" } ], "entityType": "person", "riskLevel": "", "match_score": 0.7 } } } ``` ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required field is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/aml/v2/screening" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "schema": "individual", "unique_reference": "ref_8821", "properties": { "names": "John Doe", "date_of_birth": "1985-04-15", "nationality": "NG" }, "screening_options": { "pep_check": true, "sanction": true, "adverse_media_check": true, "match_threshold": 0.85 } }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/aml/v2/screening", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ schema: "individual", properties: { names: "John Doe", date_of_birth: "1985-04-15" }, screening_options: { pep_check: true, sanction: true, adverse_media_check: true } }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/aml/v2/screening", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={ "schema": "individual", "properties": { "names": "John Doe", "date_of_birth": "1985-04-15" }, "screening_options": { "pep_check": True, "sanction": True, "adverse_media_check": True }, }, ) data = res.json() ``` ```json POST /api/v1/aml/v2/screening theme={null} { "entity": { "entity_type": "individual", "entity_id": "123450987qwergoi", "date": "2026-01-20T10:15:10.257Z", "total_results": 47, "total_articles": 43, "search_query": "John Doe", "risk_level": "Medium", "match_status": "Confirmed Match", "results": [ { "name": [ "John Doe Adekunle" ], "entity_type": "individual", "source_type": "PEP", "date_of_birth": [ "1952-03-29" ], "gender": [ "male" ], "country": [ "ng" ], "positions": [ "Senator", "State Governor (1999-2007)" ], "match": true }, { "source_type": "ADVERSE_MEDIA", "media_category": "political", "articles": [ { "timestamp": "2025-06-01T01:27:35Z", "headline": "Opposition queries spending under President's tenure", "source": "https://example.news/article/70169100" } ] } ] } } ``` # Business AML screening Source: https://docs.dojah.io/api-reference/aml-background/business-screening Screen a business by name against sanctions, watchlists, PEP and adverse media, then fetch full match details for any candidate.
POST /api/v1/aml/screening/organization
Screen a business by name against sanctions, watchlists, PEP and adverse-media sources, then pull full match details for any candidate it returns. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | ------------- | ------- | -------- | -------------------------------------------------------------------------------------------------------- | | `entity_name` | string | Yes | The business name to screen (e.g. `"Belinda Gates Foundation"`). | | `match_score` | integer | Yes | Minimum name-match score to return, `0`–`100` (%) — controls how close a name must be to count as a hit. | ## Response Returns a `matchResults` array of candidate profiles. Each entry has a `MatchType` (e.g. `"Entity"`), the matched `Name`, a `ProfileId`, and a `NameMatchScore` (`0`–`1`). The business screen returns only these lightweight candidates — it does *not* embed the underlying sanctions, PEP or adverse-media records. ## Get full match details Take the `ProfileId` of any candidate and call `GET /api/v2/aml/screening/info` with it as the `profile_id` query parameter to retrieve the full, normalised match — `match_score`, `entryCategory`, `watch`, aliases and the supporting `media` articles. See [AML Screening → Fetch match details](/api-reference/aml-background/aml-screening#fetch-match-details) for the full response shape. ```bash cURL theme={null} curl "https://api.dojah.io/api/v2/aml/screening/info?profile_id=57994afb-357b-4288-bc5d-9f3954d037e3" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required field is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/aml/screening/organization" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "entity_name": "Belinda Gates Foundation", "match_score": 70 }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/aml/screening/organization", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ entity_name: "Belinda Gates Foundation", match_score: 70 }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/aml/screening/organization", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={ "entity_name": "Belinda Gates Foundation", "match_score": 70, }, ) data = res.json() ``` ```json POST /api/v1/aml/screening/organization theme={null} { "matchResults": [ { "MatchType": "Entity", "Name": "Gates Foundation", "ProfileId": "57994afb-357b-4288-bc5d-9f3954d037e3", "NameMatchScore": 0.2 } ] } ``` # AML screening match details Source: https://docs.dojah.io/api-reference/aml-background/screening-info-details How to read AML screening match results — the attributes on a match, its category, and how to interpret the match score.
GET /api/v2/aml/screening/info
When an AML screening returns hits, each match carries the details below. This page explains what those attributes mean and how to read the match score so you can make a compliance decision. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------------------------------------------- | | `id` | string | Yes | The reference/ID of the AML screening whose match details you want. | ## What’s in a match | Attribute | What it tells you | | ----------------------- | ------------------------------------------------------------------- | | Name & aliases | The matched entity’s primary and alternate names. | | Entity type | Whether the match is a person or an organization. | | Match score | Confidence of the match — see [the scoring guide](#scoring) below. | | Category | The AML classification — sanctions, PEP, or adverse media. | | Date of birth & country | Demographic identifiers used to confirm the match. | | Media articles | Related adverse-media references, with source and publication date. | | Risk level | Overall risk assessment for the match. | ## Match categories Every match falls into one of three types: * **Sanctions** — entities under government-enforced restrictions. * **PEPs** — Politically Exposed Persons. * **Adverse media (AM)** — negative news coverage and warnings. ## Interpreting the score Scoring prioritises sanctions over other types, exact name matches over fuzzy ones, and alignment on date of birth and country. Two scales apply, depending on the category: | Category | Score range | Meaning | | ------------------------------- | ------------- | ----------------------------------------------------------- | | Sanctions | `1.1` – `2.0` | Higher is a stronger match. | | Warnings / PEPs / Adverse media | `0.1` – `1.0` | Higher is a stronger match; `0.7` indicates an exact match. | ## Response Returns the match `entity` — its name and aliases, entity type, category (`match_types`), score, risk level, identifying fields, and any related `media`. The example on the right is representative; the live response carries the full match set. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v2/aml/screening/info?id=6e3f2a1b-9c4d-4e2f-8a1b-2c3d4e5f6a7b" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "id": "6e3f2a1b-9c4d-4e2f-8a1b-2c3d4e5f6a7b", }); const url = "https://api.dojah.io/api/v2/aml/screening/info?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v2/aml/screening/info", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "id": "6e3f2a1b-9c4d-4e2f-8a1b-2c3d4e5f6a7b" }, ) data = res.json() ``` ```json GET /api/v2/aml/screening/info theme={null} { "entity": { "id": "6e3f2a1b-9c4d-4e2f-8a1b-2c3d4e5f6a7b", "name": "John Doe", "aka": ["Johnny Doe"], "entity_type": "person", "match_types": ["sanction"], "score": 1.8, "risk_level": "high", "fields": { "date_of_birth": "1970-01-01", "country": "NG" }, "media": [ { "title": "Regulator names individuals in sanctions notice", "url": "https://example-news.com/notice", "date": "2021-05-01", "source": "Example News" } ] } } ``` # Go Source: https://docs.dojah.io/api-reference/api-clients/go Call the Dojah REST API from Go with the official Dojah client — server-side, with authentication handled for you. Call the Dojah REST API from Go with the Dojah client. This is a **server-side** client using your **secret** key (passed as `Authorization`) — never ship it in client code. For verification UI in an app, use a [Widget SDK](/api-reference/widget-sdks/choosing-an-sdk). ## Install ```bash Terminal theme={null} go get github.com/dojah-inc/dojah-sdks/go ``` ## Make a request ```go main.go theme={null} config := dojah.NewConfiguration() config.Context = context.WithValue(config.Context, dojah.ContextAPIKeys, map[string]dojah.APIKey{ "apikeyAuth": {Key: os.Getenv("DOJAH_SECRET_KEY")}, "appIdAuth": {Key: os.Getenv("DOJAH_APP_ID")}, }) client := dojah.NewAPIClient(config) result, _, err := client.AMLApi.GetScreeningInfo(context.Background()). ProfileId("WC7117469").Execute() ``` Every endpoint in the [API reference](/api-reference/get-started/introduction) is exposed on the client, grouped by API. # Java Source: https://docs.dojah.io/api-reference/api-clients/java Call the Dojah REST API from a JVM backend with the Dojah Java client — Java 8 and above, via Maven or Gradle. Call the Dojah REST API from a JVM backend with the Dojah Java client (Java 8+, Maven or Gradle). This is a **server-side** client using your **secret** key (passed as `Authorization`) — never ship it in client code. For verification UI in an app, use a [Widget SDK](/api-reference/widget-sdks/choosing-an-sdk). ## Install ```xml pom.xml theme={null} com.konfigthis.dojah dojah-java-sdk 4.1.0 ``` ## Make a request ```java Verify.java theme={null} Configuration config = new Configuration(); config.Authorization = System.getenv("DOJAH_SECRET_KEY"); config.AppId = System.getenv("DOJAH_APP_ID"); Dojah dojah = new Dojah(config); var result = dojah.aml.getScreeningInfo() .profileId("WC7117469") .execute(); ``` Every endpoint in the [API reference](/api-reference/get-started/introduction) is exposed on the client, grouped by API. # PHP Source: https://docs.dojah.io/api-reference/api-clients/php Call the Dojah REST API from PHP with the konfig/dojah-php-sdk client, which wraps authentication and every endpoint group. Call the Dojah REST API from PHP with the `konfig/dojah-php-sdk` client. It wraps authentication and every endpoint group. This is a **server-side** client using your **secret** key (passed as `Authorization`) — never ship it in client code. For verification UI in an app, use a [Widget SDK](/api-reference/widget-sdks/choosing-an-sdk). ## Install ```bash Terminal theme={null} composer require konfig/dojah-php-sdk ``` ## Make a request Initialize the client with your secret key and App ID, then call any endpoint group: ```php verify.php theme={null} $dojah = new \Dojah\Client( Authorization: getenv("DOJAH_SECRET_KEY"), AppId: getenv("DOJAH_APP_ID"), ); $result = $dojah->aML->getScreeningInfo(profile_id: "WC7117469"); ``` Every endpoint in the [API reference](/api-reference/get-started/introduction) is exposed on the client, grouped by API (e.g. `kyc`, `aML`, `kyb`). # Python Source: https://docs.dojah.io/api-reference/api-clients/python Call the Dojah REST API from Python 3.6+ with the official Dojah client, using your secret key server-side. Call the Dojah REST API from Python (3.6+) with the Dojah client. This is a **server-side** client using your **secret** key (passed as `Authorization`) — never ship it in client code. For verification UI in an app, use a [Widget SDK](/api-reference/widget-sdks/choosing-an-sdk). ## Install ```bash Terminal theme={null} pip install dojah-python-sdk ``` ## Make a request ```python verify.py theme={null} import os from dojah_client import Dojah dojah = Dojah( authorization=os.environ["DOJAH_SECRET_KEY"], app_id=os.environ["DOJAH_APP_ID"], ) result = dojah.aml.get_screening_info(profile_id="WC7117469") ``` Every endpoint in the [API reference](/api-reference/get-started/introduction) is exposed on the client, grouped by API. # TypeScript Source: https://docs.dojah.io/api-reference/api-clients/typescript Call the Dojah REST API from Node.js or TypeScript with the typed Dojah client. Call the Dojah REST API from Node.js / TypeScript with the typed Dojah client. This is a **server-side** client using your **secret** key (passed as `Authorization`) — never ship it in client code. For verification UI in an app, use a [Widget SDK](/api-reference/widget-sdks/choosing-an-sdk). ## Install ```bash Terminal theme={null} npm install dojah-typescript-sdk ``` ## Make a request ```ts verify.ts theme={null} import { Dojah } from "dojah-typescript-sdk" const dojah = new Dojah({ authorization: process.env.DOJAH_SECRET_KEY, appId: process.env.DOJAH_APP_ID, }) const result = await dojah.aml.getScreeningInfo({ profileId: "WC7117469" }) ``` Every endpoint in the [API reference](/api-reference/get-started/introduction) is exposed on the client, grouped by API. # Verify BVN or NIN with a selfie Source: https://docs.dojah.io/api-reference/biometrics-liveness/bvn-nin-selfie Match a selfie against the photo on file for a Nigerian BVN or NIN, and pull the identity record in the same call.
POST /api/v1/kyc/bvn/verify
Match a user’s selfie against the photo held for their Nigerian BVN or NIN, and retrieve the full identity record in the same call. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | -------------- | ------ | -------- | ---------------------------------------------------------------------------------- | | `bvn / nin` | string | Yes | The identifier to verify — `bvn` for the BVN endpoint, `nin` for the NIN endpoint. | | `selfie_image` | string | Yes | The selfie image, Base64-encoded (strip the `data:image/jpeg;base64,` prefix). | | `bvn` | | No | | ## Response The BVN endpoint returns the BVN identity record with a nested `selfie_verification` object (`confidence_value` and `match`). Response trimmed for readability. ## Verify NIN with a selfie Call `POST /api/v1/kyc/nin/verify` with `nin` and `selfie_image` (and optional `first_name` / `last_name`) to match a selfie against the photo on file for a NIN. It returns the NIN identity record with the same `selfie_verification` object. ```json 200 — /api/v1/kyc/nin/verify theme={null} { "entity": { "nin": "7*****83753", "firstname": "JOHN", "surname": "MUSA", "gender": "m", "birthdate": "10-06-1983", "selfie_verification": { "confidence_value": 99.81, "match": true } } } ``` ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required field is missing or the image is malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/kyc/bvn/verify" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "bvn": "22222222222", "selfie_image": "/9j/4AAQSkZJRgABAQ…" }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/kyc/bvn/verify", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ bvn: "22222222222", selfie_image: "/9j/4AAQSkZJRgABAQ…" }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/kyc/bvn/verify", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={ "bvn": "22222222222", "selfie_image": "/9j/4AAQSkZJRgABAQ…" }, ) data = res.json() ``` ```json POST /api/v1/kyc/bvn/verify theme={null} { "entity": { "bvn": "2*****41123", "first_name": "JOHN", "middle_name": "DOE", "last_name": "MUSA", "date_of_birth": "15-Apr-1985", "phone_number1": "08134720263", "gender": "Male", "image": "[base64 image data]", "selfie_verification": { "confidence_value": 99.99, "match": true } } } ``` # Liveness Check Source: https://docs.dojah.io/api-reference/biometrics-liveness/liveness-check Detect whether a selfie image is of a real, live person — and read face attributes like age range, gender, emotion, and image quality.
POST /api/v1/ml/liveness
Send a selfie image (Base64) to check whether it’s a real, live person, and get back detailed face attributes — age range, gender, emotions, and image quality. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------------------------------------------------------ | | `image` | string | Yes | The selfie image, Base64-encoded (strip any `data:image/jpeg;base64,` prefix). | ## Response Returns an `entity` with a `liveness` object — `liveness_check` (whether it passed) and `liveness_probability` — and a `face` object with detection details, attribute confidences, and image quality. The response below is trimmed for readability. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required field is missing or the image is malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/ml/liveness" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "image": "/9j/4AAQSkZJRgABAQ…" }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/ml/liveness", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ image: "/9j/4AAQSkZJRgABAQ…" }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/ml/liveness", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={ "image": "/9j/4AAQSkZJRgABAQ…" }, ) data = res.json() ``` ```json POST /api/v1/ml/liveness theme={null} { "entity": { "face": { "face_detected": true, "message": "face detected", "multiface_detected": false, "details": { "age_range": { "low": 21, "high": 27 }, "smile": { "value": false, "confidence": 99.40308380126953 }, "gender": { "value": "Male", "confidence": 99.94355773925781 }, "eyeglasses": { "value": false, "confidence": 99.33769989013672 }, "sunglasses": { "value": false, "confidence": 99.07188415527344 }, "beard": { "value": true, "confidence": 99.83099365234375 }, "mustache": { "value": true, "confidence": 94.46673583984375 }, "eyes_open": { "value": true, "confidence": 98.43293762207031 }, "mouth_open": { "value": false, "confidence": 95.88761901855469 }, "emotions": [ { "type": "CALM", "confidence": 98.60491180419922 }, { "type": "SAD", "confidence": 0.7328033447265625 }, { "type": "CONFUSED", "confidence": 0.07017453014850616 }, { "type": "SURPRISED", "confidence": 0.02899765968322754 }, { "type": "HAPPY", "confidence": 0.028069814667105675 }, { "type": "ANGRY", "confidence": 0.018787384033203125 }, { "type": "DISGUSTED", "confidence": 0.004357099533081055 }, { "type": "FEAR", "confidence": 0.0009387731552124023 } ] }, "quality": { "brightness": 54.561920166015625, "sharpness": 83.14741516113281 }, "confidence": 99.99991607666016, "bounding_box": { "width": 0.4428365230560303, "height": 0.30233171582221985, "left": 0.2544552981853485, "top": 0.3601169288158417 } }, "liveness": { "liveness_check": true, "liveness_probability": 98 } } } ``` # Photo ID + Selfie Source: https://docs.dojah.io/api-reference/biometrics-liveness/photo-id-selfie Match a selfie against a government-issued photo ID and read the ID's details — a face-match check for onboarding.
POST /api/v1/kyc/photoid/verify
Match a user’s selfie against a government-issued photo ID (passport, NIN, voter’s card, or driver’s licence) and read the details extracted from the ID. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | --------------- | ------ | -------- | -------------------------------------------------------------------------------------- | | `photoid_image` | string | Yes | The photo ID image, Base64-encoded (passport, NIN, voter's card, or driver's licence). | | `selfie_image` | string | Yes | The selfie image, Base64-encoded (strip the `data:image/jpeg;base64,` prefix). | | `first_name` | string | No | Expected first name, to cross-check against the ID. | | `last_name` | string | No | Expected last name, to cross-check against the ID. | ## Response Returns an `entity.selfie` object with the face-match `confidence_value` (0–100) and a boolean `match`, plus image-quality flags, the detected `card_type`, and per-name match results. As a guide, a `confidence_value` of **90+** is a strong match and **60+** is a successful match. Tune the threshold to your risk tolerance. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required field is missing or the image is malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/kyc/photoid/verify" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "photoid_image": "/9j/4AAQSkZJRgABAQ…", "selfie_image": "/9j/4AAQSkZJRgABAQ…" }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/kyc/photoid/verify", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ photoid_image: "/9j/4AAQSkZJRgABAQ…", selfie_image: "/9j/4AAQSkZJRgABAQ…" }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/kyc/photoid/verify", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={ "photoid_image": "/9j/4AAQSkZJRgABAQ…", "selfie_image": "/9j/4AAQSkZJRgABAQ…" }, ) data = res.json() ``` ```json POST /api/v1/kyc/photoid/verify theme={null} { "entity": { "selfie": { "confidence_value": 99.37, "match": true, "photoId_image_blurry": false, "selfie_image_blurry": false, "selfie_glare": false, "photoId_glare": false, "age_range": "26-40 Years", "sunglasses": false, "card_type": "VOTER'S CARD", "first_name": { "match": true, "confidence_value": 100 }, "last_name": { "match": true, "confidence_value": 100 } } } } ``` # Global business search Source: https://docs.dojah.io/api-reference/business-verification/global-business-search Search global commercial registries for a company by name.
GET /api/v1/kyb/business/search
Search global commercial registries for a company by name and country. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | -------------- | ------ | -------- | -------------------------------------------------------- | | `name` | string | Yes | The business name to search for (partial or full match). | | `country_code` | string | Yes | The country code of the business's country. | ## Response Returns an `entity` array of matching companies, each with its `internationalNumber` and country. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/kyb/business/search?name=ABCD&country_code=EX" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "name": "ABCD", "country_code": "EX", }); const url = "https://api.dojah.io/api/v1/kyb/business/search?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/kyb/business/search", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "name": "ABCD", "country_code": "EX" }, ) data = res.json() ``` ```json GET /api/v1/kyb/business/search theme={null} { "entity": [ { "name": "ABCD GLOBAL INDUSTRIES LTD", "internationalNumber": "200045678", "country": { "name": "Exampleland", "code": "EX" } }, { "name": "ABCD HOLDINGS PLC", "internationalNumber": "200098765", "country": { "name": "Exampleland", "code": "EX" } } ] } ``` # Lookup CAC Source: https://docs.dojah.io/api-reference/business-verification/lookup-cac Verify a Nigerian company with its CAC registration (RC) number — confirm its name, status, registration details, and (advanced) its directors and shareholders.
GET /api/v1/kyc/cac/basic
Verify a Nigerian company with its CAC registration (RC) number — confirm its name, status, and registration details. The advanced variant also returns the company’s affiliates (directors and shareholders). ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | -------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------- | | `rc_number` | string | Yes | The company's CAC registration (RC) number. | | `company_type` | string | Yes | One of `BUSINESS_NAME`, `COMPANY`, `INCORPORATED_TRUSTEES`, `LIMITED_PARTNERSHIP`, or `LIMITED_LIABILITY_PARTNERSHIP`. | ## Response The basic lookup (`/api/v1/kyc/cac/basic`) returns an `entity` with the company name, type, status, and location. ## Advanced lookup For the fuller record — registration date, registered address, share details, and the company’s **affiliates** (directors, proprietors, shareholders) — call `GET /api/v1/kyc/cac/advance` with the same parameters. ```json 200 — /api/v1/kyc/cac/advance theme={null} { "entity": { "company_name": "JOHN DOE LIMITED", "rc_number": "1234567", "address": "John doe street opposite dunamis church", "state": "Plateau", "city": "Jos Town (Capital)", "lga": "Jos south", "email": "abc@gmail.com", "type_of_company": "BUSINESS_NAME", "date_of_registration": "2024-07-19T08:00:06.224+00:00", "nature_of_business": null, "share_capital": null, "share_details": {}, "affiliates": [ { "first_name": "JOHN", "last_name": "MUSA", "affiliate_type": "PROPRIETOR", "gender": "MALE", "phone_number": "+2348132464910", "nationality": "Nigeria", "country": "NIGERIA" } ] } } ``` ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `429` | Too many requests — back off and retry. | ## Sandbox Test with `rc_number=1261103` or `rc_number=14320749` against `https://sandbox.dojah.io`. See [Sandbox & test data](/api-reference/get-started/sandbox-test-data) for every test value. ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/kyc/cac/basic?rc_number=1261103&company_type=COMPANY" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "rc_number": "1261103", "company_type": "COMPANY", }); const url = "https://api.dojah.io/api/v1/kyc/cac/basic?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/kyc/cac/basic", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "rc_number": "1261103", "company_type": "COMPANY" }, ) data = res.json() ``` ```json GET /api/v1/kyc/cac/basic theme={null} { "entity": { "company_name": "JOHN DOE LIMITED", "type_of_company": "BUSINESS_NAME", "status": "Not Active", "rc_number": "1234567", "business_number": "1234567", "state": "Lagos", "city": "Lagos", "lga": "Kosofe", "business": "7a666454-8ce0-44e2-ac32-3e8cb04b6b72" } } ``` # Lookup Kenya Business Source: https://docs.dojah.io/api-reference/business-verification/lookup-kenya-business Verify a Kenyan business by its registration number and retrieve its company name, status, registration details, directors and shareholders.
GET /api/v1/ke/kyb/business
Verify a Kenyan business by its registration number and retrieve its company name, status, registration details, directors and shareholders. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------------------- | ------ | -------- | ---------------------------------------------------------------- | | `registration_type` | string | Yes | Business registration type — one of `pvt`, `bn`, `llp`, or `bo`. | | `registration_number` | string | Yes | The business registration number. | ## Response Returns an `entity` with the business’s name, status, registration details, and its `partners` and `shares`. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/ke/kyb/business?registration_type=pvt®istration_number=PVT-XXXXXXXX" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "registration_type": "pvt", "registration_number": "PVT-XXXXXXXX", }); const url = "https://api.dojah.io/api/v1/ke/kyb/business?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/ke/kyb/business", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "registration_type": "pvt", "registration_number": "PVT-XXXXXXXX", }, ) data = res.json() ``` ```json GET /api/v1/ke/kyb/business theme={null} { "entity": { "business_name": "SAMPLE VENTURES LIMITED", "status": "registered", "registration_date": "01 January 2020", "postal_address": "00000 - 00100", "physical_address": "Sample Plaza, Moi Avenue, Fl: 1st, Nairobi", "phone_number": "+254700000000", "registration_number": "PVT-XXXXXXXX", "registration_type": "pvt", "branch": null, "email": "info@sampleventures.co.ke", "kra_pin": null, "verified": 1, "partners": [ { "type": "director", "shares": [], "postal_code": "", "postal_address": "", "phone_number": "", "name": "JOHN DOE", "id_type": "alien", "id_number": "10******", "gender": "M", "email": "" }, { "type": "director_shareholder", "shares": [ { "name": "ORDINARY", "number_of_shares": 100000 } ], "postal_code": "", "postal_address": "", "phone_number": "", "name": "ACME HOLDINGS, INC.", "id_type": "foreign_company", "id_number": "10000000", "gender": "Other", "email": "" }, { "type": "secretary", "shares": [], "postal_code": "", "postal_address": "", "phone_number": "", "name": "JANE DOE", "id_type": "citizen", "id_number": "29****", "gender": "F", "email": "" } ], "shares": [ { "shares": 100000, "value": "150.00", "name": "ORDINARY" } ], "encumbrances": [] } } ``` # Lookup TIN Source: https://docs.dojah.io/api-reference/business-verification/lookup-tin Look up a Nigerian company's Tax Identification Number (TIN) from its CAC registration (RC) number.
GET /api/v1/kyc/cac/tin
Look up a Nigerian company’s Tax Identification Number (TIN) directly from its CAC registration (RC) number. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | -------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------- | | `rc_number` | string | Yes | The company's CAC registration (RC) number. | | `company_type` | string | Yes | One of `BUSINESS_NAME`, `COMPANY`, `INCORPORATED_TRUSTEES`, `LIMITED_PARTNERSHIP`, or `LIMITED_LIABILITY_PARTNERSHIP`. | ## Response Returns an `entity` with the company’s name, its `tax_id`, type, and RC number. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `429` | Too many requests — back off and retry. | ## Sandbox Test with `rc_number=1261103` or `rc_number=14320749` against `https://sandbox.dojah.io`. See [Sandbox & test data](/api-reference/get-started/sandbox-test-data) for every test value. ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/kyc/cac/tin?rc_number=1261103&company_type=COMPANY" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "rc_number": "1261103", "company_type": "COMPANY", }); const url = "https://api.dojah.io/api/v1/kyc/cac/tin?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/kyc/cac/tin", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "rc_number": "1261103", "company_type": "COMPANY" }, ) data = res.json() ``` ```json GET /api/v1/kyc/cac/tin theme={null} { "entity": { "company_name": "ANON LIMITED", "tax_id": "123456789987", "company_type": "COMPANY", "rc_number": "1261103" } } ``` # Lookup Zambia Business Source: https://docs.dojah.io/api-reference/business-verification/lookup-zambia-business Verify a Zambian business by its registration number and name, and retrieve its registered company details and nature of business.
GET /api/v1/zm/kyb/business
Verify a Zambian business by its registration number and name, and retrieve its registered company details and nature of business. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------------- | ------ | -------- | --------------------------------- | | `entity_number` | string | Yes | The business registration number. | | `entity_name` | string | Yes | The registered business name. | ## Response Returns an `entity` with the business’s name, type, registration details, status, and nature of business. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/zm/kyb/business?entity_number=123456789091&entity_name=JOHN%20DOE%20INDUSTRIES%20LIMITED" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "entity_number": "123456789091", "entity_name": "JOHN DOE INDUSTRIES LIMITED", }); const url = "https://api.dojah.io/api/v1/zm/kyb/business?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/zm/kyb/business", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "entity_number": "123456789091", "entity_name": "JOHN DOE INDUSTRIES LIMITED", }, ) data = res.json() ``` ```json GET /api/v1/zm/kyb/business theme={null} { "entity": { "entity_name": "JOHN DOE INDUSTRIES LIMITED", "entity_type": "Local Company - Limited by Shares", "registration_number": "123456789091", "registration_date": "01/01/2021", "status": "Active", "nature_of_business": "Restaurants and mobile food service activities", "isic_classification": "5610. Restaurants and mobile food service activities", "isic_description": "Restaurants and mobile food service activities. This class includes the provision of food services to customers, whether they are served while seated or serve themselves from a display of items, whether they eat the prepared meals on the premises, take them out or have them delivered. This includes the preparation and serving of meals for immediate consumption from motorized vehicles or non-motorized carts.\r\n\r\nThis class includes activities of:\r\n- restaurants\r\n- cafeterias\r\n- fast-food restaurants\r\n- pizza delivery\r\n- take-out eating places\r\n- ice cream truck vendors\r\n- mobile food carts\r\n- food preparation in market stalls\r\n\r\nThis class also includes:\r\n- restaurant and bar activities connected to transportation, when carried out by separate units" } } ``` # Errors & status codes Source: https://docs.dojah.io/api-reference/core-concepts/errors-status-codes Every Dojah API status code explained — 400, 401, 402, 424, 429 and more — plus how to handle each. Every response carries a standard HTTP status code. Use it to tell what happened and how your integration should react. For identity endpoints such as BVN and NIN, the codes developers handle most often are `400`, `401`, `402`, `404`, and `424`. ## Reading a response **2xx** means success, **4xx** means something about your request, credentials, wallet, or supplied identifier needs attention, and **5xx** means the problem is on Dojah’s side. A `404` can still be a valid verification outcome — it may mean the identifier was not found at the source. ## Status codes | Code | Meaning | What your integration should do | | --------------------------- | --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | `200` OK | The request was processed. The body contains the expected data. | Continue the flow and read the `entity` object. | | `400` Bad Request | The payload is malformed, missing required fields, or the supplied value cannot be processed. | Fix validation before retrying. For BVN/NIN, confirm the identifier length and query/body field names. | | `401` Unauthorized | The API key is missing, invalid, expired, or sent with a `Bearer` prefix. | Check `Authorization` and `AppId`. Send the secret key raw, not as `Bearer {{secret_key}}`. | | `402` Payment Required | The request cannot complete because the wallet balance is too low. | Stop production retries until the wallet is funded. | | `403` Forbidden | You do not have permission to access this resource. | Confirm the account has access to the product or environment. | | `404` Not Found | The endpoint or identifier was not found. | Confirm the URL first. If the URL is correct, ask the user to confirm the identifier or use another verification path. | | `405` Method Not Allowed | The request method is not allowed for this endpoint. | Check whether the endpoint expects `GET`, `POST`, or another method. | | `408` Request Timeout | Your request took longer than expected. | Retry with backoff. | | `424` Failed Dependency | A dependent source, such as a government or identity provider, did not respond or failed. | Retry after a short delay and show a temporary-unavailable message if it persists. | | `429` Too Many Requests | Too many requests were sent in a short period. | Slow down and retry with exponential backoff. | | `500` Internal Server Error | Something went wrong on Dojah’s side. | Retry with backoff; contact support if it persists. | | `504` Gateway Timeout | The system did not respond in time. | Retry with backoff. | ## Common integration failures | Symptom | Likely cause | Fix | | ---------------------------------------- | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | `401` on every request | Secret key is missing, wrong, or sent as `Bearer ...`. | Send `Authorization: {{secret_key}}` and `AppId: {{app_id}}`. | | Works in sandbox but fails in production | Base URL, credentials, product access, or wallet balance differs between environments. | Check [Environments](/api-reference/get-started/environments) and [Wallet & billing](/api-reference/core-concepts/wallet-billing). | | BVN/NIN request returns `400` | Identifier is malformed, missing, or not accepted by the source. | Send the identifier as a string and confirm the endpoint’s required parameter name. | | BVN/NIN request returns `404` | No record was found for that identifier. | Ask the user to confirm the identifier or try another verification path. | | Intermittent `424` | Upstream identity source is temporarily unavailable. | Retry later; do not ask the user to repeatedly re-enter the same details. | ## Retry behavior Only retry failures that can recover without changing the request. | Code | Retry? | Notes | | ------------- | ------ | ------------------------------------------------------- | | `400` | No | Fix the request first. | | `401` | No | Fix credentials first. | | `402` | No | Fund the wallet first. | | `404` | No | Confirm the endpoint URL or identifier first. | | `408` | Yes | Retry with backoff. | | `424` | Yes | Retry after a short delay; the source may recover. | | `429` | Yes | Retry with exponential backoff and reduce request rate. | | `500` / `504` | Yes | Retry with exponential backoff. | ## Handling errors * **4xx** — fix the request, credentials, wallet, or identifier before retrying; retrying unchanged usually will not help. * **402** — fund your wallet, then retry. * **429 and 5xx** — retry with exponential backoff. * **424** — retry after a delay; the dependency may be temporarily down. ```ts Minimal retry policy theme={null} const retryable = new Set([408, 424, 429, 500, 504]); if (!response.ok) { if (retryable.has(response.status)) { // Retry with exponential backoff. } else { // Fix request data, credentials, wallet balance, or identifier first. } } ``` # File links & expiry Source: https://docs.dojah.io/api-reference/core-concepts/file-links-expiry File URLs returned by Dojah (selfies, documents) are temporary and expire within about an hour — copy them to your own storage. When a response or webhook includes a file — a selfie, an ID image, a document scan — it’s a temporary URL, not permanent storage. Save it before it expires. ## Links are short-lived File URLs Dojah returns expire within about **one hour**. After that the link stops working and the file is no longer reachable from it. ## What to do * **Download immediately.** When you receive a file URL, fetch the file and store it in your own system right away. * **Don’t persist the URL.** Saving the link instead of the file means a broken reference within the hour. * **Re-fetch if needed.** If you only have the verification reference, call the endpoint again to get a fresh link. **Applies to webhooks too.** File URLs inside [webhook](/api-reference/core-concepts/webhooks-signatures) payloads expire on the same schedule — copy them as soon as the event arrives. # Glossary Source: https://docs.dojah.io/api-reference/core-concepts/glossary Common Dojah terms in one place — authentication, verification, business checks, fraud signals and platform mechanics, defined plainly. The terms that show up across the dashboard, the API and these docs — so you can read any page without guessing. ## Authentication & security | Term | Meaning | | --------------------- | ------------------------------------------------------------------------------------------- | | **Apps** | Your registered applications within the Dojah platform. | | **Public key** | Shared key used to verify requests or data from Dojah. Safe for client-side use. | | **Secret key** | Confidential key used to authenticate your API requests. Server-side only. | | **Sandbox** | A testing environment for running API calls without touching live data or spending credits. | | **Live (production)** | Your real environment, where actual user and business data is processed. | | **Webhook** | A callback that notifies your server in real time when an event happens. | See [Authentication](/api-reference/get-started/authentication) and [Environments](/api-reference/get-started/environments). ## Identity & verification | Term | Meaning | | ------------------------- | ------------------------------------------------------------------------------------ | | **EasyOnboard** | Dojah’s onboarding suite, combining eKYC, document and biometric verification. | | **eKYC** | Electronic Know-Your-Customer verification using digital data or uploaded documents. | | **Document verification** | Checks the validity of national ID cards, passports and driver’s licences. | | **Face match** | Compares a user’s selfie against the image on a government-issued document. | | **Liveness detection** | Confirms a real human is present, using anti-spoofing checks. | | **Government lookup** | Validates IDs such as NIN, BVN, Voter ID and passport against authoritative sources. | ## Business verification | Term | Meaning | | ------------------------- | ---------------------------------------------------------------------------------------------- | | **Business verification** | Validating a business identity against official databases or documents. | | **CAC lookup** | Fetches company details from Nigeria’s Corporate Affairs Commission. | | **TIN verification** | Looks up a Nigerian company’s Tax Identification Number from its CAC registration (RC) number. | | **Global business check** | Search and validate international business records. | | **eKYB upload** | Upload registration documents for verification against government databases. | ## Fraud intelligence | Term | Meaning | | ------------------ | ------------------------------------------------------------------------------------------ | | **EasyDetect** | Dojah’s fraud detection platform, analysing behavioural, transactional and device signals. | | **AML screening** | Checks global watchlists, sanctions lists and PEPs (politically exposed persons). | | **Credit check** | Assesses credit history, behavioural score and loan performance. | | **Phone check** | Screens a phone number for line status, reputation and carrier insights. | | **Email check** | Assesses email validity, domain reputation and usage signals. | | **IP screening** | Identifies risky or anonymised IPs by geolocation and proxy status. | | **User screening** | Runs fraud signals against behavioural history, usage velocity and blacklists. | | **Custom lists** | Blacklists or allowlists your team uploads to flag known entities. | ## Platform mechanics | Term | Meaning | | -------------------- | --------------------------------------------------------------------------------------- | | **Flow link** | A shareable URL that drops a user into a verification or onboarding flow. | | **Ingest URL** | The endpoint you send real-time or batch events to for analysis. | | **Reference ID** | A unique identifier for each verification attempt, used for tracking and auditing. | | **Confidence score** | How confident the system is about a match or decision — usually 0–100. | | **Case** | A flagged verification or transaction that needs human review in the dashboard. | | **Velocity** | A risk signal based on how often a user, phone, device or IP appears in a short window. | # Verification statuses Source: https://docs.dojah.io/api-reference/core-concepts/verification-statuses What each Dojah verification status means — Ongoing, Pending, Completed, Failed, and Abandoned — across the verification lifecycle. A verification moves through a lifecycle. Its status tells you where it is and whether a result is ready — useful when tracking flows and handling webhook events. ## The statuses | Status | What it means | | --------- | --------------------------------------------------------- | | Ongoing | The verification has started and is actively in progress. | | Pending | Submitted and awaiting a result or review. | | Completed | Finished — a result is available. | | Failed | The verification could not be completed. | | Abandoned | The user left the flow before finishing. | ## Statuses vs HTTP codes These are different things. An [HTTP status code](/api-reference/core-concepts/errors-status-codes) describes the result of a single API call; a verification status describes where the verification itself sits in its lifecycle. A call can return `200` while the verification is still **Ongoing**. ## Tracking status Track status changes in real time with [webhooks](/api-reference/core-concepts/webhooks-signatures), or look one up with the [Get verification](/api-reference/verifications/get-verification) endpoint. # Wallet & billing Source: https://docs.dojah.io/api-reference/core-concepts/wallet-billing How Dojah billing works — a prepaid pay-as-you-go wallet, the 402 low-balance response, and checking your balance. Dojah is pay-as-you-go. Each production call draws from a prepaid wallet — keep it funded and your integration keeps running. ## How billing works Every successful production request charges your wallet. Costs vary by the check you call. Sandbox calls are always free, so you can build and test without spending anything — see [Sandbox & test data](/api-reference/get-started/sandbox-test-data). ## Checking your balance Read your current wallet balance programmatically with the [Get Balance](/api-reference/wallet-utilities/get-balance) endpoint, or from the dashboard. ## Low balance (402) If your balance can’t cover a call, the request returns `402 Payment Required` and isn’t processed. Top up to resume — see [Errors & status codes](/api-reference/core-concepts/errors-status-codes). **Avoid surprises.** Monitor your balance and set up alerts so production traffic never stalls on a `402`. ## Funding your wallet Add funds from the dashboard. For the step-by-step walkthrough, see the [Fund your wallet](/dashboard-guide/getting-started/fund-your-wallet) guide. # Webhooks & signatures Source: https://docs.dojah.io/api-reference/core-concepts/webhooks-signatures Receive real-time Dojah events, subscribe to services, and verify webhook authenticity with HMAC SHA256 signatures. Get notified the moment a verification, screening, or message event happens — instead of polling. Dojah POSTs each event to a URL you register, and signs it so you can confirm it’s genuine. ## How webhooks work You subscribe a URL to a **service**. When a matching event occurs, Dojah sends an HTTP `POST` with a JSON body to that URL. Respond `200` to acknowledge receipt. ## Subscribe to a service Register a callback URL against a service with `POST /api/v1/webhook/subscribe`. You can also fetch and delete subscriptions. ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/webhook/subscribe" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "webhook": "https://yourapp.com/dojah/webhook", "service": "kyc_widget" }' ``` Documented services include `kyc_widget`, `address`, `sms`, and `AML Monitoring`, spanning verification, fraud, AML, and messaging events. ## Event payload Events arrive as JSON with the event fields at the top level — unlike REST responses, webhook payloads don’t use the `entity` wrapper. Always look the event up against your own records using its reference before acting on it. ## Verify events are from Dojah Before trusting a payload, confirm it came from Dojah using any of these: Accept webhook calls only from Dojah’s IP: `135.119.89.106`. HMAC SHA256 of the JSON body, signed with your secret key. Recompute and compare. HMAC SHA256 of just your secret key. Recompute and compare. ```js Node.js — verify x-dojah-signature theme={null} const crypto = require("crypto"); function isFromDojah(req) { const expected = crypto .createHmac("sha256", process.env.DOJAH_SECRET_KEY) .update(JSON.stringify(req.body)) .digest("hex"); return expected === req.headers["x-dojah-signature"]; } ``` **Always verify.** Treat unverified webhook calls as untrusted — never grant access or update records from a payload you haven’t authenticated. **File links expire.** Any file URLs inside a webhook payload are temporary — see [File links & expiry](/api-reference/core-concepts/file-links-expiry). # Analyse a business document Source: https://docs.dojah.io/api-reference/document-analysis/business-document Analyse a business registration certificate or other business document and extract its registration number, legal name, entity type and registered address.
POST /api/v1/document/analysis/business\_document
Submit a business registration certificate or other business document by URL and get back the detected document type, registration number, legal name, entity type and registered address. Accepts image files (JPEG, PNG) — PDFs aren’t supported. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | ------------- | ------ | -------- | --------------------------------------------------- | | `input_type` | string | Yes | `url` (default) or `base64`. | | `input_value` | string | Yes | The image URL (or Base64) of the business document. | ## Response A `200` returns the extracted business details under `entity` — see the panel on the right. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required field is missing or the image can't be read. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `424` | Failed dependency — the analysis engine couldn't process the document. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/document/analysis/business_document" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "input_type": "url", "input_value": "https://example.com/certificate.jpg" }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/document/analysis/business_document", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ input_type: "url", input_value: "https://example.com/certificate.jpg" }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/document/analysis/business_document", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={ "input_type": "url", "input_value": "https://example.com/certificate.jpg" }, ) data = res.json() ``` ```json POST /api/v1/document/analysis/business_document theme={null} { "entity": { "result": { "status": "success", "message": "" }, "document_type": "Business Registration Certificate", "issuing_country": "Sandbox Country", "issuing_authority": "Sandbox State Business Authority", "registration_number": "SBX-0000", "business": { "legal_name": "Sandbox Demo Company Ltd.", "entity_type": "Incorporated", "nature_of_business": ["Software Development", "Testing Services"] }, "principal_place_of_business": { "street": "123 Sandbox Street", "city": "Testville", "lga": "", "state": "SB", "country": "Sandbox Country" }, "registration_date": "2025-01-01" } } ``` # Analyse an identity document Source: https://docs.dojah.io/api-reference/document-analysis/document-analysis Analyse an ID document — passport, driver's licence, national ID — for authenticity and extract every field, across 11,000+ document types in 200 countries.
POST /api/v1/document/analysis
Submit the front (and optionally back) of an ID — passport, driver’s licence, national ID, residence permit — and get back authenticity signals, the detected document type, cropped images, and every extracted field. Supports 11,000+ document types across 200 countries. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | ---------------- | ------ | -------- | ------------------------------------------------------------------------------------- | | `input_type` | string | Yes | `url` or `base64` of an image. Defaults to `url`. | | `imagefrontside` | string | Yes | Base64 or URL of the document. If Base64, strip the `data:image/jpeg;base64,` prefix. | | `imagebackside` | string | No | Base64 or URL of the document's back side. | | `images` | string | No | Base64 or URL of an additional document image. | ## Response fields The `entity.status` object summarises the checks; `document_type`, `document_images`, and `text_data` carry the extracted data. | Field | Type | Description | | ----------------- | ------- | ----------------------------------------------------------------------------------------- | | `overall_status` | integer | `1` means VALID, `0` means INVALID. | | `reason` | string | `VALID` or `INVALID`. | | `document_type` | string | `Yes` if the document has a recognised type (e.g. PASSPORT, DRIVER’S LICENCE), else `No`. | | `document_images` | string | `Yes` if a holder’s image was found, else `No`. | | `text` | string | `Yes` if readable text was found, else `No`. | | `expiry` | string | `Yes` if an expiry date was found, else `No`. | ## Response A `200` returns the analysis under `entity` — see the panel on the right. Each item in `text_data` has a `status` of `1` (read), `0` (not present), or `2` (present but unreadable). The `text_data` array is trimmed below; the live response returns every detected field. ## Business documents To analyse a registration certificate or other business document instead of a personal ID, call `POST /api/v1/document/analysis/business_document`. It accepts `input_type` (`url`, the default) and `input_value` (the image URL of the business document), and extracts the registration number, legal name, entity type, and registered address across 11,000+ business document types in 200 countries. ```json 200 — /api/v1/document/analysis/business_document theme={null} { "entity": { "result": { "status": "success", "message": "" }, "document_type": "Business Registration Certificate", "issuing_country": "Sandbox Country", "issuing_authority": "Sandbox State Business Authority", "registration_number": "SBX-0000", "business": { "legal_name": "Sandbox Demo Company Ltd.", "entity_type": "Incorporated", "nature_of_business": ["Software Development", "Testing Services"] }, "principal_place_of_business": { "street": "123 Sandbox Street", "city": "Testville", "lga": "", "state": "SB", "country": "Sandbox Country" }, "registration_date": "2025-01-01" } } ``` ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required field is missing or the image can't be read. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `424` | Failed dependency — the analysis engine couldn't process the document. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/document/analysis" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "input_type": "base64", "imagefrontside": "/9j/4AAQSkZJRgABAQ…" }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/document/analysis", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ input_type: "base64", imagefrontside: "/9j/4AAQSkZJRgABAQ…" }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/document/analysis", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={ "input_type": "base64", "imagefrontside": "/9j/4AAQSkZJRgABAQ…" }, ) data = res.json() ``` ```json POST /api/v1/document/analysis theme={null} { "entity": { "status": { "overall_status": 0, "reason": "NOT_VALID", "document_images": "Yes", "text": "Yes", "document_type": "Yes", "expiry": "No" }, "document_type": { "document_name": "United States - Permanent Resident Card (2010)", "document_country_name": "United States", "document_country_code": "USA" }, "document_images": { "portrait": "[base64 image data]", "document_front_side": "[base64 image data]", "document_back_side": "[base64 image data]" }, "text_data": [ { "field_name": "Document Number", "field_key": "document_number", "status": 1, "value": "12345678" }, { "field_name": "Sex", "field_key": "sex", "status": 1, "value": "M" }, { "field_name": "Date of Birth", "field_key": "dob", "status": 1, "value": "1990-08-01" }, { "field_name": "Date of Expiry", "field_key": "expiry_date", "status": 0, "value": "" } ] } } ``` # Generic OCR Source: https://docs.dojah.io/api-reference/document-analysis/generic-ocr Run OCR on any image with the Dojah Generic OCR service and get back the raw text it contains, line by line.
POST /api/v1/ml/ocr/generic
Run optical character recognition on any image and get back the raw text it contains, line by line — useful when you need the text off a document the structured endpoints don’t cover. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | ---------------------------------------------------------------------------------------------------- | | `img` | string | Yes | Base64 value of the image. **Do not** include the data-type prefix (e.g. `data:image/jpeg;base64,`). | ## Response A `200` returns `entity.data` — an array of the text fragments detected in the image, in reading order. The example below is trimmed; the live response returns every line. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required field is missing or the image can't be read. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `424` | Failed dependency — the analysis engine couldn't process the document. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/ml/ocr/generic" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "img": "/9j/4AAQSkZJRgABAQ…" }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/ml/ocr/generic", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ img: "/9j/4AAQSkZJRgABAQ…" }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/ml/ocr/generic", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={ "img": "/9j/4AAQSkZJRgABAQ…" }, ) data = res.json() ``` ```json POST /api/v1/ml/ocr/generic theme={null} { "entity": { "data": [ "National Identity Management System", "Federal Republic of Nigeria", "National Identification Number Slip (NINS)", "Surname:", "John", "First Name:", "Doe", "NIN:", "70142123456", "Gender:", "M", "Issue Date:", "26/08/2014" ] } } ``` # Utility Bill analysis Source: https://docs.dojah.io/api-reference/document-analysis/utility-bill Extract the name, address, provider and issue date from a utility bill, and check whether the bill is recent, with the Dojah Document Analysis API.
POST /api/v1/document/analysis/utility\_bill
Extract the name, address, provider, and issue date from a utility bill — a common proof-of-address document — and check whether the bill is recent. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | ------------- | ------ | -------- | ------------------------------ | | `input_type` | string | Yes | `url`. Defaults to `url`. | | `input_value` | string | Yes | Image URL of the utility bill. | ## Response A `200` returns the parsed bill under `entity` — `identity_info` (name and meter number), `address_info`, the `provider_name`, the `bill_issue_date`, and a `metadata.is_recent` flag you can use to enforce a recency policy on proof of address. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required field is missing or the image can't be read. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `424` | Failed dependency — the analysis engine couldn't process the document. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/document/analysis/utility_bill" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "input_type": "url", "input_value": "https://example.com/bill.jpg" }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/document/analysis/utility_bill", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ input_type: "url", input_value: "https://example.com/bill.jpg" }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/document/analysis/utility_bill", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={ "input_type": "url", "input_value": "https://example.com/bill.jpg" }, ) data = res.json() ``` ```json POST /api/v1/document/analysis/utility_bill theme={null} { "entity": { "result": { "status": "success", "message": "" }, "identity_info": { "full_name": "JOHN DOE MUSA", "meter_number": "SBX12345678" }, "address_info": { "street": "123 Sandbox Street SBX001", "city": "Testville", "state": "SB", "country": "Sandbox Country" }, "provider_name": "Sandbox Power Company", "bill_issue_date": "2025-01-15", "amount_paid": "100", "metadata": { "extraction_date": "2025-08-15T00:00:00.000Z", "is_recent": true } } } ``` # EasyAuthentication Source: https://docs.dojah.io/api-reference/easyauthentication Re-authenticate returning users with a liveness check — register a liveness record, then match new captures against it with the EasyAuthentication widget. **EasyAuthentication** confirms a *returning* user by comparing a fresh liveness capture against a liveness record you already hold for them. Instead of running full identity verification again, the user takes a short liveness check. There are two operations, and the same widget performs both: | Operation | What it does | Needs a `reference_id` | | ------------------ | ------------------------------------------------------------------- | ---------------------- | | **Registration** | Creates the liveness record the user will be matched against later. | No | | **Authentication** | Compares a new liveness capture against that stored record. | Yes | Authentication needs a valid `reference_id` from a completed registration — or from an [EasyOnboard](/api-reference/hosted-flows-easyonboard/how-hosted-flows-work) session that included a liveness step. Without a record to compare against, there is nothing to authenticate. ## How it works Create an EasyAuthentication flow in the dashboard. Publishing it produces a `widget_id` that identifies the flow. See [AuthFlows](/dashboard-guide/workflows/easyauthentication/authflows). Open the widget **without** a `reference_id`. The user completes a liveness capture, Dojah stores it as their base record, and a `reference_id` is returned. Save the `reference_id` against that user in your own system. You need it for every future authentication. Open the widget **with** the user’s `reference_id`. The new capture is matched against the stored record and a result is returned. ## Widget parameters The widget is opened as a URL on `https://identity.dojah.io/`: | Parameter | Required | Description | | -------------- | ------------------ | ---------------------------------------------------------------------------- | | `widget_type` | Yes | `register` to create a liveness record, `authenticate` to match against one. | | `widget_id` | Yes | The published EasyAuthentication flow to load. | | `reference_id` | For `authenticate` | The Auth ID returned by the user’s registration. | ## Register a user When the user has no stored liveness record, open the widget with no `reference_id`: ```text Registration URL theme={null} https://identity.dojah.io/?widget_type=register&widget_id={WIDGET_ID} ``` The user completes the liveness capture, a new liveness record is created, and a `reference_id` (also shown as the Auth ID) is generated. The session is logged under [Customers](/dashboard-guide/workflows/easyauthentication/customers). Take the `reference_id` from the [webhook](/api-reference/core-concepts/webhooks-signatures) rather than the dashboard, so registration is captured automatically. ## Authenticate a returning user Open the widget with the `reference_id` you stored for that user: ```text Authentication URL theme={null} https://identity.dojah.io/?widget_type=authenticate&widget_id={WIDGET_ID}&reference_id={USER_ID} ``` ```text Example theme={null} https://identity.dojah.io/?widget_type=authenticate&widget_id=698f71930312c0db5b9a7cb2&reference_id=d8065e79-44b5-461b-b6e6-f1c6cdb80c11 ``` 🔑}> The `USER_ID` in this authentication URL is generated by Dojah automatically — you do not create it yourself. It is returned in the dashboard or via webhook (EasyOnboard notification) after registration or an EasyOnboard session that included a liveness step. Pass that value as `reference_id`. The new capture is compared against the stored record, a result is returned, and the attempt is logged under [Authentications](/dashboard-guide/workflows/easyauthentication/authentications). ## Statuses | Status | Meaning | | ----------- | ----------------------------------------------- | | `success` | The liveness capture matched the stored record. | | `failed` | The capture did not match. | | `abandoned` | The user did not finish the flow. | **Don’t decide on the client.** Treat the widget callback as a signal that the flow finished, not proof that the user passed. Confirm the status server-side from the webhook before you release a sensitive action — see [Webhooks & signatures](/api-reference/core-concepts/webhooks-signatures). ## Rules to know * No `reference_id` means **registration** — a new liveness record is created. * A valid `reference_id` means **authentication** — the capture is matched against the existing record. * An invalid `reference_id` causes authentication to fail. * Authentication never overwrites the registration record, so the base capture stays stable over time. * Registration and authentication sessions are logged separately, under **Customers** and **Authentications**. ## Link an EasyOnboard flow If you already onboard users with EasyOnboard, you can reuse the liveness they captured there instead of registering them a second time: The EasyOnboard flow must capture liveness — that capture becomes the base record. Link the EasyOnboard flow in your EasyAuthentication flow **before** the user completes onboarding verification. Linking it afterwards won’t backfill existing sessions. Onboarding produces a `reference_id` you can pass straight to `widget_type=authenticate`. ## Integration methods The widget can be opened as a redirect URL, in a JavaScript WebView, or in an embedded iframe. Whichever you use, include the `reference_id` when authenticating. ## Handling the reference ID A `reference_id` is the key to a user’s stored biometric record. Store it server-side alongside your user record, never in `localStorage`, cookies, or a URL you log. Anyone who can supply a valid `reference_id` can attempt authentication against that record. ## Related * [EasyAuthentication in the dashboard](/dashboard-guide/workflows/easyauthentication) — create flows and review every attempt. * [Liveness check](/api-reference/biometrics-liveness/liveness-check) — run liveness directly against the API instead of the widget. * [How hosted flows work](/api-reference/hosted-flows-easyonboard/how-hosted-flows-work) — first-time verification with EasyOnboard. * [Webhooks & signatures](/api-reference/core-concepts/webhooks-signatures) — receive and verify results server-side. # Backfill Events Source: https://docs.dojah.io/api-reference/easydetect/backfill-events Upload historical banking, payment, or onboarding events to Dojah EasyDetect so fraud models learn normal behaviour before you switch to real-time scoring.
POST /api/ingest/backfill
Upload historical events that occurred before you integrated the real-time API. Fraud models need past data to learn what “normal” looks like — a user’s usual login locations, transaction amounts, and timing — so early real-time scoring is accurate. ## Endpoint | Method | URL | | ------ | --------------------------------------------- | | POST | `https://ingest.dojah.io/api/ingest/backfill` | ## Headers | Header | Required | Description | | --------------- | -------- | ----------------------------------------------------- | | `Authorization` | Yes | Your private/secret key, sent as-is — *not* `Bearer`. | | `Content-Type` | Yes | `application/json`. | ## Body parameters Backfill takes the same payload as the real-time endpoint — see the [banking, payments, and onboarding templates](/api-reference/easydetect/send-events#request-body-templates) for the full field list. | Parameter | Type | Required | Description | | --------- | ------ | -------- | --------------------------------------------------------------------------------- | | `key` | string | Yes | Your Ingest key from EasyDetect settings. | | `type` | string | Yes | Event type: `banking`, `payments`, or `onboarding`. | | `event` | object | Yes | The historical event payload, using the same nested objects as a real-time event. | ## Response Backfilled events are accepted for training and are not scored in real time, so no per-event verdict is returned. Batches are processed asynchronously; monitor progress from **EasyDetect** on your dashboard. ## Errors | Code | Meaning | | ----- | ---------------------------------------------------------------------------------- | | `400` | Bad request — `type` is invalid or a required field is missing. | | `401` | Unauthorized — check your `Authorization` key (no `Bearer` prefix) and body `key`. | | `422` | Unprocessable — an event in the batch failed validation. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request POST \ "https://ingest.dojah.io/api/ingest/backfill" \ -H "Authorization: {{secret_key}}" \ -H "Content-Type: application/json" \ -d '{ "key": "{{ingest_key}}", "type": "banking", "event": { "transaction": { "id": "87554303-3f75-4883", "time": "2022-08-01T09:20:00.000Z", "amount": 15400, "currency": "NGN", "type": "transfer" }, "user": { "user_id": "9931fac0-6bfa-4b3c", "registration_time": "2021-05-10T08:00:00.000Z" } } }' ``` ```js Node.js theme={null} const res = await fetch("https://ingest.dojah.io/api/ingest/backfill", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ key: process.env.DOJAH_INGEST_KEY, type: "banking", event: { transaction: { id: "87554303-3f75-4883", time: "2022-08-01T09:20:00.000Z", amount: 15400, currency: "NGN", type: "transfer", }, user: { user_id: "9931fac0-6bfa-4b3c", registration_time: "2021-05-10T08:00:00.000Z", }, }, }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://ingest.dojah.io/api/ingest/backfill", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "Content-Type": "application/json", }, json={ "key": os.environ["DOJAH_INGEST_KEY"], "type": "banking", "event": { "transaction": { "id": "87554303-3f75-4883", "time": "2022-08-01T09:20:00.000Z", "amount": 15400, "currency": "NGN", "type": "transfer", }, "user": { "user_id": "9931fac0-6bfa-4b3c", "registration_time": "2021-05-10T08:00:00.000Z", }, }, }, ) data = res.json() ``` ```json POST /api/ingest/backfill theme={null} { "status": "accepted", "message": "Events queued for backfill processing" } ``` # Send Events Source: https://docs.dojah.io/api-reference/easydetect/send-events Push banking, payment, or onboarding events to Dojah EasyDetect and get a real-time Allow, Block, or Review verdict from rules, behaviour, and ML.
POST /api/ingest
Push banking, payment, or onboarding events to EasyDetect as they happen and get a real-time Allow, Block, or Review verdict. Dojah scores each event against your rules, behavioural signals, and ML in milliseconds. ## Base URL EasyDetect exposes a dedicated ingest host. Send new events to the real-time endpoint; upload historical data with [Backfill Events](/api-reference/easydetect/backfill-events). | Purpose | Method | URL | | ------------------- | ------ | --------------------------------------------- | | Real-time events | POST | `https://ingest.dojah.io/api/ingest` | | Historical backfill | POST | `https://ingest.dojah.io/api/ingest/backfill` | ## Headers | Header | Required | Description | | --------------- | -------- | ----------------------------------------------------- | | `Authorization` | Yes | Your private/secret key, sent as-is — *not* `Bearer`. | | `Content-Type` | Yes | `application/json`. | ## Request body Every request carries three top-level fields. The `event` object holds the nested objects below — include as many as apply to your event `type` for more accurate scoring. Fields marked required must be present; the rest are optional but recommended. The `key` in the request body is your **Ingest key**, which is not the same as the secret key you send in the `Authorization` header. Find your Ingest key in EasyDetect settings on your dashboard, and see [Connect a Flow](/dashboard-guide/fraud-risk/easydetect/events) for where it lives. ### Top-level fields | Field | Type | Required | Description | | ------- | ------ | -------- | --------------------------------------------------- | | `key` | string | Yes | Your Ingest key from EasyDetect settings. | | `type` | string | Yes | Event type: `banking`, `payments`, or `onboarding`. | | `event` | object | Yes | Event payload containing the nested objects below. | ### event.transaction — banking, payments | Field | Type | Required | Description | | ----------------- | ------ | -------- | ----------------------------------------------------------------------------- | | `id` | string | No | Unique transaction ID. | | `time` | string | Yes | Transaction timestamp, ISO 8601. | | `amount` | number | No | Transaction amount. | | `currency` | string | No | Currency code (e.g. `NGN`, `XAF`). | | `ref` | string | No | Transaction reference. | | `session_id` | string | No | Session identifier. | | `type` | string | No | `deposit`, `debit`, `credit`, `transfer`, `purchase`, `refund`, `withdrawal`. | | `channel` | string | No | `online`, `mobile`, `atm`, `branch`, `pos`. | | `purpose` | string | No | e.g. `bill payment`, `transfer`, `airtime`, `salary payment`. | | `source_of_funds` | string | No | e.g. `employment income`, `savings`, `business`, `investment`. | ### event.user — all types | Field | Type | Required | Description | | ---------------------- | ------ | -------- | ----------------------------------------------------------- | | `user_id` | string | No | Unique user identifier. | | `user_type` | string | No | `individual`, `business`, `government`, `other`. | | `registration_time` | string | Yes | Registration timestamp, ISO 8601. | | `email` | string | No | User email address. | | `name` | string | No | User full name. | | `dob` | string | No | Date of birth, `YYYY-MM-DD` (payments, onboarding). | | `tier` | string | No | `basic`, `silver`, `gold`, `platinum`. | | `account_type` | string | No | `savings`, `checking`, `business`, `student`. | | `gender` | string | No | `male`, `female`, `other`. | | `balance` | number | No | Account balance before the transaction. | | `mobile` | string | No | User phone number. | | `last_pin_change` | string | No | Last PIN change, ISO 8601. | | `last_password_change` | string | No | Last password change, ISO 8601. | | `credit_score` | string | No | User credit score (payments, onboarding). | | `employer_information` | object | No | `annual_income`, `employment_status`, `employer_name`. | | `kyc_information` | array | No | KYC documents, each with `id_number`, `id_type`, `country`. | ### Other event objects | Object | Applies to | Key fields | | ---------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `event.receiver` | banking | `account_name`, `bank_name`, `account_number`, `country`. | | `event.sender` | banking | `account_name`, `bank_name`, `account_number`, `country`. | | `event.payment` | payments | `payment_id`, `is_recurring`, `method_type`, `scheme`, `card_funding`, `card_last_four`, `expiry_month`, `expiry_year`, `is_3ds_enabled`, `is_card_present`, `cvv_provided`, `avs_passed`, `name_on_card`, `billing_address`. | | `event.merchant` | payments | `name`, `category`, `country`. | | `event.device` | all types | `type`, `os`, `model`, `language`, `ip_address`, `device_id`. | | `event.address` | all types | `city`, `street`, `address1`, `address2`, `region`, `zipcode`, `country`. | | `event.meta` | banking | Array of custom `key`/`value` objects for additional context. | ## Request body templates Each event `type` expects a different combination of the objects above. Start from the template that matches your use case and drop any field you don't collect — only `key`, `type`, `event.transaction.time` (banking and payments), and `event.user.registration_time` are required. ```json Banking theme={null} { "key": "{{ingest_key}}", "type": "banking", "event": { "transaction": { "id": "87554303-3f75-4883-8fb8-48fce003859f", "time": "2022-12-12T12:15:05.391Z", "amount": 8291, "currency": "NGN", "ref": "xaf", "session_id": "xaf", "type": "deposit", "channel": "mobile", "purpose": "salary payment", "source_of_funds": "employment income" }, "user": { "user_id": "9931fac0-6bfa-4b3c-842c-7840006d89b6", "user_type": "individual", "registration_time": "2022-12-12T12:15:05.392Z", "email": "erik.miller@buchanan.com", "name": "Trevor Arias", "tier": "silver", "account_type": "checking", "gender": "male", "balance": 24500.5, "mobile": "5797454931", "last_pin_change": "2022-11-01T08:30:00.000Z", "last_password_change": "2022-10-15T14:22:10.000Z" }, "sender": { "account_name": "Anon Doe", "bank_name": "Paystack TITAN", "account_number": "NG0567890321", "country": "Nigeria" }, "receiver": { "account_name": "John Doe", "bank_name": "EcoBank", "account_number": "CM21100375689", "country": "Cameroon" }, "device": { "type": "mobile", "os": "Android", "model": "Pixel 7", "language": "en-US", "ip_address": "154.72.170.233", "device_id": "ff97adb7-8d3d-4f15-94df-87e21e1212de" }, "address": { "city": "North Sarah", "street": "6238 Walker Unions Suite 802", "country": "Morocco" }, "meta": [ { "key": "value" } ] } } ``` ```json Payments theme={null} { "key": "{{ingest_key}}", "type": "payments", "event": { "transaction": { "id": "87554303-3f75-4883-8fb8-48fce003859f", "time": "2022-12-12T12:15:05.391Z", "amount": 8291, "currency": "NGN", "ref": "xaf", "session_id": "xaf", "type": "purchase", "channel": "online", "purpose": "bill payment", "source_of_funds": "employment income" }, "user": { "user_id": "9931fac0-6bfa-4b3c-842c-7840006d89b6", "user_type": "individual", "registration_time": "2022-12-12T12:15:05.392Z", "email": "erik.miller@buchanan.com", "name": "Trevor Arias", "dob": "1980-01-01", "tier": "silver", "account_type": "checking", "gender": "male", "balance": 24500.5, "mobile": "5797454931", "last_pin_change": "2022-11-01T08:30:00.000Z", "last_password_change": "2022-10-15T14:22:10.000Z", "credit_score": "720", "employer_information": { "annual_income": "4500000", "employment_status": "employed", "employer_name": "Innovate Solutions" }, "kyc_information": [ { "id_number": "1234567890", "id_type": "bvn", "country": "NG" }, { "id_number": "1234567890", "id_type": "nin", "country": "NG" } ] }, "payment": { "payment_id": "9931fac0-6bfa-4b3c-842c", "is_recurring": true, "method_type": "card", "scheme": "Visa", "card_funding": "debit", "card_last_four": "9876", "expiry_month": "10", "expiry_year": "25", "is_3ds_enabled": true, "is_card_present": true, "cvv_provided": true, "avs_passed": true, "name_on_card": "John Buchanan", "billing_address": { "city": "North Sarah", "street": "6238 Walker Unions Suite 802", "country": "Morocco" } }, "merchant": { "name": "Merchant 1", "category": "electronics", "country": "Nigeria" }, "device": { "type": "mobile", "os": "Android", "model": "Pixel 7", "language": "en-US", "ip_address": "154.72.170.233", "device_id": "ff97adb7-8d3d-4f15-94df-87e21e1212de" }, "address": { "address1": "6238 Walker Unions Suite 802", "address2": "", "city": "North Sarah", "region": "", "zipcode": "23401", "country": "Morocco" } } } ``` ```json Onboarding theme={null} { "key": "{{ingest_key}}", "type": "onboarding", "event": { "user": { "user_id": "9931fac0-6bfa-4b3c-842c-7840006d89b6", "user_type": "individual", "registration_time": "2022-12-12T12:15:05.392Z", "email": "erik.miller@buchanan.com", "name": "Trevor Arias", "dob": "1980-01-01", "tier": "silver", "account_type": "checking", "gender": "male", "balance": 24500.5, "mobile": "5797454931", "last_pin_change": "2022-11-01T08:30:00.000Z", "last_password_change": "2022-10-15T14:22:10.000Z", "credit_score": "720", "employer_information": { "annual_income": "4500000", "employment_status": "employed", "employer_name": "Innovate Solutions" }, "kyc_information": [ { "id_number": "1234567890", "id_type": "bvn", "country": "NG" }, { "id_number": "1234567890", "id_type": "nin", "country": "NG" } ] }, "device": { "type": "mobile", "os": "Android", "model": "Pixel 7", "language": "en-US", "ip_address": "154.72.170.233", "device_id": "ff97adb7-8d3d-4f15-94df-87e21e1212de" }, "address": { "address1": "6238 Walker Unions Suite 802", "address2": "", "city": "North Sarah", "region": "", "zipcode": "23401", "country": "Morocco" } } } ``` ## Response Dojah scores the event and delivers the result to your [webhook](/api-reference/core-concepts/webhooks-signatures) — an overall `score`, a `decision.action` of `Allow`, `Block`, or `Review`, and the `behavioral` signals that fired (with a description of each). The original `event` is echoed back for context. ## Errors | Code | Meaning | | ----- | ---------------------------------------------------------------------------------- | | `400` | Bad request — `type` is invalid or a required field is missing. | | `401` | Unauthorized — check your `Authorization` key (no `Bearer` prefix) and body `key`. | | `422` | Unprocessable — the event payload failed validation. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request POST \ "https://ingest.dojah.io/api/ingest" \ -H "Authorization: {{secret_key}}" \ -H "Content-Type: application/json" \ -d '{ "key": "{{ingest_key}}", "type": "banking", "event": { "transaction": { "id": "87554303-3f75-4883", "time": "2022-12-12T12:15:05.391Z", "amount": 8291, "currency": "NGN", "type": "transfer", "channel": "mobile" }, "user": { "user_id": "9931fac0-6bfa-4b3c", "registration_time": "2022-12-12T12:15:05.392Z", "email": "erik.miller@buchanan.com", "name": "Trevor Arias" }, "device": { "ip_address": "154.72.170.233", "device_id": "ff97adb7-8d3d-4f15" } } }' ``` ```js Node.js theme={null} const res = await fetch("https://ingest.dojah.io/api/ingest", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ key: process.env.DOJAH_INGEST_KEY, type: "banking", event: { transaction: { id: "87554303-3f75-4883", time: "2022-12-12T12:15:05.391Z", amount: 8291, currency: "NGN", type: "transfer", channel: "mobile", }, user: { user_id: "9931fac0-6bfa-4b3c", registration_time: "2022-12-12T12:15:05.392Z", email: "erik.miller@buchanan.com", name: "Trevor Arias", }, device: { ip_address: "154.72.170.233", device_id: "ff97adb7-8d3d-4f15", }, }, }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://ingest.dojah.io/api/ingest", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "Content-Type": "application/json", }, json={ "key": os.environ["DOJAH_INGEST_KEY"], "type": "banking", "event": { "transaction": { "id": "87554303-3f75-4883", "time": "2022-12-12T12:15:05.391Z", "amount": 8291, "currency": "NGN", "type": "transfer", "channel": "mobile", }, "user": { "user_id": "9931fac0-6bfa-4b3c", "registration_time": "2022-12-12T12:15:05.392Z", "email": "erik.miller@buchanan.com", "name": "Trevor Arias", }, "device": { "ip_address": "154.72.170.233", "device_id": "ff97adb7-8d3d-4f15", }, }, }, ) data = res.json() ``` ```json POST /api/ingest theme={null} { "score": 30, "decision": { "action": "Allow", "rule_status": false }, "behavioral": { "UnusualTimeTransactions": { "state": true, "description": "User transaction time is outside of normal business hours" }, "AbnormalTransactionVolume": { "state": true, "description": "User has abnormally high transaction volume within a short period" } }, "event": { "transaction": { "id": "Dojah-20231111085937073", "amount": 300, "currency": "NGN", "type": "deposit" }, "user": { "user_id": "4ac1bc59-34ad-485a", "name": "Maplerad-Provarex-Acc" } } } ``` # Account Statement Analysis Source: https://docs.dojah.io/api-reference/financial-credit/account-statement Analyse a customer's bank-statement PDF with the Dojah API — upload the statement to get an account ID, then fetch income, expense and cash-flow insight.
POST /api/v1/financial/transactions/pdf
Turn a customer’s bank-statement PDF into structured financial insight — income, spending, cash-flow and affordability signals. A two-step flow: upload the statement to get an account ID, then fetch the analysis. ## Headers | Header | Required | Description | | --------------- | -------- | ---------------------------------------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `multipart/form-data` for the upload (set automatically when you attach the file). | ## Body parameters | Parameter | Type | Required | Description | | ----------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------- | | `bank_code` | string | Yes | The bank code for the statement's account. See [Fetch Banks](/api-reference/financial-credit/fetch-banks). | | `statement` | file | Yes | The customer's statement of account, as a PDF document. | ## Step 2 — Financial analysis Call `GET /api/v1/financial/analysis` with the `account_id` from step 1 to retrieve the analysis. | Parameter | Type | Required | Description | | ------------ | ------ | -------- | --------------------------------- | | `account_id` | string | Yes | The `acct_id` returned in step 1. | The `entity` groups results into five objects: `accountBreakdown` (balances, monthly/weekly averages, statement period), `expenseBreakdown` (spend by category), `fundsManagement` (cash-flow, loan and gambling signals), `inflowBreakdown` (salary and additional income) and `transactionRoutineBreakdown` (transaction ranges and recency). Response trimmed below for readability. ```json 200 — /api/v1/financial/analysis theme={null} { "entity": { "accountBreakdown": { "TotalCreditEntry": 306935.75, "TotalDebitMade": 321986.57, "averageMonthlyCredits": 25577.98, "averageMonthlyDebits": 20124.16, "closingBalance": 0, "firstDateInStatement": "2021-04-12", "lastDateInStatement": "2022-07-03", "numberOfTransactingMonths": 6, "periodInStatement": "April - July" }, "expenseBreakdown": { "mostFrequentExpenseCategory": "atm_and_pos_transactions", "averageMonthlyTotalExpenses": 53555.55, "totalExpenseOnAirtimeAndData": 13200, "totalExpenseOnTransfer": 70155.02 }, "fundsManagement": { "accountActivity": 0.1, "accountSweep": "No", "gamblingStatus": "No Gambling Transactions Found", "overallInflowToOutflowAmount": "Negative Cash Flow", "totalLoanAmount": 0 }, "inflowBreakdown": { "aSalaryEarner": "No", "AdditionalIncome": "Yes", "averageAdditionalIncome": 9166.67, "netAverageMonthlySalary": 0 }, "transactionRoutineBreakdown": { "lastCreditReceived": "2022-03-04", "lastDebitMade": "2022-07-03", "mostFrequentTransactionRange": "<10000", "totalAmountOfTransactions": 129 } } } ``` ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — missing `bank_code`/`statement`, or an unreadable PDF. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `424` | Failed dependency — the analysis source could not process the statement. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/financial/transactions/pdf" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -F "bank_code=011" \ -F "statement=@statement.pdf" ``` ```js Node.js theme={null} import fs from "fs"; const form = new FormData(); form.append("bank_code", "011"); form.append("statement", new Blob([fs.readFileSync("statement.pdf")]), "statement.pdf"); const res = await fetch("https://api.dojah.io/api/v1/financial/transactions/pdf", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, body: form, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/financial/transactions/pdf", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, data={ "bank_code": "011" }, files={ "statement": open("statement.pdf", "rb") }, ) data = res.json() ``` ```json POST /api/v1/financial/transactions/pdf theme={null} { "entity": { "acct_id": "1234a5b6-20bb-4e16-b711-56c5bd7a3c90" } } ``` # Credit summary Source: https://docs.dojah.io/api-reference/financial-credit/credit-bureau Pull a consolidated credit report for a customer from the Nigerian credit bureaus using their BVN.
GET /api/v1/credit\_bureau
Pull a consolidated credit report for a customer by BVN — aggregating CRC, Credit Registry and FirstCentral — with their loan history, enquiries, creditors, and portfolio totals. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | ---------------------------------------- | | `bvn` | string | Yes | The customer's Bank Verification Number. | ## Response Returns an `entity` with the customer’s bio-data and a `score` object aggregating each bureau’s status, credit enquiries, creditors, loan history and performance, and portfolio totals. The example is representative; the live response can be large. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/credit_bureau?bvn=22345678901" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "bvn": "22345678901", }); const url = "https://api.dojah.io/api/v1/credit_bureau?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/credit_bureau", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "bvn": "22345678901" }, ) data = res.json() ``` ```json GET /api/v1/credit_bureau theme={null} { "entity": { "address": "ELEGANZA HOUSE,15B JOSEPH WESLEY STR.BROAD STREET 025 NG LAGOS NIGERIA ", "bvn": "1*****78901", "dateOfBirth": "01/01/1904", "email": "", "gender": "Male", "name": "John Doe Anon", "phone": "080123456789", "score": { "bureauStatus": { "crc": "success", "creditRegistry": "success", "firstCentral": "success" }, "creditEnquiries": [ { "source": "CREDIT_REGISTRY", "value": [ { "contactPhone": "234 (1) 2798800", "date": "2022-11-13T00:00:00", "loanProvider": "Suretree Systems Limited", "reason": "N/A" } ] } ], "creditEnquiriesSummary": [ { "source": "CREDIT_REGISTRY", "value": { "Last12MonthCount": "38", "Last36MonthCount": "101", "Last3MonthCount": "4" } } ], "creditors": [ { "source": "CREDIT_REGISTRY", "value": [ { "Address": "Stallion Plaza 36 Marina Lagos Island Lagos", "Name": "Union Bank of Nigeria Plc", "Phone": "0123456789", "Subscriber_ID": "734289734289248261" } ] } ], "highestLoanAmount": [ { "source": "CRC", "value": 5000 } ], "lastReportedDate": [ { "source": "CRC", "value": "13/Nov/2022" } ], "loanHistory": [ { "source": "CRC", "value": [ { "accountNumber": "01234567893", "dateReported": "30-Apr-2019", "installmentAmount": "", "lastPaymentDate": "", "loanAmount": "5000", "loanDuration": null, "loanProvider": "UNION BANK OF NIGERIA PLC", "outstandingBalance": "0", "overdueAmount": "0", "paymentHistory": [], "performanceStatus": "Performing", "status": "Open", "type": "Overdraft" } ] } ], "loanPerformance": [ { "source": "FIRST_CENTRAL", "value": [ { "accountNumber": "12345678928181192", "loanAmount": 250800, "loanCount": 1, "loanProvider": "Union Bank Nigeria Plc Lagos", "noOfNonPerforming": 0, "noOfPerforming": 1, "outstandingBalance": 0, "overdueAmount": 0, "performanceStatus": "Performing", "status": "Closed" } ] } ], "maxNoOfDays": [ { "source": "CRC", "value": null } ], "totalBorrowed": [ { "source": "CRC", "value": 445800 } ], "totalMonthlyInstallment": [ { "source": "CRC", "value": 10000 } ], "totalNoOfActiveLoans": [ { "source": "CRC", "value": 1 } ], "totalNoOfClosedLoans": [ { "source": "CRC", "value": 2 } ], "totalNoOfDelinquentFacilities": [ { "source": "CRC", "value": 0 } ], "totalNoOfInstitutions": [ { "source": "CRC", "value": 1 } ], "totalNoOfLoans": [ { "source": "CRC", "value": 3 } ], "totalNoOfOverdueAccounts": [ { "source": "CRC", "value": 0 } ], "totalNoOfPerformingLoans": [ { "source": "CRC", "value": 3 } ], "totalOutstanding": [ { "source": "CRC", "value": 0 } ], "totalOverdue": [ { "source": "CRC", "value": 0 } ] }, "searchedDate": "2023-12-13T08:42:25.835Z" } } ``` # Credit Score & Credit Summary Source: https://docs.dojah.io/api-reference/financial-credit/credit-score Pull a Nigerian customer's credit profile by BVN with the Dojah API — a FICO-style credit score with rating, or a full multi-bureau credit summary.
GET /api/v1/fico\_score
Pull a customer’s credit profile from the Nigerian bureaus using their BVN. Two views: a single FICO-style score with a rating, or a full multi-bureau summary of loans, enquiries and creditors. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------------------------- | | `bvn` | string | Yes | The customer's 11-digit Bank Verification Number. | ## Credit Score response `GET /api/v1/fico_score` returns an `entity` with the customer’s identity (masked `bvn`, name, phone, gender, date of birth, address) and a `score` object holding the `ficoScore` — its numeric `score`, a `rating` (e.g. `AVERAGE`) and the `reasons` behind it — plus delinquency counts and the last reported date. ## Credit Summary Call `GET /api/v1/credit_bureau` with the same `bvn` for an aggregated view across the bureaus (`CRC`, `CREDIT_REGISTRY`, `FIRST_CENTRAL`). Inside `score`, `bureauStatus` reports per-bureau success, and metrics like `loanHistory`, `creditEnquiries`, `creditors`, `totalNoOfActiveLoans` and `totalOutstanding` are each an array of `{ source, value }` objects keyed by bureau. Response trimmed below. ```json 200 — /api/v1/credit_bureau theme={null} { "entity": { "bvn": "1*****78901", "name": "John Doe Anon", "phone": "080123456789", "gender": "Male", "dateOfBirth": "01/01/1904", "score": { "bureauStatus": { "crc": "success", "creditRegistry": "success", "firstCentral": "success" }, "totalNoOfActiveLoans": [ { "source": "CRC", "value": 1 } ], "totalNoOfClosedLoans": [ { "source": "CRC", "value": 2 } ], "totalBorrowed": [ { "source": "CRC", "value": 445800 } ], "totalOutstanding": [ { "source": "CRC", "value": 0 } ], "loanHistory": [ { "source": "CRC", "value": [ { "loanProvider": "UNION BANK OF NIGERIA PLC", "loanAmount": "5000", "performanceStatus": "Performing", "status": "Open" } ] } ] }, "searchedDate": "2023-12-13T08:42:25.835Z" } } ``` ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — `bvn` missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No credit record found for the supplied BVN. | | `424` | Failed dependency — a credit bureau is temporarily unavailable. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/fico_score?bvn=22222222222" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "bvn": "22222222222" }); const url = "https://api.dojah.io/api/v1/fico_score?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/fico_score", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "bvn": "22222222222" }, ) data = res.json() ``` ```json GET /api/v1/fico_score theme={null} { "entity": { "bvn": "1*****78901", "name": "Ndaka Kadir Hassan", "phone": "081234567789", "gender": "Male", "dateOfBirth": "18/02/1994", "score": { "hasLoans": "YES", "totalNoOfDelinquentFacilities": 2, "ficoScore": { "score": 610, "rating": "AVERAGE", "reasons": "There is serious delinquency on the accounts…" }, "lastReportedDate": "30-APR-2021" }, "searchedDate": "2023-12-20T11:56:38.886Z" } } ``` # Fetch Banks Source: https://docs.dojah.io/api-reference/financial-credit/fetch-banks Fetch the list of supported Nigerian banks and their bank codes with the Dojah API — use the codes for NUBAN resolution and statement analysis.
GET /api/v1/general/banks
Retrieve the list of supported Nigerian banks with their bank codes. Use these codes with Resolve NUBAN and Account Statement. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters This endpoint takes no query parameters. Send the request with your headers only. ## Response Returns an `entity` array. Each item is a bank object with a `name` and its `code`. | Field | Type | Description | | ------ | ------ | ----------------------------------------------------- | | `name` | string | The bank’s display name, e.g. `Access Bank`. | | `code` | string | The bank code to pass to other endpoints, e.g. `044`. | ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------- | | `400` | Invalid request. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/general/banks" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/general/banks", { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/general/banks", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, ) data = res.json() ``` ```json GET /api/v1/general/banks theme={null} { "entity": [ { "name": "Access Bank", "code": "044" }, { "name": "Zenith Bank", "code": "057" }, { "name": "ALAT by WEMA", "code": "035A" }, { "name": "Globus Bank", "code": "00103" }, { "name": "Parallex MFB", "code": "015" } // …full list of supported banks ] } ``` # NUBAN KYC status Source: https://docs.dojah.io/api-reference/financial-credit/nuban-kyc-status Check the KYC status and identity details tied to a Nigerian bank account (NUBAN).
GET /api/v1/kyc/nuban/status
Return the account holder’s identity and KYC compliance tier for a Nigerian bank account. Unlike Resolve NUBAN (which returns just the name), this returns the linked identity type and kyc\_status tier. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | ---------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------ | | `account_number` | string | Yes | The bank account (NUBAN) number. | | `bank_code` | integer | Yes | The bank's numeric code. Get the list from [Fetch Banks](/api-reference/financial-credit/fetch-banks). | ## Response Returns an `entity` with the account name and currency, the resolved identity (`identity_type`, `identity_number`), the holder’s names, and the `kyc_status` tier. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/kyc/nuban/status?account_number=3046XXXX407&bank_code=058" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "account_number": "3046XXXX407", "bank_code": "058", }); const url = "https://api.dojah.io/api/v1/kyc/nuban/status?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/kyc/nuban/status", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "account_number": "3046XXXX407", "bank_code": "058", }, ) data = res.json() ``` ```json GET /api/v1/kyc/nuban/status theme={null} { "entity": { "account_currency": "NGN", "account_name": "JOHN DOE MUSA", "account_number": "3046***407", "bank": "GTB", "kyc_status": "2", "first_name": "John", "identity_number": "*********556", "identity_type": "BVN", "last_name": "Musa", "other_names": "DOE" } } ``` # Resolve NUBAN Source: https://docs.dojah.io/api-reference/financial-credit/resolve-nuban Resolve a Nigerian NUBAN account number to the registered account holder's name with the Dojah API — pass an account number and bank code.
GET /api/v1/general/account
Resolve a Nigerian bank account number (NUBAN) to the name registered on the account. A lightweight name check — pass an account number and its bank code, get back the account holder’s name. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | ---------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------ | | `account_number` | string | Yes | A valid 10-digit NUBAN account number. | | `bank_code` | string | Yes | The bank's numeric code (e.g. `011`). Get the full list from [Fetch Banks](/api-reference/financial-credit/fetch-banks). | ## Response Returns an `entity` with the confirmed `account_number` and the resolved `account_name`. This is a name-resolution check only. For a full identity payload (BVN-linked names, date of birth, address) tied to the account, use the KYC NUBAN lookup (`GET /api/v1/kyc/nuban`). ## Errors | Code | Meaning | | ----- | ---------------------------------------------------------------------------------- | | `400` | Invalid request parameters — `account_number` or `bank_code` missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `404` | Could not resolve the account name. Check the parameters or try again. | | `429` | Too many requests — back off and retry. | ## Sandbox Test with `account_number=3046507407` and `bank_code=011` against `https://sandbox.dojah.io`. See [Sandbox & test data](/api-reference/get-started/sandbox-test-data) for every test value. ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/general/account?account_number=3046507407&bank_code=011" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "account_number": "3046507407", "bank_code": "011", }); const url = "https://api.dojah.io/api/v1/general/account?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/general/account", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "account_number": "3046507407", "bank_code": "011" }, ) data = res.json() ``` ```json GET /api/v1/general/account theme={null} { "entity": { "account_number": "3046507407", "account_name": "FEMI ADEWALE KOLAWOLE" } } ``` # Email Check Source: https://docs.dojah.io/api-reference/fraud-risk/email-check Submit an email address to receive a risk profile — reputation, breach exposure, disposable-email detection, domain analysis and deliverability signals.
GET /api/v1/fraud/email
Submit an email address and get back a risk profile: reputation, breach exposure, disposable-email detection, domain analysis and deliverability signals. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------------- | ------ | -------- | ---------------------------- | | `email_address` | string | Yes | The email address to screen. | ## Response Returns an `entity` with an overall `reputation`, a `suspicious` flag, the number of `references` seen, and a `details` object covering blacklisting, breach and credential-leak history, domain age, disposable/free-provider detection, deliverability and the social `profiles` the address is linked to. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `429` | Too many requests — back off and retry. | ## Sandbox Test with `email_address=johndoe@gmail.com` against `https://sandbox.dojah.io`. See [Sandbox & test data](/api-reference/get-started/sandbox-test-data) for every test value. ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/fraud/email?email_address=johndoe%40gmail.com" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "email_address": "johndoe@gmail.com", }); const url = "https://api.dojah.io/api/v1/fraud/email?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/fraud/email", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "email_address": "johndoe@gmail.com", }, ) data = res.json() ``` ```json GET /api/v1/fraud/email theme={null} { "entity": { "email": "johndoe@gmail.com", "reputation": "high", "suspicious": false, "references": 178, "details": { "blacklisted": false, "malicious_activity": false, "malicious_activity_recent": false, "credentials_leaked": true, "credentials_leaked_recent": false, "data_breach": true, "first_seen": "07/01/2008", "last_seen": "03/22/2021", "domain_exists": true, "domain_reputation": "n/a", "new_domain": false, "days_since_domain_creation": 9474, "suspicious_tld": false, "spam": false, "free_provider": true, "disposable": false, "deliverable": true, "accept_all": false, "valid_mx": true, "primary_mx": "gmail-smtp-in.l.google.com", "spoofable": true, "spf_strict": true, "dmarc_enforced": false, "profiles": [ "aboutme", "flickr", "angellist", "foursquare", "myspace", "twitter", "vimeo", "linkedin" ] } } } ``` # IP Screening Source: https://docs.dojah.io/api-reference/fraud-risk/ip-screening Submit an IP address to receive a risk profile — blacklist score, geolocation, and proxy or VPN detection for fraud and access decisions.
GET /api/v1/fraud/ip
Submit an IP address and get back a risk profile: blacklist score, geolocation, and proxy, VPN or Tor detection for fraud and access decisions. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | ------------ | ------ | -------- | ---------------------------------------- | | `ip_address` | string | Yes | The IP address to screen (IPv4 or IPv6). | ## Response Returns an `entity` wrapping a `report` — the `blacklists` summary, geolocation `information`, an `anonymity` breakdown (proxy / web-proxy / VPN / hosting / Tor) and an overall `risk_score` — plus a `success` flag. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/fraud/ip?ip_address=2.58.56.101" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "ip_address": "2.58.56.101", }); const url = "https://api.dojah.io/api/v1/fraud/ip?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/fraud/ip", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "ip_address": "2.58.56.101", }, ) data = res.json() ``` ```json GET /api/v1/fraud/ip theme={null} { "entity": { "report": { "ip": "2.58.56.101", "blacklists": { "detections": 11, "engines_count": 85, "detection_rate": "13%", "scantime": "0.92" }, "information": { "reverse_dns": "powered.by.rdp.sh", "continent_code": "EU", "continent_name": "Europe", "country_code": "DE", "country_name": "Germany", "country_currency": "EUR", "country_calling_code": "49", "region_name": "Hamburg", "city_name": "Hamburg", "latitude": 53.575321197509766, "longitude": 10.015339851379395, "isp": "1337 Services GmbH", "asn": "AS210558" }, "anonymity": { "is_proxy": false, "is_webproxy": false, "is_vpn": false, "is_hosting": false, "is_tor": true }, "risk_score": { "result": 100 } }, "success": true } } ``` # Phone Check Source: https://docs.dojah.io/api-reference/fraud-risk/phone-check Screen a phone number for fraud risk — carrier, country, and fraud signals before you onboard or approve high-value actions.
GET /api/v1/fraud/phone
Screen a phone number for risk before you onboard or approve a high-value action — carrier, country, line type and fraud signals in one call. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | -------------------------------------------------------------- | | `phone` | string | Yes | The phone number to screen (international format recommended). | ## Response Returns an `entity` with a `valid` flag, carrier and country `information`, the number’s `format`, a `risk_score`, and fraud flags — `leaked`, `spammer`, `disposable`, `suspicious`, `recent_abuse` and `active`. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/fraud/phone?phone=2348101234567" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "phone": "2348101234567", }); const url = "https://api.dojah.io/api/v1/fraud/phone?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/fraud/phone", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "phone": "2348101234567", }, ) data = res.json() ``` ```json GET /api/v1/fraud/phone theme={null} { "entity": { "phone": "2348101234567", "valid": true, "information": { "type": "Wireless", "carrier": "MTN Nigeria", "country": "NG", "city": "N/A", "zipcode": "N/A", "region": "Nigeria", "dialing_code": 234, "mnc": "12", "mcc": "123", "time_zone": "Africa/Lagos" }, "format": { "formatted": "+2348101234567", "local": "0810 123 4567" }, "risk_score": 0, "leaked": false, "spammer": false, "disposable": false, "suspicious": false, "recent_abuse": false, "active": true, "active_status": "N/A" } } ``` # User Screening Source: https://docs.dojah.io/api-reference/fraud-risk/user-screening Screen a user by name, date of birth, email, phone and IP against AML, phone, email and IP-risk signals before onboarding.
GET /api/v1/fraud/user
Screen a prospective user in one call — name, date of birth, email, phone and IP are checked against AML watchlists and phone, email and IP-risk signals, returning a single overall risk score. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------------- | ------ | -------- | --------------------------------------------------- | | `first_name` | string | Yes | The user's first name. | | `last_name` | string | Yes | The user's last name. | | `middle_name` | string | No | The user's middle name. | | `date_of_birth` | string | Yes | Date of birth, `YYYY-MM-DD`. | | `email` | string | No | The user's email address — adds email-risk signals. | | `phone` | string | No | The user's phone number — adds phone-risk signals. | | `ip_address` | string | No | The user's IP address — adds IP-risk signals. | ## Response Returns an `entity` with an `overall_risk_score` plus the underlying `phone_check_result`, `aml_screening_result`, `email_check_result` and `ip_check_result` breakdowns, and a request `uuid`. Any signal you don’t pass a parameter for is omitted. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/fraud/user?first_name=John&last_name=Doe&middle_name=Asake&date_of_birth=1990-01-01&email=test%40example.com&phone=16502969060&ip_address=2.58.56.101" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "first_name": "John", "last_name": "Doe", "middle_name": "Asake", "date_of_birth": "1990-01-01", "email": "test@example.com", "phone": "16502969060", "ip_address": "2.58.56.101", }); const url = "https://api.dojah.io/api/v1/fraud/user?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/fraud/user", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "first_name": "John", "last_name": "Doe", "middle_name": "Asake", "date_of_birth": "1990-01-01", "email": "test@example.com", "phone": "16502969060", "ip_address": "2.58.56.101", }, ) data = res.json() ``` ```json GET /api/v1/fraud/user theme={null} { "entity": { "overall_risk_score": 80, "phone_check_result": { "account_details_registered": [ "skype", "angelist", "instagram" ], "carrier": "T-MOBILE USA, INC", "country": "US", "disposable": false, "flags": [], "number": 16502969060, "score": 4, "type": "mobile", "valid": true }, "aml_screening_result": [ { "match_type": "Individual", "name": "John Asake Doe", "nameMatchScore": 80, "profileId": "WC2095906" } ], "email_check_result": { "account_details_registered": [ "skype", "angelist", "instagram" ], "breach_details": { "first_breach": null, "haveibeenpwned_listed": false, "number_of_breaches": 0 }, "domain_details": { "accept_all": false, "created": "2004-09-27 18:06:20", "custom": true, "disposable": false, "dmarc_enforced": false, "domain": "example.com", "expires": "2023-09-27 18:06:20", "free": false, "registered": true, "registered_to": "NameFind LLC", "registrar_name": "GoDaddy.com, LLC", "spf_strict": false, "suspicious_tld": false, "tld": ".com", "updated": "2022-08-16 04:46:10", "valid_mx": false, "website_exists": true }, "deliverable": false, "email": "test@example.com", "score": 4, "type": "mobile", "valid": true }, "ip_check_result": { "ip": "2.58.56.101", "blacklists": { "detections": 11, "engines_count": 85, "detection_rate": "13%" }, "ip_details": { "reverse_dns": "powered.by.rdp.sh", "continent_code": "EU", "continent_name": "Europe", "country_code": "DE", "country_name": "Germany", "country_currency": "EUR", "country_calling_code": "49", "region_name": "Hamburg", "city_name": "Hamburg", "latitude": 53.575321197509766, "longitude": 10.015339851379395, "isp": "1337 Services GmbH", "asn": "AS210558" }, "anonymity": { "is_proxy": false, "is_webproxy": false, "is_vpn": false, "is_hosting": false, "is_tor": true }, "risk_score": { "result": 100 } } }, "uuid": "41f963a5-3d6b-41ec-aac8-bbc5247a4966" } ``` # Authentication Source: https://docs.dojah.io/api-reference/get-started/authentication Authenticate Dojah API requests with your AppId and secret key — key types, headers, the Bearer gotcha, and keeping secrets safe. Every Dojah API request is authenticated with two headers — your `AppId` and your secret key. Keys are created per app in your dashboard. ## Your keys Each app has two keys for two different jobs: | Key | Where it’s used | Notes | | ---------- | ------------------------------------------ | --------------------------------------- | | Public key | Client-side — Widget SDKs and hosted flows | Safe to ship in frontend code. | | Secret key | Server-side — REST API requests | Never expose. Treat it like a password. | Find both under **Developers → Configuration** in the dashboard, where you can also regenerate them. ## Authorizing a request Send your secret key in the `Authorization` header **raw** — not as `Bearer` — alongside your `AppId`. | Header | Required | Value | | --------------- | -------- | ---------------------------- | | `Authorization` | Yes | Your secret key, sent as-is. | | `AppId` | Yes | Your app’s App ID. | `POST /api/v1/messaging/otp` ```bash cURL theme={null} curl -X POST "https://sandbox.dojah.io/api/v1/messaging/otp" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "sender_id": "Dojah", "destination": "2348012345678", "channel": "sms" }' ``` ```js Node.js theme={null} const res = await fetch("https://sandbox.dojah.io/api/v1/messaging/otp", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ sender_id: "Dojah", destination: "2348012345678", channel: "sms" }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://sandbox.dojah.io/api/v1/messaging/otp", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={"sender_id": "Dojah", "destination": "2348012345678", "channel": "sms"}, ) data = res.json() ``` **Common mistake.** Prefixing the key with `Bearer` causes a `401`. Send the key on its own. ## Keep your secret key safe * Call the API only from your **backend** — never from browser or mobile code. * Store keys in environment variables or a secrets manager, not in source control. * Use **sandbox** keys while developing; swap to live keys only in production. * If a key leaks, **regenerate** it from the dashboard immediately. ## Authentication errors | Code | Meaning | | ----- | ----------------------------------------------------------- | | `401` | Missing/invalid key or App ID — or a stray `Bearer` prefix. | | `403` | The key is valid but not permitted for this resource. | # Environments Source: https://docs.dojah.io/api-reference/get-started/environments Dojah sandbox vs production — base URLs, what each returns, and the checklist for going live. Dojah has two environments. You choose between them by the base URL you call — the headers, request bodies, and response shapes are identical. ## Base URLs | Environment | Base URL | Data | Charges | | ----------- | -------------------------- | -------------------- | -------------------------- | | Sandbox | `https://sandbox.dojah.io` | Mock / deterministic | None | | Production | `https://api.dojah.io` | Live results | Per call, from your wallet | **Same code, different host.** To switch environments you only change the base URL and use that environment’s keys — nothing else about the request changes. ## Sandbox Use sandbox to build and test end-to-end without spending credits. It returns predictable mock responses so you can exercise success and error paths — for example, the OTP in sandbox is always `1234`. See [Sandbox & test data](/api-reference/get-started/sandbox-test-data). ## Production Production returns real data from the underlying sources and draws from your prepaid wallet on each successful call. A low balance returns `402 Payment Required` — keep the wallet funded to avoid interruptions. ## Going live Top up so production calls don’t hit `402`. See the [Fund your wallet](/dashboard-guide/getting-started/fund-your-wallet) guide. Point requests at `https://api.dojah.io`. Replace sandbox `AppId` and keys with the live values from your dashboard. Run your main flows once against production to confirm keys, wallet, and webhooks all work. # Dojah API reference Source: https://docs.dojah.io/api-reference/get-started/introduction Dojah API reference — verify identities and prevent fraud across Africa with a REST API, Widget SDKs, and no-code hosted flows. Verify identities and stop fraud across Africa — through a REST API, drop-in Widget SDKs, or no-code hosted flows. This reference covers every endpoint, the SDKs, and the concepts you need to go live. **New here?** Jump to [making your first call](#first-call) — create an app, grab your keys, and run it in a few minutes. ## Ways to integrate Pick the approach that fits your product. Most teams combine the hosted flow for onboarding with direct API calls for specific checks. 🔌} href="/api-reference/get-started/introduction"> Call any check directly from your server — KYC, KYB, AML, biometrics, and more. 🧩} href="/api-reference/widget-sdks/react"> Drop Dojah’s verification UI into web or mobile with a few lines of code. 🪄} href="/api-reference/get-started/introduction"> Build a branded onboarding flow in EasyOnboard — no code required. ## Base URLs The environment is determined by the base URL you call. Authentication and request bodies are identical across both. | Environment | Base URL | Charges | | ----------- | -------------------------- | -------------------------- | | Sandbox | `https://sandbox.dojah.io` | None — mock data | | Production | `https://api.dojah.io` | Per call, from your wallet | See [Environments](/api-reference/get-started/environments) for the full comparison and the go-live checklist. ## Authenticate Every request carries two headers: your `AppId` and your secret key in `Authorization` (sent raw — *not* as `Bearer`). Full details in [Authentication](/api-reference/get-started/authentication). ## Make your first call Create an app, grab your keys, and make your first authenticated call in sandbox — no charges, no setup beyond an account. In the dashboard, go to **Developers → Configuration** and create an app. Copy its `AppId`, public key, and secret key. Use the base URL `https://sandbox.dojah.io`. Sandbox returns mock data and never charges your wallet. Send a one-time passcode. In sandbox the OTP is always `1234`, so you can run the full flow for free. Confirm the code, then switch to production keys and the live base URL when you’re ready. ### Your first request Set the two auth headers and post to the Messaging endpoint. Swap `{{secret_key}}` and `{{app_id}}` for your own. `POST /api/v1/messaging/otp` ```bash cURL theme={null} curl -X POST "https://sandbox.dojah.io/api/v1/messaging/otp" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "sender_id": "Dojah", "destination": "2348012345678", "channel": "sms" }' ``` ```js Node.js theme={null} const res = await fetch("https://sandbox.dojah.io/api/v1/messaging/otp", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ sender_id: "Dojah", destination: "2348012345678", channel: "sms" }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://sandbox.dojah.io/api/v1/messaging/otp", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={"sender_id": "Dojah", "destination": "2348012345678", "channel": "sms"}, ) data = res.json() ``` ### What you get back A `200` with a `reference_id` — hold onto it to validate the code the user enters. ```json 200 — OK theme={null} { "entity": { "reference_id": "edd37ab5-48ec-4481-8cf9-ba5chu7c41f7", "destination": "2348012345678", "status": "SMS sent successfully" } } ``` **Server-side only.** Your secret key must never ship in client code. Make API calls from your backend — see [Authentication](/api-reference/get-started/authentication). ## How billing works Dojah is pay-as-you-go. Each successful production call draws from a prepaid **wallet**; if the balance is too low a request returns `402 Payment Required`. Sandbox calls are always free. See [Wallet & billing](/api-reference/core-concepts/wallet-billing) for checking your balance and handling low-balance errors. ## Start building 🔑} href="/api-reference/get-started/authentication"> Keys, headers, and keeping secrets safe. 🌐} href="/api-reference/get-started/environments"> Sandbox vs production, and going live. 🧪} href="/api-reference/get-started/sandbox-test-data"> Test end-to-end without spending credits. # Quickstart Source: https://docs.dojah.io/api-reference/get-started/quickstart Make your first Dojah API call in minutes — get your keys, hit a sandbox endpoint with test data, or drop in the hosted widget. Make your first Dojah verification in a few minutes. Grab your keys, call a sandbox endpoint with test data, then swap in your live keys when you’re ready to go live. ## 1. Get your API keys Every request is authenticated with two values from your dashboard under [Developers → Configuration](/dashboard-guide/integrations/developers#configuration): | Credential | Header | Where to use it | | ---------- | --------------- | ------------------------------------------------------------------------------------------------------ | | App ID | `AppId` | Identifies your app on every request. | | Secret key | `Authorization` | Server-side only. Sent **raw** — *not* as `Bearer`. | | Public key | — | Client-side / widget only (see [hosted flows](/api-reference/hosted-flows-easyonboard/launch-a-flow)). | **Keep your secret key server-side.** Never ship it in web or mobile code — use the public key with the widget for anything client-facing. ## 2. Make your first call Sandbox is free and returns predictable mock data, so you can build end-to-end without spending credits. This looks up a Nigerian NIN using the sandbox test value `70123456789`: ```bash cURL theme={null} curl "https://sandbox.dojah.io/api/v1/kyc/nin?nin=70123456789" \ -H "AppId: {{app_id}}" \ -H "Authorization: {{secret_key}}" ``` A successful response wraps the result in an `entity` object: ```json JSON theme={null} { "entity": { "first_name": "JOHN", "last_name": "DOE", "gender": "m", "date_of_birth": "1990-01-01" } } ``` See [Sandbox & test data](/api-reference/get-started/sandbox-test-data) for every test value (BVN, OTP, bank account and more), and [Browse the API](/api-reference/get-started/introduction) for the full endpoint list. ## 3. Prefer no code? Use the widget If you’d rather not build request flows yourself, drop in the hosted widget and let Dojah handle the UI, capture and verification steps: ```html HTML theme={null} ``` The script tag takes no `async`/`defer`. Full options and callbacks are on [Launch a flow](/api-reference/hosted-flows-easyonboard/launch-a-flow). ## Next steps * [Environments](/api-reference/get-started/environments) — sandbox vs production and the go-live checklist. * [Authentication](/api-reference/get-started/authentication) — headers, keys and common `401`s. * [Sandbox & test data](/api-reference/get-started/sandbox-test-data) — every value you can test with. * [Errors & status codes](/api-reference/core-concepts/errors-status-codes) — including `402` and `424`. # Sandbox & test data Source: https://docs.dojah.io/api-reference/get-started/sandbox-test-data Test Dojah end-to-end in the sandbox — mock responses, the test OTP, no wallet charges, and moving to production. The sandbox mirrors the production API but returns predictable mock data and never charges your wallet — so you can build and test the whole flow for free. ## Using the sandbox Point your requests at the sandbox base URL and use your sandbox keys: ```text Base URL theme={null} https://sandbox.dojah.io ``` Requests, headers, and response shapes match production exactly — only the data is simulated. See [Environments](/api-reference/get-started/environments) for the full comparison. ## Test values Pass these credentials in sandbox to get deterministic, successful responses. They work only against `https://sandbox.dojah.io` and never return real data. ### Identity & KYC | Check | Sandbox value | | ------------ | ------------- | | NIN | `70123456789` | | BVN | `22222222222` | | Phone number | `09011111111` | ### Business verification | Check | Sandbox value | | --------------- | --------------------- | | RC / CAC number | `1261103`, `14320749` | | TIN | `18609323-0001` | ### Financial | Check | Sandbox value | | ----------------------- | ------------------------------------- | | NUBAN (Resolve account) | Account `3046507407`, bank code `011` | ### Messaging & contact | Check | Sandbox value | | ------------------ | ------------------- | | OTP (Validate OTP) | `1234` | | Email | `johndoe@gmail.com` | ### User screening & lookups | Check | Sandbox value | | -------------- | -------------------------------------- | | Account lookup | Phone `08137877844`, BVN `22271325557` | ### Address verification Address checks expose sample reference IDs that return each lifecycle state — **completed**, **pending**, and **failed** — so you can build and test every branch. See the Address Verification reference for the per-state reference IDs. **No charges.** Sandbox calls never draw from your wallet, so you can run them as often as you need while developing. **Tip.** The OTP is always `1234` in sandbox, so you can run send → validate end-to-end without a real device. ## Moving to production When your flow works in sandbox, follow the [go-live checklist](/api-reference/get-started/environments#going-live): fund your wallet, switch to `https://api.dojah.io`, and swap in your live keys. **Note.** Sandbox results are not real verifications. Never use mock data to make a live trust decision. # Flow results & webhooks Source: https://docs.dojah.io/api-reference/hosted-flows-easyonboard/flow-results-webhooks Receive hosted-flow results the right way — client callbacks for UX, webhooks for the authoritative outcome, confirmed via reference_id. A hosted flow reports its outcome two ways. Use client callbacks to update your UI — but treat the **webhook** as the source of truth before granting access. ## Two ways to get the result | Channel | Use it for | | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------ | | Client callbacks (`onSuccess` / `onError` / `onClose`) | Reacting in the UI — show a spinner, a thank-you, or an error. | | [Webhook](/api-reference/core-concepts/webhooks-signatures) (`kyc_widget` service) | The authoritative, tamper-proof result, delivered to your backend. | **Never trust the client for the decision.** A user can manipulate the browser. Grant access only after your backend receives and [verifies](/api-reference/core-concepts/webhooks-signatures#verify-events-are-from-dojah) the webhook. ## Tie sessions together with reference\_id Pass a `reference_id` (minimum 10 characters) when you launch the flow. It comes back in the callback and the webhook, so you can match the result to the right user. Store it when you start the session. ## Receive the webhook Subscribe your backend URL to the `kyc_widget` service, then verify every event is genuinely from Dojah before acting on it. * [Subscribe to the `kyc_widget` service](/api-reference/core-concepts/webhooks-signatures#subscribe-to-a-service) * [Verify the event signature](/api-reference/core-concepts/webhooks-signatures#verify-events-are-from-dojah) ## Check the verification status The event carries the flow’s status. See [Verification statuses](/api-reference/core-concepts/verification-statuses) for what each value means, or look one up later with the [Get verification](/api-reference/verifications/get-verification) endpoint. **File links expire.** Selfies and documents in the result are temporary URLs — copy them to your own storage right away. See [File links & expiry](/api-reference/core-concepts/file-links-expiry). # How hosted flows work Source: https://docs.dojah.io/api-reference/hosted-flows-easyonboard/how-hosted-flows-work How Dojah EasyOnboard hosted flows work — build a verification flow in the dashboard, embed the widget, and receive the result. A hosted flow is a ready-made, mobile-friendly verification journey you build in **EasyOnboard** — no backend required to get started. Design it once in the dashboard, then drop it into web or mobile. **Most teams start here.** Hosted flows handle ID capture, liveness, and document upload UI for you — you only handle the result. ## The lifecycle In EasyOnboard, drag and arrange verification steps — ID types, liveness, document upload — and set rules. No code. Publishing the flow produces a `widget_id` that identifies it. Launch the flow with the web widget, a mobile SDK, or a hosted link — all driven by that `widget_id`. The user moves through the branded flow; Dojah runs the checks. You get the outcome via client callbacks and — authoritatively — via a [webhook](/api-reference/core-concepts/webhooks-signatures). Always confirm server-side. ## Widget types The `type` you launch with sets which experience loads: | Type | Use it for | | ---------------- | ----------------------------------------------------------- | | `custom` | A flow you’ve configured in EasyOnboard (the usual choice). | | `verification` | A standard verification experience. | | `identification` | Identity capture and lookup. | | `liveness` | A liveness-only check. | ## Ways to run a flow 🌐} href="/api-reference/hosted-flows-easyonboard/launch-a-flow"> Embed the JavaScript `Connect` widget on your site. 🧩} href="/api-reference/widget-sdks/react"> Launch the same flow from React, React Native, Flutter, iOS, or Android. 🔔} href="/api-reference/hosted-flows-easyonboard/flow-results-webhooks"> Receive and verify the outcome server-side. # Launch a flow — web widget Source: https://docs.dojah.io/api-reference/hosted-flows-easyonboard/launch-a-flow Embed the Dojah Connect web widget — load the script, initialize with your keys and widget_id, and handle the callbacks. Embed a published EasyOnboard flow on your site with the `Connect` JavaScript widget. Load the script, initialize it with your keys and `widget_id`, and open it on a click. ## Add the widget script Load the widget from Dojah’s CDN. Don’t add `async` or `defer` — the `Connect` class must be available when you initialize it. ```html HTML theme={null} ``` ## Initialize Connect Create a `Connect` instance with your options, then call `setup()` and `open()` — typically on a button click. ```js JavaScript theme={null} const options = { app_id: "your_app_id", p_key: "your_public_key", type: "custom", embed: true, container: "#embed-container", config: { widget_id: "your_widget_id" }, reference_id: "unique-ref-12345", user_data: { first_name: "John", last_name: "Musa", dob: "1990-05-16", residence_country: "NG", email: "john@example.com", }, gov_data: { bvn: "", nin: "" }, metadata: { user_id: "121" }, onSuccess: function (response) { console.log("Success", response); }, onError: function (err) { console.log("Error", err); }, onClose: function () { console.log("Widget closed"); }, }; const connect = new Connect(options); document.querySelector("#button-connect").addEventListener("click", function () { connect.setup(); connect.open(); }); ``` ## Options | Option | Type | Description | | ------------------ | ------- | -------------------------------------------------------------------------- | | `app_id` | string | Your application ID from the dashboard. | | `p_key` | string | Your public key (safe for client-side use). | | `type` | string | Widget variant: `custom`, `verification`, `identification`, or `liveness`. | | `config.widget_id` | string | The published EasyOnboard flow to load. | | `reference_id` | string | Your tracking ID for this session (minimum 10 characters). | | `user_data` | object | Pre-fills user fields; a complete set skips the user-data screen. | | `gov_data` | object | Pre-fills government identifiers such as `bvn`, `nin`. | | `metadata` | object | Custom data echoed back in callbacks and webhooks. | | `embed` | boolean | `true` renders inline in `container`; `false` opens a modal overlay. | | `container` | string | CSS selector of the host element when `embed` is `true`. | ## Callbacks | Callback | Fires when | | --------------------- | ------------------------------------------ | | `onSuccess(response)` | The user completes all verification steps. | | `onError(err)` | An error prevents a step from completing. | | `onClose()` | The user exits via the close button. | **Don’t decide on the client.** An `onSuccess` means the flow finished — not that the user passed. Confirm the outcome server-side — see [Flow results & webhooks](/api-reference/hosted-flows-easyonboard/flow-results-webhooks). ## Other platforms To launch the same flow in a mobile or React app, use a [Widget SDK](/api-reference/widget-sdks/react) — those need only the `widget_id`. # Lookup Angola National ID Source: https://docs.dojah.io/api-reference/individual-verification/angola/national-id Verify an Angolan national ID number and return the holder's name and registration status.
GET /api/v1/ao/kyc/nin
Verify an Angolan national ID number and return the holder’s name and registration status. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | --------------------------- | | `id` | string | Yes | Angolan National ID Number. | ## Response Returns an `entity` object. `active` is a Portuguese status string (e.g. `Ativo`). ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/ao/kyc/nin?id=001234567898665" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "id": "001234567898665", }); const url = "https://api.dojah.io/api/v1/ao/kyc/nin?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/ao/kyc/nin", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "id": "001234567898665" }, ) data = res.json() ``` ```json GET /api/v1/ao/kyc/nin theme={null} { "entity": { "first_name": "JOHN", "last_name": "MUSA", "id_number": "001234567898665", "active": "Ativo" } } ``` # Canada eKYC Source: https://docs.dojah.io/api-reference/individual-verification/canada/ekyc Verify a Canadian individual against credit-reference and telephony data sources and return a match decision.
POST /api/v1/ca/kyc
Verify a Canadian individual against credit-reference and telephony data sources, returning a match decision. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | --------------- | ------ | -------- | --------------------------- | | `first_name` | string | Yes | First name. | | `last_name` | string | Yes | Last name. | | `middle_name` | string | No | Middle name. | | `date_of_birth` | string | Yes | Date of birth (YYYY-MM-DD). | | `gender` | string | Yes | `M` or `F`. | | `street_name` | string | Yes | Street name. | | `house_number` | string | Yes | House number. | | `city` | string | Yes | City. | | `post_code` | string | Yes | Post code. | ## Response Returns an `entity` with a `summary.decisionMatrix.decision` outcome plus the `creditReference` and `telephony` data blocks. Trimmed below. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/ca/kyc" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "first_name": "John", "last_name": "Musa", "date_of_birth": "1969-12-12", "gender": "M", "street_name": "184th Street", "house_number": "3688", "city": "Edmonton", "post_code": "T5J 2R4" }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/ca/kyc", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ first_name: "John", last_name: "Musa", date_of_birth: "1969-12-12", gender: "M", street_name: "184th Street", house_number: "3688", city: "Edmonton", post_code: "T5J 2R4", }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/ca/kyc", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={ "first_name": "John", "last_name": "Musa", "date_of_birth": "1969-12-12", "gender": "M", "street_name": "184th Street", "house_number": "3688", "city": "Edmonton", "post_code": "T5J 2R4", }, ) data = res.json() ``` ```json POST /api/v1/ca/kyc theme={null} { "entity": { "creditReference": { "creditReferenceSummary": { "idVerified": "1" }, "summary": { "decision": "1" } }, "searchRef": "37873fcc-6281-4913-b6df-5f26497abfab", "summary": { "decisionMatrix": { "decision": { "outcome": "1", "reason": "Individual has a full match to forename surname premise postcode with ID verified and DOB" } }, "kycSummary": { "address": { "count": "4" }, "alerts": { "count": "0" }, "dateOfBirth": { "count": "3" }, "fullNameAndAddress": { "count": "1" }, "surnameAndAddress": { "count": "0" } } }, "telephony": { "summary": { "decision": "1" }, "type": "Result" } } } ``` # Validate a Ghana Digital Address Source: https://docs.dojah.io/api-reference/individual-verification/ghana/digital-address Validate a Ghana digital address (GhanaPost GPS code) and return its location details.
GET /api/v1/gh/kyc/address/gps
Validate a Ghana digital address (GhanaPost GPS code) and return its location details. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------------------------------------- | | `address` | string | Yes | The digital address / GhanaPost GPS code, e.g. `AK-012-3456`. | ## Response Returns an `entity` object with the record for the supplied identifier. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/gh/kyc/address/gps?address=AK-012-3456" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "address": "AK-012-3456", }); const url = "https://api.dojah.io/api/v1/gh/kyc/address/gps?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/gh/kyc/address/gps", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "address": "AK-012-3456" }, ) data = res.json() ``` ```json GET /api/v1/gh/kyc/address/gps theme={null} { "entity": { "street_name": "Mercy Cl", "community": "Kwaso Community", "district": "District Name", "region": "Western", "postal_area": "Western", "post_code": "WS001", "location": "4.930449802346897,-1.736600565930667" } } ``` # Lookup Ghana Card Source: https://docs.dojah.io/api-reference/individual-verification/ghana/ghana-card Verify a Ghana Card (national ID) and fetch the holder's details from the national identity database.
GET /api/v1/gh/kyc/card
Verify a Ghana Card (national ID) and fetch the holder’s details from the national identity database. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------------ | | `id` | string | Yes | The Ghana Card (National ID) number. | ## Response Returns an `entity` object with the record for the supplied identifier. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/gh/kyc/card?id=GHA-123456789-0" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "id": "GHA-123456789-0", }); const url = "https://api.dojah.io/api/v1/gh/kyc/card?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/gh/kyc/card", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "id": "GHA-123456789-0" }, ) data = res.json() ``` ```json GET /api/v1/gh/kyc/card theme={null} { "entity": { "first_name": "JOHN", "last_name": "DOE", "gender": "M" } } ``` # Lookup Ghana Passport Source: https://docs.dojah.io/api-reference/individual-verification/ghana/passport Verify a Ghanaian international passport and fetch the holder's details from the immigration database.
GET /api/v1/gh/kyc/passport
Verify a Ghanaian international passport and fetch the holder’s details from the immigration database. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | -------------------- | | `id` | string | Yes | The passport number. | ## Response Returns an `entity` object with the record for the supplied identifier. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/gh/kyc/passport?id=G0000000" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "id": "G0000000", }); const url = "https://api.dojah.io/api/v1/gh/kyc/passport?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/gh/kyc/passport", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "id": "G0000000" }, ) data = res.json() ``` ```json GET /api/v1/gh/kyc/passport theme={null} { "entity": { "id": "G0000000", "first_name": "John", "middle_name": "Doe", "last_name": "Musa", "date_of_birth": "1990-04-05", "gender": "MALE", "issue_date": "2017-11-03", "expiry_date": "2022-10-03", "place_of_birth": "TEMA", "place_of_issue": "ACCRA", "picture": "/9j/4AAQSkZJRg…", "is_first_name_match": false, "is_middle_name_match": true, "is_last_name_match": true, "is_date_of_birth_match": true } } ``` # Lookup Kenya KRA PIN Source: https://docs.dojah.io/api-reference/individual-verification/kenya/kra-pin Verify a Kenya Revenue Authority (KRA) PIN and return the taxpayer's registration and obligation details.
GET /api/v1/ke/kyc/kra
Verify a Kenya Revenue Authority (KRA) PIN and return the taxpayer’s registration status. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------- | | `pin` | string | Yes | The KRA PIN number. | ## Response Returns an `entity` object with the taxpayer’s status and tax obligation. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/ke/kyc/kra?pin=A1234567890" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "pin": "A1234567890", }); const url = "https://api.dojah.io/api/v1/ke/kyc/kra?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/ke/kyc/kra", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "pin": "A1234567890" }, ) data = res.json() ``` ```json GET /api/v1/ke/kyc/kra theme={null} { "entity": { "current_status": "Registered", "effective_from_date": "23/03/2006", "effective_to_date": "", "obligation_name": "Income Tax - Resident Individual", "pin": "A1234567890", "pin_status": "Active", "taxpayer_name": "JOHN DOE" } } ``` # Lookup Kenya National ID Source: https://docs.dojah.io/api-reference/individual-verification/kenya/national-id Verify a Kenyan national ID number and fetch the holder's details from the national database.
GET /api/v1/ke/kyc/id
Verify a Kenyan national ID number and fetch the holder’s details, with per-field match flags. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | ----------------------- | | `id` | string | Yes | The national ID number. | ## Response Returns an `entity` object with the holder’s record and per-field match booleans. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/ke/kyc/id?id=12345678" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "id": "12345678", }); const url = "https://api.dojah.io/api/v1/ke/kyc/id?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/ke/kyc/id", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "id": "12345678" }, ) data = res.json() ``` ```json GET /api/v1/ke/kyc/id theme={null} { "entity": { "date_of_birth": "1996-02-21", "first_name": "John", "gender": "M", "id": "123456789", "is_date_of_birth_match": true, "is_first_name_match": true, "is_gender_match": true, "is_last_name_match": true, "is_middle_name_match": true, "last_name": "Musa", "middle_name": "Doe" } } ``` # Lookup Kenya Passport Source: https://docs.dojah.io/api-reference/individual-verification/kenya/passport Verify a Kenyan international passport and fetch the holder's details from the immigration database.
GET /api/v1/ke/kyc/passport
Verify a Kenyan international passport and return the holder’s biographic details and photo. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | ----------- | ------ | -------- | -------------------- | | `id_number` | string | Yes | The passport number. | ## Response Returns an `entity` object. The `photo` fields are base64 JPEG data (truncated below). ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/ke/kyc/passport?id_number=A00123456" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "id_number": "A00123456", }); const url = "https://api.dojah.io/api/v1/ke/kyc/passport?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/ke/kyc/passport", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "id_number": "A00123456" }, ) data = res.json() ``` ```json GET /api/v1/ke/kyc/passport theme={null} { "entity": { "address": "BOX 12345-67890 NAIROBI KAREN KAREN LOCATION", "citizenship": "", "date_of_birth": "2000-09-20", "date_of_birth_from_passport": "", "date_of_issue": "2019-02-14", "expiration_date": "2022-02-13", "first_name": "John", "gender": "M", "last_name": "Musa", "middle_name": "Doe", "occupation": "", "passport_number": "A00000000", "phone_number": "Not Available", "phone_number2": "Not Available", "photo": "/9j/4AAQSkZJRg…", "photo_from_passport": "/9j/4AAQSkZJRg…", "place_of_birth": "NAIROBI" } } ``` # Advanced NIN Lookup Source: https://docs.dojah.io/api-reference/individual-verification/nigeria/advanced-nin A richer NIN lookup — the standard identity data plus extra fields such as tax ID, for compliance and risk.
GET /api/v1/kyc/nin/advance
A richer NIN lookup — the standard identity data plus extra fields such as tax ID, for compliance and risk. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------------------ | | `nin` | string | Yes | A valid 11-digit National Identity Number. | ## Response Returns an `entity` with the holder’s names, gender, date of birth, phone number, and a base64-encoded `photo` — plus the fields the [basic lookup](/api-reference/individual-verification/nigeria/lookup-nin) doesn’t carry: residence address, state of origin, and tax details. The `nin` is echoed back masked. | Field | Type | Description | | --------------------------------- | ------ | -------------------------------------------------------- | | `entity.nin` | string | The NIN used for the lookup, masked | | `entity.first_name` | string | First name of the holder | | `entity.middle_name` | string | Middle name of the holder | | `entity.last_name` | string | Surname of the holder | | `entity.date_of_birth` | string | Date of birth, `YYYY-MM-DD` | | `entity.phone_number` | string | Phone number linked to the NIN | | `entity.gender` | string | Gender of the holder | | `entity.photo` | string | Base64-encoded photograph | | `entity.residence_address_line_1` | string | First line of the registered residential address | | `entity.origin_state` | string | State of origin | | `entity.tax_id` | string | Taxpayer Identification Number (TIN) tied to the holder. | | `entity.tax_residency` | string | State tax authority the holder is registered with. | `tax_id`, `photo`, and the address fields are sensitive personal data. Store only what you need, keep it encrypted at rest, and never write these values to logs — mask them the way the API masks `nin`. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ## Sandbox Test with `nin=70123456789` against `https://sandbox.dojah.io`. See [Sandbox & test data](/api-reference/get-started/sandbox-test-data) for every test value. ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/kyc/nin/advance?nin=70123456789" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "nin": "70123456789", }); const url = "https://api.dojah.io/api/v1/kyc/nin/advance?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/kyc/nin/advance", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "nin": "70123456789" }, ) data = res.json() ``` ```json GET /api/v1/kyc/nin/advance theme={null} { "entity": { "nin": "1*****78910", "first_name": "John", "last_name": "Musa", "middle_name": "Doe", "date_of_birth": "1909-01-11", "phone_number": "081123456798", "gender": "Male", "photo": "/9j/4AAQSz…", "residence_address_line_1": "Ikeja", "origin_state": "Lagos", "tax_id": "211111111111111111", "tax_residency": "Lagos State" } } ``` # Age & identity verification Source: https://docs.dojah.io/api-reference/individual-verification/nigeria/age-identity-verification Verify a person's age and identity in one call using their phone number, account number, or BVN.
GET /api/v1/kyc/age\_verification
Confirm a person’s identity and age in one call. Supply their name plus one of a phone number, account number, or BVN — set mode to choose which — and optionally a date of birth to check against. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | ---------------- | ------- | -------- | ----------------------------------------------------------------- | | `mode` | string | Yes | Verification method — `phone_number`, `account_number`, or `bvn`. | | `first_name` | string | Yes | The individual's first name. | | `last_name` | string | Yes | The individual's last name. | | `bvn` | string | No | Required when `mode` is `bvn`. | | `account_number` | string | No | Required when `mode` is `account_number`. | | `bank_code` | string | No | Required when `mode` is `account_number`. | | `phone_number` | string | No | Required when `mode` is `phone_number`. | | `dob` | string | No | Date of birth to check against, `YYYY-MM-DD`. | | `strict` | boolean | No | Enforce a strict match. Default `false`. | ## Response Returns an `entity` with the matched `first_name`, `last_name`, `date_of_birth`, and a `verification` boolean. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/kyc/age_verification?mode=bvn&first_name=John&last_name=Musa&bvn=22345678901" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "mode": "bvn", "first_name": "John", "last_name": "Musa", "bvn": "22345678901", }); const url = "https://api.dojah.io/api/v1/kyc/age_verification?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/kyc/age_verification", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "mode": "bvn", "first_name": "John", "last_name": "Musa", "bvn": "22345678901", }, ) data = res.json() ``` ```json GET /api/v1/kyc/age_verification theme={null} { "entity": { "first_name": "JOHN", "last_name": "MUSA", "date_of_birth": "1993-06-10", "verification": true } } ``` # Lookup BVN Source: https://docs.dojah.io/api-reference/individual-verification/nigeria/lookup-bvn Look up a Nigerian Bank Verification Number (BVN) and return the holder's record.
GET /api/v1/kyc/bvn/full
Retrieve the record tied to a Bank Verification Number (BVN). Use the advanced variant for enrollment and address details. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------------------ | | `bvn` | string | Yes | A valid 11-digit Bank Verification Number. | ## Response Returns an `entity` with the holder’s name, gender, date of birth, registered phone numbers, and a base64 `image`. The `bvn` is masked. ## Advanced lookup Call `GET /api/v1/kyc/bvn/advance` with the same `bvn` to also get enrollment bank/branch, account level, residence and origin details. ```json 200 — /api/v1/kyc/bvn/advance theme={null} { "entity": { "bvn": "2*****234567", "first_name": "JOHN", "last_name": "MUSA", "middle_name": "DOE", "gender": "Male", "date_of_birth": "1997-05-16", "phone_number1": "08012345678", "image": "BASE 64 IMAGE", "email": "johndoe@gmail.com", "enrollment_bank": "GTB", "enrollment_branch": "IKEJA", "level_of_account": "LEVEL 2", "lga_of_origin": "OSOGBO", "lga_of_residence": "IKEJA", "marital_status": "SINGLE", "nationality": "NIGERIAN", "phone_number2": "08012345678", "state_of_origin": "OSUN", "state_of_residence": "LAGOS", "title": "MISS", "watch_listed": "NO" } } ``` ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ## Sandbox Test with `bvn=22222222222` against `https://sandbox.dojah.io`. See [Sandbox & test data](/api-reference/get-started/sandbox-test-data) for every test value. ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/kyc/bvn/full?bvn=22222222222" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "bvn": "22222222222", }); const url = "https://api.dojah.io/api/v1/kyc/bvn/full?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/kyc/bvn/full", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "bvn": "22222222222" }, ) data = res.json() ``` ```json GET /api/v1/kyc/bvn/full theme={null} { "entity": { "bvn": "2*****234567", "first_name": "JOHN", "last_name": "MUSA", "middle_name": "DOE", "gender": "Male", "date_of_birth": "1997-05-16", "phone_number1": "08012345678", "image": "BASE 64 IMAGE", "phone_number2": "08012345678" } } ``` # Lookup NIN Source: https://docs.dojah.io/api-reference/individual-verification/nigeria/lookup-nin Look up a Nigerian National Identity Number (NIN) and return the holder's identity record.
GET /api/v1/kyc/nin
Retrieve the identity record tied to a Nigerian National Identity Number (NIN) from NIMC. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------------------ | | `nin` | string | Yes | A valid 11-digit National Identity Number. | ## Response Returns an `entity` with the holder’s name, gender, date of birth, phone number, and a base64-encoded `photo`. ## Other NIN lookups Two variants return more than the basic record — each documented on its own page: * [Advanced NIN](/api-reference/individual-verification/nigeria/advanced-nin) — the identity data plus extra fields like `tax_id` and `tax_residency`. * [NIN Slip](/api-reference/individual-verification/nigeria/nin-slip) — the person’s NIN slip data (`GET /api/v1/kyc/nin/nin_slip`). ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ## Sandbox Test with `nin=70123456789` against `https://sandbox.dojah.io`. See [Sandbox & test data](/api-reference/get-started/sandbox-test-data) for every test value. ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/kyc/nin?nin=70123456789" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "nin": "70123456789", }); const url = "https://api.dojah.io/api/v1/kyc/nin?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/kyc/nin", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "nin": "70123456789" }, ) data = res.json() ``` ```json GET /api/v1/kyc/nin theme={null} { "entity": { "first_name": "John", "last_name": "Musa", "gender": "Male", "middle_name": "Doe", "photo": "/9j/4AAQSkZJRgABAgAAAQABAAD/2wBD…", "date_of_birth": "1982-01-01", "phone_number": "08012345678", "employment_status": "unemployment", "marital_status": "Single" } } ``` # Lookup NIN Slip Source: https://docs.dojah.io/api-reference/individual-verification/nigeria/nin-slip Fetch a person's NIN slip data and identity record from NIMC using their National Identity Number.
GET /api/v1/kyc/nin/nin\_slip
Fetch a person’s NIN slip data and identity record from NIMC using their National Identity Number. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------------------ | | `nin` | string | Yes | A valid 11-digit National Identity Number. | ## Response Returns an `entity` object with the record for the supplied identifier. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ## Sandbox Test with `nin=70123456789` against `https://sandbox.dojah.io`. See [Sandbox & test data](/api-reference/get-started/sandbox-test-data) for every test value. ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/kyc/nin/nin_slip?nin=70123456789" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "nin": "70123456789", }); const url = "https://api.dojah.io/api/v1/kyc/nin/nin_slip?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/kyc/nin/nin_slip", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "nin": "70123456789" }, ) data = res.json() ``` ```json GET /api/v1/kyc/nin/nin_slip theme={null} { "entity": { "nin": "1*****78910", "first_name": "John", "last_name": "Musa", "middle_name": "Doe", "date_of_birth": "1909-01-11", "phone_number": "081123456798", "gender": "Male", "photo": "/9j/4AAQSkZJRg…", "employment_status": "unemployed", "marital_status": "single", "birth_state": "Lagos", "residence_address_line_1": "2, ANON STREET", "residence_lga": "Lagos West", "residence_state": "Lagos", "height": "171", "nin_id": "JVBERi0xLjQ…" } } ``` # Phone number Source: https://docs.dojah.io/api-reference/individual-verification/nigeria/phone-number Look up the identity linked to a Nigerian phone number.
GET /api/v1/kyc/phone\_number/basic
Resolve the identity registered to a Nigerian phone number. A basic and an advanced variant are available. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | -------------- | ------ | -------- | ------------------------------ | | `phone_number` | string | Yes | A valid Nigerian phone number. | ## Response The basic variant returns name, gender, nationality, date of birth, and the MSISDN. ## Advanced lookup Call `GET /api/v1/kyc/phone_number` for an extended record that also includes a base64 `photo` and a `customer` reference. ```json 200 — /api/v1/kyc/phone_number theme={null} { "entity": { "first_name": "JOHN", "last_name": "MUSA", "middle_name": "DOE", "date_of_birth": "1960-12-12", "phone_number": "08012345678", "photo": "BASE 64 IMAGE", "gender": "M", "customer": "9b2ac137-5360-4050-b412-4fa6728a31fb" } } ``` ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ## Sandbox Test with `phone_number=09011111111` against `https://sandbox.dojah.io`. See [Sandbox & test data](/api-reference/get-started/sandbox-test-data) for every test value. ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/kyc/phone_number/basic?phone_number=09011111111" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "phone_number": "09011111111", }); const url = "https://api.dojah.io/api/v1/kyc/phone_number/basic?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/kyc/phone_number/basic", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "phone_number": "09011111111" }, ) data = res.json() ``` ```json GET /api/v1/kyc/phone_number/basic theme={null} { "entity": { "first_name": "JOHN", "middle_name": "DOE", "last_name": "MUSA", "gender": "Male", "nationality": "NGA", "date_of_birth": "1990-05-16", "msisdn": "23481222222222" } } ``` # Validate BVN Source: https://docs.dojah.io/api-reference/individual-verification/nigeria/validate-bvn Match a name and date of birth against a BVN record and get per-field confidence scores.
GET /api/v1/kyc/bvn
Confirm that a name and date of birth match a BVN — without pulling the full record. Returns a per-field match status and confidence score. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | ------------ | ------ | -------- | --------------------------------------------- | | `bvn` | string | Yes | A valid BVN number. | | `first_name` | string | No | First name to match against the record. | | `last_name` | string | No | Last name to match against the record. | | `dob` | string | No | Date of birth to match, in yyyy-mm-dd format. | ## Response Each supplied field comes back with a `status` (matched or not) and, for names, a `confidence_value` from 0–100. Use this when you only need to verify identity, not retrieve it. ## When the BVN isn’t found An unknown BVN returns `400` with an error message: ```json 400 — Bad Request theme={null} { "error": "BVN not found" } ``` ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ## Sandbox Test with `bvn=22222222222` against `https://sandbox.dojah.io`. See [Sandbox & test data](/api-reference/get-started/sandbox-test-data) for every test value. ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/kyc/bvn?bvn=22222222222&first_name=John&last_name=Musa&dob=1997-05-16" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "bvn": "22222222222", "first_name": "John", "last_name": "Musa", "dob": "1997-05-16", }); const url = "https://api.dojah.io/api/v1/kyc/bvn?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/kyc/bvn", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "bvn": "22222222222", "first_name": "John", "last_name": "Musa", "dob": "1997-05-16" }, ) data = res.json() ``` ```json GET /api/v1/kyc/bvn theme={null} { "entity": { "bvn": { "value": "2*****89012", "status": true }, "first_name": { "confidence_value": 100, "status": true }, "last_name": { "confidence_value": 100, "status": true } } } ``` # Lookup South Africa National ID Source: https://docs.dojah.io/api-reference/individual-verification/south-africa/national-id Verify a South African national ID number and fetch the holder's details from the Home Affairs database.
GET /api/v1/za/kyc/id
Verify a South African national ID number and fetch the holder’s Home Affairs record. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | ----------- | ------ | -------- | --------------------------------- | | `id_number` | string | Yes | South African National ID Number. | ## Response Returns an `entity` object with the holder’s Home Affairs record. ## With photograph To also return the holder’s photo, call the `id_withphoto` variant. It takes the same `id_number` query parameter and returns the same `entity` object plus a base64 `photo` field. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/za/kyc/id?id_number=1234567890192" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "id_number": "1234567890192", }); const url = "https://api.dojah.io/api/v1/za/kyc/id?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/za/kyc/id", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "id_number": "1234567890192" }, ) data = res.json() ``` ```json GET /api/v1/za/kyc/id theme={null} { "entity": { "id_number": "1234567890192", "first_name": "JOHN", "last_name": "MUSA", "middle_name": "DOE", "date_of_birth": "1900-12-18", "phone_number": "", "address": "", "marital_status": "SINGLE", "gender": "Male", "issued_date": "2020-01-20", "full_name": "JOHN DOE MUSA", "smart_card_issued": "YES", "card_date": "2020-01-20", "book_date": "2020-01-20", "living_status": "ALIVE" } } ``` # Lookup Uganda NIN Source: https://docs.dojah.io/api-reference/individual-verification/uganda/nin Verify a Ugandan National Identification Number (NIN) and fetch the holder's details from the NIRA database.
GET /api/v1/ug/kyc/nin
Verify a Ugandan National Identification Number (NIN) and fetch the holder’s details. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | ------------ | ------ | -------- | -------------------------------------- | | `nin` | string | Yes | National Identification Number (NIN). | | `first_name` | string | No | The first name of the document holder. | | `last_name` | string | No | The last name of the document holder. | ## Response Returns an `entity` object with the holder’s record. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/ug/kyc/nin?nin=CM123456789AB" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "nin": "CM123456789AB", }); const url = "https://api.dojah.io/api/v1/ug/kyc/nin?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/ug/kyc/nin", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "nin": "CM123456789AB" }, ) data = res.json() ``` ```json GET /api/v1/ug/kyc/nin theme={null} { "entity": { "id_number": "CM123456789AB", "first_name": "John", "last_name": "Musa", "middle_name": "Doe", "date_of_birth": "1990-01-01" } } ``` # Lookup Uganda Telco Subscriber Source: https://docs.dojah.io/api-reference/individual-verification/uganda/telco-subscriber Verify a Ugandan mobile phone subscriber's registered name against the telco database.
POST /api/v1/ug/kyc/telco
Verify a Ugandan mobile subscriber’s registered name against the telco’s records. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | -------------- | ------ | -------- | ----------------------------------- | | `first_name` | string | Yes | First name of the subscriber. | | `last_name` | string | Yes | Last name of the subscriber. | | `phone_number` | string | Yes | The phone number of the subscriber. | ## Response Returns an `entity` object with the verified subscriber name and a percentage name-match. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/ug/kyc/telco" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "first_name": "John", "last_name": "Musa", "phone_number": "+25612345678" }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/ug/kyc/telco", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ first_name: "John", last_name: "Musa", phone_number: "+25612345678", }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/ug/kyc/telco", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={ "first_name": "John", "last_name": "Musa", "phone_number": "+25612345678", }, ) data = res.json() ``` ```json POST /api/v1/ug/kyc/telco theme={null} { "entity": { "first_name": "John", "last_name": "Musa", "name_check_error": null, "network_name": "", "percentage_name_match": 100, "phone_is_mm_registered": false, "phone_number": "+25612345678", "verified_name": "John Doe Musa" } } ``` # Lookup Uganda Voter ID Source: https://docs.dojah.io/api-reference/individual-verification/uganda/voter-id Verify a Ugandan voter and return their polling details from the electoral register.
GET /api/v1/ug/kyc/voter
Verify a Ugandan voter by voter number, application ID, or NIN, plus first and last name. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | ------------ | ------ | -------- | -------------------------------------------------------------- | | `id` | string | Yes | The Voter Number, Application ID, or National ID Number (NIN). | | `first_name` | string | Yes | The first name of the document holder. | | `last_name` | string | Yes | The last name of the document holder. | ## Response Returns an `entity` object with the voter’s polling details and name-match flags. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/ug/kyc/voter?id=12345678&first_name=John&last_name=Musa" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "id": "12345678", "first_name": "John", "last_name": "Musa", }); const url = "https://api.dojah.io/api/v1/ug/kyc/voter?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/ug/kyc/voter", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "id": "12345678", "first_name": "John", "last_name": "Musa" }, ) data = res.json() ``` ```json GET /api/v1/ug/kyc/voter theme={null} { "entity": { "voter_number": "12345678", "first_name": "JOHN", "last_name": "MUSA", "gender": "M", "village": "BIROBOKA", "district": "KYANKWANZI", "constituency": "BIROBOKA - KAYANJA PRIMARY SCHOOL", "sub_county": "BUTEMBA COUNTY", "parish": "KYANKWANZI TOWN COUNCIL", "polling_station": "BIROBOKA WARD", "is_first_name_match": true, "is_last_name_match": true } } ``` # United Kingdom eKYC Source: https://docs.dojah.io/api-reference/individual-verification/united-kingdom/ekyc Verify a UK individual against multiple identity data sources and return an aggregated match result.
GET /api/v1/uk/kyc
Verify a UK individual against multiple identity data sources and return an aggregated match result. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------------- | ------ | -------- | --------------------------- | | `first_name` | string | Yes | First name. | | `last_name` | string | Yes | Last name. | | `middle_name` | string | No | Middle name. | | `date_of_birth` | string | Yes | Date of birth (YYYY-MM-DD). | | `gender` | string | Yes | `M` or `F`. | | `country` | string | Yes | Country code — `GBR`. | | `street_name` | string | Yes | Street name. | | `house_number` | string | Yes | House number. | | `post_code` | string | Yes | Post code. | ## Response Returns an `entity` with an `interpretResult` plus the per-source `rawResponse` matches. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/uk/kyc?first_name=John&last_name=Musa&date_of_birth=1969-12-12&gender=M&country=GBR&street_name=Baker Street&house_number=221&post_code=NW1 6XE" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "first_name": "John", "last_name": "Musa", "date_of_birth": "1969-12-12", "gender": "M", "country": "GBR", "street_name": "Baker Street", "house_number": "221", "post_code": "NW1 6XE", }); const url = "https://api.dojah.io/api/v1/uk/kyc?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/uk/kyc", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "first_name": "John", "last_name": "Musa", "date_of_birth": "1969-12-12", "gender": "M", "country": "GBR", "street_name": "Baker Street", "house_number": "221", "post_code": "NW1 6XE" }, ) data = res.json() ``` ```json GET /api/v1/uk/kyc theme={null} { "entity": { "interpretResult": "Pass", "message": "Matching performed using 11,8 sources as per profile", "rawResponse": [ { "AddressMatch": "NoMatch", "DataSource": "Resident Roll", "DobMatch": "Partial", "FirstNameMatch": "Initial", "SurnameMatch": "Full" } ], "transactionResult": "Success" } } ``` # Lookup Zambia National ID Source: https://docs.dojah.io/api-reference/individual-verification/zambia/national-id Verify a Zambian National Registration Card (NRC) and return the taxpayer's status and TPIN.
GET /api/v1/zm/kyc/nrc
Verify a Zambian National Registration Card (NRC) and return the taxpayer’s status and TPIN. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | ---------------------------------------- | | `nrc` | string | Yes | National Registration Card (NRC) number. | ## Response Returns an `entity` object with the taxpayer’s name, status, and TPIN. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/zm/kyc/nrc?nrc=123456/78/9" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "nrc": "123456/78/9", }); const url = "https://api.dojah.io/api/v1/zm/kyc/nrc?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/zm/kyc/nrc", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "nrc": "123456/78/9" }, ) data = res.json() ``` ```json GET /api/v1/zm/kyc/nrc theme={null} { "entity": { "taxpayer_name": "John Doe", "current_status": "ACTIVE", "is_deregistered": 0, "tax_types": "", "nrc": "123456/78/9", "tpin": "1234567890" } } ``` # Zimbabwe Credit Check (FCB) Source: https://docs.dojah.io/api-reference/individual-verification/zimbabwe/credit-check Run an FCB credit check for a Zimbabwean individual and return their credit score and status.
GET /api/v1/zw/kyc/fcb
Run an FCB credit check for a Zimbabwean individual and return their credit score and status. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | ---------------- | ------ | -------- | ---------------------------------- | | `id_number` | string | Yes | The Zimbabwean National ID number. | | `dob` | string | Yes | Date of birth, `YYYY-MM-DD`. | | `name` | string | Yes | The individual's first name. | | `surname` | string | Yes | The individual's last name. | | `gender` | string | Yes | `M` or `F`. | | `marital_status` | string | Yes | `M` (married) or `S` (single). | | `mobile_number` | string | Yes | The individual's contact number. | ## Response Returns an `entity` object with the individual’s credit score and status. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/zw/kyc/fcb?id_number=12345678A90&dob=1990-01-01&name=JOHN&surname=DOE&gender=M&marital_status=S&mobile_number=263771234567" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "id_number": "12345678A90", "dob": "1990-01-01", "name": "JOHN", "surname": "DOE", "gender": "M", "marital_status": "S", "mobile_number": "263771234567", }); const url = "https://api.dojah.io/api/v1/zw/kyc/fcb?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/zw/kyc/fcb", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "id_number": "12345678A90", "dob": "1990-01-01", "name": "JOHN", "surname": "DOE", "gender": "M", "marital_status": "S", "mobile_number": "263771234567", }, ) data = res.json() ``` ```json GET /api/v1/zw/kyc/fcb theme={null} { "entity": { "id_number": "12345678A90", "full_name": "JOHN DOE MUSA", "dob": "1901-01-01", "gender": "F", "score": 288, "status": "GOOD" } } ``` # Lookup Zimbabwe National ID Source: https://docs.dojah.io/api-reference/individual-verification/zimbabwe/national-id Verify a Zimbabwean national ID number and return the holder's civil-registry record.
GET /api/v1/zw/kyc/nin
Verify a Zimbabwean national ID number and return the holder’s civil-registry record. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | ----------- | ------ | -------- | ------------------------------ | | `id_number` | string | Yes | Zimbabwean National ID number. | ## Response Returns an `entity` object with the holder’s civil-registry record. ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------------- | | `400` | Bad request — a required parameter is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `402` | Insufficient wallet balance. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `404` | No record found for the supplied identifier. | | `424` | The upstream source was unavailable — retry shortly. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/zw/kyc/nin?id_number=451234561E45" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "id_number": "451234561E45", }); const url = "https://api.dojah.io/api/v1/zw/kyc/nin?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/zw/kyc/nin", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "id_number": "451234561E45" }, ) data = res.json() ``` ```json GET /api/v1/zw/kyc/nin theme={null} { "entity": { "person_no": "451234561E45", "status": "A", "surname": "MUSA", "first_name": "JOHN", "sex": "F", "date_of_birth": "1901-01-01", "date_of_death": "1961-01-01", "birth_place": "Earth" } } ``` # Message Status Source: https://docs.dojah.io/api-reference/messaging/message-status Check the delivery status of a message using its message_id with the Dojah Messaging API.
GET /api/v1/messaging/sms/get\_status
Check the current delivery status of a message, using the message\_id returned by Send SMS. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | ------------ | ------ | -------- | -------------------------------------------- | | `message_id` | string | Yes | The `message_id` from the Send SMS response. | ## Response Returns an `entity` with the message’s current delivery `status`. | Field | Type | Description | | -------- | ------ | ------------------------------------------------------------------ | | `status` | string | Current delivery status, e.g. `DELIVERED`, `PENDING`, or `FAILED`. | ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------- | | `400` | Bad request — `message_id` is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/messaging/sms/get_status?message_id=dj_c8095767-c69f-4bd7-aa52-7cb469effb51" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "message_id": "dj_c8095767-c69f-4bd7-aa52-7cb469effb51", }); const url = "https://api.dojah.io/api/v1/messaging/sms/get_status?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/messaging/sms/get_status", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "message_id": "dj_c8095767-c69f-4bd7-aa52-7cb469effb51" }, ) data = res.json() ``` ```php PHP theme={null} "dj_c8095767-c69f-4bd7-aa52-7cb469effb51", ]); $ch = curl_init("https://api.dojah.io/api/v1/messaging/sms/get_status?" . $q); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: " . getenv("DOJAH_SECRET_KEY"), "AppId: " . getenv("DOJAH_APP_ID"), ], ]); $data = json_decode(curl_exec($ch), true); ``` ```json GET /api/v1/messaging/sms/get_status theme={null} { "entity": { "status": "DELIVERED" } } ``` # Send OTP Source: https://docs.dojah.io/api-reference/messaging/send-otp Send a one-time passcode over SMS, WhatsApp, voice, or email with the Dojah Messaging API, then validate it with the returned reference_id.
POST /api/v1/messaging/otp
Send a one-time passcode over SMS, WhatsApp, voice, or email. The response returns a reference\_id you’ll pass to Validate OTP to confirm the code the user enters. ## Headers | Header | Required | Description | | --------------- | -------- | ---------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | ------------- | ------- | -------- | ------------------------------------------------------------------------ | | `sender_id` | string | Yes | A registered Sender ID to send from. | | `destination` | string | Yes | Recipient phone number (for SMS, WhatsApp, voice). | | `channel` | string | Yes | Delivery channel: `sms`, `whatsapp`, `voice`, or `email`. | | `email` | string | No | Recipient email address — required when `channel` is `email`. | | `length` | integer | No | Number of digits in the code, 4–10. Default `6`. | | `expiry` | integer | No | Minutes before the code expires. Default `10`. | | `priority` | boolean | No | Send in priority mode. Default `false`. | | `otp` | integer | No | Supply your own code (4–10 digits) instead of having Dojah generate one. | ## Response Returns `200 OK` with an `entity` object. Store the `reference_id` — it’s the only way to validate the code later. | Field | Type | Description | | -------------- | ------ | ------------------------------------------------------------- | | `reference_id` | string | Unique ID for this OTP. Pass it to Validate OTP. | | `destination` | string | The phone number or email the code was sent to. | | `status` | string | Human-readable delivery status, e.g. `SMS sent successfully`. | ## Errors | Code | Meaning | | ----- | ------------------------------------------------------------------------------------------------------------------------- | | `400` | Bad request — a required field is missing or malformed. | | `401` | Unauthorized — check your `Authorization` key and `AppId`. | | `402` | Payment required — your wallet balance is too low. [Fund your wallet](/dashboard-guide/getting-started/fund-your-wallet). | | `422` | Unprocessable — e.g. an unregistered `sender_id` or invalid `channel`. | | `429` | Too many requests — slow your request rate and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/messaging/otp" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "sender_id": "Dojah", "destination": "2348012345678", "channel": "sms", "length": 6, "expiry": 10 }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/messaging/otp", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ sender_id: "Dojah", destination: "2348012345678", channel: "sms", length: 6, expiry: 10, }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/messaging/otp", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={ "sender_id": "Dojah", "destination": "2348012345678", "channel": "sms", "length": 6, "expiry": 10, }, ) data = res.json() ``` ```php PHP theme={null} true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ "Authorization: " . getenv("DOJAH_SECRET_KEY"), "AppId: " . getenv("DOJAH_APP_ID"), "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode([ "sender_id" => "Dojah", "destination" => "2348012345678", "channel" => "sms", "length" => 6, "expiry" => 10, ]), ]); $data = json_decode(curl_exec($ch), true); ``` ```json POST /api/v1/messaging/otp theme={null} { "entity": { "reference_id": "edd37ab5-48ec-4481-8cf9-ba5chu7c41f7", "destination": "2348012345678", "status": "SMS sent successfully" } } ``` # Send SMS Source: https://docs.dojah.io/api-reference/messaging/send-sms Send a plain text message over SMS or WhatsApp to one or more recipients with the Dojah Messaging API.
POST /api/v1/messaging/sms
Send a plain text message over SMS or WhatsApp to one or more recipients. The response returns a message\_id you can pass to Message Status to track delivery. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | ------------- | ------- | -------- | ---------------------------------------------------------------------------- | | `destination` | string | Yes | Recipient phone number. Send to several at once by comma-separating numbers. | | `message` | string | Yes | The body of the message to send. | | `channel` | string | Yes | Delivery channel: `sms`, `whatsapp`, or `voice`. | | `sender_id` | string | No | A registered Sender ID to send from. | | `priority` | boolean | No | Send in priority mode. Default `false`. | ## Response Returns an `entity` with the queued message’s identifiers. Keep the `message_id` — it’s what you pass to [Message Status](/api-reference/messaging/message-status). | Field | Type | Description | | -------------- | ------ | ------------------------------------------------------------------------ | | `status` | string | Queue status of the message, e.g. `Sent`. | | `mobile` | string | The recipient number the message was sent to. | | `message_id` | string | Unique ID for the message — pass it to Message Status to check delivery. | | `reference_id` | string | Reference for this send. | ## Errors | Code | Meaning | | ----- | ------------------------------------------------------------------------------------------------------------------- | | `400` | Bad request — a required field is missing or malformed. | | `401` | Unauthorized — check your `Authorization` key and `AppId`. | | `402` | Payment required — your wallet balance is too low. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `422` | Unprocessable — e.g. an unregistered `sender_id` or invalid `channel`. | | `429` | Too many requests — slow your request rate and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/messaging/sms" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "sender_id": "Dojah", "destination": "2348012345678", "channel": "sms", "message": "Your order has shipped." }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/messaging/sms", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ sender_id: "Dojah", destination: "2348012345678", channel: "sms", message: "Your order has shipped.", }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/messaging/sms", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={ "sender_id": "Dojah", "destination": "2348012345678", "channel": "sms", "message": "Your order has shipped.", }, ) data = res.json() ``` ```php PHP theme={null} true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ "Authorization: " . getenv("DOJAH_SECRET_KEY"), "AppId: " . getenv("DOJAH_APP_ID"), "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode([ "sender_id" => "Dojah", "destination" => "2348012345678", "channel" => "sms", "message" => "Your order has shipped.", ]), ]); $data = json_decode(curl_exec($ch), true); ``` ```json POST /api/v1/messaging/sms theme={null} { "entity": { "status": "Sent", "mobile": "2349069278034", "message_id": "dj_c8095767-c69f-4bd7-aa52-7cb469effb51", "reference_id": "cc7f9a23-959a-4708-ac6e-5cffec7682ba" } } ``` # Register a Sender ID Source: https://docs.dojah.io/api-reference/messaging/sender-id Register a custom SMS sender ID and fetch the sender IDs registered on your app.
POST /api/v1/messaging/sender\_id
Register a custom name to send SMS from (your Sender ID), and list the sender IDs registered on your app. This page covers two endpoints: register a sender ID and fetch your registered sender IDs. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | ----------- | ------ | -------- | --------------------------------------------------------------------- | | `sender_id` | string | Yes | The custom sender name to register. Must be fewer than 11 characters. | ## Response A `200` confirms the registration request under `entity.message`. The sender ID is *not* active until Dojah approves it — you’ll receive an email once it’s activated. See the panel on the right. ## Fetch registered Sender IDs List the sender IDs registered on your app, each with its activation status and creation time. This endpoint takes no query parameters. ```http GET /api/v1/messaging/sender_ids theme={null} curl "https://api.dojah.io/api/v1/messaging/sender_ids" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```json 200 — OK theme={null} { "entity": [ { "sender_id": "Dojah", "activated": true, "createdAt": "2020-10-30T09:54:17.145Z" } ] } ``` ## Errors | Code | Meaning | | ----- | ------------------------------------------------------------------------------------------------------------------- | | `400` | Bad request — a required field is missing or malformed. | | `401` | Unauthorized — check your `Authorization` key and `AppId`. | | `402` | Payment required — your wallet balance is too low. [Fund your wallet](/api-reference/core-concepts/wallet-billing). | | `422` | Unprocessable — e.g. an unregistered `sender_id` or invalid `channel`. | | `429` | Too many requests — slow your request rate and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/messaging/sender_id" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "sender_id": "MyBrand" }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/messaging/sender_id", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ sender_id: "MyBrand", }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/messaging/sender_id", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={ "sender_id": "MyBrand" }, ) data = res.json() ``` ```php PHP theme={null} true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ "Authorization: " . getenv("DOJAH_SECRET_KEY"), "AppId: " . getenv("DOJAH_APP_ID"), "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode([ "sender_id" => "MyBrand", ]), ]); $data = json_decode(curl_exec($ch), true); ``` ```json POST /api/v1/messaging/sender_id theme={null} { "entity": { "message": "Sender ID Request Successful, you will get an email once it's activated." } } ``` # Validate OTP Source: https://docs.dojah.io/api-reference/messaging/validate-otp Confirm a one-time passcode against the reference_id returned by Send OTP with the Dojah Messaging API.
GET /api/v1/messaging/otp/validate
Confirm the one-time passcode a user entered against the reference\_id returned by Send OTP. Returns whether the code is correct and still within its expiry window. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | -------------- | ------ | -------- | ----------------------------------------------------------------------------------- | | `code` | string | Yes | The OTP the user received and entered. | | `reference_id` | string | Yes | The `reference_id` returned when you sent the OTP — identifies which code to check. | ## Response Returns an `entity` whose `valid` flag is `true` when the code matches and has not expired, and `false` otherwise. | Field | Type | Description | | ------- | ------- | ---------------------------------------------------------------------------------- | | `valid` | boolean | `true` if the code is correct and unexpired; `false` if it is wrong or has lapsed. | ## Errors | Code | Meaning | | ----- | ------------------------------------------------------------------ | | `400` | Bad request — `code` or `reference_id` is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `422` | Unprocessable — the `reference_id` is unknown or already consumed. | | `429` | Too many requests — back off and retry. | ## Sandbox The OTP is always `1234` in sandbox — test with `code=1234` and the `reference_id` from [Send OTP](/api-reference/messaging/send-otp) against `https://sandbox.dojah.io`. See [Sandbox & test data](/api-reference/get-started/sandbox-test-data) for every test value. ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/messaging/otp/validate?code=1234&reference_id=edd37ab5-48ec-4481-8cf9-ba5chu7c41f7" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "code": "1234", "reference_id": "edd37ab5-48ec-4481-8cf9-ba5chu7c41f7", }); const url = "https://api.dojah.io/api/v1/messaging/otp/validate?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/messaging/otp/validate", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "code": "1234", "reference_id": "edd37ab5-48ec-4481-8cf9-ba5chu7c41f7", }, ) data = res.json() ``` ```php PHP theme={null} "1234", "reference_id" => "edd37ab5-48ec-4481-8cf9-ba5chu7c41f7", ]); $ch = curl_init("https://api.dojah.io/api/v1/messaging/otp/validate?" . $q); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: " . getenv("DOJAH_SECRET_KEY"), "AppId: " . getenv("DOJAH_APP_ID"), ], ]); $data = json_decode(curl_exec($ch), true); ``` ```json GET /api/v1/messaging/otp/validate theme={null} { "entity": { "valid": true } } ``` # Get verification Source: https://docs.dojah.io/api-reference/verifications/get-verification Fetch the complete result of a single verification by its reference ID — every check that ran, with its data, status, and message.
GET /api/v1/kyc/verification
Fetch the complete result of a single verification by its reference ID — every check that ran (ID, selfie, government data, AML, address) with its data, status, and message. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | -------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `reference_id` | string | Yes | The verification's reference ID, as shown on the dashboard or returned by [List verifications](/api-reference/verifications/list-verifications) (e.g. `DJ-31038041E0`). | ## Response Returns the full verification record. The top-level fields summarise the verification; the nested `data` object holds each individual check that ran, keyed by type — each with its own `data`, `status`, and `message`. | Field | Type | Description | | ---------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `reference_id` | string | The verification’s unique reference. | | `status` | boolean | Whether the verification completed successfully overall. | | `verification_status` | string | Status label — `Ongoing`, `Pending`, `Completed`, `Failed`, or `Abandoned`. See [Verification statuses](/api-reference/core-concepts/verification-statuses). | | `verification_type` | string | The identity type checked (e.g. `RC-NUMBER`, `BVN`, `NIN`). | | `verification_mode` | string | How the user was captured (e.g. `LIVENESS`). | | `id_type` | string | The government ID type used (e.g. `BVN`). | | `data` | object | Per-check breakdown — `id`, `email`, `selfie`, `government_data`, `business_data`, `additional_document`, and more. | | `aml` | object | AML screening result for the subject. | | `metadata` | object | Capture context — `ipinfo` (geo/ISP) and `device_info` (user agent). | | `selfie_url`, `id_url`, `back_url` | string | Links to captured media. **Expire \~1 hour** — see [File links & expiry](/api-reference/core-concepts/file-links-expiry). | ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------- | | `400` | Bad request — `reference_id` is missing or malformed. | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `404` | No verification found for the supplied `reference_id`. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/kyc/verification?reference_id=DJ-31038041E0" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "reference_id": "DJ-31038041E0", }); const url = "https://api.dojah.io/api/v1/kyc/verification?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/kyc/verification", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "reference_id": "DJ-31038041E0" }, ) data = res.json() ``` ```json GET /api/v1/kyc/verification theme={null} { "status": true, "reference_id": "DJ-31038041E0", "id_type": "BVN", "verification_status": "Completed", "verification_type": "RC-NUMBER", "verification_mode": "LIVENESS", "message": "Successfully completed the verification.", "aml": { "status": false }, "data": { "id": { "data": { "id_url": "https://images.dojah.io/id_sample_id.jpg", "id_data": { "last_name": "Musa", "first_name": "John", "document_type": "National ID", "document_number": "123456789" } }, "status": true, "message": "Successfully verified your id" }, "selfie": { "data": { "selfie_url": "https://images.dojah.io/selfie.jpg" }, "status": true, "message": "Successfully validated your liveness" }, "government_data": { "data": { "bvn": { … }, "nin": { … } }, "status": true } }, "metadata": { "ipinfo": { "city": "Lagos", "country": "Nigeria" }, "device_info": "Mozilla/5.0 …" }, "selfie_url": "https://images.dojah.io/selfie.jpg", "verification_url": "https://app.dojah.io/verifications/bio-data/49fd74a4-…" } ``` # List verifications Source: https://docs.dojah.io/api-reference/verifications/list-verifications Retrieve a paginated list of every verification run on your account, with optional search, date, and status filters.
GET /api/v1/kyc/verifications
Retrieve a paginated list of every verification run on your account, with optional search, date-range, and status filters. Use it to reconcile results, build an audit view, or poll for completed checks. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | ---------------------------------------------------------------------- | | `term` | string | No | Search by email address or `reference_id`. | | `start` | string | No | Start-date filter, format `YYYY-MM-DD`. | | `end` | string | No | End-date filter, format `YYYY-MM-DD`. | | `status` | string | No | Filter by status — one of `Ongoing`, `Pending`, `Completed`, `Failed`. | ## Response Returns an `entity` object with a `data` array of verification summaries and a `meta` object for pagination. | Field | Type | Description | | --------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | `data[].reference_id` | string | Unique reference for the verification — pass it to [Get verification](/api-reference/verifications/get-verification) for the full result. | | `data[].verificationStatus` | string | Current status (`Ongoing`, `Pending`, `Completed`, `Failed`, `Abandoned`). See [Verification statuses](/api-reference/core-concepts/verification-statuses). | | `data[].datetime` | string | When the verification was created. | | `data[].full_name` | string | Resolved full name of the verified individual (when applicable). | | `data[].selfieUrl` | string | Link to the captured selfie. **Expires \~1 hour** — see [File links & expiry](/api-reference/core-concepts/file-links-expiry). | | `meta.total_count` | number | Total verifications matching the filter. | | `meta.item_per_page` | number | Items returned per page. | | `meta.current_page` | number | The current page index. | ## Errors | Code | Meaning | | ----- | ----------------------------------------------------------------- | | `400` | Bad request — a filter value is malformed (e.g. an invalid date). | | `401` | Unauthorized — check your key and `AppId` (no `Bearer` prefix). | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/kyc/verifications?status=Completed" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const params = new URLSearchParams({ "status": "Completed", }); const url = "https://api.dojah.io/api/v1/kyc/verifications?" + params; const res = await fetch(url, { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/kyc/verifications", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, params={ "status": "Completed" }, ) data = res.json() ``` ```json GET /api/v1/kyc/verifications theme={null} { "entity": { "data": [ { "reference_id": "DJ-479A8E4159", "app_id": "64d4ab23b2793b00401a2993", "verificationStatus": "Completed", "datetime": "2024-07-19 17:06:05", "environment": "production", "first_name": "JOHN", "last_name": "MUSA", "full_name": "JOHN DOE MUSA", "business_name": "ANON Enterprises", "selfieUrl": "https://dojah-kyc.s3.../sandbox_kyc_image.png", "verificationUrl": "https://app.dojah.io/verifications/bio-data/DJ-479A8E4159" } ], "meta": { "total_count": 107, "item_per_page": 10, "current_page": 1 } } } ``` # Get wallet balance Source: https://docs.dojah.io/api-reference/wallet-utilities/get-balance Fetch your Dojah wallet balance — a simple GET that returns the funds available to your app, so you can monitor spend and avoid 402 errors.
GET /api/v1/balance
Fetch your Dojah wallet balance. Every paid API call draws down this balance, so poll it to monitor spend or guard against a 402 Insufficient wallet balance before a batch of requests. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Query parameters This endpoint takes no query parameters — authentication is by header only. Your `AppId` identifies which wallet to read. ## Response Returns an `entity` with a single `wallet_balance` field — a string amount in your account currency (NGN). | Field | Type | Description | | ---------------- | ------ | ----------------------------------------- | | `wallet_balance` | string | Funds currently available in your wallet. | ## Errors | Code | Meaning | | ----- | ----------------------------------------------------------------------------------- | | `400` | Invalid request parameters. | | `401` | App couldn't be validated — check your secret key and `AppId` (no `Bearer` prefix). | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/balance" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/balance", { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/balance", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, ) data = res.json() ``` ```json GET /api/v1/balance theme={null} { "entity": { "wallet_balance": "14132.00" } } ``` # States & LGAs Source: https://docs.dojah.io/api-reference/wallet-utilities/states-lgas Nigerian geography lookups — fetch all states, then the Local Government Areas within a state. For address forms, validation, and location-based logic.
GET /api/v1/general/states
Two utility lookups for Nigerian geography: fetch all 36 states (plus the FCT), then fetch the Local Government Areas within any one of them. Use them to populate address forms, validate user input, and drive location-based logic. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## List of states Call `GET /api/v1/general/states` with no query parameters. Returns a `states` array of every Nigerian state name (including the Federal Capital Territory). ```json 200 — OK theme={null} { "states": [ "Abia", "Adamawa", "Akwa Ibom", "Anambra", "Bauchi", "Bayelsa", "Benue", "Borno", "Cross River", "Delta", "Ebonyi", "Edo", "Ekiti", "Enugu", "Federal Capital Territory", "Gombe", "Imo", "Jigawa", "Kaduna", "Kano", "Katsina", "Kebbi", "Kogi", "Kwara", "Lagos", "Nasarawa", "Niger", "Ogun", "Ondo", "Osun", "Oyo", "Plateau", "Rivers", "Sokoto", "Taraba", "Yobe", "Zamfara" ] } ``` ## List of LGAs Call `GET /api/v1/general/states/lgas` with a `state` query parameter (a state name from the list above). Returns an `lgas` array of the Local Government Areas in that state. | Parameter | Type | Required | Description | | --------- | ------ | -------- | -------------------------------------------------------------------------- | | `state` | string | Yes | The state name obtained from the [states](#states) endpoint, e.g. `Lagos`. | ```http GET /api/v1/general/states/lgas theme={null} curl --request GET "https://api.dojah.io/api/v1/general/states/lgas?state=Lagos" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```json 200 — OK theme={null} { "lgas": [ "Agege", "Ajeromi-Ifelodun", "Alimosho", "Amuwo-Odofin", "Apapa", "Badagry", "Epe", "Eti-Osa", "Ibeju-Lekki", "Ifako-Ijaiye", "Ikeja", "Ikorodu", "Kosofe", "Lagos Island", "Lagos Mainland", "Mushin", "Ojo", "Oshodi-Isolo", "Shomolu", "Surulere" ] } ``` ## Errors | Code | Meaning | | ----- | -------------------------------------------------------------------------------------------------- | | `400` | Bad request — for the LGA lookup, the `state` parameter is missing or not a recognised state name. | | `401` | Unauthorized — check your secret key and `AppId` (no `Bearer` prefix). | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl --request GET \ "https://api.dojah.io/api/v1/general/states" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} // States — no params. For LGAs add ?state=Lagos const res = await fetch("https://api.dojah.io/api/v1/general/states", { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests # States — no params. LGAs: params={"state": "Lagos"} res = requests.get( "https://api.dojah.io/api/v1/general/states", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, ) data = res.json() ``` ```json GET /api/v1/general/states theme={null} { "states": [ "Abia", "Adamawa", "Akwa Ibom", "…", "Lagos", "…", "Zamfara" ] } ``` # Delete a webhook subscription Source: https://docs.dojah.io/api-reference/webhook-management/delete-subscription Remove a webhook subscription by service name to stop Dojah from delivering its events.
DELETE /api/v1/webhook/delete
Stop delivering events for a service by removing its subscription. Identify the subscription by its service name; the matching webhook for the calling environment is removed. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `service` | string | Yes | The service whose subscription to delete — e.g. `sms`, `kyc_widget`, `address`. The subscription removed is the one for the environment of the key you call with. | ## Response A `200` returns a confirmation string in `entity`. Dojah stops sending events for that service immediately. To re-enable delivery later, [subscribe](/api-reference/webhook-management/subscribe) again. While a subscription is live, always confirm each delivery’s signature — see [Webhooks & signatures](/api-reference/core-concepts/webhooks-signatures#verify-events-are-from-dojah). ## Errors | Code | Meaning | | ----- | ---------------------------------------------------------------------- | | `400` | Bad request — `service` is missing or isn't a recognised value. | | `401` | Unauthorized — check your secret key and `AppId` (no `Bearer` prefix). | | `404` | No subscription found for that service in this environment. | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl -X DELETE "https://api.dojah.io/api/v1/webhook/delete" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "service": "kyc_widget" }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/webhook/delete", { method: "DELETE", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ service: "kyc_widget", }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.delete( "https://api.dojah.io/api/v1/webhook/delete", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], "Content-Type": "application/json", }, json={ "service": "kyc_widget", }, ) data = res.json() ``` ```json DELETE /api/v1/webhook/delete theme={null} { "entity": "webhook deleted successfully" } ``` # Fetch webhook subscriptions Source: https://docs.dojah.io/api-reference/webhook-management/fetch-subscriptions List every webhook registered for your Dojah app — callback URL, service, environment, and last delivery status.
GET /api/v1/webhook/fetch
List every webhook currently registered for your app — each with its callback URL, the service it listens to, the environment, and the last delivery status. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | ## Parameters None. The subscriptions returned are those of the app and environment tied to the key you call with — call with your sandbox key for sandbox subscriptions, your live key for live ones. ## Response Returns `entity` as an array of subscription objects. Each carries: | Field | Description | | ------------------------------- | ---------------------------------------------------------------------------------------------- | | `app_id` | The app the subscription belongs to. | | `endpoint` | The callback URL receiving events. | | `environment` | `live` or `sandbox`. | | `service` | The subscribed service — e.g. `sms`, `kyc_widget`. | | `confirmation_status` | Status of the most recent delivery (e.g. `DELIVERED`), or `null` if nothing has been sent yet. | | `date_created` / `date_updated` | When the subscription was created and last changed. | ## Errors | Code | Meaning | | ----- | ---------------------------------------------------------------------- | | `401` | Unauthorized — check your secret key and `AppId` (no `Bearer` prefix). | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl "https://api.dojah.io/api/v1/webhook/fetch" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/webhook/fetch", { headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, }, }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.get( "https://api.dojah.io/api/v1/webhook/fetch", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, ) data = res.json() ``` ```json GET /api/v1/webhook/fetch theme={null} { "entity": [ { "app_id": "61e6bef823664a003647505f", "endpoint": "https://yourapp.com/webhooks/dojah", "environment": "live", "service": "sms", "confirmation_status": "DELIVERED", "date_created": "2022-01-18T14:31:36.810231+01:00", "date_updated": "2022-01-18T14:31:36.810319+01:00" } ] } ``` # Subscribe to a webhook Source: https://docs.dojah.io/api-reference/webhook-management/subscribe Register a callback URL so Dojah POSTs verification, SMS, address, and AML events to your server in real time.
POST /api/v1/webhook/subscribe
Register a callback URL so Dojah POSTs events to your server as they happen — verification results, SMS delivery, address checks, and AML monitoring hits. One subscription per service, per environment. ## Headers | Header | Required | Description | | --------------- | -------- | --------------------------------------------------- | | `Authorization` | Yes | Your app's secret key, sent as-is — *not* `Bearer`. | | `AppId` | Yes | The App ID from your dashboard. | | `Content-Type` | Yes | `application/json` | ## Body parameters | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------------------------------------------------------------------ | | `webhook` | string | Yes | The callback URL where Dojah will `POST` events. Must be publicly reachable over HTTPS. | | `service` | string | Yes | Which service to subscribe to. One of `kyc_widget`, `sms`, `address`, or `AML Monitoring`. | ## Response A `200` returns a confirmation string in `entity`. Dojah then delivers each event as a `POST` to your URL. Payloads arrive at the top level with **no `entity` wrapper** — verify them before trusting the contents. ## Verifying deliveries Every webhook request carries an `x-dojah-signature` (HMAC-SHA256 of the JSON payload, keyed with your secret) and originates from Dojah’s IP `135.119.89.106`. Confirm the signature on every request before acting on it. See [Webhooks & signatures](/api-reference/core-concepts/webhooks-signatures#verify-events-are-from-dojah) for the full verification recipe and payload reference. Any file URLs inside a payload expire in about an hour — [download them promptly](/api-reference/core-concepts/file-links-expiry). ## Errors | Code | Meaning | | ----- | --------------------------------------------------------------------------------------- | | `400` | Bad request — `webhook` or `service` is missing, or `service` isn't a recognised value. | | `401` | Unauthorized — check your secret key and `AppId` (no `Bearer` prefix). | | `429` | Too many requests — back off and retry. | ```bash cURL theme={null} curl -X POST "https://api.dojah.io/api/v1/webhook/subscribe" \ -H "Authorization: {{secret_key}}" \ -H "AppId: {{app_id}}" \ -H "Content-Type: application/json" \ -d '{ "webhook": "https://yourapp.com/webhooks/dojah", "service": "kyc_widget" }' ``` ```js Node.js theme={null} const res = await fetch("https://api.dojah.io/api/v1/webhook/subscribe", { method: "POST", headers: { Authorization: process.env.DOJAH_SECRET_KEY, AppId: process.env.DOJAH_APP_ID, "Content-Type": "application/json", }, body: JSON.stringify({ webhook: "https://yourapp.com/webhooks/dojah", service: "kyc_widget", }), }); const data = await res.json(); ``` ```python Python theme={null} import os, requests res = requests.post( "https://api.dojah.io/api/v1/webhook/subscribe", headers={ "Authorization": os.environ["DOJAH_SECRET_KEY"], "AppId": os.environ["DOJAH_APP_ID"], }, json={ "webhook": "https://yourapp.com/webhooks/dojah", "service": "kyc_widget", }, ) data = res.json() ``` ```json POST /api/v1/webhook/subscribe theme={null} { "entity": "Webhook added successfully" } ``` # Android (Kotlin) Source: https://docs.dojah.io/api-reference/widget-sdks/android-kotlin Launch Dojah's verification flow in an Android app with the Dojah Android SDK, distributed via JitPack. Minimum SDK 21. Launch Dojah’s verification flow in an Android app with the Dojah Android SDK (distributed via JitPack). Minimum SDK 21. Mobile SDKs launch by **WidgetID** (from [EasyOnboard](/dashboard-guide/workflows/easyonboard)). See [Choosing an SDK](/api-reference/widget-sdks/choosing-an-sdk). ## Install Add JitPack to your repositories and the dependency to your module `build.gradle`, then set `android.enableJetifier=true` in `gradle.properties`: ```groovy build.gradle theme={null} repositories { maven { url "https://jitpack.io" } } implementation 'com.github.dojah-inc:sdk-kotlin:' ``` ## Initialize ```kotlin MainActivity.kt theme={null} DojahSdk.with(context).launch( "your_widget_id", // required referenceId = "DJ-123456", // optional email = "user@email.com", // optional ) ``` `DojahSdk` lives in `com.dojah_inc.dojah_android_sdk`, and `context` is your activity context. ## Resources * [GitHub — dojah-inc/sdk-kotlin](https://github.com/dojah-inc/sdk-kotlin) (SDK and example app) * [JitPack — latest version](https://jitpack.io/#dojah-inc/sdk-kotlin) · [GitHub Packages](https://github.com/dojah-inc/sdk-kotlin/packages/2174016) * [Choosing an SDK](/api-reference/widget-sdks/choosing-an-sdk) · [EasyOnboard](/dashboard-guide/workflows/easyonboard) # Choosing an SDK Source: https://docs.dojah.io/api-reference/widget-sdks/choosing-an-sdk Pick between Dojah's widget SDKs, which render the hosted verification UI inside your app, and the API clients that call the REST endpoints from your server. Two ways to integrate in code: **widget SDKs** render Dojah’s hosted verification UI inside your app, while **API clients** call the REST endpoints from your server. Here’s how to pick — plus the configuration and response model shared by every widget SDK. ## Widget SDKs vs API clients | | Widget SDKs | API clients | | -------- | ----------------------------------------- | ------------------------- | | Runs on | The client (web / mobile app) | Your server | | UI | Dojah’s hosted flow, built in EasyOnboard | None — you build your own | | Uses | App ID + **public** key | App ID + **secret** key | | Best for | End-to-end onboarding with no UI work | Direct, individual checks | ## Available SDKs **Widget SDKs** — drop-in verification UI: * [Web (JavaScript)](/api-reference/widget-sdks/web-javascript) * [React](/api-reference/widget-sdks/react) * [React Native](/api-reference/widget-sdks/react-native) * [Flutter](/api-reference/widget-sdks/flutter) * [iOS (Swift)](/api-reference/widget-sdks/ios-swift) * [Android (Kotlin)](/api-reference/widget-sdks/android-kotlin) **API clients** — call the REST API from your backend: * [PHP](/api-reference/api-clients/php) · [Java](/api-reference/api-clients/java) · [Python](/api-reference/api-clients/python) · [Go](/api-reference/api-clients/go) · [TypeScript](/api-reference/api-clients/typescript) ## Packages and repositories | Platform | Package | Source | | ------------------- | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | Web (JavaScript) | [widget.dojah.io/widget.js](https://widget.dojah.io/widget.js) | — | | React | [dojah-kyc-sdk-react](https://www.npmjs.com/package/dojah-kyc-sdk-react) | [React-Js-sdk](https://github.com/dojah-inc/React-Js-sdk) | | React Native (CLI) | [dojah-kyc-sdk-react\_native](https://www.npmjs.com/package/dojah-kyc-sdk-react_native) | [dojah-react-native-sdk](https://github.com/dojah-inc/dojah-react-native-sdk) | | React Native (Expo) | [dojah-kyc-sdk-react-expo](https://www.npmjs.com/package/dojah-kyc-sdk-react-expo) | [dojah\_kyc\_sdk\_rn\_expo](https://github.com/dojah-inc/dojah_kyc_sdk_rn_expo) | | Flutter (native) | [dojah\_kyc\_sdk\_flutter](https://pub.dev/packages/dojah_kyc_sdk_flutter) | [Dojah-flutter-sdk](https://github.com/dojah-inc/Dojah-flutter-sdk) | | Flutter (WebView) | [flutter\_dojah\_kyc](https://pub.dev/packages/flutter_dojah_kyc) | [Flutter-SDK](https://github.com/dojah-inc/Flutter-SDK) | | iOS (Swift) | SPM / CocoaPods | [sdk-swift](https://github.com/dojah-inc/sdk-swift) · [releases](https://github.com/dojah-inc/sdk-swift/releases) | | Android (Kotlin) | [JitPack](https://jitpack.io/#dojah-inc/sdk-kotlin) | [sdk-kotlin](https://github.com/dojah-inc/sdk-kotlin) | ## Configuration options The **web** widgets (JavaScript, React, and the Flutter WebView build) take an options object: | Option | Type | Required | Description | | ----------- | ------ | -------- | ------------------------------------------------------------------------ | | `app_id` | string | Yes | Your application’s App ID from the dashboard. | | `p_key` | string | Yes | Your public key (safe to use on the client). | | `type` | string | Yes | Widget type — `custom`, `verification`, `identification`, or `liveness`. | | `config` | object | No | Flow config, primarily `{ widget_id }` from EasyOnboard. | | `user_data` | object | No | Prefill `first_name`, `last_name`, `dob`, `residence_country`, `email`. | | `gov_data` | object | No | Prefill government IDs such as `bvn`, `nin`. | | `metadata` | object | No | Any key/value pairs echoed back to you and in webhooks. | **Mobile SDKs are simpler.** React Native, Flutter, iOS and Android launch with just a **WidgetID** (plus an optional reference ID and email). The whole flow — checks, branding, data collection — is configured in [EasyOnboard](/dashboard-guide/workflows/easyonboard) and identified by that WidgetID. ## Handling the response The web widgets report flow events through callbacks: | Callback | When it fires | | --------------------- | -------------------------------------------------------------- | | `onSuccess(response)` | The flow finished and submitted — `response` holds the result. | | `onError(err)` | Something failed during the flow. | | `onClose()` | The user closed the widget. | Always confirm a verification **server-side** via [webhooks](/api-reference/core-concepts/webhooks-signatures) — never trust the client `success` event alone. Mobile flows report results via webhooks and the EasyOnboard [Verifications](/dashboard-guide/workflows/easyonboard/verifications) tab. # Flutter Source: https://docs.dojah.io/api-reference/widget-sdks/flutter Launch Dojah's verification flow in a Flutter app with the dojah_kyc_sdk_flutter package. Launch Dojah’s verification flow in a Flutter app with the `dojah_kyc_sdk_flutter` package. Mobile SDKs launch by **WidgetID** (from [EasyOnboard](/dashboard-guide/workflows/easyonboard)). A WebView build, `flutter_dojah_kyc`. See [Choosing an SDK](/api-reference/widget-sdks/choosing-an-sdk). ## Install ```bash Terminal theme={null} flutter pub add dojah_kyc_sdk_flutter ``` ## Initialize ```dart main.dart theme={null} import 'package:dojah_kyc_sdk_flutter/dojah_kyc_sdk_flutter.dart'; DojahKyc.launch( "your_widget_id", // required referenceId: "DJ-123456", // optional email: "user@email.com", // optional ) ``` ## Resources **Native SDK** * [pub.dev — dojah\_kyc\_sdk\_flutter](https://pub.dev/packages/dojah_kyc_sdk_flutter) * [GitHub — dojah-inc/Dojah-flutter-sdk](https://github.com/dojah-inc/Dojah-flutter-sdk) · [example app](https://github.com/dojah-inc/Dojah-flutter-sdk/tree/main/example) **WebView SDK** * [pub.dev — flutter\_dojah\_kyc](https://pub.dev/packages/flutter_dojah_kyc) * [GitHub — dojah-inc/Flutter-SDK](https://github.com/dojah-inc/Flutter-SDK) **Underlying native SDKs** * [GitHub — dojah-inc/sdk-swift](https://github.com/dojah-inc/sdk-swift) · [releases](https://github.com/dojah-inc/sdk-swift/releases) * [GitHub — dojah-inc/sdk-kotlin](https://github.com/dojah-inc/sdk-kotlin) · [JitPack](https://jitpack.io/#dojah-inc/sdk-kotlin) # iOS (Swift) Source: https://docs.dojah.io/api-reference/widget-sdks/ios-swift Present Dojah's verification flow in an iOS app with the Dojah Swift SDK, added through Swift Package Manager. Present Dojah’s verification flow in an iOS app with the Dojah Swift SDK, added via Swift Package Manager. Mobile SDKs launch by **WidgetID** (from [EasyOnboard](/dashboard-guide/workflows/easyonboard)). See [Choosing an SDK](/api-reference/widget-sdks/choosing-an-sdk). ## Install Add the package in Xcode (**File → Add Packages…**) using the repository URL, on the `main` branch: ```swift Swift Package Manager theme={null} https://github.com/dojah-inc/sdk-swift.git ``` Add the usage descriptions your flow needs to `Info.plist`: `NSCameraUsageDescription`, `NSMicrophoneUsageDescription` (video), and `NSLocationWhenInUseUsageDescription` (location). ## Initialize Call `DojahWidgetSDK.initialize` with your WidgetID and a `UINavigationController` to present on: ```swift ViewController.swift theme={null} DojahWidgetSDK.initialize( widgetID: "your_widget_id", // required referenceID: "DJ-123456", // optional emailAddress: "user@email.com", // optional navController: navigationController // required ) ``` ## CocoaPods If your project uses CocoaPods rather than Swift Package Manager — which is how the React Native and Flutter SDKs pull iOS in — add the pod from the `pod-package` branch: ```ruby Podfile theme={null} pod 'Realm', '~> 10.52.2', :modular_headers => true pod 'DojahWidget', :git => 'https://github.com/dojah-inc/sdk-swift.git', :branch => 'pod-package' ``` ## Resources * [GitHub — dojah-inc/sdk-swift](https://github.com/dojah-inc/sdk-swift) (SDK and example app) * [Releases and changelog](https://github.com/dojah-inc/sdk-swift/releases) — check here before pinning a version * [Choosing an SDK](/api-reference/widget-sdks/choosing-an-sdk) · [EasyOnboard](/dashboard-guide/workflows/easyonboard) # React Source: https://docs.dojah.io/api-reference/widget-sdks/react Launch Dojah's hosted verification flow inside a React app with the Dojah React SDK. Drop Dojah’s hosted verification flow into a React app with the `dojah-kyc-sdk-react` component. You design the flow once in [EasyOnboard](/dashboard-guide/workflows/easyonboard), then render it by passing your keys and widget type. **Which SDK?** This is the *widget* SDK — it renders Dojah’s UI. To call endpoints directly from your server, use an [API client](/api-reference/widget-sdks/choosing-an-sdk#widget-sdks-vs-api-clients) instead. Not sure? See [Choosing an SDK](/api-reference/widget-sdks/choosing-an-sdk). ## Requirements * **React 19** or later (declared as a peer dependency). * An **App ID** and **public key** from your [dashboard](/dashboard-guide/integrations/developers#api-tokens). * A published **widget** (EasyOnboard flow) whose `widget_id` you’ll pass in. ## Install Add the package with npm or yarn: ```bash Terminal theme={null} # npm npm install dojah-kyc-sdk-react --save # or yarn yarn add dojah-kyc-sdk-react ``` ## Initialize Import the component and render it with your credentials and a `response` handler. Passing all of `userData` auto-skips the user-data screen. ```jsx App.jsx theme={null} import React from 'react' import Dojah from 'dojah-kyc-sdk-react' const App = () => { const appID = "your_app_id" const publicKey = "your_public_key" const type = "custom" const config = { widget_id: "your_widget_id" } const userData = { first_name: "Chijioke", last_name: "", dob: "2022-05-01" } const govData = { bvn: "", nin: "" } const metadata = { user_id: "121" } const referenceId = "unique-ref-12345" const response = (type, data) => { if (type === "success") console.log("verified", data) if (type === "error") console.log("failed", data) if (type === "close") console.log("widget closed") } return ( ) } export default App ``` ## Props | Prop | Type | Required | Description | | ------------- | -------- | -------- | ------------------------------------------------------------------------------ | | `appID` | string | Yes | Your application’s App ID. | | `publicKey` | string | Yes | Your account public key (safe for the client). | | `type` | string | Yes | Widget type, e.g. `custom`, `verification`, `liveness`. | | `response` | function | Yes | Callback `(type, data)` for flow events — see below. | | `config` | object | No | Flow config, primarily `{ widget_id }` from EasyOnboard. | | `userData` | object | No | Prefill `first_name`, `last_name`, `dob`. Full set skips the user-data screen. | | `govData` | object | No | Prefill government IDs such as `bvn`, `nin`. | | `metadata` | object | No | Any key/value pairs echoed back to you and in webhooks. | | `referenceId` | string | No | Your unique reference for this session (use >10 chars). | ## Handling the response The `response` callback fires with a `type` string as the user moves through the flow: | `type` | When it fires | | --------- | --------------------------------- | | `loading` | The widget is initializing. | | `begin` | The user has started the flow. | | `success` | The flow finished and submitted. | | `error` | Something failed during the flow. | | `close` | The user closed the widget. | **Don’t trust the client for the final decision.** A `success` event means the flow completed — not that the user passed. Confirm the outcome from your backend using the `reference_id` (via [Get verification](/api-reference/verifications/get-verification) or a [webhook](/api-reference/core-concepts/webhooks-signatures)) before granting access. ## Theming & branding Colors, logo, and which steps appear are configured on the **flow itself** in EasyOnboard, not in code — the component just renders the published `widget_id`. To restyle the flow, edit it in the dashboard and republish; no app changes needed. **Note.** Switch `appID` and `publicKey` to your live keys before shipping to production — sandbox keys won’t bill or return real data. ## Resources * [GitHub — dojah-inc/React-Js-sdk](https://github.com/dojah-inc/React-Js-sdk) * [npm — dojah-kyc-sdk-react](https://www.npmjs.com/package/dojah-kyc-sdk-react) * [Choosing an SDK](/api-reference/widget-sdks/choosing-an-sdk) · Hosted flows (EasyOnboard) # React Native Source: https://docs.dojah.io/api-reference/widget-sdks/react-native Launch Dojah's verification flow in a React Native app — with the bare CLI package or the Expo package, including EAS Build for iOS without Xcode. Launch Dojah’s verification flow in a React Native app — one codebase for iOS and Android. There are two packages: one for bare React Native CLI projects and one for Expo projects. Mobile SDKs launch by **WidgetID** — you design the flow in [EasyOnboard](/dashboard-guide/workflows/easyonboard) and its WidgetID identifies it. See [Choosing an SDK](/api-reference/widget-sdks/choosing-an-sdk). ## Pick your package | Your project | Package | Launch with | | ----------------------- | ---------------------------- | ---------------------- | | React Native CLI (bare) | `dojah-kyc-sdk-react_native` | `launchDojahKyc()` | | Expo | `dojah-kyc-sdk-react-expo` | `DojahKycSdk.launch()` | Both packages contain native code, so **the flow cannot run in Expo Go**. Expo projects need a [development build](#build-with-eas-no-xcode-required) — either from EAS Build or from a local `npx expo run:ios` / `run:android`. Requirements are the same either way: **iOS 14+** and **Android SDK 21+**. ## React Native CLI ### Install ```bash Terminal theme={null} npm install dojah-kyc-sdk-react_native # or yarn add dojah-kyc-sdk-react_native ``` ### iOS setup Add the Dojah pods to your app target in `ios/Podfile`, then install them: ```ruby ios/Podfile theme={null} target 'YourApp' do # ... pod 'Realm', '~> 10.52.2', :modular_headers => true pod 'DojahWidget', :git => 'https://github.com/dojah-inc/sdk-swift.git', :branch => 'pod-package' end ``` ```bash Terminal theme={null} cd ios && pod install ``` Add the usage descriptions your flow needs to `Info.plist`: `NSCameraUsageDescription`, `NSMicrophoneUsageDescription` (video), and `NSLocationWhenInUseUsageDescription` (address/location checks). The SDK presents itself from a navigation controller, so your root view must be inside one. In `AppDelegate.mm`: ```objc AppDelegate.mm theme={null} #import #import - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"YourApp" initialProperties:nil]; UIViewController *rootViewController = [UIViewController new]; rootViewController.view = rootView; UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController]; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; self.window.rootViewController = navigationController; [self.window makeKeyAndVisible]; return YES; } ``` Replace `@"YourApp"` with your app’s registered module name. ### Android setup Add JitPack to your repositories — in `android/build.gradle` or `android/settings.gradle`: ```groovy android/build.gradle theme={null} allprojects { repositories { maven { url "https://jitpack.io" } } } ``` Permissions ship with the package, so there’s nothing to add to your manifest. ### Launch the flow ```js App.js theme={null} import { launchDojahKyc } from 'dojah-kyc-sdk-react_native' launchDojahKyc( "your_widget_id", // required "DJ-123456", // optional reference ID "user@email.com" // optional email ) ``` Pass `null` for the reference ID and email if you aren’t using them. ## Expo ### Install ```bash Terminal theme={null} npx expo install dojah-kyc-sdk-react-expo expo-build-properties ``` ### Configure app.json Add the Dojah config plugin, the iOS usage descriptions, and the extra pods the native SDK needs: ```json app.json theme={null} { "expo": { "ios": { "infoPlist": { "NSCameraUsageDescription": "We use the camera to capture your ID and selfie.", "NSMicrophoneUsageDescription": "We use the microphone to record liveness videos.", "NSPhotoLibraryUsageDescription": "We use your photo library to upload documents.", "NSLocationWhenInUseUsageDescription": "We use your location to verify your address." } }, "plugins": [ "dojah-kyc-sdk-react-expo", [ "expo-build-properties", { "android": { "compileSdkVersion": 36, "targetSdkVersion": 36, "buildToolsVersion": "36.0.0" }, "ios": { "deploymentTarget": "15.1", "extraPods": [ { "name": "Realm", "version": "~> 10.52.2", "modular_headers": true }, { "name": "DojahWidget", "git": "https://github.com/dojah-inc/sdk-swift.git", "branch": "pod-package" } ] } } ] ] } } ``` The Dojah config plugin already raises `compileSdkVersion`, `targetSdkVersion`, `buildToolsVersion`, the Android Gradle Plugin (8.9.1+) and the Gradle wrapper during prebuild — it never lowers values you set higher. The `expo-build-properties` Android block above just pins them explicitly. Then generate the native projects: ```bash Terminal theme={null} npx expo prebuild ``` Skip this step if you build with EAS and don’t keep `ios/` and `android/` in your repo — EAS runs prebuild on the build worker for you. ### Launch the flow `DojahKycSdk.launch()` returns a promise that resolves to the flow’s exit status: ```js App.js theme={null} import DojahKycSdk from 'dojah-kyc-sdk-react-expo' const status = await DojahKycSdk.launch( "your_widget_id", // required "DJ-123456", // optional reference ID "user@email.com", // optional email { userData: { firstName: "John", lastName: "Doe", dob: "1990-01-01" }, govData: { bvn: "", nin: "" }, metadata: { user_id: "121" }, } ) switch (status) { case 'approved': break // all steps completed case 'pending': break // awaiting review case 'failed': break // a check did not pass case 'closed': break // user exited the flow } ``` The optional fourth argument also accepts `govId`, `location`, `businessData`, and `address`. **Don’t trust the client for the final decision.** `approved` means the user finished the flow, not that they passed every check. Confirm the outcome server-side with the `reference_id` — via [Get verification](/api-reference/verifications/get-verification) or a [webhook](/api-reference/core-concepts/webhooks-signatures) — before granting access. ## Build with EAS (no Xcode required) [EAS Build](https://docs.expo.dev/build/introduction/) compiles your app on Expo’s hosted macOS and Linux workers. That means you can produce an installable — and store-ready — iOS build from Windows or Linux without a Mac or a local Xcode install. It’s the recommended path for Expo projects using the Dojah SDK, since the SDK’s native code rules out Expo Go. ```bash Terminal theme={null} npm install -g eas-cli npx expo install expo-dev-client eas login ``` `expo-dev-client` is what makes a custom build usable as a development client — you keep fast refresh and the dev menu while running your own native code. Generate `eas.json`, then define the profiles you need: ```bash Terminal theme={null} eas build:configure ``` ```json eas.json theme={null} { "build": { "development": { "developmentClient": true, "distribution": "internal" }, "ios-simulator": { "extends": "development", "ios": { "simulator": true } }, "production": { "autoIncrement": true, "ios": { "resourceClass": "large" } } }, "submit": { "production": {} } } ``` Use `ios-simulator` when you just want to run the flow on an iOS Simulator — those builds need no Apple Developer account. The `development` profile produces a device build, which does. `resourceClass: "large"` is optional; it speeds up the long CocoaPods step (Realm plus the Dojah pod) and isn’t available on the free plan. ```bash Terminal theme={null} eas device:create ``` This registers a device UDID with your Apple team so the ad hoc provisioning profile covers it. Skip it for simulator builds. EAS runs `npx expo prebuild` on the worker, so everything in the `app.json` plugin block above is applied there — you don’t need to commit native folders. If you *have* committed `ios/` and `android/`, EAS uses them as-is and skips prebuild. In that case run `npx expo prebuild --clean` locally and commit the result whenever you change your Dojah or build-properties config. ```bash Terminal theme={null} # iOS, installable on registered devices eas build --platform ios --profile development # iOS Simulator build (.app) eas build --platform ios --profile ios-simulator # Android .apk for devices and emulators eas build --platform android --profile development ``` On the first iOS build, EAS offers to generate and store your distribution certificate and provisioning profile — accept it, or supply your own credentials. Build logs stream in the terminal and stay available on your project’s page at [expo.dev](https://expo.dev). When the build finishes, the CLI prompts to install it on a connected device or a running simulator. Then start the bundler: ```bash Terminal theme={null} npx expo start --dev-client ``` Your app now launches the real Dojah flow. JavaScript changes reload instantly — you only rebuild when native dependencies change. ```bash Terminal theme={null} eas build --platform ios --profile production eas submit --platform ios --latest ``` `eas submit` uploads the binary to App Store Connect (or Google Play with `--platform android`) from the same machine — again, no Xcode or Transporter needed. **Native changes need a new build.** `eas update` ships JavaScript over the air only. Installing or upgrading `dojah-kyc-sdk-react-expo`, or editing the plugin config, always requires a rebuild. ### ProGuard / R8 rules for Android release builds EAS production builds run R8 minification. If you’ve enabled shrinking, add keep rules or the SDK will fail at runtime with `ClassNotFoundException`, `NoSuchMethodError`, or a blank WebView. In Expo, set them through `expo-build-properties` — no `proguard-rules.pro` file needed: ```ts app.config.ts theme={null} android: { enableProguardInReleaseBuilds: true, enableShrinkResourcesInReleaseBuilds: true, extraProguardRules: [ '-keep class com.dojah.** { *; }', '-keep class com.dojah_inc.** { *; }', '-keepclassmembers class com.dojah.** { *; }', '-dontwarn com.dojah.**', '-keepclassmembers class * { @android.webkit.JavascriptInterface ; }', '-keepattributes JavascriptInterface', '-keepattributes Signature,InnerClasses,EnclosingMethod', '-keepattributes RuntimeVisibleAnnotations,RuntimeVisibleParameterAnnotations', '-keepclassmembers,allowshrinking,allowobfuscation interface * { @retrofit2.http.* ; }', '-if interface * { @retrofit2.http.* ; }', '-keep,allowobfuscation interface <1>', '-keep,allowobfuscation,allowshrinking interface retrofit2.Call', '-keep,allowobfuscation,allowshrinking class retrofit2.Response', '-keep class com.google.gson.** { *; }', '-keep public class * implements com.bumptech.glide.module.GlideModule', '-dontwarn okhttp3.**', '-dontwarn okio.**', ].join('\n'), } ``` Bare CLI projects add the same rules to `android/app/proguard-rules.pro` instead. ### Troubleshooting EAS builds The `DojahWidget` pod is fetched from a Git branch, and EAS caches it between builds. Force a fresh checkout: ```bash Terminal theme={null} eas build --platform ios --profile development --clear-cache ``` The error mentions compiling against API 36 or needing AGP 8.9.1+. Make sure `"dojah-kyc-sdk-react-expo"` is listed in your `plugins` array — the plugin raises those versions during prebuild. If you keep native folders in the repo, re-run `npx expo prebuild --clean` and commit. The native SDK requires iOS 14 or later. Set `ios.deploymentTarget` in the `expo-build-properties` plugin config (`"15.1"` is a safe value for recent Expo SDKs) and rebuild. A usage description is missing. Every permission your flow touches needs an `infoPlist` entry in `app.json` — iOS terminates the app when one is absent. Almost always R8 stripping the SDK. Add the ProGuard rules above. To confirm the cause quickly, temporarily disable shrinking and rebuild. ## WebView fallback If you need a UI the native launcher doesn’t provide, render the hosted flow in a WebView: ```jsx Verify.jsx theme={null} ``` You can prefill the flow with query parameters such as `user_data[first_name]`, `user_data[email]`, `user_data[dob]`, and `metadata[user_id]`. ## Resources **React Native CLI** * [npm — dojah-kyc-sdk-react\_native](https://www.npmjs.com/package/dojah-kyc-sdk-react_native) * [GitHub — dojah-inc/dojah-react-native-sdk](https://github.com/dojah-inc/dojah-react-native-sdk) (example app) **Expo** * [npm — dojah-kyc-sdk-react-expo](https://www.npmjs.com/package/dojah-kyc-sdk-react-expo) * [GitHub — dojah-inc/dojah\_kyc\_sdk\_rn\_expo](https://github.com/dojah-inc/dojah_kyc_sdk_rn_expo) (example app) * [Expo — EAS Build documentation](https://docs.expo.dev/build/introduction/) · [eas.json reference](https://docs.expo.dev/eas/json/) **Underlying native SDKs** * [GitHub — dojah-inc/sdk-swift](https://github.com/dojah-inc/sdk-swift) · [releases](https://github.com/dojah-inc/sdk-swift/releases) * [GitHub — dojah-inc/sdk-kotlin](https://github.com/dojah-inc/sdk-kotlin) · [JitPack](https://jitpack.io/#dojah-inc/sdk-kotlin) # Theming in EasyOnboard Source: https://docs.dojah.io/api-reference/widget-sdks/theming-in-easyonboard # Web (JavaScript) Source: https://docs.dojah.io/api-reference/widget-sdks/web-javascript Drop Dojah's hosted verification flow into any web page with the Connect widget — a single script tag, no framework required. Drop Dojah’s hosted verification flow into any web page with the `Connect` widget — a single script, no framework required. This is a **widget SDK** — it renders Dojah’s UI with your **public** key. Shared options & response events live in [Choosing an SDK](/api-reference/widget-sdks/choosing-an-sdk). ## Install Add the widget script to your page. Don’t use `async`/`defer` — the inline code may run before the library loads. ```html index.html theme={null} ``` ## Initialize Create a `Connect` instance with your credentials and callbacks, then open it on a click: ```js app.js theme={null} const options = { app_id: "your_app_id", p_key: "your_public_key", type: "custom", config: { widget_id: "your_widget_id" }, metadata: { user_id: "121" }, onSuccess: function (response) { console.log("Success", response) }, onError: function (err) { console.log("Error", err) }, onClose: function () { console.log("Widget closed") }, } const connect = new Connect(options) document.querySelector("#button-connect").addEventListener("click", function () { connect.setup() connect.open() }) ``` `type` can be `custom`, `verification`, `identification`, or `liveness`. See [Configuration options](/api-reference/widget-sdks/choosing-an-sdk#configuration-options) and [Handling the response](/api-reference/widget-sdks/choosing-an-sdk#handling-the-response) for the full set. ## TypeScript `Connect` is attached to `window` at runtime, so declare it to keep TypeScript happy. Add a `types/index.d.ts` file and point `compilerOptions.typeRoots` at that folder: ```ts types/index.d.ts theme={null} export {} declare global { interface Window { Connect: any } } ``` Then instantiate it from `window`: ```ts app.ts theme={null} const connect = new window.Connect(options) ``` ## Resources * [Widget script — widget.dojah.io/widget.js](https://widget.dojah.io/widget.js) * [Hosted flow — identity.dojah.io](https://identity.dojah.io) · [EasyOnboard](/dashboard-guide/workflows/easyonboard) * Framework wrappers: [React](/api-reference/widget-sdks/react) · [React Native](/api-reference/widget-sdks/react-native) · [Flutter](/api-reference/widget-sdks/flutter) # Changelog — 2023 Source: https://docs.dojah.io/changelog/2023 Dojah product updates shipped in 2023. ## 2023 ### Dec
New Enhancement
Business Email Authentication & dashboard improvements

Business Email Authentication lets you control onboarding emails with a disposable-email toggle and a free-provider option. This release also added an on-site verification demo, downloadable AML lookup results, refreshed login screens with marketing updates, and a Glasses On upgrade allowing human review of glasses-on verifications.

Business Email Authentication
### Nov
Developer
EasyOnboard JavaScript integration

Integrating the verification widget got easier: save your EasyOnboard flow, choose the "websdk" option in the integration section, then copy the generated JavaScript and paste it into your application to embed the ID verification widget.

EasyOnboard JavaScript integration
### Oct
Enhancement Fix
EasyOnboard improvements & verification customization

EasyOnboard improvements prevent duplicate flow titles, add a table delete button, and warn about unsaved changes, alongside various bug fixes. Advanced identity verification customization also arrived, letting businesses detect users by device brightness level and choose whether to verify with or without glasses from the Fraud Check settings.

Verification customization
# Changelog — 2024 Source: https://docs.dojah.io/changelog/2024 Dojah product updates shipped in 2024. ## 2024 ### Aug
New Compliance
Custom Questions & Verification Analytics

Custom Questions let you gather compliance information and assess user risk with single-select, multi-select, or open-answer fields added directly to EasyOnboard verification pages. Verification Analytics launched with status metrics, geographical distribution, conversion rate, average completion time, and flexible timeframe filtering for data-driven decisions.

### Apr
New
Multi-channel OTP verification

A more flexible OTP process lets you choose how users receive one-time passcodes — via SMS or WhatsApp — or send to both channels simultaneously for users on unreliable networks so codes always get through.

Multi-channel OTP verification
### Mar
Enhancement New
Widget enhancements, Global Business Search & sidebar revamp

The ID widget gained Email OTP for BVN Advanced, file-upload controls, camera-flip on capture screens, consolidated EasyOnboard configuration, and multi-device screen control. Global Business Search added worldwide company lookup with reliable data sources, and the dashboard sidebar was revamped for clearer navigation and re-categorized products.

Widget enhancements
### Feb
New Enhancement
Lookup overhaul, Business AML screening & Document Analysis

Easy Lookup was reworked to separate individual and business lookups and to support batch lookups across multiple users. AML screening expanded to cover business screening in one unified feature, and the no-code Document Analysis tool launched with a drag-and-drop interface, multi-document support, instant feedback, and detailed validity results.

Lookup and AML screening
# Changelog — 2025 Source: https://docs.dojah.io/changelog/2025 Dojah product updates shipped in 2025. ## 2025 ### Dec
Fix
Dashboard navigation & UI fixes

Fixed navigation issues and UI inconsistencies on the dashboard, and corrected error handling for failed verifications to provide clearer feedback.

### Nov
Improvement Compliance
Duplicate ID separation, cookie management & team roles

Duplicate ID and Resume Verification are now fully separated across the pipeline for independent configuration. A cookie management interface lets users manage preferences by category, and a default team role ensures consistent access permissions for newly created companies.

Team roles and permissions
### Oct
New Compliance
Digital Address Verification & Compliance Register

Comprehensive Digital Address Verification validates addresses through live geolocation tracking (50-meter radius), utility bill validation, and proof-of-address capture, with automated cross-checks and fraud controls for mismatched data. The Compliance Register launched covering Fintech, Logistics, Real Estate, Crypto, and E-commerce with requirements, deadlines, and status tracking.

### Sep
Enhancement Security
Liveness & Image Match scoring, Trust Page

Fine-tune EasyOnboard fraud checks with customizable threshold sliders for Liveness and Image Match (0–24 Failed, 25–64 Pending, 65–100 Successful). Updated User Data Match requires at least two of three names to match official records, a new Trust Page communicates security and compliance, and confirmation pages can now be customized per outcome.

Liveness and image match scoring configuration
### Aug
UX
Widget UI enhancements

A cleaner, more intuitive widget interface streamlines verification — reducing drop-offs during onboarding and ID verification, with smoother step transitions and improved clarity at each stage.

Updated verification widget
### Jul
New Developer
Email notifications & API documentation revamp

Multiple team members can now receive email alerts for balance depletion and system updates via Settings → Email Notifications. The API documentation was restructured for a better developer experience — clearer endpoint descriptions, improved navigation, and detailed integration examples.

Email notification settings
### Jun
Compliance New
AML case management & Easy Authentication

AML screening evolved from simple watchlist checks into a full case management system — search, auto-generated results, case assignment, status updates, risk levels, ongoing monitoring, comments, audit trail, and PDF download. Easy Authentication also launched for liveness-based fast re-authentication of returning users.

AML case management
### May
Fix
Bug fixes

Fixed navigation issues and UI inconsistencies on the dashboard, and corrected error handling for failed verifications.

### Apr
New Compliance
Reverification

Reverification enables identity record updates to keep information valid and compliant. Triggered from the Verification Dashboard, the previous verification is marked invalid and the new attempt becomes active — with or without a reference ID, plus SDK integration via reference\_id or email parameters.

Reverification flow
### Mar
Enhancement
Automated country detection & low-balance alerts

Geo-IP-based detection auto-selects the user's country at the start of verification, reducing friction and ID-type errors. A low-balance notification system adds real-time wallet monitoring and threshold alerts across Government Lookup, EasyOnboard, and Document Analysis to prevent failed verifications.

Country detection and balance alerts
### Feb
UX New
Widget enhancements & invoice downloads

The QR Code screen was redesigned for clearer multi-device verification, and the Government Data page was restructured to reduce confusion. ID upload instructions were clarified, a Sandbox Government Data page was added, and invoice downloads arrived in Billings → Transaction History with automatic generation.

QR code multi-device verification
### Jan
Enhancement UX
Signature canvas & roles cleanup

The signature page now lets users draw an actual signature via a canvas instead of text entry only. The Roles & Permissions page received a cleaner design with expandable dropdowns for easier viewing and management of permission details.

Signature canvas
# Changelog — 2026 Source: https://docs.dojah.io/changelog/2026 Dojah product updates shipped in 2026. ## 2026 ### Jul
New Security Enhancement
Feature enhancements

We are excited to share a few updates added to the dashboard to enhance experiences on the Dojah platform.

Table Refresh Button

We've added dedicated Refresh buttons to the most frequently used tables across the application.

This enhancement allows users to refresh individual tables without reloading the entire page, making it faster and more convenient to view the latest data while improving the overall user experience.

The refresh buttons are present on the

  • Verify Individual table
  • Verify Business table
  • EasyOnboard Verification table
  • EasyDetect Profiles table
  • EasyDetect Cases table
  • EasyDetect Events table
  • API Usage table
Refresh button on the Individual Verification table
Authorized Signatory Compliance Enhancement

We've enhanced the compliance flow to capture the name and job title of the authorized signatory directly from the Master Service Agreement (MSA).

This enhancement ensures the details of the individual who signed the agreement are recorded, improving compliance records, auditability, and documentation accuracy.

Signature section capturing the authorized signatory name and job title on the Master Service Agreement
New: IP Whitelisting for Secure API Access

Developers can now secure their Dojah integrations with IP Whitelisting. This feature allows teams to define a trusted list of IP addresses that are permitted to access their APIs.

By restricting API requests to approved servers or networks, organizations can prevent unauthorized access, strengthen production security, and reduce the risk of compromised API credentials being used from untrusted environments. IP Whitelisting is available from the Developers section of the dashboard and can be updated as your infrastructure evolves.

How to Add an IP Address to the Whitelist

  1. From the side menu, navigate to Developers.
  2. Click Developers to open the developer tab.
  3. Select the IP Whitelist tab from the available options.
  4. Click Add IP Address.
  5. Enter a name for the IP address in the Name field.
  6. Enter the IP address you want to whitelist in the Address field.
  7. Click on “Add IP Address” to save the IP address to your whitelist.
IP Whitelisting tab in the Developers section before any addresses are added
Add IP Address dialog with Name and IP address fields
Allowed Origins for Verification Widgets

We've introduced an Allowed Origins setting for verification widgets, giving developers greater control over where their verification flows can be embedded and launched.

When enabled, only approved domains can access the widget, helping prevent unauthorized usage, strengthen security, and ensure verification flows are only available on trusted websites. This setting also supports wildcard domains for organizations managing multiple subdomains.

How to Configure Allowed Origins

  1. Navigate to EasyOnboard from the side menu.
  2. Create a flow and navigate to the settings tab of the flow
  3. Scroll to the Allowed Origin section.
  4. Toggle on the Restrict allowed origins to limit access to specific domains.
  5. In the Add an origin field, enter the domain you want to allow.
    • Example: example.com
  6. Click Add to add the domain to the allowed list.
  7. Repeat the process to add additional domains if needed.
  8. To allow verification flows to launch from any domain, disable Restrict allowed origins.
Allowed Origin section in the EasyOnboard flow settings with Restrict allowed origins enabled
### Jun
Enhancement New
Sign-up entry point, Compliance updates & Dojah Learning

A new sign-up option on the login page lets users create an account faster. The Compliance module adds Company Type and Job Title fields plus a Compliance Requirements modal, EasyOnboard gains Region & City distribution analytics, liveness checks can now use the device's back camera for assisted onboarding, and a new in-app Dojah Learning hub offers guides and tutorials. Usage analytics can be exported to PDF, alongside customer-table, CAC, and government-lookup navigation fixes.

New sign-up entry point
### May
Enhancement UI/UX
UserApp redesign & Compliance feature launch

A redesigned UserApp brings a cleaner interface, simplified navigation, and verification services consolidated under “Individual and Business Verify.” The EasyOnboard workflow moved from an accordion to a tab-based design with customizable fonts and button radius, a new Compliance feature centralizes onboarding processes, and light/dark mode now ships with an in-app toggle.

Redesigned Dojah UserApp
### Apr
Security
Liveness verification engine upgrade

An upgraded liveness detection engine improves real-time accuracy in confirming live captures and reduces spoofing and AI-generated image attacks. Users complete real-time actions — positioning the face in the oval frame, blinking, smiling, opening the mouth, and turning the head — with better stability and faster response times.

Liveness verification flow
### Mar
Fix
Dashboard bug fixes

Fixed navigation issues on the dashboard, resolved UI inconsistencies, and corrected error handling for failed verifications to provide clearer user feedback.

### Feb
New
Auto Top-Up & Dojah AI Support

Auto Top-Up automatically replenishes your wallet when the balance drops below a configurable threshold, preventing service interruptions. Dojah AI Support adds an in-dashboard assistant for instant answers to feature questions, documentation guidance, and troubleshooting — with the option to escalate to a human.

Auto Top-Up configuration
### Jan
Fraud prevention New
Duplicate image detection, PDF export & analytics

Automated duplicate image detection flags repeated images across verification attempts to prevent fraud. Verification PDF downloads make record-keeping and compliance reporting easy, analytics now track abandoned steps to surface drop-off points, and EasyOnboard flows were integrated into Easy Authentication for reusable liveness verification.

Verification analytics
# Changelog Source: https://docs.dojah.io/changelog/all_updates What's new across the Dojah API, SDKs, and dashboard. ## 2026 ### Jul
New Security Enhancement
Feature enhancements

We are excited to share a few updates added to the dashboard to enhance experiences on the Dojah platform.

Table Refresh Button

We've added dedicated Refresh buttons to the most frequently used tables across the application.

This enhancement allows users to refresh individual tables without reloading the entire page, making it faster and more convenient to view the latest data while improving the overall user experience.

The refresh buttons are present on the

  • Verify Individual table
  • Verify Business table
  • EasyOnboard Verification table
  • EasyDetect Profiles table
  • EasyDetect Cases table
  • EasyDetect Events table
  • API Usage table
Refresh button on the Individual Verification table
Authorized Signatory Compliance Enhancement

We've enhanced the compliance flow to capture the name and job title of the authorized signatory directly from the Master Service Agreement (MSA).

This enhancement ensures the details of the individual who signed the agreement are recorded, improving compliance records, auditability, and documentation accuracy.

Signature section capturing the authorized signatory name and job title on the Master Service Agreement
New: IP Whitelisting for Secure API Access

Developers can now secure their Dojah integrations with IP Whitelisting. This feature allows teams to define a trusted list of IP addresses that are permitted to access their APIs.

By restricting API requests to approved servers or networks, organizations can prevent unauthorized access, strengthen production security, and reduce the risk of compromised API credentials being used from untrusted environments. IP Whitelisting is available from the Developers section of the dashboard and can be updated as your infrastructure evolves.

How to Add an IP Address to the Whitelist

  1. From the side menu, navigate to Developers.
  2. Click Developers to open the developer tab.
  3. Select the IP Whitelist tab from the available options.
  4. Click Add IP Address.
  5. Enter a name for the IP address in the Name field.
  6. Enter the IP address you want to whitelist in the Address field.
  7. Click on “Add IP Address” to save the IP address to your whitelist.
IP Whitelisting tab in the Developers section before any addresses are added
Add IP Address dialog with Name and IP address fields
Allowed Origins for Verification Widgets

We've introduced an Allowed Origins setting for verification widgets, giving developers greater control over where their verification flows can be embedded and launched.

When enabled, only approved domains can access the widget, helping prevent unauthorized usage, strengthen security, and ensure verification flows are only available on trusted websites. This setting also supports wildcard domains for organizations managing multiple subdomains.

How to Configure Allowed Origins

  1. Navigate to EasyOnboard from the side menu.
  2. Create a flow and navigate to the settings tab of the flow
  3. Scroll to the Allowed Origin section.
  4. Toggle on the Restrict allowed origins to limit access to specific domains.
  5. In the Add an origin field, enter the domain you want to allow.
    • Example: example.com
  6. Click Add to add the domain to the allowed list.
  7. Repeat the process to add additional domains if needed.
  8. To allow verification flows to launch from any domain, disable Restrict allowed origins.
Allowed Origin section in the EasyOnboard flow settings with Restrict allowed origins enabled
### Jun
Enhancement New
Sign-up entry point, Compliance updates & Dojah Learning

A new sign-up option on the login page lets users create an account faster. The Compliance module adds Company Type and Job Title fields plus a Compliance Requirements modal, EasyOnboard gains Region & City distribution analytics, liveness checks can now use the device's back camera for assisted onboarding, and a new in-app Dojah Learning hub offers guides and tutorials. Usage analytics can be exported to PDF, alongside customer-table, CAC, and government-lookup navigation fixes.

New sign-up entry point
### May
Enhancement UI/UX
UserApp redesign & Compliance feature launch

A redesigned UserApp brings a cleaner interface, simplified navigation, and verification services consolidated under “Individual and Business Verify.” The EasyOnboard workflow moved from an accordion to a tab-based design with customizable fonts and button radius, a new Compliance feature centralizes onboarding processes, and light/dark mode now ships with an in-app toggle.

Redesigned Dojah UserApp
### Apr
Security
Liveness verification engine upgrade

An upgraded liveness detection engine improves real-time accuracy in confirming live captures and reduces spoofing and AI-generated image attacks. Users complete real-time actions — positioning the face in the oval frame, blinking, smiling, opening the mouth, and turning the head — with better stability and faster response times.

Liveness verification flow
### Mar
Fix
Dashboard bug fixes

Fixed navigation issues on the dashboard, resolved UI inconsistencies, and corrected error handling for failed verifications to provide clearer user feedback.

### Feb
New
Auto Top-Up & Dojah AI Support

Auto Top-Up automatically replenishes your wallet when the balance drops below a configurable threshold, preventing service interruptions. Dojah AI Support adds an in-dashboard assistant for instant answers to feature questions, documentation guidance, and troubleshooting — with the option to escalate to a human.

Auto Top-Up configuration
### Jan
Fraud prevention New
Duplicate image detection, PDF export & analytics

Automated duplicate image detection flags repeated images across verification attempts to prevent fraud. Verification PDF downloads make record-keeping and compliance reporting easy, analytics now track abandoned steps to surface drop-off points, and EasyOnboard flows were integrated into Easy Authentication for reusable liveness verification.

Verification analytics
## 2025 ### Dec
Fix
Dashboard navigation & UI fixes

Fixed navigation issues and UI inconsistencies on the dashboard, and corrected error handling for failed verifications to provide clearer feedback.

### Nov
Improvement Compliance
Duplicate ID separation, cookie management & team roles

Duplicate ID and Resume Verification are now fully separated across the pipeline for independent configuration. A cookie management interface lets users manage preferences by category, and a default team role ensures consistent access permissions for newly created companies.

Team roles and permissions
### Oct
New Compliance
Digital Address Verification & Compliance Register

Comprehensive Digital Address Verification validates addresses through live geolocation tracking (50-meter radius), utility bill validation, and proof-of-address capture, with automated cross-checks and fraud controls for mismatched data. The Compliance Register launched covering Fintech, Logistics, Real Estate, Crypto, and E-commerce with requirements, deadlines, and status tracking.

### Sep
Enhancement Security
Liveness & Image Match scoring, Trust Page

Fine-tune EasyOnboard fraud checks with customizable threshold sliders for Liveness and Image Match (0–24 Failed, 25–64 Pending, 65–100 Successful). Updated User Data Match requires at least two of three names to match official records, a new Trust Page communicates security and compliance, and confirmation pages can now be customized per outcome.

Liveness and image match scoring configuration
### Aug
UX
Widget UI enhancements

A cleaner, more intuitive widget interface streamlines verification — reducing drop-offs during onboarding and ID verification, with smoother step transitions and improved clarity at each stage.

Updated verification widget
### Jul
New Developer
Email notifications & API documentation revamp

Multiple team members can now receive email alerts for balance depletion and system updates via Settings → Email Notifications. The API documentation was restructured for a better developer experience — clearer endpoint descriptions, improved navigation, and detailed integration examples.

Email notification settings
### Jun
Compliance New
AML case management & Easy Authentication

AML screening evolved from simple watchlist checks into a full case management system — search, auto-generated results, case assignment, status updates, risk levels, ongoing monitoring, comments, audit trail, and PDF download. Easy Authentication also launched for liveness-based fast re-authentication of returning users.

AML case management
### May
Fix
Bug fixes

Fixed navigation issues and UI inconsistencies on the dashboard, and corrected error handling for failed verifications.

### Apr
New Compliance
Reverification

Reverification enables identity record updates to keep information valid and compliant. Triggered from the Verification Dashboard, the previous verification is marked invalid and the new attempt becomes active — with or without a reference ID, plus SDK integration via reference\_id or email parameters.

Reverification flow
### Mar
Enhancement
Automated country detection & low-balance alerts

Geo-IP-based detection auto-selects the user's country at the start of verification, reducing friction and ID-type errors. A low-balance notification system adds real-time wallet monitoring and threshold alerts across Government Lookup, EasyOnboard, and Document Analysis to prevent failed verifications.

Country detection and balance alerts
### Feb
UX New
Widget enhancements & invoice downloads

The QR Code screen was redesigned for clearer multi-device verification, and the Government Data page was restructured to reduce confusion. ID upload instructions were clarified, a Sandbox Government Data page was added, and invoice downloads arrived in Billings → Transaction History with automatic generation.

QR code multi-device verification
### Jan
Enhancement UX
Signature canvas & roles cleanup

The signature page now lets users draw an actual signature via a canvas instead of text entry only. The Roles & Permissions page received a cleaner design with expandable dropdowns for easier viewing and management of permission details.

Signature canvas
## 2024 ### Aug
New Compliance
Custom Questions & Verification Analytics

Custom Questions let you gather compliance information and assess user risk with single-select, multi-select, or open-answer fields added directly to EasyOnboard verification pages. Verification Analytics launched with status metrics, geographical distribution, conversion rate, average completion time, and flexible timeframe filtering for data-driven decisions.

### Apr
New
Multi-channel OTP verification

A more flexible OTP process lets you choose how users receive one-time passcodes — via SMS or WhatsApp — or send to both channels simultaneously for users on unreliable networks so codes always get through.

Multi-channel OTP verification
### Mar
Enhancement New
Widget enhancements, Global Business Search & sidebar revamp

The ID widget gained Email OTP for BVN Advanced, file-upload controls, camera-flip on capture screens, consolidated EasyOnboard configuration, and multi-device screen control. Global Business Search added worldwide company lookup with reliable data sources, and the dashboard sidebar was revamped for clearer navigation and re-categorized products.

Widget enhancements
### Feb
New Enhancement
Lookup overhaul, Business AML screening & Document Analysis

Easy Lookup was reworked to separate individual and business lookups and to support batch lookups across multiple users. AML screening expanded to cover business screening in one unified feature, and the no-code Document Analysis tool launched with a drag-and-drop interface, multi-document support, instant feedback, and detailed validity results.

Lookup and AML screening
## 2023 ### Dec
New Enhancement
Business Email Authentication & dashboard improvements

Business Email Authentication lets you control onboarding emails with a disposable-email toggle and a free-provider option. This release also added an on-site verification demo, downloadable AML lookup results, refreshed login screens with marketing updates, and a Glasses On upgrade allowing human review of glasses-on verifications.

Business Email Authentication
### Nov
Developer
EasyOnboard JavaScript integration

Integrating the verification widget got easier: save your EasyOnboard flow, choose the "websdk" option in the integration section, then copy the generated JavaScript and paste it into your application to embed the ID verification widget.

EasyOnboard JavaScript integration
### Oct
Enhancement Fix
EasyOnboard improvements & verification customization

EasyOnboard improvements prevent duplicate flow titles, add a table delete button, and warn about unsaved changes, alongside various bug fixes. Advanced identity verification customization also arrived, letting businesses detect users by device brightness level and choose whether to verify with or without glasses from the Fraud Check settings.

Verification customization
# Status page Source: https://docs.dojah.io/changelog/status Check the real-time operational status of Dojah's services. Dojah publishes live uptime and incident history for its APIs and services on a dedicated status page. Use it to confirm whether an issue is on Dojah's side and subscribe to updates during incidents. View real-time uptime, current incidents, and historical availability for Dojah's APIs and dashboard. Opens in a new tab. # Billings Source: https://docs.dojah.io/dashboard-guide/account/billings Everything money-related in one place — your wallet, payments, receipts, and transaction history all in one place. The **Billings** page (under **Account**) shows your **wallet balance** with **Top up wallet**, your **payment threshold**, and **Auto Top-Up** across the top, and your full **transaction history** below. Adding funds and turning on auto top-up are covered in [Fund your wallet](/dashboard-guide/getting-started/fund-your-wallet) — this page focuses on the records and settings. The Billings page — wallet balance and transaction history ## Transaction history Every wallet top-up is listed here. **Search** by reference number, **filter** by date, status, or payment type, and **export** the list for your records. | Column | What it shows | | ---------------- | --------------------------------------------- | | Amount | The amount you topped up, before VAT. | | VAT | VAT applied to the top-up (7.5%). | | Total Amount | Amount plus VAT — what you actually paid. | | Reference Number | The unique reference for the transaction. | | Status | **Successful**, **Initiated**, or **Failed**. | | Payment Type | Paystack or Bank Transfer. | | Date Created | When the top-up was made. | ### Invoices & receipts Open a transaction’s actions menu (the **⋮** at the end of the row) to **Download Invoice** or **Download Receipt** — handy for accounting and reconciliation. ## Payment settings The controls above the table manage how you pay: | Setting | What it does | | ----------------- | ---------------------------------------------------------------------------- | | Payment threshold | The balance that triggers Auto Top-Up. Set it under **Manage threshold**. | | Auto Top-Up | Turn automatic funding on or off; **Configure** sets the top-up amount. | | Saved card | The card used for payments and auto top-up — update it with **Change Card**. | ## Frequently asked questions Open **Billings** in the dashboard. The **Transaction history** table lists every charge and top-up, so you can track exactly what your wallet was spent on. Each transaction has an **Invoices & receipts** entry you can download for accounting and reconciliation. Use **Change Card** in the payment settings above the transaction table. The saved card is used for both manual payments and Auto Top-Up. The payment threshold is the balance that triggers **Auto Top-Up**. Set it under **Manage threshold** so your wallet refills before live verifications stop. # Settings Source: https://docs.dojah.io/dashboard-guide/account/settings Manage your organization — your profile, your team and their access, security, notifications, and your activity records. **Settings** is organized into sub-sections down the left: [Profile](/dashboard-guide/account/settings/profile), [Email Notifications](/dashboard-guide/account/settings/email-notifications), [Team](/dashboard-guide/account/settings/team), [Audit](/dashboard-guide/account/settings/audit), [Exports](/dashboard-guide/account/settings/exports), and [Messaging](/dashboard-guide/account/settings/messaging). Your details, password, and 2FA. Which alerts your team receives. Members, roles, and permissions. Every action taken in your account. Request and download data exports. Your SMS and WhatsApp message log. ## Frequently asked questions Two built-in roles — **Admin** (full access to all modules and settings) and **Developer Support** (developer tools and verification modules, with limited account access) — plus any **custom roles** you create with Create Role. They’re three cumulative levels set per module. **View** is read-only; **Manage** adds creating, editing, and running actions; **Delete** adds removing records. Granting Delete includes Manage and View. Go to **Settings → Team** and select **Invite Member**. Enter their email and assign a role; they’ll receive an invitation and appear in the list as **Pending** until they accept. Yes. Open **Roles & Permissions** and select **Create Role**, then set the permission level (View, Manage, or Delete) for each module to match exactly what that role should be able to do. From **Settings → Team**, select **Transfer Ownership** and choose the member to hand the Owner role to. There is one Owner per organization at a time. # Audit Source: https://docs.dojah.io/dashboard-guide/account/settings/audit A record of every action taken in your account — who did what and when — filterable and exportable for reviews. The **Audit Trail** records every action taken in your account — who did what and when (for example inviting a team member, regenerating an API key, changing a role, or updating billing). Filter the trail and **Export** it for compliance and security reviews. The Audit Trail in Dojah Settings # Email Notifications Source: https://docs.dojah.io/dashboard-guide/account/settings/email-notifications Choose which email alerts you and your team receive, so the right people stay informed without inbox noise. Choose which email alerts you and your team receive — such as low wallet balance, system updates, weekly reports, new team members, and API alerts — so the right people stay informed without inbox noise. # Exports Source: https://docs.dojah.io/dashboard-guide/account/settings/exports Request and download data exports — your lookup history, address verification records, and more. Request and download **data exports** — for example your individual lookup history or address verification records. Each export shows its **source** and **status** (Initiated or Completed); once it’s complete, you can **Download** the file. Data Exports in Dojah Settings # Messaging Source: https://docs.dojah.io/dashboard-guide/account/settings/messaging A log of every SMS and WhatsApp message sent through Dojah, with its delivery status. A log of every message sent through Dojah — **SMS** and **WhatsApp** OTPs and alerts. See totals for messages sent and not sent, and a row for each message with its sender, recipient, type, ID, and delivery **status**. Filter and **Export** as needed. The Messaging log in Dojah Settings # Profile Source: https://docs.dojah.io/dashboard-guide/account/settings/profile Your personal account details and security — name, email, phone, password, and two-factor authentication. Your personal account details and security. Update your **name**, **email**, and **phone number**, and under **Security** you can **change your password** and enable **Two-Factor Authentication (2FA)** for an extra layer of protection. The Profile section of Dojah Settings ## Two-Factor Authentication (2FA) 2FA adds a second step at sign-in: after your password, you enter a one-time code from an authenticator app, so a stolen password alone can’t get into your account. You manage it from **Profile → Security**. **Set up an authenticator app** In **Profile → Security**, switch on **Two-Factor Authentication (2FA)**. A **Setup 2FA** dialog opens with a QR code. Open an authenticator app — **Google Authenticator**, **Authy**, or similar — and scan the QR code to add your Dojah account. Your app begins generating 6-digit codes. Confirm to finish enabling 2FA. From then on, you’ll enter a current code from the app each time you sign in. **Disabling 2FA.** To turn it off, switch the **Two-Factor Authentication** toggle back off in **Profile → Security**; your account will then sign in with just your password. For security, we recommend keeping 2FA enabled. # Team Source: https://docs.dojah.io/dashboard-guide/account/settings/team Manage who has access to your organization — invite members, assign roles, and set per-module permissions. Manage who has access to your organization. The **Team Members** list shows each person’s **role**, **status** (Active, Pending, or Expired), and when they were added. From here you can **Invite Member** (by email, with a role), edit or remove a member, and **Transfer Ownership** of the account. Team Members in Dojah Settings ## Roles & permissions Select **Roles & Permissions** to define exactly what each role can access. Dojah ships with two built-in roles, and you can build your own with **Create Role**. | Role | Access | | ----------------- | ----------------------------------------------------------------------------------------------- | | Admin | Full access to all modules and settings — the highest level of access. | | Developer Support | Access to developer tools and verification modules, with limited account-level access. | | Custom role | Create your own with **Create Role** and set the permission level for each module individually. | Access is set **per module** (Verify Individual, Verify Business, EasyOnboard, EasyAuthentication, Business Registrations, EasyDetect, Custom Lists, Developers, API Status, Compliance, Billings, Settings, and Logs). For each module, a role is granted one of three permission levels — and each level builds on the one before it: | Permission | What it grants | | ---------- | ----------------------------------------------------------------------------------------------------------------------------------- | | View | See the module and its data — read-only. The member can open and review, but not make changes. | | Manage | Everything in **View**, plus create, edit, and run actions in the module — for example running a verification or publishing a flow. | | Delete | Everything in **Manage**, plus the ability to **delete** records in the module — the highest level of access. | Because the levels are cumulative, granting **Delete** implies **Manage** and **View**; granting **Manage** implies **View**. Set the level for each module on a role, then save. The Roles & Permissions matrix in Dojah Settings # Support Source: https://docs.dojah.io/dashboard-guide/account/support Reach the Dojah team without leaving your dashboard — start a chat, attach what you need, and your conversation is waiting when you come back. The **Support** page opens a live chat with the Dojah team. Describe your issue, and a support agent replies in the same thread. Your conversation history stays on the page, so you can pick up where you left off. **Where to find it.** Open **Support** under **Account** in the sidebar. It’s the fastest way to reach the team — no email thread or ticket number to track. ## The support chat The page is a single conversation with **Dojah Support**. Your messages line up on the right; replies from the team appear on the left, each labelled with the agent’s name. Date stamps mark when each message was sent. The Support chat in the Dojah dashboard | Element | What it is | | ------------- | ----------------------------------------------------------------------------------- | | Dojah Support | The header at the top of the thread — you’re always talking to the Dojah team here. | | Your messages | Right-aligned, in blue. Everything you send. | | Team replies | Left-aligned, in white, labelled with the support agent’s name. | | Date | Sits under each group of messages, so you can see when a conversation happened. | | Composer | The message box at the bottom, with an attachment button and a send button. | ## Sending a message Type into the composer at the bottom and press **Enter** to send. To add a new line without sending, use **Shift + Enter**. The send button lights up once there’s something to send. **Attach a file.** Select the **paperclip** in the composer to add a screenshot or document. A picture of the error or the response you got helps the team resolve things faster. ## Replies from the team A support agent answers in the same thread, with their name above their reply. When the same person sends several messages in a row, they’re grouped together under one name to keep the conversation easy to read. Because the history lives on the page, you can reopen **Support** any time to revisit an earlier exchange. ## Frequently asked questions Open **Support** under **Account** in the dashboard sidebar. Type your message in the composer and press **Enter** — a support agent replies in the same chat. There’s no separate ticket to raise. Yes. Select the **paperclip** in the composer to attach a file. Sharing a screenshot of the error or the response you received usually helps the team get to an answer faster. Your full history stays on the **Support** page. Reopen it and scroll up to see earlier messages and the team’s replies, each with its date. Press **Shift + Enter** to drop to a new line within the same message. **Enter** on its own sends what you’ve typed. # Usage Source: https://docs.dojah.io/dashboard-guide/account/usage Track every API call you make — volumes, success rates, costs, and where your traffic comes from. The **Usage** page logs every API call across your apps, so you can monitor activity, spot failures, and understand your usage patterns. It has two views: the [Usage log](#usage-log) and [Usage Analytics](#usage-analytics). Use **Filters** to narrow by app, service, status, or date, and **Export** to download the data. **Usage vs. Billings.** Usage tracks the calls you’ve *made* — volume, outcome, and cost per call. [Billings](/dashboard-guide/account/billings) tracks money *in* — your top-ups, receipts, and invoices. ## Usage log The default view opens with three headline counts — **Total API Calls**, **Successful**, and **Failed** — above a row-by-row log of every call. **What counts as successful?** A call is counted as **Successful** whenever Dojah returns a response — including a **404**, which means the lookup ran but found no matching record. Every other outcome is counted as **Failed**. The Usage log in the Dojah dashboard | Column | What it shows | | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | App Name | The app that made the call. | | Mode | How the call was made — **API** (direct integration), **Widget** (the hosted verification widget), or **Portal Lookup** (run directly from the dashboard). | | Services | The check that ran, e.g. BVN Basic, CAC Name Check, or NIN Verification. | | Cost | What that call cost (₦0.00 for calls that aren’t billed). | | Date/Time | When the call was made. | | Status | The response code paired with the outcome — e.g. **200 · Success**, **404 · Success**, or **400 · Failed**. | Not sure what a code means? The **“What do these codes mean?”** link opens a reference for every response code. ## Usage Analytics Select **Analytics** to switch from the raw log to an overview of your usage patterns, verification categories, and geographic distribution. The Usage Analytics view in the Dojah dashboard * **Status Distribution** — the share of successful vs. failed calls. * **Country Distribution** — where your verifications come from (for example Nigeria, Ghana, Kenya, South Africa). * **Top Services** — your most-used checks, by call count and share. ## Frequently asked questions **Usage** tracks the API calls you’ve made — how many, their outcome, and the cost of each. [Billings](/dashboard-guide/account/billings) tracks money into your wallet — top-ups, receipts, and invoices. Usage is the activity side; Billings is the money side. No. A call counts as **Successful** whenever Dojah returns a response — and that includes a **404**, which simply means the lookup ran but found no matching record. Only outcomes where no valid response is returned are counted as **Failed**. The Status column always shows the exact response code; use **“What do these codes mean?”** for the full reference. Yes. Select **Export** to download your usage — apply Filters first (by app, service, status, or date) to export just the records you need. Open **Usage Analytics** and check **Top Services**, which ranks your checks by call volume and share — handy for understanding cost drivers and planning capacity. # EasyDetect Source: https://docs.dojah.io/dashboard-guide/fraud-risk/easydetect Real-time fraud detection and risk scoring — build detection flows, score every event as it happens, review the ones that look risky, and watch risk build up per customer. **EasyDetect** scores the things your users do — transactions, logins, sign-ups — against rules you define, and returns a decision in real time. You build the logic once as a [flow](/dashboard-guide/fraud-risk/easydetect/flows), send [events](/dashboard-guide/fraud-risk/easydetect/events) to Dojah’s API, and EasyDetect decides whether to **Allow**, **Flag**, or **Block** each one. Anything flagged becomes a [case](/dashboard-guide/fraud-risk/easydetect/cases) to review, and risk accumulates into a [profile](/dashboard-guide/fraud-risk/easydetect/profiles) for each customer. Group detection rules for a kind of event (a transaction, a login) and set the score thresholds for each decision. Pass user events to EasyDetect through the API as they happen. Each event is scored and returned as Allow, Flag, or Block — instantly. Flagged events open as cases your team works, with help from AI. Risk rolls up per customer so repeat offenders rise to the top. Your fraud dashboard at a glance. Aggregated risk per customer. Flagged events awaiting review. Every scored action and its decision. Rules, scores, and thresholds. Entity details and risk tiers. Compliance-ready PDF reports. ## Frequently asked questions EasyDetect is Dojah’s real-time fraud-detection product. You define detection **flows** (sets of rules), send user **events** to the API, and EasyDetect scores each one and returns a decision — Allow, Flag, or Block. It lives under **Fraud & Risk** in the dashboard. An **event** is a single scored action (a transaction, login, or onboarding). A **case** is an event that was flagged and needs a human to review and resolve. A **profile** is one customer’s aggregated risk — a score and tier built from all of their events. Open a **flow** and select **Manage Rules** to open the Rule Builder. Add a rule with a name, a **score** and **weight**, a severity **type**, and one or more **conditions** (field, operator, value). The rule’s score is added to an event whenever its conditions match. Each rule that fires adds its **score × weight** to the event’s total. That total is compared to the flow’s **Decision Output** thresholds to Allow, Flag, or Block the event. A customer’s scores roll up into their profile, and the **Risk Tier Configuration** in Configuration sets the boundaries between the Low, Medium, High, and Very High tiers. Yes. In the Rule Builder, the **AI Rule Assistant** takes a plain-language description of what you want to catch and proposes rules to add, edit, or remove. You review each proposal and accept or reject it before the flow is published. # Cases Source: https://docs.dojah.io/dashboard-guide/fraud-risk/easydetect/cases Events flagged for human review — work them with AI assistance or resolve them manually. A **case** is an event that was flagged for a human to review. The headline cards count **Total**, **Pending**, and **Resolved** cases; the table shows each case’s ID, the profile it belongs to, its risk score, who it’s assigned to, and its status. The EasyDetect cases list with risk scores and statuses Open a case to see the transaction, user, and risk indicators, then resolve it two ways: **Review with AI** gives a recommended decision with a confidence score, and **Manual Review** lets you choose **Allow** or **Block**, add a reason, and select **Resolve Case**. # Configuration Source: https://docs.dojah.io/dashboard-guide/fraud-risk/easydetect/configuration Global fraud-detection settings — your reporting entity details and the boundaries between risk tiers. **Configuration** holds the global settings for fraud detection. Under **Entity Details** you set your reporting entity name, branch ID, and code (used in regulatory reports). Under **Risk Tier Configuration** you drag the boundaries that separate the **Low**, **Medium**, **High**, and **Very High** tiers — the same tiers used on profiles. The EasyDetect configuration with entity details and risk tier sliders **Changing tiers re-scores everyone.** Adjusting the risk-tier boundaries reclassifies *all* existing profiles against the new ranges, so review the impact before saving. # Events Source: https://docs.dojah.io/dashboard-guide/fraud-risk/easydetect/events Every action you sent to EasyDetect, with the score it received, the rules that fired, and the decision returned. An **event** is a single thing you sent to EasyDetect — a transaction, a login, or an onboarding — together with the score and decision it received. The headline cards count **Total**, **Blocked**, **Flagged**, and **Allowed** events. The EasyDetect events table with risk scores and decisions | Column | What it shows | | ---------- | ------------------------------------------------------------------- | | Event ID | The unique reference for the event. | | Profile ID | The customer the event belongs to — click through to their profile. | | Risk Score | The score the flow assigned (0–100), coloured by severity. | | Event Type | **Transaction**, **Login**, or **Onboarding**. | | Flow Name | The flow that evaluated the event. | | Decision | The outcome — **Blocked**, **Flagged**, or **Allowed**. | Open an event to see which rules fired and how the score was built — the detail view breaks down the **Evaluation Result**, an **Event Analysis**, and the exact **Event Alerts** (rules triggered, with the points each added). # Flows Source: https://docs.dojah.io/dashboard-guide/fraud-risk/easydetect/flows Reusable sets of rules applied to a kind of event, built in a visual Rule Builder with score thresholds you control. A **flow** is a reusable set of rules applied to a kind of event. Flows are either **Published** (live) or **Draft**. The list shows each flow’s use case, status, rule count, and creation date; **+ Create Flow** starts a new one — from a pre-built **template** or from scratch. The EasyDetect flows list ## The Rule Builder Open a flow and select **Manage Rules** to open the **Rule Builder** — a visual pipeline that runs an incoming event through each rule, adds up a score, then compares it to your decision thresholds. The EasyDetect Rule Builder showing a rule pipeline and decision thresholds | On a rule | What it means | | ------------------ | ------------------------------------------------------------------------------------------ | | Name & Description | What the rule detects, e.g. *Velocity Limit* or *New Device + Large Txn*. | | Score | Points added to the event’s risk score when the rule triggers. | | Weight | A multiplier on the score — higher weight means more impact. | | Type | Severity for filtering and reporting — **High**, **Medium**, or **Low**. | | Conditions | The field/operator/value tests (grouped with AND / OR) that decide whether the rule fires. | At the bottom, the **Decision Output** turns the total score into an outcome using a slider — **Allow**, **Review** (flag), and **Block** bands you can drag to make the flow more or less strict. Save your work as a **Draft** and **Publish** it when you’re ready to go live. **AI Rule Assistant.** Describe what you want to catch in plain language and EasyDetect proposes rules — adding, editing, or removing them. Review each suggestion and accept or reject it before publishing. # Overview Source: https://docs.dojah.io/dashboard-guide/fraud-risk/easydetect/overview Your fraud dashboard — total events, active cases, blocked events, pass rate, and the rules firing most often. The **Overview** is your fraud dashboard. Headline cards show **Total Events**, **Active Cases**, **Blocked Events**, and your **Pass Rate**, with charts for alerts over time, risk distribution, and the rules firing most often — plus a list of recent cases. Quick links jump to **Manage Flows** and **Pending Cases**. The EasyDetect overview dashboard with stats and charts # Profiles Source: https://docs.dojah.io/dashboard-guide/fraud-risk/easydetect/profiles One customer’s aggregated risk — a score and tier built up from every event they’ve generated. A **profile** is one customer’s aggregated risk. Each carries a **risk score** (0–100) and a **risk tier** — **Low**, **Medium**, **High**, or **Very High** — built up from every event they’ve generated. The headline cards count profiles in each tier. The EasyDetect profiles list with risk scores and tiers Open a profile for the full picture — a risk gauge and an AI overview, plus tabs for **Customer Information**, **Financial Activity**, **Behavioral & Device**, **Network Analysis**, and **Geographic Activity**. Search by name or profile ID, filter by tier, and export. # Reporting Source: https://docs.dojah.io/dashboard-guide/fraud-risk/easydetect/reporting Compliance-ready PDF reports built from your events, profiles, and cases — for internal audits and regulatory filings. EasyDetect includes built-in reporting for internal data audits, corporate governance, and external regulatory compliance. It compiles data from your events, user profiles, and flagged cases into structured, compliance-ready **PDF** reports you can use internally or submit directly to financial-oversight authorities. ## Report types Three report classifications are available, depending on the module you’re working in — all generated as PDF: | Report | Purpose | Available in | | --------------------------------------------- | ----------------------------------------------------------------------------------------------- | -------------- | | **Profile Summary Report** | Internal security auditing and individual risk-footprint tracking. | Profiles | | **Suspicious Transaction Report** (STR / SAR) | Documenting suspicious actions, potential fraud, or compliance breaches for regulatory filings. | Cases & Events | | **Cash Transaction Report** (CTR) | Documenting high-volume currency movements that match regulatory thresholds. | Events | ## Where reports live Reporting is distributed across three modules, so your compliance team can pull targeted documentation at each stage of an investigation: * **Profile reports** — from the [Profile Details](/dashboard-guide/fraud-risk/easydetect/profiles) view. Aggregates a customer’s complete historical risk footprint: baseline biodata, linked accounts, risk scores, tier changes, and transaction metrics. Used for internal investigations and team reviews. * **Case reports** — from the [Case Details](/dashboard-guide/fraud-risk/easydetect/cases) workspace, for transactions that entered a **Pending** state and were manually reviewed. Compiles the full audit trail — device data, behavioural assessments, and the administrator’s written reason for the decision — and generates the official **STR / SAR** for financial-intelligence filings. * **Event reports** — from the [Events Log](/dashboard-guide/fraud-risk/easydetect/events) detail panel, for real-time event auditing. Offers standalone downloads of the **CTR** (when a cash transaction is detected) and **STR / SAR** documents. **Set your entity details first.** Report headers are built from your corporate metadata in [Configuration](/dashboard-guide/fraud-risk/easydetect/configuration) — **Reporting Entity Name**, **Branch ID**, and **Reporting Entity Code**. Leaving these blank renders empty header fields on customer-facing files, so have an administrator verify them before generating reports. ## Generating & filing a report 1. **Locate the data.** Open **Profiles**, **Cases**, or **Events** and select the row or ID you need to export. 2. **Trigger the download.** Click the report button for the document you need — *Download STR Report*, *Download CTR Report*, or *Download Profile Report*. 3. **Save the PDF.** EasyDetect builds and exports a structured PDF straight to your workstation. 4. **File with your regulator.** Log into your state submission portal — for example the Central Bank of Nigeria (CBN) platform or the Nigerian Financial Intelligence Unit (NFIU) registry — and upload the PDF to fulfil your filing obligations. # Compliance Source: https://docs.dojah.io/dashboard-guide/getting-started/compliance Submit your business details so Dojah can approve your account to go live. It’s the first thing to do once you’re inside the dashboard. **Compliance** is the first item in the sidebar — marked with a red dot until it’s complete. It’s where you tell Dojah who your business is. Until your submission is approved, your account stays in **sandbox**; once it’s approved, you can switch to **live mode**. Compliance is a guided, four-step form shown down the left of the page: **Business Details**, **Business Documents**, **Directors’ Details**, and the **MSA**. Each step validates before you can continue, and you can jump back to any completed step from the stepper. Every step also has a **Compliance Requirement** link that opens detailed guidance on exactly what’s expected. **The form adapts to your country.** Dojah verifies businesses across Africa, so the exact fields depend on where your company is registered. Each step below describes the general requirement, with the country-specific details called out. *(Screenshots show the Nigerian flow as an example.)* ## Step 1 — Business Details Identify your company. Provide your registration details, registered business address, website, and a short description of what you do and how you’ll use Dojah. Your country of incorporation is filled in automatically from your account region. | Field | Required | What it’s for | | --------------------------- | -------- | ----------------------------------------------------------------------------- | | Company registration | Yes | Your official company registration number, so Dojah can confirm the business. | | Registered Business Address | Yes | Your company’s registered address. | | Country of Incorporation | Yes | Auto-filled from your account region. | | Website Link | Yes | A live, publicly accessible company website, e.g. `https://yourcompany.com`. | | Business Description | Yes | What your business does and how you intend to use Dojah’s services. |
🇳🇬 Nigeria
Enter your **RC number** and select **Verify** — Dojah resolves it against CAC, confirms your **Company Name**, and sets the **Company Type** (Business Name, Incorporated Trustees, or Limited Partnership).
🌍 Other countries
Enter your **business incorporation number**. The company name and type aren’t auto-resolved — you enter your details directly.
Compliance Step 1 — Business Details ## Step 2 — Business Documents Upload the documents that prove your registration and address. Each upload accepts a single file — drag and drop, or click to browse. You can attach additional supporting documents with **“+ Add another document”** (licenses, regulatory approvals, or partnership agreements) — these are required if you offer a regulated service.
🇳🇬 Nigeria
**CAC Certificate** (Business ID), **MEMART** (Memorandum & Articles of Association), **Status Report**, and a **Utility Bill** dated within the last 3 months.
🌍 Other countries
Your **Certificate of Incorporation**, plus any supporting documents that apply to your business.
**File requirements.** Each document can be a **PDF, JPG, or PNG**, up to **5 MB**. Make sure scans are clear, the whole document is visible, and the company name matches your registration. Compliance Step 2 — Business Documents (Nigeria example) ## Step 3 — Directors’ Details Link a director to the business. Provide their job title and a government-issued ID, then upload it. | Field | Required | What it’s for | | -------------------- | -------- | --------------------------------------------------------------------------------------- | | Job Title | Yes | The director’s role, e.g. Chief Executive Officer. | | Government-Issued ID | Yes | Choose the ID type (passport, driver’s licence, national ID…) then upload a clear copy. |
🇳🇬 Nigeria
Also enter the director’s 11-digit **BVN** and verify it — Dojah confirms their identity and fills in their name. The uploaded ID **must match the name on the BVN**.
🌍 Other countries
No BVN step — provide the director’s name and job title alongside their government-issued ID.
Compliance Step 3 — Directors' Details ## Step 4 — Master Service Agreement The final step is the **MSA**. Read through the full Master Service Agreement (`Dojah_MSA_v2.1.pdf` — you can download a copy). Then add your **signature**: switch to **Draw** to sign in the box, or **Upload** to attach an image of your signature. Finally, select **Submit for Review** to send your application to Dojah. If your application was previously returned, this button reads **Resubmit**. Compliance Step 4 — Master Service Agreement ## After you submit Your application moves through three states:
Under review Rejected Approved
| Status | What it means | | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | | Under review | Dojah’s team is checking your details. You can keep building and testing in sandbox while you wait. | | Rejected | Something needs fixing. The application comes back with a reason — update the relevant step and **Resubmit**. | | Approved | Your account is approved for **live mode**. The Compliance item disappears from the sidebar and you can switch to **Live** from the top bar. | **Don’t wait to integrate.** Approval is only required for live traffic. You can build your entire integration and test it end-to-end in sandbox while your compliance review is in progress. ## Frequently asked questions Nigerian companies provide a **CAC Certificate**, **MEMART** (Memorandum & Articles of Association), a **Status Report**, and a recent **utility bill** (dated within the last 3 months), along with an RC number and a director’s BVN. Companies registered outside Nigeria provide a **Certificate of Incorporation** and a government-issued ID. Every file can be a PDF, JPG, or PNG up to 5 MB. Yes. Every new account starts in **sandbox**, which runs on test data and is never billed, so you can build and test your entire integration first. You only need to complete compliance to run **live** verifications against real records — and you can keep working in sandbox while your application is under review. Once you submit, your application goes into **review** by Dojah’s team. If anything needs fixing it comes back as **rejected** with a reason, so you can update the relevant step and resubmit. When it’s approved, your account is switched on for live mode and the Compliance item drops off your sidebar. Dojah resolves your **RC number** against the CAC registry to confirm your company. If it fails, check that the number is entered correctly and matches your registered business name. Once it resolves, your Company Name and Company Type are filled in automatically. No. The **BVN** step is specific to Nigerian directors. If your business is registered elsewhere, you provide the director’s name, job title, and a government-issued ID instead — no BVN required. # Create your account Source: https://docs.dojah.io/dashboard-guide/getting-started/create-your-account Signing up takes a couple of minutes. Fill in a short form, confirm your email, set a password — and you’re in the dashboard, ready to explore. Account creation starts on the Dojah website, not the dashboard. Once you’ve set your password you’ll land in the dashboard in **sandbox mode**, where you can try every feature before going live. Go to [dojah.io](https://dojah.io) and select **Get Started** to open the sign-up form. A short form asks for a few details about you, your company, and how you plan to use Dojah. Use a work email you can access — the next step is sent there. Dojah emails you a link to complete registration and set your password. You land in the dashboard in **sandbox mode**, ready to explore. ## Sandbox vs. live Every new account starts in **sandbox**. It’s a full copy of the product running on test data, so you can build and try your integration end-to-end without any risk or cost. * **Sandbox** — results are simulated, nothing is billed, and no real records are touched. Ideal for development and testing. * **Live** — verifications run against real records and your wallet is charged. Live access is unlocked once you complete compliance. You can switch between the two with the **Live / Sandbox** toggle in the top bar at any time. **Next: go live.** Your first task inside the dashboard is [compliance](/dashboard-guide/getting-started/compliance) — submitting your business details so Dojah can approve your account to switch from sandbox to live mode. ## Frequently asked questions Go to [dojah.io](https://dojah.io) and select **Get Started**, fill in the short sign-up form, then open the email link to set your password. Once that’s done you’re signed in to the dashboard, starting in sandbox mode. Yes. Every account starts in **sandbox**, a full copy of the product running on test data that’s never billed. You only pay for **live** verifications once you’ve completed compliance. Sandbox is a safe testing environment — results are simulated, no real records are touched, and nothing is charged to your wallet. It’s ideal for building and testing your integration end-to-end before going live. Complete [compliance](/dashboard-guide/getting-started/compliance) to get your account approved, then use the **Live / Sandbox** toggle in the top bar. # Fund your wallet Source: https://docs.dojah.io/dashboard-guide/getting-started/fund-your-wallet Live verifications are charged to your Dojah wallet. Add funds to keep them running, and turn on auto top-up so you never run dry. Your **wallet** holds the balance every live request draws from. Each verification is billed per call, so a funded wallet is what keeps live traffic flowing. You can manage it from [Account → Billings](/dashboard-guide/account/billings), where you’ll see your balance, top up, and review your transaction history. **Sandbox is free.** You only need a funded wallet for **live** verifications. Testing in sandbox never touches your balance. The wallet balance card and transaction history on the Billings page ## Top up your wallet Select **Top up wallet** from the [Billings page](/dashboard-guide/account/billings) (or the dashboard) and follow the steps: Type how much you’d like to add — the minimum is **₦50,000**. Before you pay, the modal shows a breakdown of your amount, VAT, and the total. **Paystack** to pay instantly by card, or **Bank Transfer** to send the total to Dojah’s account details shown in the modal. Complete the payment. Your balance updates as soon as the payment succeeds, and the top-up appears in your transaction history. The Top Up Wallet modal — amount, VAT, and payment method ## Auto Top-Up Rather than topping up by hand, turn on **Auto Top-Up** to add funds automatically whenever your balance runs low — so live verifications never stop for an empty wallet. | Setting | What it does | | ------------------ | ---------------------------------------------------------------------- | | Auto Top-Up toggle | Turns automatic funding on or off. | | Threshold | The balance that triggers a top-up. Set it under **Manage threshold**. | | Configure | Set the top-up amount and the saved card used for automatic payments. | **Tip.** Auto Top-Up needs a saved card on file. Once it’s set, top-ups happen in the background and show up in your transaction history like any other payment. ## Transaction history Every top-up is recorded under [Billings](/dashboard-guide/account/billings) with its amount, VAT, total, reference number, payment type, and status (**Successful**, **Initiated**, or **Failed**). You can search, filter, and export the list. The full billing breakdown is covered later under [Account → Billings](/dashboard-guide/account/billings). ## Frequently asked questions The minimum top-up is **₦50,000**. The modal shows your amount, VAT, and total before you pay. Yes — **7.5% VAT** is applied to each top-up. You’ll see the amount, VAT, and total broken down before you confirm payment. Pay instantly by card with **Paystack**, or use **Bank Transfer** to send the total to Dojah’s account details shown in the modal. Auto Top-Up automatically adds funds when your balance drops below a threshold you set, so live verifications never stop for an empty wallet. It uses a saved card on file. No. Sandbox is free, so you can build and test without any balance. You only need to fund your wallet to run live verifications. # Getting around the dashboard Source: https://docs.dojah.io/dashboard-guide/getting-started/getting-around-the-dashboard A quick tour of the two things that are always on screen — the top bar you’ll use everywhere, and the sidebar that organizes every feature. The Dojah dashboard, showing the top bar and sidebar ## The top bar The top bar is where you switch context and get help. From left to right: | Control | What it does | | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | Company switcher | Switch between the companies you belong to. The active company carries a blue dot. | | Live / Sandbox | Flip between live and sandbox. You can switch to **Live** only after compliance is approved — until then, you’re prompted to complete it. | | Theme | Switch between light and dark mode. | | Profile | Your avatar opens the account menu, including **sign out**. | ### Switching company If you belong to more than one company, select the company name in the top bar to switch between them. Each company has its own data, wallet, and settings — including a dedicated **Sandbox Env** for testing. The company switcher open in the top bar ### Learn on dojah The **Learn on dojah** button in the top bar opens Dojah’s learning hub — guides, tutorials, and product walkthroughs — in a new tab. [Open Learn on dojah ↗](https://dojah.io/learn) ## The sidebar The sidebar groups every feature so related tools sit together. The groups are: | Group | What’s inside | | ------------ | ----------------------------------------------------------------------------------------------------------- | | Top level | **Compliance** (shown with a red dot until approved), **Dashboard**, **Fraud Signals**, and **Customers**. | | Verify | **Individual** and **Business** — run one-off verifications. | | Workflows | **EasyOnboard** (no-code verification flows) and **EasyAuthentication** (fast re-auth for returning users). | | Fraud & Risk | **EasyDetect** — real-time transaction and fraud monitoring. | | Integrations | **Developers**, **API Status**, and **Custom Lists**. | | Account | **Support**, **Usage**, **Billings**, and **Settings**. | **Tip.** Once compliance is approved, the Compliance item drops off the sidebar — so the nav reflects exactly what your account can do. ## Frequently asked questions Select the company name in the top bar to open the company switcher. Each company you belong to has its own data, wallet, and settings, including a dedicated sandbox environment. The **Learn on dojah** button in the top bar opens Dojah’s learning hub at dojah.io/learn in a new tab. Sandbox runs on test data and is free; Live runs real verifications against actual records and charges your wallet. Switch between them with the toggle in the top bar — Live unlocks once you complete compliance. # Customers Source: https://docs.dojah.io/dashboard-guide/home/customers A directory of everyone you’ve verified, in one searchable place. The **Customers** page collects all the people profiled across your verifications into a single directory. Every verified individual becomes a customer profile, so you can look anyone up by ID or name, see which app verified them, and open their full record. The **Total Customers** count at the top tracks how many you’ve built up. The Customers directory in the Dojah dashboard ## The customer list Each row is one customer profile: | Column | What it shows | | ------------ | ----------------------------------------------- | | Customer ID | The unique identifier for the customer profile. | | Name | The customer’s full name. | | Gender | The customer’s gender, where available. | | App Name | The app the customer was verified through. | | Countries | The countries associated with the customer. | | Status | The profile’s validity, e.g. **Valid**. | | Date Updated | When the profile was last updated. | Select the view icon at the end of a row to open that customer’s full profile. ## Viewing a customer Opening a customer shows their full profile — a consolidated view of everything Dojah knows about them, gathered from every verification you’ve run. A customer profile in the Dojah dashboard The profile is made up of: * **Header** — the customer’s name, verified status, number of verifications, and country, plus actions to **Lookup Another ID** (run a further check on them), **Download Report**, or start a **New Lookup**. * **Customer Overview** — the consolidated identity record (first/middle/last name, gender, date of birth, country, and created/updated dates), with a green seal on each verified field. * **Tabs** — each data source appears as its own tab (e.g. **Phone Number**, **AML Screening**). The tab shows the data returned for that check — personal data, photo, and more. * **Team Comments** — leave notes on the customer so your team can collaborate on a case. ## Finding a customer **Search** by ID or name to jump to a specific person, and narrow the list with the **Date** and **Apps** filters — handy when you run verifications across more than one app. **Profiles build automatically.** You don’t add customers by hand — each one is created as you run verifications, so the directory grows alongside your activity. ## Frequently asked questions Profiles are built automatically as you run verifications — you don’t add customers by hand. Each verified individual becomes a customer profile, so the directory grows alongside your activity. Yes. Search by ID or name to find a specific person, and narrow the list with the **Date** and **Apps** filters — useful when you verify across more than one app. A **Customer Overview** with the consolidated identity record (verified fields carry a green seal), tabs for each data source (such as Phone Number and AML Screening), team comments, and actions to look up another ID or download a report. # Dashboard Source: https://docs.dojah.io/dashboard-guide/home/dashboard Your home screen — a snapshot of your account, with quick links to everything else. The **Dashboard** is where you land when you sign in. New accounts see a setup checklist; from then on it’s an at-a-glance view of your wallet, usage, recent verifications, and fraud signals. The date filter in the top-right sets the period for the metrics. The Dojah dashboard home screen ## Getting started checklist On a new account, **“Welcome to Dojah”** walks you through the steps to get going, with a progress bar tracking how far you are: | Step | What it does | | ---------------------------- | ---------------------------------------------------------------------------------------------------------- | | Account created | Done as soon as you sign up. | | Complete compliance | **Start** opens [Compliance](/dashboard-guide/getting-started/compliance) to submit your business details. | | Top up your wallet | **Top up** opens the wallet so you can [add funds](/dashboard-guide/getting-started/fund-your-wallet). | | Make your first verification | **Try it** sends you to run your first check. | ## Quick Actions Shortcuts to the things you do most often: * **Verify Individual** — run a one-off individual verification. * **Verify Business** — run a one-off business verification. * **Create Verify Link** — generate a shareable verification link. * **View Docs** — jump to the documentation. ## Wallet & usage at a glance Two cards give you the numbers that matter: * **Wallet Balance** — your current balance, with a **Top Up** shortcut. * **Usage Snapshot** — your success rate plus **Total Calls**, **Successful**, and **Failed** counts for the selected period. ## Recent Verifications A live list of your latest checks, split into **Individuals** and **Businesses** tabs. Each row shows who was verified, the check type (NIN, BVN, AML, Document, Address…), its status (**Verified**, **Pending**, or **Failed**), and when it ran. **View all** opens the full list. Recent Verifications, Fraud Overview, and Explore More on the dashboard ## Fraud Overview A summary of fraud signals across your account — **Total**, **Critical**, and **High** counts, plus **Insights** (notable patterns) and **Recommendations** (suggested actions). **View all** opens **Fraud Signals**. ## Explore More Cards introducing other products you can add — **EasyDetect**, **EasyOnboard**, **EasyAuthentication**, and **AML & Watchlist** — each with a **Learn More** link. ## Frequently asked questions The dashboard is your home screen — a snapshot of your account with a setup checklist, wallet balance, usage snapshot, recent verifications, and a fraud overview, plus quick links to everything else. On a new account, the **Welcome to Dojah** checklist walks you through account creation, completing compliance, topping up your wallet, and making your first verification, with a progress bar. Yes. Use the date filter in the top-right to set the period — the usage snapshot and metrics update to match. # Fraud Signals Source: https://docs.dojah.io/dashboard-guide/home/fraud-signals See how the people you verify compare across the wider Dojah network — advisory signals that help you spot risk. **Fraud Signals** surfaces suspicious patterns around the people you verify. It has two views, shown in the sidebar: [Dojah Intelligence](/dashboard-guide/home/fraud-signals/dojah-intelligence) (network signals) and [My Signals](/dashboard-guide/home/fraud-signals/my-signals) (your own account). How the identities you’ve checked compare across the wider Dojah network. The fraud signals raised by your own verifications and workflows. ## Frequently asked questions No. Fraud Signals are **advisory** — they show how an identity compares across the Dojah network to inform your decision. Dojah never auto-rejects anyone; you choose whether to confirm fraud or dismiss a signal. **Dojah Intelligence** shows network signals — how the identities you’ve checked compare across the wider Dojah network. **My Signals** shows the fraud signals raised by your own verifications and workflows. Open the flagged identity in the **review queue**, then record your own decision — confirm fraud or dismiss it. The network signal stays advisory, so nothing is rejected automatically. # Dojah Intelligence Source: https://docs.dojah.io/dashboard-guide/home/fraud-signals/dojah-intelligence Network signals — how the identities you verify compare across the wider Dojah network. Compares the identities you’ve checked against the **Dojah network** to reveal patterns you couldn’t see from your own data alone — an identity used by multiple people, a phone in an account cluster, a face under several IDs. **Signals are advisory.** Use them to *inform*, not replace, your own checks. Dojah does not auto-reject anyone based on a signal. The Dojah Intelligence overview ## Network overview The top of the view summarizes what the network found: | Metric | What it shows | | ------------------------- | --------------------------------------------------------------------- | | Identities checked | How many of your verifications were compared against the network. | | Network matches | How many matched something in the network (with the share of checks). | | High-risk | Matches that warrant review. | | Confirmed-fraud proximity | Identities linked to known fraud. | Below that, **Risk level distribution** breaks matches into High, Medium, and Low, and **Signals by type** shows what the network is flagging most — for example *ID used by multiple people*, *Phone in account cluster*, *Document seen elsewhere*, *Face under multiple IDs*, and *Linked to confirmed fraud*. ## Review queue The actionable list — identities flagged by the network, ready for you to look at. Search by name, ID, or signal, and filter by **Risk**, **Signal**, **Status**, or date. The Dojah Intelligence review queue | Status | What it means | | --------- | --------------------- | | Open | Not yet reviewed. | | Reviewing | Being looked into. | | Dismissed | Reviewed and cleared. | Opening an item lets you record your own decision — **confirm fraud** or dismiss it. Confirming captures *your* judgement; the network signal stays advisory, so nothing is rejected automatically. # My Signals Source: https://docs.dojah.io/dashboard-guide/home/fraud-signals/my-signals The fraud signals raised by your own verifications and workflows, over the period you choose. The signals raised by **your own** verifications and workflows, over the period you choose. The My Signals view ## At a glance Headline counts — **Total Signals**, **Critical**, **High**, and **Medium** — sit above a **Signal Trend** chart (signals over time by severity) and a **By Category** breakdown (Identity Mismatch, Velocity Abuse, Blocklist Hit, Document Fraud, Geolocation Anomaly, AML/PEP Match). ## Insights & Recommendations **Insights** call out patterns in your data (for example, identity mismatches up week-on-week, a noisy IP range, peak hours, or a high-signal app). **Recommendations** suggest actions to reduce risk — enable IP blocking, add a liveness check, or update your blocklist — each tagged by severity. ## All signals **View Signals** opens the full list, where you can search and filter by **Severity**, **Category**, and **Source** (Individual & Business Verification, EasyAuthentication, EasyOnboard, EasyDetect, and Custom Lists). # API Status Source: https://docs.dojah.io/dashboard-guide/integrations/api-status See the real-time health of every Dojah service — KYC, KYB, and messaging — with per-service status, recent uptime, and incident banners. The **API Status** page shows whether Dojah’s services are running normally. When a verification is failing, it’s the first place to check: it tells you at a glance whether the issue is on Dojah’s side and which specific service is affected. **Service health, not your integration.** This page reflects the health of Dojah’s own services. If a check is failing only for you while the service shows **ONLINE**, the cause is more likely your request or balance — check the response code in [Usage](/dashboard-guide/account/usage), or reach the team via [Support](/dashboard-guide/account/support). ## The status banner At the top of the page, a banner summarises overall health. When everything is healthy it reads **All systems operational**. When one or more services are down, it switches to a count — for example *“6 services offline in the past hour”* — with a short breakdown of how many are offline versus experiencing interruptions. The API Status page with the summary banner and collapsed service categories ## Service categories Services are grouped into collapsible categories. Each header shows an **issue count** if any of its services are affected, and a **Last checked** timestamp. Click a category to expand it and see the services inside. * **Nigeria KYC APIs** — identity checks for Nigeria (BVN, NIN, CAC, and more). * **Ghana KYC APIs** — identity checks for Ghana (Ghana Card, Passport, and more). * **Other African Countries KYC APIs** — checks for Kenya, South Africa, Uganda, and others. * **KYB APIs** — business verification (CAC Basic, CAC Advanced, TIN Lookup). * **Messaging APIs** — OTP delivery over SMS, WhatsApp, and Email. ## Reading a service’s status Expanding a category reveals a card for each service. The card shows the service’s current status, when it was last updated, and a short strip of recent uptime. An expanded API Status category showing service cards with status badges and uptime bars | On the card | What it shows | | ------------ | ------------------------------------------------------------------------------------ | | Service | The name of the API or check, e.g. **KYC BVN**, **GH Passport**, or **SMS OTP**. | | Status badge | The service’s current state — **Online**, **Service Interruption**, or **Offline**. | | Timestamp | When that service’s status was last updated. | | Uptime bars | A short strip of recent history. A red bar marks a period when the service was down. | ### What the statuses mean | Status | Meaning | | ----------------------- | ------------------------------------------------------------------------------------------- | | 🟢 Online | The service is operating normally. | | 🟡 Service Interruption | The service is up but experiencing intermittent issues — some requests may fail or be slow. | | 🔴 Offline | The service is currently unavailable. Dojah’s team is notified and investigating. | ## Frequently asked questions Open **API Status** under **Integrations** in the dashboard. The banner at the top tells you whether all systems are operational, and each service category shows the status of its individual services. Expand a category to find the specific check you’re using. **Online** means the service is running normally. **Service Interruption** means it’s up but having intermittent issues, so some requests may fail or be slow. **Offline** means it’s currently unavailable and Dojah’s team is investigating. They’re a recent uptime history for that service. A **red** bar marks a period when the service was down, so a card with red bars had a recent outage even if it’s back online now. An **Offline** status means the issue is on Dojah’s side, and the team is already investigating — there’s nothing to fix in your integration. Retry once the service returns to **Online**. If a check is failing for you but API Status shows the service is **Online**, check the response code in [Usage](/dashboard-guide/account/usage) or reach out via [Support](/dashboard-guide/account/support). # Custom Lists Source: https://docs.dojah.io/dashboard-guide/integrations/custom-lists Build reusable sets of values — countries, emails, phone numbers, IPs, BVNs, NINs — to block or monitor across your fraud prevention rules. A **custom list** is a named set of values you maintain once and reference from your fraud prevention rules. Rather than repeating the same blocked country or flagged email in every rule, you keep it in one list and point your rules at the list — update the list, and every rule that uses it follows. **Where lists are used.** Custom Lists are the building blocks for your fraud rules — for example, a *Blocked Countries* list or a *VPN IP Addresses* list that your **EasyDetect** rules check against. Find them under **Integrations** in the sidebar. ## The Custom Lists table The main view lists every custom list you’ve created. Use **Search** to find one by name, and **+ Create List** to add a new one. Click a list’s name to open it and manage its items. The Custom Lists table in the Dojah dashboard | Column | What it shows | | ------------ | --------------------------------------------------------------------------- | | List Name | The name you gave the list. Click it to open the list and manage its items. | | Items | How many entries the list currently holds. | | Created By | The team member who created the list. | | Date Added | When the list was created. | | Date Updated | When an item in the list was last changed. | | ⋮ (actions) | The three-dot menu to **Edit** or **Delete** the list. | ## Creating a list Select **+ Create List** to open the form. Give the list a name and description, choose its **Type**, then add the values it should hold. The Create List form in the Dojah dashboard | Field | What it does | | ----------- | ------------------------------------------------------------------------------------------------------------------------------- | | List name | A label for the list, e.g. *Blocked Countries*. | | Description | A short note on what the list is for. | | Type | The kind of value the list holds — **Countries**, **Email**, **Phone Number**, **IP Address**, **BVN**, **NIN**, or **Others**. | | Add items | Type a value and press **Enter** (or **Add**) to add it. Each value appears as a chip you can remove. | | Bulk upload | Drag & drop or browse a **CSV file** to add many values at once. | ## Viewing and editing a list Click a list’s name to open its detail view, where every entry shows as a chip. From here you can **Search items**, **Add Item**, or remove a value with the **×** on its chip. To rename a list, change its description, or delete it, use the **⋮** menu on its row in the table. A custom list's items shown as removable chips **Deleting is permanent.** Removing a list deletes it and all of its items, and the action can’t be undone. Any rule that relied on the list will no longer find it — check your fraud rules before deleting. ## Frequently asked questions A custom list is a named set of values — such as countries, emails, phone numbers, or IP addresses — that you maintain in one place and reference from your fraud prevention rules. Updating the list updates every rule that uses it, so you don’t have to edit each rule by hand. A list can hold **Countries**, **Email** addresses, **Phone Number**s, **IP Address**es, **BVN**s, **NIN**s, or **Others**. You set the type when you create the list. In the Create or Edit form, use the **bulk upload** area to drag & drop or browse a **CSV file**. You can also add values one at a time by typing each and pressing **Enter**. Yes. Open the **⋮** menu on the list’s row and choose **Edit** to change its details and items, or **Delete** to remove it. Deleting is permanent — the list and all its items are removed and can’t be recovered. # Developers Source: https://docs.dojah.io/dashboard-guide/integrations/developers Your integration hub — manage API keys and apps, create and revoke API tokens, and subscribe to webhooks, all in one place. The **Developers** page is where you wire Dojah into your product. It’s split into three tabs — [Configuration](#configuration), [API Tokens](#api-tokens), and [Webhooks](#webhooks) — with a link out to the full API **Documentation**. **Keep your secrets secret.** Your private key and API tokens grant access to your account — never expose them in client-side code or commit them to source control. Revoking a token or generating new keys takes effect immediately, so anything still using the old credential will stop working. ## Configuration The **Configuration** tab holds your API keys and your apps. A badge shows whether you’re viewing **Production** or **Sandbox** keys — this follows your live/sandbox mode, so toggle modes to switch which set you see. The Developers Configuration tab showing API keys and the apps table | Element | What it does | | ----------------- | ----------------------------------------------------------------------------------------------------------- | | Public key | Shown in full. Use **Copy** to grab it — it’s safe to use in client-side integrations. | | Private key | Hidden by default. Select **Reveal key** and enter your password to view it, then **Copy**. Keep it secret. | | Generate New Keys | Rotates your keys (password required). Existing keys are invalidated immediately. | ### Apps An **app** represents a single integration — typically one product or service you’re connecting to Dojah. Each app has its own **App ID** and brand assets (a logo and primary color, used to style the verification experiences your users see), and your [API tokens](#api-tokens) and [webhooks](#webhooks) are each tied to a specific app. If you run more than one product, giving each its own app keeps their credentials, webhooks, and branding cleanly separate. | Element | What it does | | ---------- | ------------------------------------------------------------------------------------------------------------------------------- | | Create App | Sets up a new app with a name, logo, and brand color. Each app gets its own **App ID**. | | Apps table | Lists your apps with their App ID and creation date. Use the **Edit** and **Delete** icons on a row to update or remove an app. | ## API Tokens The **API Tokens** tab manages the tokens that authenticate your requests. Each token has a name and a masked **Token ID** — select the eye icon and enter your password to reveal it. Use **Create Token** to add one (give it a name and choose the app it belongs to). The Developers API Tokens tab with inline Edit and Delete actions Manage an existing token with the two actions on its row: | Action | What it does | | --------- | --------------------------------------------------------------------------------------------------------------------- | | ✎ Edit | Rename the token. Its ID stays the same. | | 🗑 Delete | Revoke the token for good. Any application using it loses access immediately, so confirm nothing depends on it first. | ## Webhooks The **Webhooks** tab lets you receive real-time event notifications. Select **Subscribe** to point an app at an endpoint: choose the app, enter your **Webhook URL**, and pick the service whose events you want. The Developers Webhooks tab listing webhook subscriptions | Column | What it shows | | --------------- | ------------------------------------------------------------------- | | App Name | The app the webhook belongs to. | | Environment | **Live** or **Sandbox**. | | Service Type | The service whose events are delivered, e.g. KYC Widget or SMS. | | Date Subscribed | When the subscription was created. | | End Point | The URL events are sent to. | | Actions | **Copy** the endpoint, **View** the subscription, or **Delete** it. | ## Frequently asked questions Open **Developers** under **Integrations** and stay on the **Configuration** tab. Your public key is shown in full; reveal the private key by selecting **Reveal key** and entering your password. The badge tells you whether you’re viewing Production or Sandbox keys — switch your live/sandbox mode to see the other set. An **app** represents one integration — usually a single product or service you’re connecting to Dojah. It has its own **App ID** and brand assets (logo and primary color, used to style the verification experiences your users see), and your API tokens and webhook subscriptions are each linked to a specific app. Running several products? Give each its own app so their credentials, webhooks, and branding stay separate. Your **API keys** (public and private) are the core credentials for an environment and live on the Configuration tab. **API tokens** are named credentials you create on the API Tokens tab — handy when you want separate, individually revocable tokens for different uses. You can rename or revoke a token without touching your main keys. On the **API Tokens** tab, each token row has two icons at the end: **Edit** (the pencil) to rename it, and **Delete** (the trash) to revoke it. Deleting is permanent and takes effect immediately — anything using that token will lose access. Go to the **Webhooks** tab and select **Subscribe**. Choose the app, enter the **Webhook URL** where events should be delivered, and pick the service whose events you want to receive. The new subscription appears in the table, where you can copy, view, or delete it. Generating new keys rotates your credentials and **invalidates the existing ones immediately**. Any integration still using the old keys will start failing, so update your apps with the new keys right away. You’ll be asked for your password to confirm. # Business Verification Source: https://docs.dojah.io/dashboard-guide/verify/business-verification Verify and manage business entities and corporate registrations — CAC lookups, directors and shareholders, global company checks, AML screening, and document analysis, one at a time or in bulk. **Business Verification** (KYB) is where you run checks on a company and review the results. Like Individual Verification, it has three parts: the [history](#verification-history) of every lookup you’ve run, the [New Lookup](#running-a-lookup) form for running a fresh check, and the [result](#reading-a-result) view for each one. **Business or individual?** Use Business Verification to check a *company* — its registration, directors, and risk. To verify a *person*, use [Individual Verification](/dashboard-guide/verify/individual-verification) (KYC) instead. ## Verification types Dojah offers five kinds of business check. Which ones are available depends on the **country** you choose — Global Check, AML Screening, and Document Analysis work everywhere, while the CAC lookups are specific to Nigeria. | Type | What it does | Where | | ----------------- | ------------------------------------------------------------------------------------------ | ---------------- | | CAC Basic | Confirms a company’s CAC registration — name, RC number, status, and registered address. | 🇳🇬 Nigeria | | CAC Advanced | Everything in CAC Basic, plus the company’s **directors** and **shareholders**. | 🇳🇬 Nigeria | | Global Check | Looks up a company in global business registries by name. | 🌍 All countries | | AML Screening | Screens a business against global watchlists, sanctions, PEP, and adverse-media databases. | 🌍 All countries | | Document Analysis | Reads and validates an uploaded business document (front and back). | 🌍 All countries | ## Running a lookup Select **+ New Lookup** to open the form. Choose your **Country**, the **App Name** to record the lookup under, and the **Verification Type** — the form then shows the fields that check needs. For a CAC lookup, you enter the **Company Name** and/or **RC Number**. The New Lookup form for a CAC business verification | Step | What it does | | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | Country | The country whose registries you’re checking. This decides which verification types are available. | | App Name | The app the lookup is recorded under. | | Verification Type | Which of the five checks to run. The fields below change to match. | | Single / Batch | **Single** runs one lookup; **Batch** lets you upload a CSV to run many at once (give the batch a name so you can find them later). | | Link to an existing business | Optional. Attach this result to a business you already have — leave blank to create a new one. | What you provide depends on the check: **CAC** lookups take a company name or RC number; **Global Check** takes a company name; **AML Screening** takes the organisation name, registration number, and risk categories; and **Document Analysis** takes an uploaded document. The submit button reads **Verify Business** (or **Upload & Run** for a batch). **Verifying many businesses at once.** Switch to **Batch**, name the batch, and upload a CSV (a template is provided). Track batch progress from the **Batches** button on the history view. ## Verification history The default view lists everything you’ve run, split into three tabs — one per result type. Each tab opens with its own headline counts and a table you can **Search**, **Filter**, and **Export**. The Business Verification history table on the Business Data tab | Tab | Lists | Key columns | | -------------------- | ----------------------------- | --------------------------------------------------------- | | Business Data | CAC and Global Check lookups. | Business Name · ID Type · Status · Date Updated | | AML Screening | Business AML screenings. | Name · Risk Level · Result · Status · Entity · Monitoring | | Address Verification | Address checks. | Reference · Name · Phone Number · Status · Date Created | Status reads differently per check — a business lookup shows **Found** or **Not Found**; an AML case shows its match status and risk level; an address check moves through **Pending**, **Completed**, **Failed**, or **Cancelled**. ## Reading a result Open a verification to see the full result. The header shows the company’s name, an overall status (**Verified**, **Pending**, or **All Failed**), its reference, and how many checks are attached. Down the left is a summary sidebar; the main panel has a tab per verification. A business verification result showing the business overview and CAC data | Sidebar section | What it shows | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Business Overview | The company details gathered — name, RC number, type, country, dates — with a check that flags where they match or differ across the business’s verifications. | | Case Info | For AML Screening only: the case ID, match score, risk level, and assignee. Risk level and assignee are editable so you can work the case. | | Timeline | A step-by-step log of how the verification ran. | | Team Comments | Notes from your team — add your own to keep a record on the case. | Each **verification tab** shows that check’s data. A **CAC Advanced** result adds **Directors** and **Shareholders** tables; **AML Screening** lists any watchlist matches; **Document Analysis** shows the uploaded document. A failed check shows the error and a retry option instead. Use **Download Report** to export the result as a PDF — you can choose which verifications to include — or **Lookup Another ID** to run a new check for the same business. ## Frequently asked questions Go to **Verify → Business** and select **+ New Lookup**. Choose the country, the app to record it under, and the verification type, then enter the company’s details (for a CAC lookup, its name or RC number) and select **Verify Business**. The result appears in your history and in the business’s profile. **CAC Basic** confirms a company’s core registration — name, RC number, status, and registered address. **CAC Advanced** returns all of that *plus* the company’s **directors** and **shareholders**, so you can see who owns and runs the business. Yes. **Global Check**, **AML Screening**, and **Document Analysis** are available in every country. The **CAC** lookups are specific to Nigeria, since they query the Corporate Affairs Commission registry. On the New Lookup form, switch from **Single** to **Batch**, give the batch a name, and upload a CSV (a template is provided). Each batch runs as a group, and you can track progress and find past uploads from the **Batches** button on the history view. Yes — run an **AML Screening** check. It screens the organisation against global sanctions, PEP, and adverse-media databases, and returns any matches with a risk level you can review and assign on the result’s **Case Info** panel. # Individual Verification Source: https://docs.dojah.io/dashboard-guide/verify/individual-verification Verify and manage individual identities across multiple countries — government ID lookups, address checks, credit reports, AML screening, and document analysis, one at a time or in bulk. **Individual Verification** is where you run identity checks on a person and review the results. The page has three parts: the [history](#verification-history) of every lookup you’ve run, the [New Lookup](#running-a-lookup) form for running a fresh check, and the [result](#reading-a-result) view for each verification. **Verifications and customers.** Each lookup can be attached to a customer — either a new one or an existing record you link on the form. Results then roll up into the person’s profile on the [Customers](/dashboard-guide/home/customers) page, so you build one identity over time instead of scattered checks. ## Verification types Dojah offers five kinds of individual check. Which ones are available depends on the **country** you choose — AML Screening and Document Analysis work everywhere, while the others cover Nigeria and a set of other countries. | Type | What it does | Where | | -------------------- | --------------------------------------------------------------------------------------------------------------- | ----------------------------- | | Government Lookup | Checks a government-issued ID — NIN, BVN, passport, driver’s licence, and more — against the official registry. | 🌍 Nigeria & select countries | | Address Verification | Confirms a physical address, with field-agent photos of the location. | 🇳🇬 Nigeria | | Credit Check | Pulls a credit report — score, loan summary, and behavioural analysis — from a BVN. | 🇳🇬 Nigeria | | AML Screening | Screens a person against global watchlists, sanctions, PEP, and adverse-media databases. | 🌍 All countries | | Document Analysis | Analyses an uploaded ID document (front and back) to read and validate it. | 🌍 All countries | ## Running a lookup Select **+ New Lookup** to open the form. Choose your **Country**, the **App Name** to record the lookup under, and the **Verification Type** — the form then shows the fields that check needs. For a Government Lookup, for example, you pick an **ID Type** and enter the **ID Number**. The New Lookup form for an individual government ID verification | Step | What it does | | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | Country | The country whose registries you’re checking. This decides which verification types and ID types are available. | | App Name | The app the lookup is recorded under. | | Verification Type | Which of the five checks to run. The fields below change to match. | | Single / Batch | **Single** runs one lookup; **Batch** lets you upload a CSV to run many at once (give the batch a name so you can find them later). | | Link to an existing customer | Optional. Attach this result to a customer you already have — leave blank to create a new one. | The submit button names itself for the check — **Run Lookup**, **Submit Address**, **Perform Search**, or **Upload** — and becomes available once the required fields are filled. **Verifying many people at once.** Switch to **Batch**, name the batch, and upload a CSV (a template is provided). Track batch progress from the **Batches** button on the history view. ## Verification history The default view lists everything you’ve run, split into four tabs — one per result type. Each tab opens with its own headline counts and a table you can **Search**, **Filter**, and **Export**. The Individual Verification history table on the Government Data tab | Tab | Lists | Key columns | | -------------------- | -------------------------- | --------------------------------------------------------- | | Government Data | Government Lookup results. | Name · ID Type · ID Number · Status · Date Updated | | AML Screening | AML screenings. | Name · Risk Level · Result · Status · Entity · Monitoring | | Address Verification | Address checks. | Reference · Name · Phone Number · Status · Date Created | | Document Analysis | Document analyses. | Name · ID Type · Status · Date Uploaded | Status reads differently per check — a Government Lookup shows **User Found** or **User Not Found**; an address check moves through **Pending**, **Completed**, **Failed**, or **Cancelled**; an AML case shows its match status and risk level. ## Reading a result Open a verification to see the full result. The header shows the person’s photo, name, an overall status (**Verified**, **Pending**, or **All Failed**), and how many checks are attached. Down the left is a summary sidebar; the main panel has a tab per verification. An individual verification result showing the profile, sidebar, and verification tabs | Sidebar section | What it shows | | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Customer Overview | The identity fields gathered — name, gender, date of birth, country — with a check that flags where they match or differ across the person’s verifications. | | Case Info | For AML Screening only: the case ID, match score, risk level, and assignee. Risk level and assignee are editable so you can work the case. | | Timeline | A step-by-step log of how the verification ran. | | Team Comments | Notes from your team — add your own to keep a record on the case. | Each **verification tab** shows that check’s data: a Government Lookup lists the returned personal data and photo; AML Screening lists any watchlist matches; a Credit Check breaks down into **Credit Score**, **Credit Summary**, and **Behavioral Analysis**. A failed check shows the error and a **Retry This Lookup** button instead. Use **Download Report** to export the result as a PDF — you can choose which verifications to include — or **Lookup Another ID** to run a new check for the same person. ## Frequently asked questions Go to **Verify → Individual** and select **+ New Lookup**. Choose the country, the app to record it under, and the verification type, then fill in the details (for example an ID type and number for a Government Lookup) and run it. The result appears in your history and on the person’s customer profile. It depends on the country. In Nigeria you can verify **NIN**, **BVN**, phone number, driver’s licence, voter’s card, passport, and TIN; other countries have their own national IDs and passports. The available ID types appear once you pick a country and choose **Government Lookup**. **Government Lookup** checks an ID against an official registry; **Address Verification** confirms a physical address; **Credit Check** pulls a credit report from a BVN; **AML Screening** screens against sanctions, PEP, and watchlists; and **Document Analysis** reads and validates an uploaded ID document. AML Screening and Document Analysis are available in every country. On the New Lookup form, switch from **Single** to **Batch**, give the batch a name, and upload a CSV (a template is provided). Each batch runs as a group, and you can track progress and find past uploads from the **Batches** button on the history view. Yes. Open the result and select **Download Report**. When a person has more than one verification, you can choose which ones to include before exporting the PDF. # EasyAuthentication Source: https://docs.dojah.io/dashboard-guide/workflows/easyauthentication Re-authenticate returning users in seconds — build auth flows using OTP, PIN, biometrics, or magic links, then monitor every authentication and the customers behind them. **EasyAuthentication** verifies that a *returning* user is who they say they are. You set up an [auth flow](/dashboard-guide/workflows/easyauthentication/authflows) — an authentication method delivered over a channel — integrate it, and from then on each attempt is recorded as an [authentication](/dashboard-guide/workflows/easyauthentication/authentications). The people who authenticate become [customers](/dashboard-guide/workflows/easyauthentication/customers) you can track over time, and the [Overview](/dashboard-guide/workflows/easyauthentication/overview) shows how it’s all performing. Choose an authentication method — OTP, PIN, biometric, or magic link — and the channel to deliver it. Trigger authentication from your product with the hosted link, API, or SDK. Returning users confirm their identity; each attempt is scored as Successful, Failed, or Expired. Track every authentication and customer, and dig into any session. **EasyAuthentication vs. EasyOnboard.** [EasyOnboard](/dashboard-guide/workflows/easyonboard) verifies a user the *first* time (capturing their identity and liveness). EasyAuthentication confirms a *returning* user — and can **link an EasyOnboard flow** so a biometric check matches against the liveness they enrolled during onboarding. How your authentication is performing. Build flows from a method and a channel. Every authentication attempt in detail. The people authenticating, over time. ## Frequently asked questions EasyAuthentication is Dojah’s product for re-authenticating returning users. You build an **auth flow** using a method — OTP, PIN, biometric, or magic link — and a delivery channel, integrate it into your product, and every attempt is recorded under **Authentications**. It lives under **Workflows** in the dashboard. **EasyOnboard** verifies a user for the *first* time — capturing their identity and liveness. **EasyAuthentication** confirms a *returning* user. You can link an EasyOnboard flow (one with a liveness step) so a biometric re-auth matches against the face the user enrolled at onboarding. **OTP** (a one-time code over SMS, Email, or WhatsApp), **PIN** (in-app), **Biometric** (a face capture with liveness, via the SDK), and **Magic Link** (a one-tap link over Email). You choose the method and channel when you create the flow. Go to **AuthFlows** and select **+ Create Flow**, then pick the authentication method and channel. Configure its branding under **Appearance**, set rules and links under **Settings**, and **Publish** to generate a shareable authentication link. **Expired** means the session timed out before the user finished — for example, an OTP code that wasn’t entered in time. It’s distinct from **Failed**, where a check was attempted but didn’t pass. # Authentications Source: https://docs.dojah.io/dashboard-guide/workflows/easyauthentication/authentications Every authentication attempt, with its status, the liveness match behind it, and device and IP detail. **Authentications** lists every authentication attempt. Headline cards count **Total**, **Successful**, and **Failed**; the table shows the user, reference and auth IDs, app, status, and time. Search, filter by status or app, and export. The EasyAuthentication authentications session log | Status | Meaning | | ---------- | ---------------------------------------------------------------------- | | Successful | The user confirmed their identity. | | Failed | The check didn’t pass — e.g. a wrong code or a face that didn’t match. | | Expired | The session timed out before the user completed it. | Open an authentication to see the detail. The **Bio data** tab shows the **Registered Liveness** photo (enrolled earlier) next to the **Authentication** photo from this attempt, so you can see the match; the **IP/Device Check** tab shows device and IP details (including VPN/proxy flags). A sidebar carries the IDs, a timeline of the attempt, and any failure reason. # AuthFlows Source: https://docs.dojah.io/dashboard-guide/workflows/easyauthentication/authflows Pair an authentication method — OTP, PIN, biometric, or magic link — with a delivery channel, then brand and publish it. An **auth flow** pairs an authentication **method** with a delivery **channel**. The list shows each flow’s app, status (**Published** or **Draft**), and creation date; **+ Create Flow** starts a new one. The EasyAuthentication AuthFlows list | Method | How the user authenticates | Channels | | ---------- | ------------------------------------------------------------------- | -------------------- | | OTP | A one-time code they enter to confirm their identity. | SMS, Email, WhatsApp | | PIN | A secret PIN they set. | In-App | | Biometric | A face capture with liveness, matched against their enrolled photo. | SDK | | Magic Link | A one-tap link that signs them in. | Email | ## The auth-flow builder Open a flow to configure it in the builder — a two-panel view with a live preview on the right. Work across three tabs: The EasyAuthentication auth-flow builder with a live OTP preview | Tab | What it sets | | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Appearance | Branding — linked app, logo, brand colour, display name, font, and button radius. The preview updates as you go. | | Settings | **Link EasyOnboard Flow** (reuse an onboarding flow’s liveness for fast re-auth), **Notifications** (webhook/email + support email), **Countries**, and the **Confirmation Page** (default page or a redirect URL). | | Integration | A **Shareable Link** to the hosted authentication page (once published), plus a link to the [SDK & API reference](/api-reference/get-started/introduction) for embedding it. | **Reuse your onboarding liveness.** Under **Settings → Link EasyOnboard Flow**, connect an EasyOnboard flow that has a liveness step. Biometric re-authentication then matches the user’s selfie against the face they enrolled at onboarding — only flows with a liveness step can be linked. # Customers Source: https://docs.dojah.io/dashboard-guide/workflows/easyauthentication/customers Everyone who has authenticated through your flows, with their registered liveness and authentication history. **Customers** lists everyone who has authenticated through your flows, with their flow, user and reference IDs, and the date. Open a customer to see their registered liveness and authentication history. The EasyAuthentication customers list From a customer, select **Analysis** to open an **Authentication Analysis** — a per-customer view of their successful, failed, and abandoned attempts over time, useful for spotting unusual patterns on a single account. # Overview Source: https://docs.dojah.io/dashboard-guide/workflows/easyauthentication/overview Monitor authentication performance across all your flows — success rate, attempts over time, and recent authentications. The **Overview** monitors authentication performance across all your flows. Headline cards show **Successful**, **Failed**, and **Abandoned** attempts with your overall **success rate**, a chart of authentications over time, and a list of recent authentications. The EasyAuthentication overview dashboard # EasyOnboard Source: https://docs.dojah.io/dashboard-guide/workflows/easyonboard Build no-code customer onboarding flows — assemble the verification steps you need in a visual builder, share a hosted link or embed the SDK, and review every session in one place. **EasyOnboard** lets you package several checks — ID, liveness, address, custom questions — into a single branded flow your users complete themselves. You build a [workflow](/dashboard-guide/workflows/easyonboard/workflows) once, share its hosted link, and every completed session lands under [Verifications](/dashboard-guide/workflows/easyonboard/verifications) for review. The [Overview](/dashboard-guide/workflows/easyonboard/overview) tracks how your onboarding is performing. Add the steps you want in the no-code builder and brand it to match your product. Publish to get a hosted verification link, or embed it in your app with the SDK. Each person completes your flow on the hosted page; checks run as they go. Every session lands in Verifications with its result, ready to review. **EasyOnboard vs. Verify.** EasyOnboard hands the flow to your *user* — they complete a hosted, multi-step journey themselves. The [Verify](/dashboard-guide/verify/individual-verification) pages are for checks *you* run one at a time from the dashboard. How your onboarding is performing. Build and edit your onboarding flows. Review every completed session. ## Frequently asked questions EasyOnboard is Dojah’s no-code tool for building customer onboarding flows. You assemble verification steps — ID, liveness, address, custom questions — into a single branded **workflow**, share it as a hosted link or embed it with the SDK, and review every completed session under **Verifications**. It lives under **Workflows** in the dashboard. Go to **Workflows** and select **+ Create Flow** — start from a template or from scratch. In the builder, add steps under the **Steps** tab, brand the flow under **Appearance**, set your review and country rules under **Settings**, then **Publish**. Publish the workflow, then open the **Integration** tab. You’ll find a **Shareable Link** — a hosted verification page you can send to users — and a link to the [SDK & API reference](/api-reference/get-started/introduction) for embedding the same flow in your web or mobile app. From the Steps catalogue: **Get Started** (welcome), **User Data**, **Government Data** (NIN, BVN, passport, licence), **Government Issued ID**, **Liveness**, **Address**, **Email**, and custom **Questions**. You can also turn on **fraud rules** — age limits, liveness/ID-photo matching, AML screening, duplicate-ID and IP/device checks, and more. Open the **Verifications** tab. Every session appears with its status — **Successful**, **Failed**, **Ongoing**, **Pending**, or **Abandoned** — and you can open any one to see the submitted data, per-step results, timeline, and cost. # Overview Source: https://docs.dojah.io/dashboard-guide/workflows/easyonboard/overview Track how your onboarding is performing — conversion, status and country distribution, top failure reasons, and where users drop off. The **Overview** monitors verification performance across all your workflows. Headline cards show **Successful**, **Failed**, **In Progress**, and **Abandoned** sessions with your overall **conversion rate**, alongside charts for status and country distribution, the top failure reasons, the steps users abandon most, and verifications over time. The EasyOnboard overview dashboard # Verifications Source: https://docs.dojah.io/dashboard-guide/workflows/easyonboard/verifications Every session users have run through your workflows, with its status, submitted data, per-step results, and cost. **Verifications** lists every session a user has run through your workflows. Headline cards count **Successful**, **Failed**, **In Progress**, and **Abandoned** sessions; the table shows each session’s name, reference ID, status, reason, and date. Switch between **All Verifications** and **My Pending Verifications**, and search, filter, or export. The EasyOnboard verifications session log | Status | Meaning | | ---------- | ------------------------------------------------------------------- | | Successful | The user completed the flow and passed its checks. | | Failed | A check didn’t pass — the reason is shown on the row and in detail. | | Ongoing | The user is partway through the flow. | | Pending | Awaiting a result — for example, a manual review. | | Abandoned | The user started but left before finishing. | Open a session to see the data the user submitted and the result of each step, plus a sidebar with the **overview**, any **failure reason**, a **timeline**, **webhook** status, related **sessions**, and the **cost** breakdown. From here you can **Download Report** or **Reverify** the user. # Workflows Source: https://docs.dojah.io/dashboard-guide/workflows/easyonboard/workflows Create and edit reusable onboarding flows in the no-code builder — branding, verification steps, fraud rules, settings, and integration. A **workflow** is a reusable onboarding flow. The list shows each workflow’s app, status (**Published** or **Draft**), session count, estimated cost, and creation date. Select **+ Create Flow** to start a new one — from a pre-built **template** (Lending, Crypto, Digital Biz, BNPL) or from scratch. A second tab, **Verification links**, tracks individual links you’ve shared. The EasyOnboard workflows list A workflow is tied to an **app** — its branding and verification data run under that app’s keys. Pick the app when you create the flow. See [Apps](/dashboard-guide/integrations/developers#apps) for how apps work. ## The workflow builder Open a workflow to edit it in the **builder** — a two-panel view with a live phone preview on the right, so you see exactly what users will. Work is organised across five tabs: [Appearance](#appearance), [Steps](#steps), [Fraud Check](#fraud-check), [Settings](#settings), and [Integration](#integration). Save your work as a **Draft** and **Publish** when it’s ready. The EasyOnboard workflow builder showing steps and a live preview ### Appearance Brands the widget so it matches your product. Settings here drive the live preview. | Setting | What it controls | | -------------------- | ----------------------------------------------------------------------------- | | Branding | The linked app, a logo (PNG, SVG, or JPG, up to 2 MB), and your brand colour. | | Display Name | The name shown at the top of the widget. | | Font | The widget font — e.g. Inter, DM Sans, Manrope, Poppins, Lato, or Roboto. | | Button Border Radius | The roundness of buttons, from square to pill. | ### Steps The verification steps in the flow, in order. Add them from a catalogue: | Step | What it collects | | -------------------- | -------------------------------------------------------------- | | Get Started | A welcome screen shown before verification begins. | | User Data | Name, email, and phone number. | | Government Data | A government ID lookup — NIN, BVN, passport, driver’s licence. | | Government Issued ID | Capture and verification of an ID document. | | Liveness | A selfie with liveness detection to confirm a real person. | | Address | Residential address verification. | | Email | Email verification by one-time password. | | Questions | Your own custom questions (open, single-, or multiple-choice). | Each step shows its own cost, and the builder totals an **estimated cost per verification** as you go. ### Fraud Check Under **Fraud Rules** you switch on checks that watch for suspicious activity as a user goes through the flow. Each rule is toggled on or off, and you choose what happens when it triggers — **Pending** (flag the session for your review) or **Fail** (reject it automatically). | Fraud rule | What it checks | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | User Data | Whether the name and date of birth are consistent across data sources. | | Age Limit | Flags users below a minimum age you set. | | Liveness Check | Compares the selfie against the submitted ID photo, with liveness-score and image-match thresholds. | | AML Screening | Screens against sanctions and PEP databases — choose which lists (**PEP**, **Adverse Media**, **Sanctions**, **Warning**) and a match-score threshold. | | Duplicate ID | Blocks reuse of the same ID number or face across verifications. | | IP / Device Screening | Flags suspicious devices, VPNs, or proxies. | | Digital Address | Verifies the user’s address by matching their geolocation. | ### Settings Controls how verifications are reviewed, who’s notified, and where the flow runs: | Setting | What it controls | | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Review Process | **Automatic** returns a result as soon as the checks finish; **Manual** holds each session for your team to review before a result is returned to the user. | | Business Notifications | How your team is alerted to verifications — by **webhook**, **email**, or both. | | User Notifications | Email updates sent to the user, plus the support email they can reach you on. | | Countries | Allow or block specific countries — or allow them all. | | Resume Verifications | Let users pick up an unfinished verification where they left off. | | Same-Device Agent Resume | Allow a verification to be resumed on the same device. | | Multiple Device Verification | Allow a user to continue a verification across more than one device. | | Confirmation Page | Show Dojah’s default completion page, or set a **Redirect URL** to send users back into your app afterwards. | ### Integration How you take the flow live. Once a workflow is published, the **Integration** tab gives you a **Shareable Link** — a hosted verification page you can send straight to users — plus a link to the [SDK & API reference](/api-reference/get-started/introduction) for embedding the same flow in your own web or mobile product. The EasyOnboard integration tab with a shareable link and SDK docs # What do you want to do? Source: https://docs.dojah.io/get-started Find the task you need across the dashboard and the API — start typing, or browse by area. # Get help with Dojah Source: https://docs.dojah.io/support Four ways to reach Dojah — Help Centre, Slack community, technical support, and dashboard live chat — plus what to include so an integration issue can be traced quickly. Four ways to reach us, depending on what you need. Start with the Help Centre for account and product questions — come to technical support when an endpoint is not behaving the way the reference says it should. 📚} href="https://support.dojah.io"> Self-serve answers on pricing, onboarding, accounts and billing. 💬} href="https://join.slack.com/t/dojahinc/shared_invite/zt-ng9ch04k-bT5sVBnTY6Fa1ffQ0SAxpQ"> Quick questions and integration advice from the community. 🛠️} href="mailto:support@dojah.io"> Failing calls, unexpected responses and production incidents. ⚡} href="/dashboard-guide/account/support"> A live thread with the team, inside your dashboard. ## Which channel do I need? | If you… | Use | | -------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | | Have a pricing, billing or account question | [Help Centre](https://support.dojah.io) | | Are evaluating Dojah and want to discuss volumes or a contract | [Help Centre](https://support.dojah.io) | | Want to know which endpoint fits your use case | [Slack community](https://join.slack.com/t/dojahinc/shared_invite/zt-ng9ch04k-bT5sVBnTY6Fa1ffQ0SAxpQ) | | Are getting an error you cannot explain from the reference | [Technical support](mailto:support@dojah.io) | | Have calls failing in production | [Technical support](mailto:support@dojah.io) | | Need a webhook redelivered or a verification re-run | [Technical support](mailto:support@dojah.io) | | Want to talk to an agent now, from inside the dashboard | [Dashboard live chat](/dashboard-guide/account/support) | | Need your wallet funded or a payment reconciled | [Dashboard live chat](/dashboard-guide/account/support) | ## Before you report a technical issue The team can resolve an integration issue far faster with the details that identify the exact call. Include as much of this as you have: | Detail | Why it helps | | ----------------------------- | ------------------------------------------------------------------------------ | | The endpoint and method | `GET /api/v1/kyc/bvn/full` narrows it immediately. | | Environment | Whether you called `api.dojah.io` or `sandbox.dojah.io`. | | Your `AppId` | Identifies the app whose logs to search. | | Timestamp, with the time zone | Lets the team find the request in the logs. | | The full response body | Including any reference or request id Dojah returned. | | The HTTP status code | Tells the team whether it is your request, your wallet, or an upstream source. | | What you expected instead | Separates a bug from an endpoint doing what it is documented to do. | **Never share your secret key.** Not in Slack, not in an email, not in a screenshot. Dojah will never ask for it. Send your `AppId` instead — it identifies your app without granting access to it. If a secret key has been exposed, rotate it from the dashboard straight away. **Redact customer data.** BVNs, NINs, phone numbers and document images belong in the dashboard chat or an email to technical support — never in the public Slack community. ## Check these first A large share of the issues that reach support are answered by four pages: * [Errors & status codes](/api-reference/core-concepts/errors-status-codes) — what each code means, which are worth retrying, and the failures that come up most. * [Authentication](/api-reference/get-started/authentication) — the cause of nearly every `401`, usually a `Bearer` prefix that should not be there. * [Environments](/api-reference/get-started/environments) — why a call that works in sandbox can fail in production. * [Wallet & billing](/api-reference/core-concepts/wallet-billing) — the `402` that stops production calls until the wallet is funded. ## Frequently asked questions The live chat on the **Support** page of your dashboard — it opens a thread with the Dojah team, with no ticket number to track. See [Support in the dashboard](/dashboard-guide/account/support). Use Slack for questions about how Dojah works — which endpoint to call, how a flow is meant to behave. Use technical support when a specific call is failing, because the team needs your `AppId` and timestamps to trace it, and those do not belong in a public channel. Share the endpoint, the status code and the shape of the error. Do not share secret keys, `AppId` values, or customer identifiers such as BVNs and NINs — the community channel is public. Send those to technical support instead. Contact technical support with the endpoint, the time the failures started, and the status codes you are seeing. A run of `424` responses usually means an upstream identity source is unavailable rather than a fault in your integration — see [Errors & status codes](/api-reference/core-concepts/errors-status-codes). # Use cases Source: https://docs.dojah.io/use-cases Verification stacks by industry — the same Dojah building blocks, ordered for what you are regulated for. Fintech, lending, crypto and betting.
# Betting & Gaming Source: https://docs.dojah.io/use-cases/betting The recommended Dojah verification stack for betting and gaming — age and identity checks, biometrics, self-exclusion lists, and fraud signals at signup.
# Crypto & Web3 Source: https://docs.dojah.io/use-cases/crypto The recommended Dojah verification stack for exchanges and wallets — government ID, biometrics, sanctions screening, IP risk, and transaction monitoring.
# Fintech & Neobanks Source: https://docs.dojah.io/use-cases/fintech The recommended Dojah verification stack for fintech and neobanks — government ID, biometrics, AML screening, and real-time transaction monitoring.
# Lending & Credit Source: https://docs.dojah.io/use-cases/lending The recommended Dojah verification stack for lenders — BVN lookup, biometrics, credit bureau history, and AML screening before you disburse.