Skip to content

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.

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.

POST/api/legacy/agent/kyc/identity-verificationscope: kyc:upload

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.

POST/api/legacy/agent/kyc/identity-cross-checkscope: kyc:upload

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.

POST/api/legacy/agent/kyc/address-verificationscope: kyc:upload

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.

POST/api/legacy/agent/kyc/livenessscope: kyc:upload

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.

POST/api/legacy/agent/kyc/corporate-principalsscope: kyc:upload

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.

POST/api/legacy/agent/kyc/corporate-principals/{principalId}/documentsscope: kyc:upload

Multipart: documentType (form field) and file. Attaches a document to the principal; size limits as in the table below.

POST/api/legacy/agent/kyc/documentsscope: kyc:upload

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.

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.

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.

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_1 to LEVEL_2 needs no request: supply both BVN and NIN through update agent identity.

The partner portal has no KYC page. Document status for the agents and merchants you onboarded is reported by webhook.