Your First Payout
In this tutorial you'll send your first payout through NextAPI — from checking your balance, to creating a payout request, to receiving confirmation.
Time: ~10 minutes Prerequisites: Sandbox credentials from /sandbox. Complete Your First API Call first if you haven't verified your auth yet.
What you'll build
By the end of this tutorial you'll have:
- Checked your account balance in the sandbox
- Sent a payout to a test bank account
- Checked the payout status
- Understood the payout lifecycle
Step 1: Get your account ID
You need an account ID to send a payout from. If you followed the first API call tutorial, you already have a merchant and account. Otherwise, list your merchants first:
- cURL
- Node.js
curl -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
"https://api.partners.nextpay.world/v2/merchants"
const response = await fetch('https://api.partners.nextpay.world/v2/merchants', {
headers: {
'Authorization': 'Basic ' + Buffer.from('YOUR_CLIENT_ID:YOUR_CLIENT_SECRET').toString('base64'),
},
});
const { data: merchants } = await response.json();
console.log(merchants[0].id); // merchant ID
Then list accounts for that merchant:
curl -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
"https://api.partners.nextpay.world/v2/merchants/merch_01HXYZ/accounts"
Note the id from an account in the response — you'll use this as account_id in the payout request.
Step 2: Check your balance
Before sending a payout, confirm the account has available funds. In sandbox, accounts start with test funds pre-loaded.
- cURL
- Node.js
curl -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
"https://api.partners.nextpay.world/v2/accounts/acct_01HXYZ/balances"
const response = await fetch(
'https://api.partners.nextpay.world/v2/accounts/acct_01HXYZ/balances',
{
headers: {
'Authorization': 'Basic ' + Buffer.from('YOUR_CLIENT_ID:YOUR_CLIENT_SECRET').toString('base64'),
},
}
);
const balance = await response.json();
console.log(`Available: PHP ${(balance.available / 100).toFixed(2)}`);
{
"available": 10000000,
"pending": 0,
"reserved": 0,
"currency": "PHP"
}
10000000 centavos = PHP 100,000.00. Only available funds can be disbursed.
Step 3: Send a payout
Create a payout request to send PHP 100.00 (10000 centavos) to a test BPI account:
- cURL
- Node.js
- Python
curl -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
-X POST "https://api.partners.nextpay.world/v2/payout-requests" \
-H "Content-Type: application/json" \
-H "X-Idempotency-Key: tutorial-payout-001" \
-d '{
"account_id": "acct_01HXYZ",
"amount": 10000,
"recipient": {
"type": "bank_account",
"bank_code": "BPI",
"account_number": "1234567890",
"account_name": "Test Recipient"
},
"description": "My first payout",
"reference": "tutorial-payout-001"
}'
const response = await fetch('https://api.partners.nextpay.world/v2/payout-requests', {
method: 'POST',
headers: {
'Authorization': 'Basic ' + Buffer.from('YOUR_CLIENT_ID:YOUR_CLIENT_SECRET').toString('base64'),
'Content-Type': 'application/json',
'X-Idempotency-Key': 'tutorial-payout-001',
},
body: JSON.stringify({
account_id: 'acct_01HXYZ',
amount: 10000, // PHP 100.00
recipient: {
type: 'bank_account',
bank_code: 'BPI',
account_number: '1234567890',
account_name: 'Test Recipient',
},
description: 'My first payout',
reference: 'tutorial-payout-001',
}),
});
const payoutRequest = await response.json();
console.log('Payout Request ID:', payoutRequest.id);
console.log('Status:', payoutRequest.status);
import requests
import base64
credentials = base64.b64encode(b'YOUR_CLIENT_ID:YOUR_CLIENT_SECRET').decode()
response = requests.post(
'https://api.partners.nextpay.world/v2/payout-requests',
headers={
'Authorization': f'Basic {credentials}',
'Content-Type': 'application/json',
'X-Idempotency-Key': 'tutorial-payout-001',
},
json={
'account_id': 'acct_01HXYZ',
'amount': 10000,
'recipient': {
'type': 'bank_account',
'bank_code': 'BPI',
'account_number': '1234567890',
'account_name': 'Test Recipient',
},
'description': 'My first payout',
'reference': 'tutorial-payout-001',
}
)
payout_request = response.json()
print(f"Payout Request ID: {payout_request['id']}")
print(f"Status: {payout_request['status']}")
Response
{
"id": "pr_01HABC",
"account_id": "acct_01HXYZ",
"amount": 10000,
"status": "initiated",
"description": "My first payout",
"reference": "tutorial-payout-001",
"recipient": {
"type": "bank_account",
"bank_code": "BPI",
"account_number": "1234567890",
"account_name": "Test Recipient"
},
"created_at": "2025-11-15T10:30:00Z"
}
status: "initiated" — the payout is queued and being processed. It's not instant.
Step 4: Check the payout status
Poll the payout request to see when it completes:
- cURL
- Node.js
curl -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
"https://api.partners.nextpay.world/v2/payout-requests/pr_01HABC"
const response = await fetch(
'https://api.partners.nextpay.world/v2/payout-requests/pr_01HABC',
{
headers: {
'Authorization': 'Basic ' + Buffer.from('YOUR_CLIENT_ID:YOUR_CLIENT_SECRET').toString('base64'),
},
}
);
const payoutRequest = await response.json();
console.log('Status:', payoutRequest.status);
In sandbox, payouts simulate real processing time. Check again after a few seconds and you should see:
{
"id": "pr_01HABC",
"status": "completed",
...
}
Step 5: Understand the status progression
A payout request moves through these states:
initiated → processing → completed
↘ failed
| Status | Meaning |
|---|---|
initiated | Accepted, queued for processing |
processing | Submitted to the bank rail |
completed | Bank confirmed receipt |
failed | Could not be delivered — see error field for reason |
In production, InstaPay payouts typically complete in under 30 seconds. PESONet payouts complete at the next batch cutoff (10 AM or 3 PM Manila time).
What's next?
You've sent your first payout. Here's where to go from here:
- Handle failures gracefully: Handle Payout Failures — error classification, retry strategies
- Send to many recipients: Run Mass Payroll — batch payout API
- Get notified in real time: Setup Webhooks — instead of polling
- Understand the lifecycle: Payout Lifecycle — full state machine