Create Sub-Merchant Wallets
NextAPI organises funds in a three-level hierarchy: Partner → Merchant → Account. As a partner, you create merchants to represent the businesses or entities on your platform, and accounts under each merchant to hold and move funds.
This guide walks through creating a merchant, provisioning accounts, and structuring your wallet hierarchy for common platform patterns.
How the hierarchy works
Partner (you)
├── Merchant A (e.g. a business on your platform)
│ ├── Account: Collection ← receives QRPH payments
│ └── Account: Disbursement ← sends payouts
├── Merchant B
│ ├── Account: Collection
│ └── Account: Disbursement
└── Merchant C
└── Account: General ← single account for smaller merchants
- Merchants are logical groupings — typically one per customer, entity, or business unit.
- Accounts hold balances. All money movement (collection, payout, transfer) happens at the account level.
- Transfers between accounts within your hierarchy are instant and free.
Prerequisites
- NextAPI partner credentials (Client ID and Client Secret)
- Sandbox credentials from /sandbox
Step 1: Create a merchant
- cURL
- Node.js
- Python
curl -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
-X POST "https://api.partners.nextpay.world/v2/merchants" \
-H "Content-Type: application/json" \
-d '{
"name": "Dela Cruz Sari-Sari Store",
"external_id": "merchant-delacuz-001"
}'
async function createMerchant(name, externalId) {
const response = await fetch(
'https://api.partners.nextpay.world/v2/merchants',
{
method: 'POST',
headers: {
'Authorization': 'Basic ' + Buffer.from('YOUR_CLIENT_ID:YOUR_CLIENT_SECRET').toString('base64'),
'Content-Type': 'application/json',
},
body: JSON.stringify({ name, external_id: externalId }),
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(`Failed to create merchant: ${error.message}`);
}
return response.json();
}
import requests
import base64
def create_merchant(name, external_id):
credentials = base64.b64encode(b'YOUR_CLIENT_ID:YOUR_CLIENT_SECRET').decode()
response = requests.post(
'https://api.partners.nextpay.world/v2/merchants',
headers={
'Authorization': f'Basic {credentials}',
'Content-Type': 'application/json',
},
json={'name': name, 'external_id': external_id},
)
response.raise_for_status()
return response.json()
Response
{
"id": "mrc_01HABC",
"name": "Dela Cruz Sari-Sari Store",
"external_id": "merchant-delacuz-001",
"status": "active",
"created_at": "2025-11-15T10:00:00Z"
}
Save the id (mrc_01HABC) — you'll use it to create accounts under this merchant.
Set external_id to your own internal identifier (e.g. your database primary key). This lets you look up NextAPI merchants by your own IDs and avoids storing the mrc_xxx mapping separately.
Step 2: Create accounts
Each merchant needs at least one account. Create accounts based on what the merchant will do on your platform.
- cURL
- Node.js
- Python
curl -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
-X POST "https://api.partners.nextpay.world/v2/accounts" \
-H "Content-Type: application/json" \
-d '{
"merchant_id": "mrc_01HABC",
"name": "Collection Account",
"external_id": "acct-delacuz-collection"
}'
async function createAccount(merchantId, name, externalId) {
const response = await fetch(
'https://api.partners.nextpay.world/v2/accounts',
{
method: 'POST',
headers: {
'Authorization': 'Basic ' + Buffer.from('YOUR_CLIENT_ID:YOUR_CLIENT_SECRET').toString('base64'),
'Content-Type': 'application/json',
},
body: JSON.stringify({
merchant_id: merchantId,
name,
external_id: externalId,
}),
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(`Failed to create account: ${error.message}`);
}
return response.json();
}
def create_account(merchant_id, name, external_id):
credentials = base64.b64encode(b'YOUR_CLIENT_ID:YOUR_CLIENT_SECRET').decode()
response = requests.post(
'https://api.partners.nextpay.world/v2/accounts',
headers={
'Authorization': f'Basic {credentials}',
'Content-Type': 'application/json',
},
json={
'merchant_id': merchant_id,
'name': name,
'external_id': external_id,
},
)
response.raise_for_status()
return response.json()
Response
{
"id": "acct_01HXYZ",
"merchant_id": "mrc_01HABC",
"name": "Collection Account",
"external_id": "acct-delacuz-collection",
"status": "active",
"created_at": "2025-11-15T10:01:00Z"
}
Step 3: Provision the full wallet set
For most platforms, provision merchant and accounts together at onboarding time:
async function onboardMerchant(internalMerchantId, merchantName) {
// 1. Create merchant
const merchant = await createMerchant(
merchantName,
`merchant-${internalMerchantId}`
);
// 2. Create collection account (receives QRPH payments)
const collectionAccount = await createAccount(
merchant.id,
'Collection',
`acct-${internalMerchantId}-collection`
);
// 3. Create disbursement account (sends payouts)
const disbursementAccount = await createAccount(
merchant.id,
'Disbursement',
`acct-${internalMerchantId}-disbursement`
);
return {
merchantId: merchant.id,
collectionAccountId: collectionAccount.id,
disbursementAccountId: disbursementAccount.id,
};
}
Store these IDs alongside your merchant record. You will need them to create payment intents, generate QR codes, and initiate payouts.
Common wallet patterns
Single general account
For simple use cases where a merchant both collects and disburses from the same pool:
Merchant
└── Account: General ← QRPH collections land here, payouts go out from here
Works well for small merchants or platforms where the merchant manages their own balance.
Separated collection and disbursement
Keeps incoming and outgoing funds in separate accounts. Useful when you want to control when and how much is available for payouts:
Merchant
├── Account: Collection ← QRPH / payment intent collections
└── Account: Disbursement ← funded by transfer, used for payouts only
Transfer from Collection to Disbursement on a schedule or per-event. See Transfer Funds Between Accounts.
Platform fee split
Add a platform account to capture your commission automatically:
Partner
├── Platform Account ← your platform's revenue account
├── Merchant A
│ └── Account: General ← merchant receives full payment, commission transferred out
└── Merchant B
└── Account: General
After each collection webhook, transfer your commission to the platform account. See Take a Commission from Sales.
Check account balances
curl -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
"https://api.partners.nextpay.world/v2/accounts/acct_01HXYZ/balances"
{
"account_id": "acct_01HXYZ",
"available": 150000,
"pending": 25000,
"reserved": 0,
"currency": "PHP"
}
available— immediately usable for transfers and payoutspending— collections not yet settledreserved— held for in-progress payout requests
Key constraints
- Hierarchy boundary. Transfers can only happen between accounts within your own partner hierarchy. You cannot transfer to accounts owned by another partner.
- Active status required. Accounts must be
activeto send or receive funds. - No currency choice. All accounts are PHP. Cross-currency is not supported.
Related
- Wallet Structure — the full hierarchy explained
- Transfer Funds Between Accounts — move funds within your hierarchy
- Take a Commission from Sales — split proceeds automatically
- Accept a QRPH Payment — collect into an account