Skip to content

Endpoints ​

Every endpoint of the Open API, generated from the FOID backend. The examples are real responses from a test-mode run (sandbox data). Base URL: https://api.foid.ng/api/open/v1 (locally http://localhost:8000/api/open/v1). Authenticate with Authorization: Bearer FOID_TEST_… (or FOID_LIVE_…) — except the token endpoint, which uses the sign-in app's client credentials. See Overview for auth, errors and limits.

Connection ​

GET /ping ​

Response 200

json
{
  "ok": true,
  "organisation": "Acme Wallet",
  "env": "test"
}

Verifications ​

Hosted verification: create a link, send the person to it, read the result.

POST /verifications ​

Optional header: Idempotency-Key — repeat the same request safely (same key + same body = same result).

JSON body

FieldTypeRequiredNotes
customer_refstringYour own id for this person; max length 128
subject_idstring
first_namestringmax length 80
middle_namestringmax length 80
last_namestringmax length 80
date_of_birthstringpattern ^\d{4}-\d{2}-\d{2}$
emailstring (email)
phonestringmax length 20
checksarray of nin | bvn | liveness | reverifyyesmin items 1
scopesarray of contact | financial
purposestringyesShown to the person on the consent screen; min length 3; max length 200
return_urlstringmax length 500
metadataobject
Example request
json
{
  "checks": [
    "nin",
    "liveness"
  ],
  "purpose": "Open a wallet",
  "customer_ref": "cust_1001",
  "first_name": "Ada",
  "last_name": "Obi",
  "return_url": "https://acme.example/onboarding/done"
}

Response 201

json
{
  "id": "d9588b86-660a-4737-a7a4-ff70ef99ed35",
  "object": "verification",
  "env": "test",
  "status": "pending",
  "outcome": null,
  "checks": [
    "nin",
    "liveness"
  ],
  "scopes": [
    "identity",
    "liveness"
  ],
  "purpose": "Open a wallet",
  "subject_id": "c9981038-6db3-4236-8fca-d8bbb89dadfa",
  "customer_ref": "cust_1001",
  "consent": {
    "status": "none",
    "scopes": []
  },
  "reused_foid_credential": false,
  "results": {
    "nin": {
      "status": "pending"
    },
    "liveness": {
      "status": "pending"
    }
  },
  "metadata": {},
  "expires_at": "2026-11-04T20:25:01.979339+00:00",
  "completed_at": null,
  "created_at": "2026-11-03T20:25:01.979556+00:00",
  "hosted_url": "https://app.foid.ng/verify/vs_\u2026",
  "client_token": "vs_\u2026"
}

GET /verifications ​

ParameterInTypeRequired
statusquerystring
customer_refquerystring
limitqueryinteger
offsetqueryinteger

Response 200

json
{
  "object": "list",
  "data": [
    {
      "id": "d9588b86-660a-4737-a7a4-ff70ef99ed35",
      "object": "verification",
      "env": "test",
      "status": "pending",
      "outcome": null,
      "checks": [
        "nin",
        "liveness"
      ],
      "scopes": [
        "identity",
        "liveness"
      ],
      "purpose": "Open a wallet",
      "subject_id": "c9981038-6db3-4236-8fca-d8bbb89dadfa",
      "customer_ref": "cust_1001",
      "consent": {
        "status": "none",
        "scopes": []
      },
      "reused_foid_credential": false,
      "results": {
        "nin": {
          "status": "pending"
        },
        "liveness": {
          "status": "pending"
        }
      },
      "metadata": {},
      "expires_at": "2026-11-04T20:25:01.979339+00:00",
      "completed_at": null,
      "created_at": "2026-11-03T20:25:01.979556+00:00",
      "hosted_url": "https://app.foid.ng/verify/vs_\u2026",
      "client_token": "vs_\u2026"
    }
  ],
  "has_more": false
}

GET /verifications/{verification_id} ​

ParameterInTypeRequired
verification_idpathstringyes

Response 200

json
{
  "id": "d9588b86-660a-4737-a7a4-ff70ef99ed35",
  "object": "verification",
  "env": "test",
  "status": "pending",
  "outcome": null,
  "checks": [
    "nin",
    "liveness"
  ],
  "scopes": [
    "identity",
    "liveness"
  ],
  "purpose": "Open a wallet",
  "subject_id": "c9981038-6db3-4236-8fca-d8bbb89dadfa",
  "customer_ref": "cust_1001",
  "consent": {
    "status": "none",
    "scopes": []
  },
  "reused_foid_credential": false,
  "results": {
    "nin": {
      "status": "pending"
    },
    "liveness": {
      "status": "pending"
    }
  },
  "metadata": {},
  "expires_at": "2026-11-04T20:25:01.979339+00:00",
  "completed_at": null,
  "created_at": "2026-11-03T20:25:01.979556+00:00",
  "hosted_url": "https://app.foid.ng/verify/vs_\u2026",
  "client_token": "vs_\u2026"
}

POST /verifications/{verification_id}/cancel ​

ParameterInTypeRequired
verification_idpathstringyes

Response 200

json
{
  "id": "d9588b86-660a-4737-a7a4-ff70ef99ed35",
  "object": "verification",
  "env": "test",
  "status": "cancelled",
  "outcome": null,
  "checks": [
    "nin",
    "liveness"
  ],
  "scopes": [
    "identity",
    "liveness"
  ],
  "purpose": "Open a wallet",
  "subject_id": "c9981038-6db3-4236-8fca-d8bbb89dadfa",
  "customer_ref": "cust_1001",
  "consent": {
    "status": "none",
    "scopes": []
  },
  "reused_foid_credential": false,
  "results": {
    "nin": {
      "status": "pending"
    },
    "liveness": {
      "status": "pending"
    }
  },
  "metadata": {},
  "expires_at": "2026-11-04T20:25:01.979339+00:00",
  "completed_at": null,
  "created_at": "2026-11-03T20:25:01.979556+00:00"
}

Checks ​

Server-to-server checks. You attest you collected the person's consent.

POST /checks/nin ​

Look up an NIN and match it against the name / date of birth you send.

Optional header: Idempotency-Key — repeat the same request safely (same key + same body = same result).

JSON body

FieldTypeRequiredNotes
customer_refstringYour own id for this person; max length 128
subject_idstring
first_namestringmax length 80
middle_namestringmax length 80
last_namestringmax length 80
date_of_birthstringpattern ^\d{4}-\d{2}-\d{2}$
emailstring (email)
phonestringmax length 20
numberstringyes11-digit NIN or BVN
consentobjectyes
consent.obtainedtrueyesYou confirm you collected the person's consent for this check
consent.purposestringyesmin length 3; max length 200
Example request
json
{
  "number": "12345678901",
  "first_name": "Ada",
  "last_name": "Obi",
  "date_of_birth": "1994-03-12",
  "customer_ref": "cust_1001",
  "consent": {
    "obtained": true,
    "purpose": "Account opening"
  }
}

Response 200

json
{
  "id": "880af60a-e95c-4679-b205-21e710d775e9",
  "type": "nin",
  "status": "passed",
  "reasons": [],
  "data": {
    "method": "number",
    "nin_last4": "8901",
    "name_match": true,
    "name_score": 1.0,
    "dob_match": true,
    "record": {
      "first_name": "Ada",
      "middle_name": null,
      "last_name": "Obi",
      "date_of_birth": "1994-03-12"
    }
  },
  "provider": "mock",
  "verification_id": null,
  "subject_id": "c9981038-6db3-4236-8fca-d8bbb89dadfa",
  "created_at": "2026-11-03T20:25:02.091651+00:00",
  "customer_ref": "cust_1001"
}

POST /checks/bvn ​

Look up a BVN and match it against the name / date of birth you send.

Optional header: Idempotency-Key — repeat the same request safely (same key + same body = same result).

JSON body

FieldTypeRequiredNotes
customer_refstringYour own id for this person; max length 128
subject_idstring
first_namestringmax length 80
middle_namestringmax length 80
last_namestringmax length 80
date_of_birthstringpattern ^\d{4}-\d{2}-\d{2}$
emailstring (email)
phonestringmax length 20
numberstringyes11-digit NIN or BVN
consentobjectyes
consent.obtainedtrueyesYou confirm you collected the person's consent for this check
consent.purposestringyesmin length 3; max length 200
Example request
json
{
  "number": "12345678901",
  "first_name": "Ada",
  "last_name": "Obi",
  "date_of_birth": "1994-03-12",
  "customer_ref": "cust_1001",
  "consent": {
    "obtained": true,
    "purpose": "Account opening"
  }
}

Response 200

json
{
  "id": "c9e2b5a1-8322-4f2b-b6c6-5795a4b275f4",
  "type": "bvn",
  "status": "passed",
  "reasons": [],
  "data": {
    "method": "number",
    "bvn_last4": "8901",
    "name_match": true,
    "name_score": 1.0,
    "dob_match": true,
    "record": {
      "first_name": "Ada",
      "middle_name": null,
      "last_name": "Obi",
      "date_of_birth": "1994-03-12"
    }
  },
  "provider": "mock",
  "verification_id": null,
  "subject_id": "c9981038-6db3-4236-8fca-d8bbb89dadfa",
  "created_at": "2026-11-03T20:25:02.114253+00:00",
  "customer_ref": "cust_1001"
}

POST /checks/nin-document ​

Extract the NIN from a document image (OCR), then look it up. The document photo is not used.

multipart form

FieldTypeRequiredNotes
filestringyesPhoto/scan of an NIN slip or NIMC card
consent_obtainedbooleanyes
purposestringyesmin length 3; max length 200
customer_refstring
subject_idstring
first_namestring
middle_namestring
last_namestring
date_of_birthstring

Returns the same shape as POST /checks/nin, plus the NIN read from the document (last 4 only).

Subjects ​

The people you have verified. Every read goes through the person's consent.

GET /subjects ​

ParameterInTypeRequired
customer_refquerystring
limitqueryinteger
offsetqueryinteger

Response 200

json
{
  "object": "list",
  "data": [
    {
      "id": "c9981038-6db3-4236-8fca-d8bbb89dadfa",
      "customer_ref": "cust_1001",
      "env": "test",
      "consent": {
        "status": "active",
        "scopes": [
          "identity"
        ]
      },
      "has_foid_account": false,
      "created_at": "2026-11-03T20:25:01.976005+00:00",
      "first_name": "Ada",
      "middle_name": null,
      "last_name": "Obi",
      "date_of_birth": "1994-03-12",
      "nin": {
        "verified": true,
        "last4": "8901"
      },
      "bvn": {
        "verified": true,
        "last4": "8901"
      }
    }
  ]
}

GET /subjects/{subject_id} ​

ParameterInTypeRequired
subject_idpathstringyes

Response 200

json
{
  "id": "c9981038-6db3-4236-8fca-d8bbb89dadfa",
  "customer_ref": "cust_1001",
  "env": "test",
  "consent": {
    "status": "active",
    "scopes": [
      "identity"
    ]
  },
  "has_foid_account": false,
  "created_at": "2026-11-03T20:25:01.976005+00:00",
  "first_name": "Ada",
  "middle_name": null,
  "last_name": "Obi",
  "date_of_birth": "1994-03-12",
  "nin": {
    "verified": true,
    "last4": "8901"
  },
  "bvn": {
    "verified": true,
    "last4": "8901"
  }
}

GET /subjects/{subject_id}/checks ​

ParameterInTypeRequired
subject_idpathstringyes

Response 200

json
{
  "object": "list",
  "data": [
    {
      "id": "c9e2b5a1-8322-4f2b-b6c6-5795a4b275f4",
      "type": "bvn",
      "status": "passed",
      "reasons": [],
      "data": {
        "method": "number",
        "bvn_last4": "8901",
        "name_match": true,
        "name_score": 1.0,
        "dob_match": true,
        "record": {
          "first_name": "Ada",
          "middle_name": null,
          "last_name": "Obi",
          "date_of_birth": "1994-03-12"
        }
      },
      "provider": "mock",
      "verification_id": null,
      "subject_id": "c9981038-6db3-4236-8fca-d8bbb89dadfa",
      "created_at": "2026-11-03T20:25:02.114253+00:00"
    },
    {
      "id": "880af60a-e95c-4679-b205-21e710d775e9",
      "type": "nin",
      "status": "passed",
      "reasons": [],
      "data": {
        "method": "number",
        "nin_last4": "8901",
        "name_match": true,
        "name_score": 1.0,
        "dob_match": true,
        "record": {
          "first_name": "Ada",
          "middle_name": null,
          "last_name": "Obi",
          "date_of_birth": "1994-03-12"
        }
      },
      "provider": "mock",
      "verification_id": null,
      "subject_id": "c9981038-6db3-4236-8fca-d8bbb89dadfa",
      "created_at": "2026-11-03T20:25:02.091651+00:00"
    }
  ]
}

GET /subjects/{subject_id}/trust-report ​

Financial trust signals + living credential state. FOID account holders only, scope financial.

ParameterInTypeRequired
subject_idpathstringyes

Response 403

json
{
  "error": {
    "type": "permission",
    "code": "scope_not_granted",
    "message": "No active consent for scope 'financial'"
  }
}

DELETE /subjects/{subject_id} ​

Erase a subject and everything FOID holds about them for your business (checks, face, consent).

ParameterInTypeRequired
subject_idpathstringyes

Response 204 — no body

Continue with FOID ​

Exchange the one-time code from the sign-in popup. Client credentials, not the API key.

POST /oauth/token ​

Form body (application/x-www-form-urlencoded or JSON)

FieldRequiredNotes
grant_typeyesauthorization_code
codeyesThe one-time code from the popup. Single use, expires after 60 seconds.
code_verifieryesThe PKCE verifier that matches the code_challenge used to start sign-in.
redirect_uriredirect modeExactly the one used to start sign-in (response_mode=query).
client_id + client_secretone auth methodOr HTTP Basic client_id:client_secret (recommended).
client_assertion_type + client_assertionone auth methodprivate_key_jwt: an ES256/RS256 JWT, iss=sub=client ID, aud=this URL, expires ≤ 5 min.

Errors use OAuth's format: {"error": "invalid_grant", "error_description": "…"}.

Response 200

json
{
  "object": "foid_sign_in",
  "env": "test",
  "sandbox": true,
  "nonce": "n_51b7",
  "subject_id": "ce669b19-ced4-4ff9-ac99-01d560450380",
  "scopes": [
    "contact",
    "identity",
    "profile"
  ],
  "foid_account": true,
  "face_rematched_at": null,
  "subject": {
    "id": "ce669b19-ced4-4ff9-ac99-01d560450380",
    "customer_ref": null,
    "env": "test",
    "consent": {
      "status": "active",
      "scopes": [
        "contact",
        "identity",
        "profile"
      ]
    },
    "has_foid_account": true,
    "created_at": "2026-11-03T20:25:02.497513+00:00",
    "first_name": "Chiamaka",
    "middle_name": null,
    "last_name": "Eze",
    "date_of_birth": "1990-01-01",
    "nin": {
      "verified": true,
      "last4": "0001"
    },
    "bvn": {
      "verified": true,
      "last4": "0002"
    },
    "email": "sandbox.person@example.com",
    "phone": "**********0001"
  },
  "checks": []
}

FOID — Fintech Open Identity. Test mode never touches real identity data.