KYC uploads
KYC on this API is evidence collection. You upload documents and the results of checks your own provider ran against an agent or merchant you onboarded; the bank’s compliance team reviews them in its own queue. Two outcomes are yours to trigger directly (liveness is auto-verified, and an agent holding both BVN and NIN reaches LEVEL_2 through update agent identity); every other decision is the bank’s.
Every route on this page is an agent route: the subject is named by X-Agent-Account, the agent’s 10-digit transaction account number, and must be in your estate (your own profile, or an agent or merchant you onboarded with sub-agent access on). See Ownership model.
One scope covers everything here: kyc:upload. kyc:manage and kyc:* are never granted to partners.
Verification results
Section titled “Verification results”These routes attach the results of checks you ran. Responses use a wrapper of their own: HTTP 200 { "status": "success", "message", "data" }, or HTTP 400 { "status": "error", "message", "data": null } on any failure, including an unknown account.
Identity verification
Section titled “Identity verification”Multipart: payload (JSON string) and optional photo (the photograph your provider returned). The payload is { "verificationType": "BVN" | "NIN", "payload": { ...the provider response... } }. One result per type is kept per customer; a second upload of the same type replaces the first. data echoes the stored result with verifiedAt.
Identity cross-check
Section titled “Identity cross-check”No body. Compares the stored BVN and NIN results for the agent and records whether they match. data carries compared, matchResult and matchDetails. Both results must already be stored.
Address verification
Section titled “Address verification”Multipart: metadata (JSON string) plus optional document and image files. metadata.proofType is one of:
proofType |
Needs |
|---|---|
DOCUMENT |
the document part |
IMAGE |
the image part |
URL |
metadata.proofUrl |
FIELD_VISIT |
at least one of document or image |
metadata.notes is free text for the reviewer. Each call creates a new address verification in the bank’s queue; the response data has its id and status.
Liveness
Section titled “Liveness”Multipart: metadata (JSON string) plus optional selfie and video. Metadata fields: provider (your liveness vendor), confidenceScore (decimal), resultPayload (the vendor’s response as an object) and optionally livenessImages (an object of named frames). Creates a liveness session and submits the result in one call. Liveness from an API client is stored VERIFIED at submission, with autoVerifiedReason set to LIVENESS_FROM_CHANNEL; the bank treats your liveness provider’s result as authoritative.
Corporate principals
Section titled “Corporate principals”For a merchant or agent onboarded as a registered business: add a director, shareholder, beneficial owner or signatory. JSON body:
| Field | Required | Description |
|---|---|---|
principalType |
Yes | DIRECTOR, SHAREHOLDER, BENEFICIAL_OWNER, SIGNATORY. |
firstName, lastName |
Yes | |
position |
No | |
email, phone |
No | |
bvn, nin |
One of | 11 digits. |
dateOfBirth |
No | yyyy-MM-dd. Send it; it comes back on the same verification response as the name. |
The principal is stored as verified (the API path is trusted) and queued for the bank’s screening. data is the principal with its id.
Multipart: documentType (form field) and file. Attaches a document to the principal; size limits as in the table below.
Agent documents
Section titled “Agent documents”Multipart: documentType, optional documentNumber, file. This route runs the ownership guard on the agent named in X-Agent-Account. It accepts the principal and corporate types only (PRINCIPAL_ID, PRINCIPAL_UTILITY_BILL, PRINCIPAL_PASSPORT, AUTHORIZATION_LETTER, MANDATE_LETTER, CAC_CERTIFICATE, CAC_FORM_CO2, CAC_FORM_CO7) and attaches them to the agent’s first principal, creating one from the agent’s own details if none exists. Any other type answers 0096 with is not supported for agent KYC upload. HTTP 201 on success, with the stored document:
{ "id": "d1e2f3a4-5b6c-7890-1234-567890abcdef", "principalId": "5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d", "documentType": "CAC_CERTIFICATE", "documentNumber": "BN1234567", "fileName": "cac_certificate.pdf", "fileSizeBytes": 245000, "mimeType": "application/pdf", "status": "PENDING", "verifiedAt": null, "verifiedBy": null, "rejectionReason": null}Identity, address and liveness evidence for the agent itself goes through the verification routes above, which carry the file alongside your provider’s result; there is no separate document route for those types on the agent path.
Document types and size limits
Section titled “Document types and size limits”| Group | documentType |
Max size |
|---|---|---|
| Identity | NIN, BVN, VOTERS_CARD, INTL_PASSPORT, DRIVERS_LICENSE |
10 MB |
| Identity | PASSPORT_PHOTO |
5 MB |
| Identity | SIGNATURE |
2 MB |
| Address | UTILITY_BILL, ADDRESS_VERIFICATION_PHOTO |
10 MB |
| Address | ADDRESS_VERIFICATION_DOC |
15 MB |
| Address | BANK_STATEMENT |
20 MB |
| Corporate | CAC_CERTIFICATE, CAC_FORM_CO2, CAC_FORM_CO7, MEMART, SCUML, BYLAWS, AUTHORIZATION_LETTER, MANDATE_LETTER, OPERATIONAL_LICENSE, BUSINESS_NATURE_DOC |
20 MB |
| Verification | LIVENESS_SELFIE |
5 MB |
| Verification | LIVENESS_VIDEO |
50 MB |
| Verification | SCREENING_SCORE_DOC |
10 MB |
| Director / principal | DIRECTOR_ID, DIRECTOR_UTILITY_BILL, DIRECTOR_PASSPORT, PRINCIPAL_ID, PRINCIPAL_UTILITY_BILL, PRINCIPAL_PASSPORT |
10 MB |
| Other | OTHER |
15 MB |
A file over the limit is refused with File too large for <type>. Maximum: <n> MB. The platform stores whatever Content-Type you send; it does not restrict formats.
Document status
Section titled “Document status”PENDING on upload, then VERIFIED or REJECTED by the bank’s reviewer, then possibly EXPIRED for a document with an expiry date. Webhooks kyc.document.uploaded, kyc.document.verified and kyc.document.rejected report each step, naming the customer; see Events and payloads. Liveness skips the queue, as above.
What partners cannot do
Section titled “What partners cannot do”| Route | Scope | Who |
|---|---|---|
POST /api/legacy/agent/kyc/pnd |
kyc:manage |
The bank only. Place or lift a Post-No-Debit restriction. |
POST /api/legacy/agent/kyc/tier-upgrade and POST /api/customers/{id}/tier-upgrade |
kyc:manage |
The bank only. Raise a customer’s tier, including to LEVEL_3. |
Both answer HTTP 403 SCOPE_DENIED for a partner, because kyc:manage cannot be granted to one. To request either:
- PND. Contact your relationship manager with the agent’s account number and the reason. There is no partner route for locking an agent’s account; an operational hold is the bank’s to place.
- Tier upgrade. Upload the evidence (identity result, address proof, liveness) through the routes above so it is on the agent’s file, then ask your relationship manager to raise the tier.
LEVEL_1toLEVEL_2needs no request: supply both BVN and NIN through update agent identity.
In the portal
Section titled “In the portal”The partner portal has no KYC page. Document status for the agents and merchants you onboarded is reported by webhook.