What this guide covers
If you’ve read the quickstart but aren’t sure exactly which ID goes where, or why you need to create three different things before money can move, this guide is for you. The Afriex Business API has three core building blocks. They must be created in order, and each one produces an ID that the next step needs. This guide explains what each building block is, what ID it gives you, and exactly where that ID is used.The big picture
Think of it like this: a Customer is the end user your business is acting on behalf of: the sender of a payout, or the payer of a deposit. A Payment Method holds the account on the other side: the recipient’s account for a payout, or the account you collect from for a deposit. A Transaction is the instruction to move money, and it needs to know on whose behalf you are acting and which account to use. Here is how the IDs connect:ID quick-reference
Each building block explained
Customer
What it is: A Customer is the person or business your business is acting on behalf of: the sender of a payout, or the payer of a deposit. On a payout, Afriex passes the Customer’s details to the payout rail as the sender, and the Payment Method’s details as the recipient. For example, if you run a remittance app, each user who sends money home is a Customer, and the bank account they send to is a Payment Method linked to that Customer. The Customer record stores their identity information (name, email, phone, country) and is used to attribute transactions to the right person in your system. What ID it gives you:customerId
When you use that ID:
- Pass it as
customerIdwhen creating a Payment Method (to link the account to this person) - Pass it as
customerIdwhen creating a Transaction (to identify whose account is involved)
Payment Method
What it is: A Payment Method holds the account on the other side of the transaction: the recipient’s bank account, mobile money wallet, or other financial account for a payout, or the account you collect from for a deposit. It is linked to a Customer, the person on whose behalf you are acting. On a payout, the account belongs to the recipient, who is usually not the Customer. You need a Payment Method before you can send or receive money, because the Transaction needs to know exactly which account to credit or debit. What ID it gives you:paymentMethodId
When you use that ID:
- As
destinationIdin a WITHDRAW transaction (the account the money is sent to) - As
sourceIdin a DEPOSIT transaction (the account the money is pulled from)
A Payment Method has a
type field, either WITHDRAW (used to send funds to a recipient) or DEPOSIT (used to collect funds from a customer). Make sure you create the right type for the transaction you plan to run.Virtual bank accounts
VIRTUAL_BANK_ACCOUNT is not created through the standard POST /api/v1/payment-method endpoint. It has two dedicated endpoints, and they do different things:
- Create Virtual Account (
POST /api/v1/payment-method/virtual-account) creates one. Passcurrency, optionallycustomerId, and exactly one oflabeloramount. - List Virtual Accounts (
GET /api/v1/payment-method/virtual-account) is read-only. It returns every active account for that customer and currency, and responds200withdata: []when none exist. It does not create one.
POST:
-
Static (
label): A permanent virtual bank account. The same account number is returned on every subsequent list for that customer and currency, and the customer can fund it at any time for any amount.labelis one ofSALES,OPERATIONS,PAYROLL,COLLECTIONS,VENDOR_PAYMENTS,TAX,REFUNDS,MARKETING,TREASURY,GENERAL. -
Dynamic (
amount): An account tied to a specific amount that expires after a set window (the response includesexpiresInMinutes). Use this when collecting a specific payment within a defined time.
When you pass a
customerId, virtual accounts are available in NGN and GHS. Other currencies for a specific customer are rejected with UNSUPPORTED_VIRTUAL_ACCOUNT_CURRENCY. There is also a cap on how many accounts a single business-customer-currency combination can hold; exceeding it returns VIRTUAL_ACCOUNT_LIMIT_REACHED.country; pass customerId to scope the response to a specific end-user. Use the reference on the response to reconcile incoming deposits.
Virtual accounts are for your end customers. Link each one to a customerId so payments are attributed to the right person.
Transaction
What it is: A Transaction is the actual instruction to move money. It references a Customer and (depending on the type) one of their Payment Methods. What ID it gives you:transactionId
When you use that ID:
- To check the status:
GET /api/v1/transaction/{transactionId} - It appears in webhook events so you can match notifications to records in your system
WITHDRAW: Your business wallet is the implicit source. Afriex debits your wallet automatically. You do not specify a source payment method.DEPOSIT: Your business wallet is the implicit destination. Afriex credits your wallet automatically. You do not specify a destination payment method.SWAP: Both source and destination are your business wallet. No customer or payment method IDs are needed at all.
The 3-step integration sequence
Here is the exact order of operations, with the IDs flowing from one step to the next.1
Create the Customer
Register the person on whose behalf the transaction is being made (the originator or sender).Save the
customerId from the response. You need it in the next step.2
Create the Payment Method
Register the recipient’s bank account or mobile wallet (the account the money will be sent to or collected from). Link it to the Customer from Step 1 by passing their Then create the payment method using the Save the
customerId.First, look up the correct institution code for the customer’s bank or mobile provider:institutionCode and institutionName from that response:paymentMethodId from the response. This is what goes into destinationId (or sourceId) in your transaction.3
Create the Transaction
Now create the transaction using both IDs from the previous steps.Here the recipient gets exactly 91.50 GHS and the API works out the USD cost. To show that cost before you send, call Quote a Withdrawal first.The response includes a
customerId= the ID from Step 1destinationId= thepaymentMethodIdfrom Step 2 (for a WITHDRAW)
transactionId. Use it to track status or match incoming webhook events.Transaction type payloads side by side
What changes between each type
Payment method fields by channel
Different payment channels require different fields. Use the sections below to find the exact payload shape for your channel.customerId is listed below for every channel because that is the usual case, but it is optional. Omit it and the payment method is attached to the business owner instead of an end customer. Pass it whenever the method belongs to one of your customers, which is almost always what you want.BANK_ACCOUNT: Local bank transfer
BANK_ACCOUNT: Local bank transfer
Required fields:
customerId, channel, accountName, accountNumber, countryCode, institution.institutionCode, institution.institutionNameTwo currencies differ:- EUR (IBAN): only
institution.institutionNameis required. - CNY (China):
institution.institutionBranchis required as well.
MOBILE_MONEY: M-Pesa, MTN MoMo, Airtel, etc.
MOBILE_MONEY: M-Pesa, MTN MoMo, Airtel, etc.
Required fields:
customerId, channel, accountName, accountNumber (the mobile number), countryCode, institution.institutionName. Send the provider’s institution.institutionCode from List Institutions as well.Look up valid institution codes for the country: List InstitutionsSWIFT: International wire transfer
SWIFT: International wire transfer
Required fields:
customerId, channel, accountName, accountNumber (IBAN or account number), countryCode, institution.institutionCode (SWIFT/BIC), institution.institutionName, institution.institutionAddress, recipient.recipientAddressSWIFT payouts are in USD, and need the correspondent (intermediary) bank too: institution.correspondentBankName and institution.correspondentBankAccountNumber.Use Institution Codes to resolve a SWIFT code to a bank name.UPI: India
UPI: India
Required fields:
customerId, channel, accountName, accountNumber (UPI ID / VPA), countryCode, recipient.recipientPhoneUPI takes no institution object.INTERAC: Canada
INTERAC: Canada
Required fields:
customerId, channel, accountName, accountNumber (the email address registered for Interac), countryCode, recipient.recipientEmailInterac takes no institution object.WE_CHAT: China
WE_CHAT: China
Required fields:
customerId, channel, accountName, accountNumber (phone number), countryCode, institution.institutionCode ("WECHAT"), institution.institutionName ("WECHAT"), recipient.recipientPhoneAlipay: China
Alipay: China
Alipay does not have a channel of its own. Create it on the
WE_CHAT channel and set institution.institutionCode and institution.institutionName to ALIPAY; sending "channel": "ALIPAY" is rejected.Required fields: customerId, channel, accountName, accountNumber (Alipay-linked phone number or account ID), countryCode, institution.institutionCode, institution.institutionNameVIRTUAL_BANK_ACCOUNT: Receive deposits
VIRTUAL_BANK_ACCOUNT: Receive deposits
Virtual bank accounts are not created through the standard
POST /api/v1/payment-method endpoint. Use the dedicated endpoint instead:POST creates the account; GET only lists what already exists and returns data: [] when there is none.Two shapes, determined by which field you pass to POST:With a
customerId, NGN and GHS are supported. KES and USD accounts belong to your business, so omit customerId to create them.See Create Virtual Account and List Virtual Accounts for the full request and response reference.Institution fields: which one to use and when
Theinstitution object has several fields that look similar. Here is exactly what each one is and when you need it.
How to find the right institutionCode
- Call
GET /api/v1/payment-method/institution?channel=BANK_ACCOUNT&countryCode=NG - The response returns a list of institutions, each with
institutionCodeandinstitutionName - Copy those values directly into your Payment Method creation request
000013 for GTBank. The API also accepts the older three-digit CBN sort code, such as 058.
For SWIFT and US routing numbers, use GET /api/v1/payment-method/institution/codes to resolve a known SWIFT/BIC code to a bank name.
The meta object
Every transaction must include ameta object with two required fields. Without them, the API returns a 400 error.
Common mistakes
1. Using a customerId as destinationId or sourceId
destinationId and sourceId must be a paymentMethodId, not a customerId. Both look like hex strings, which makes it easy to mix them up.
2. Skipping the 3-step sequence
You cannot create a Transaction without first creating a Customer and a Payment Method. The API returns a404 or 400 if either does not exist. Always follow: Customer → Payment Method → Transaction.
3. Mixing up DEPOSIT and WITHDRAW fields
- WITHDRAW uses
destinationId(where the money goes) - DEPOSIT uses
sourceId(where the money comes from)
destinationId on a DEPOSIT (or sourceId on a WITHDRAW) will cause the API to reject the request.
4. Assuming SWAP needs a payment method
SWAP does not touch any external account. It converts currency inside your Afriex business wallet. NocustomerId, destinationId, or sourceId is needed. Only the currency pair and the meta object are required.
5. Omitting meta.idempotencyKey or meta.reference
Both are required on every transaction. The API returns a400 if either is missing. Always generate a fresh UUID for idempotencyKey and use your own internal order or payment ID as reference.
6. Hardcoding institution codes without looking them up
Do not guess institution codes. UseGET /api/v1/payment-method/institution?channel=BANK_ACCOUNT&countryCode=NG to get the correct code for each country and channel. The same bank can have a different code in different countries.
7. Passing institutionId as input
institutionId is an output field. It appears in API responses but you never need to supply it when creating a Payment Method. The fields you pass are institutionCode and institutionName.
Tracking what happens after you create a transaction
Transactions do not complete instantly. After creation the status will bePENDING or PROCESSING. Here is how to know when it finishes.
Testing in sandbox? Sandbox transactions settle automatically in about 5 minutes. Pick the outcome with the payment method’s last four digits (e.g.
0001 for fail, 0003 to hold in PENDING until you call /simulate); add SIMULATE_INSTANT anywhere in meta.reference to speed things up to about 30 seconds. Full reference: Testing in Sandbox.TRANSACTION.UPDATED events. Afriex sends an HTTP POST to your webhook URL with the full transaction payload whenever the transaction’s status changes.
This fires on intermediate statuses too, not just terminal ones, so expect several deliveries for a single transaction. Branch on the payload’s status field to decide whether the transaction is actually finished.
See Webhook setup for configuration steps and payload examples.
Option B: Poll the status endpoint
Terminal statuses
Next steps
Quickstart
Make your first API call in under 5 minutes.
Create a Customer
Full parameter reference for customer creation.
Create a Payment Method
All channels and required fields in the API reference.
Create a Transaction
Full transaction creation reference with all fields.
Data Model Reference
Complete field-by-field documentation for all models.
Webhooks
Receive real-time transaction status updates.
