Guide
Wallets and payouts
Verify a customer, give them a wallet with its own account number, take deposits into it and pay out to any Nigerian bank.
Use wallets when you hold money for your users: a savings product, a marketplace that pays sellers, a payroll tool. Each customer wallet is a real bank account number they can fund by transfer, and you can send payouts from it — or from your own wallet — to any bank.
Verify the customer's identity
Before opening a wallet for someone, verify their BVN. Start the check; the provider texts the customer an OTP.
curl -X POST https://staging.lint.finance/api/partner/v1/identity/initiate-verification \
-H "Authorization: Bearer $LINT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "type": "bvn", "country_code": "NG", "value": "22212345678" }'{
"data": {
"id": "6b1f8a52-2d0f-4e8b-9c33-0a7f5f0e9d21",
"type": "bvn",
"status": "PENDING",
"identity": {}
}
}Collect the OTP from your customer and complete the check with the verification id:
curl -X POST https://staging.lint.finance/api/partner/v1/identity/complete-verification \
-H "Authorization: Bearer $LINT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "identity_verification_id": "6b1f8a52-2d0f-4e8b-9c33-0a7f5f0e9d21", "otp": 123456 }'When data.status is SUCCESSFUL, identity holds the details the provider returned. In the sandbox, OTP 123456 completes the check.
Create the customer
curl -X POST https://staging.lint.finance/api/partner/v1/customers/create \
-H "Authorization: Bearer $LINT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"firstname": "Ada",
"lastname": "Obi",
"email": "ada@example.com",
"phone": "08031234567",
"dob": "1994-05-17",
"reference": "user_4410",
"identity_verification_ids": ["6b1f8a52-2d0f-4e8b-9c33-0a7f5f0e9d21"]
}'reference is your own ID for the customer and must be unique among your customers. identity_verification_ids attaches the completed checks; only verifications you started and that succeeded are accepted. Keep the returned id.
Open a wallet
curl -X POST https://staging.lint.finance/api/partner/v1/wallets/create \
-H "Authorization: Bearer $LINT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "business_customer_id": "1898107f-ab12-4b27-a483-a863b7f6982e", "currency": "NGN" }'{
"data": {
"id": "209bc13c-70ce-450d-8f2e-7a870362912a",
"customer_wallet": true,
"balance": 0,
"available_balance": 0,
"currency": "NGN",
"country_code": "NG",
"account_details": {
"bank": "SafeHaven Microfinance Bank",
"account_number": "6010172152",
"account_name": "Ada Obi",
"bank_code": "999240"
},
"created_at": "2026-11-02T11:02:09+00:00",
"updated_at": "2026-11-02T11:02:09+00:00"
}
}Give the customer account_details. Anything sent to that account number lands in their wallet.
Take deposits
Each deposit triggers business.customer.wallet.deposit to your registered webhook endpoints, with the customer and wallet it belongs to — see the payload. Credit your own ledger from it, after verifying the signature.
Balances are in kobo. available_balance is what can be spent now; use it, not balance, before sending a payout.
Send a payout
1. Confirm the destination
Look up the account holder's name and show it to your user before they confirm:
curl -X POST https://staging.lint.finance/api/partner/v1/banks/resolve-account \
-H "Authorization: Bearer $LINT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "bank_code": "999240", "account_number": "5010880910" }'Bank codes come from GET /banks/ng. An account that can't be found returns 422 account_resolution_failed.
2. Send it, with an Idempotency-Key
curl -X POST https://staging.lint.finance/api/partner/v1/wallets/initiate-transfer \
-H "Authorization: Bearer $LINT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Idempotency-Key: payout-000123" \
-d '{
"debit_wallet_id": "209bc13c-70ce-450d-8f2e-7a870362912a",
"credit_account_number": "5010880910",
"credit_account_bank_code": "999240",
"amount": 1000000,
"currency": "NGN",
"remark": "Withdrawal"
}'debit_wallet_idcan be any of your wallets, yours or a customer's.amountis 1000000₦10,000.00 here. The transfer fee is charged on top, so the wallet needs amount plus fee; otherwise you get422 insufficient_balance.remark(up to 30 characters) appears on the recipient's statement.- Always send an
Idempotency-Key. If the call times out, retry with the same key; you will never pay twice.
The response is the transaction, returned with 201. Check its status: successful, or pending while the bank settles it.
3. Confirm the outcome
Payouts don't send a webhook yet. Poll the transaction list for the wallet until a pending payout settles:
curl "https://staging.lint.finance/api/partner/v1/transactions?business_customer_wallet_id=209bc13c-70ce-450d-8f2e-7a870362912a&status=pending" \
-H "Authorization: Bearer $LINT_ACCESS_TOKEN" \
-H "Accept: application/json"A pending payout ends as successful or failed. Tell your user the outcome only once it has one.
Never retry a payout without the same Idempotency-Key, and never treat a timeout as a failure. Retry with the key, or check the transactions list, before you tell your user anything.