Payment Methods API
Manage bank accounts, mobile money, crypto wallets, and virtual accounts.
Create Payment Method
const paymentMethod = await afriex.paymentMethods.create({
channel: "BANK_ACCOUNT",
customerId: "customer-id",
accountName: "John Doe",
accountNumber: "1234567890",
countryCode: "NG",
institution: {
institutionCode: "044",
institutionName: "Access Bank",
},
});customerId, channel and countryCode are always required. The account fields depend on the channel:
| Channel | accountName | accountNumber | institution |
|---|---|---|---|
BANK_ACCOUNT, MOBILE_MONEY, SWIFT, ACH_BANK_ACCOUNT, WE_CHAT | Required | Required | Required |
UPI, INTERAC | Required | Required | Not needed |
VIRTUAL_BANK_ACCOUNT | Not needed | Not needed | Not needed |
Creatable Channels:
| Channel | Description |
|---|---|
BANK_ACCOUNT | Bank transfer |
MOBILE_MONEY | Mobile money (M-Pesa, MTN, etc.) |
VIRTUAL_BANK_ACCOUNT | Virtual bank account |
ACH_BANK_ACCOUNT | US ACH bank account |
INTERAC | Interac (Canada) |
UPI | Unified Payments Interface (India) |
SWIFT | International SWIFT transfer |
WE_CHAT | WeChat Pay and Alipay (China) |
ALIPAY, CARD, CRYPTO, PAYBILL_TILL, POOL_ACCOUNT, RFP, and VIRTUAL_CARD are response-only channels — they're returned by get()/list() but can't be passed to create().
Alipay has no channel of its own. Create it on WE_CHAT with
institution.institutionCode and institutionName both set to ALIPAY.
Cards are collected through a checkout session.
For MOBILE_MONEY, send accountNumber as digits only: country code plus
national number, such as 254712345678. A leading + is rejected.
Get Payment Method
const paymentMethod = await afriex.paymentMethods.get("payment-method-id");The returned PaymentMethod carries currency, capabilities, status and reference. Virtual accounts and other provider-issued accounts also carry bankAddress, the issuing bank's postal address.
List Payment Methods
const response = await afriex.paymentMethods.list({
page: 0,
limit: 20,
channel: ["BANK_ACCOUNT", "MOBILE_MONEY"],
currencies: ["USD", "NGN"],
status: ["active", "pending"],
});Parameters:
| Field | Type | Description |
|---|---|---|
page | number | Page number, starting from 0 |
limit | number | Items per page (max 100) |
channel | string | string[] | One or more of BANK_ACCOUNT, MOBILE_MONEY, INTERAC, UPI, WE_CHAT, VIRTUAL_BANK_ACCOUNT, RFP, SWIFT |
currencies | string | string[] | Filter by one or more 3-letter currency codes |
capabilities | "WITHDRAW" | Only WITHDRAW is supported, and it is the default |
status | string | string[] | active or pending. Defaults to both |
Any other filter value answers 422. Deposit-only, deleted, expired and blocked payment methods cannot be listed; fetch them by ID.
Delete Payment Method
await afriex.paymentMethods.delete("payment-method-id");Get Institutions
List supported banks or mobile money providers:
const response = await afriex.paymentMethods.getInstitutions({
channel: "BANK_ACCOUNT",
countryCode: "NG",
});
for (const institution of response.data) {
console.log(institution.institutionName, institution.institutionCode);
}
// Returns: { data: Institution[], total, page }
// Institution: { institutionName, institutionCode, institutionAddress?, institutionBranch? }Supported channels are BANK_ACCOUNT, SWIFT, MOBILE_MONEY and ACH_BANK_ACCOUNT. Any other channel answers 400 INVALID_TRANSACTION_CHANNEL.
Resolve Institution Code
Resolve a bank code (SWIFT code or US routing number) to the corresponding institution name:
const result = await afriex.paymentMethods.resolveInstitutionCode({
searchTerm: "021000021",
country: "US",
codeType: "routing_number",
});
console.log(result.data?.bankName); // 'JPMORGAN CHASE BANK'
// Returns: { data: { bankName } }, with data null if the code does not resolvecountry defaults to US and accepts any ISO country code for swift_code lookups; routing_number is only supported when country is US.
Resolve Account
Verify account details before creating a payment method:
const response = await afriex.paymentMethods.resolveAccount({
channel: "BANK_ACCOUNT",
accountNumber: "1234567890",
institutionCode: "044",
countryCode: "NG",
});
console.log(response.data.recipientName);
// Returns: { data: ResolvedAccount }
// ResolvedAccount: { recipientName?, institutionName?, institutionCode? }institutionCode is required on both channels: the bank code for BANK_ACCOUNT, the provider code for MOBILE_MONEY.
Get Crypto Wallet
Get or create a crypto wallet address:
const response = await afriex.paymentMethods.getCryptoWallet({
asset: "USDT", // or 'USDC'
customerId: "optional-customer-id",
});
for (const { network, address } of response.data.addresses) {
console.log(network, address);
}
// Returns: { data: { id, addresses: [{ address, network }] } }
// One wallet, carrying an address per supported network
// (ETHEREUM_MAINNET, POLYGON_MAINNET, SOLANA_MAINNET, TRON_MAINNET).The API reference documents crypto wallets as production only.
List Virtual Accounts
Get existing virtual accounts for a customer:
const response = await afriex.paymentMethods.listVirtualAccounts({
customerId: "customer-id",
currency: "NGN",
});
// Returns: { data: PaymentMethod[], total, page }The call is read-only. When no account exists it returns an empty list; it never creates one.
Create Virtual Account
Generate a new virtual account:
// Static: a permanent account, grouped by purpose
const staticAccount = await afriex.paymentMethods.createVirtualAccount({
currency: "NGN",
label: "SALES",
customerId: "customer-id",
});
// Dynamic: a one-time account for a specific amount
const dynamicAccount = await afriex.paymentMethods.createVirtualAccount({
currency: "NGN",
amount: 50000,
customerId: "customer-id",
});
if (dynamicAccount) {
console.log(dynamicAccount.accountNumber, dynamicAccount.reference);
}Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
currency | string | Yes | 3-letter currency code |
label | string | No* | One of SALES, OPERATIONS, PAYROLL, COLLECTIONS, VENDOR_PAYMENTS, TAX, REFUNDS, MARKETING, TREASURY, GENERAL |
amount | number | No* | Amount for a dynamic account, which expires after a short window |
customerId | string | - | The customer to create the account for. Omit it to create one for the business. A customer's virtual account can only be NGN |
*Mutually exclusive: provide label OR amount, not both.
createVirtualAccount() returns null when the issuing bank opens the
account after the request returns. The account then arrives through the
PAYMENT_METHOD.CREATED webhook.
Simulate a Transfer (Sandbox)
A sandbox virtual account receives no money on its own. Credit one the way a real bank transfer would:
const transfer = await afriex.paymentMethods.simulateTransfer({
accountNumber: "6520751033",
amount: 2500,
currency: "NGN",
});
console.log(transfer.reference);Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
accountNumber | string | Yes | The virtual account number to pay into |
amount | number | Yes | The amount transferred |
currency | string | Yes | The account's currency |
reference | string | - | The reference a one-time account was issued with. Needed only for that account |
outcome | "success" | "failed" | - | Defaults to success |
The deposit is reported by the transaction webhook, and the balance changes as it would in production.
Sandbox only. Production answers 403.
Get Pool Account
Get the pool account for a supported country:
const poolAccount = await afriex.paymentMethods.getPoolAccount({
customerId: "customer-id",
country: "NG",
});
console.log(poolAccount.accountNumber, poolAccount.reference);Pool accounts are shared across multiple customers in a country. Use the reference on the returned payment method to reconcile incoming deposits. Every call also sends a PAYMENT_METHOD.UPDATED webhook carrying the pool account.
listPoolAccounts() is the deprecated name for the same call.
After a customer pays into the pool account, submit the proof of payment to have the deposit credited.