Skip to content

Disburse payouts

POST /payments/send disburses funds to one or many beneficiaries via mobile money or e-wallet. Up to 100 beneficiaries per call. Supports immediate, scheduled, and recurring schedules.

This is a server-side endpoint — neither SDK exposes a method for it. Call it from your backend.

sending_typeUse case
immediateOne-shot payout. The default.
scheduledDisburse on a list of explicit future dates (scheduled_dates).
recurringRecurring payroll, allowance, etc. Set frequency, start date, and number of occurrences.

For payroll, recurring is almost always the right choice — the gateway tracks each occurrence and emits a webhook per occurrence.

Terminal window
curl https://app.api.gtwy.pdirect.com/api/v1/payments/send \
-X POST \
-H "Authorization: Bearer sess_AbCdEf..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 8d3f0e2b-5c7d-4e9f-aab2-2e4f3d8c0b6e" \
-d '{
"customer_reference": "payout_2026_05_05_001",
"currency": "usd",
"receipt_mode": "mobile_money",
"notify_url": "https://merchant.example.com/pdirect/webhook",
"sending_type": "immediate",
"beneficiaries": [
{ "phone_number": "+243998857000", "amount": "10.00" }
],
"note": "Payout for May 5"
}'

Response:

{
"batch_id": "batch_xyz789",
"customer_reference": "payout_2026_05_05_001",
"total_amount": "10.00",
"total_fee": "0.10",
"successful_count": 1,
"failed_count": 0,
"pending_count": 0,
"status": "completed",
"beneficiaries": [
{
"phone_number": "+243998857000",
"amount": "10.00",
"currency": "usd",
"status": "completed",
"transaction_id": "txn_b2c_8f3a4c",
"message": "Payout sent",
"fee_amount": "0.10"
}
],
"created_at": "2026-05-05T10:15:00Z",
"completed_at": "2026-05-05T10:15:05Z"
}

The status of the batch can be completed, partial_success, pending, processing, or failed. Each beneficiary has its own status — read both.

Up to 100 beneficiaries per request. Mix mobile money and e-wallet on different lines (set receipt_mode per call, not per beneficiary):

{
"customer_reference": "payroll_2026_05",
"currency": "usd",
"receipt_mode": "mobile_money",
"notify_url": "https://merchant.example.com/pdirect/webhook",
"sending_type": "immediate",
"beneficiaries": [
{ "phone_number": "+243998857000", "amount": "1500.00" },
{ "phone_number": "+243998857001", "amount": "1500.00" },
{ "phone_number": "+243998857002", "amount": "1750.00" }
],
"note": "May payroll"
}

Validators:

  • Total of all amounts must be > 0 and <= 1,000,000.
  • No duplicate phone_number (or wallet_number for wallet receipt mode).
  • Each beneficiary must have the relevant identifier for the receipt_mode.

If you need to send to a wallet and a mobile-money number in the same logical batch, issue two separate calls — they share a customer_reference but have different batch_ids.

{
"customer_reference": "rent_2026",
"currency": "usd",
"receipt_mode": "wallet",
"notify_url": "https://merchant.example.com/pdirect/webhook",
"sending_type": "scheduled",
"scheduled_dates": ["2026-06-01", "2026-07-01", "2026-08-01"],
"beneficiaries": [
{ "wallet_number": "3005710720108954", "amount": "850.00" }
],
"note": "Quarterly rent"
}

The gateway holds the batch and disburses on each scheduled_dates entry. Each disbursement gets its own transaction_id and webhook.

{
"customer_reference": "payroll_2026_jane_doe",
"currency": "usd",
"receipt_mode": "wallet",
"notify_url": "https://merchant.example.com/pdirect/webhook",
"sending_type": "recurring",
"recurring_frequency": "monthly",
"recurring_start_date": "2026-05-15",
"recurring_occurrences": 12,
"beneficiaries": [
{ "wallet_number": "3005710720108954", "amount": "1500.00" }
],
"note": "Monthly salary"
}

recurring_frequency accepts daily, weekly, biweekly, monthly. Combine with recurring_start_date (ISO date) and recurring_occurrences (>= 1).

Each occurrence emits its own webhook. Cancelling a recurring schedule mid-flight isn’t yet exposed in the API — contact your Pdirect rep.

Always send Idempotency-Key. A network blip during a payroll disbursement is the worst possible time to issue duplicate transfers.

Terminal window
-H "Idempotency-Key: payroll-2026-05-15-jane"

The key can be deterministic (a hash of (customer_reference, period)) or a fresh UUID — as long as you can re-send the same key on retry.

Two webhooks per transaction:

  • One when the batch is created (status: pending or processing).
  • One when each beneficiary settles (status: completed or failed).

Match incoming webhooks to your local records by transaction_id for individual lines and batch_id for the batch-level update.

If you’re polling instead, use GET /payments/status/{transaction_id} on each beneficiary’s transaction_id. There is no batch-level status query in v1.

error_codeMeaningFix
1101 INVALID_AMOUNTA beneficiary amount is <= 0 or batch total > 1,000,000Validate before sending
1103 INVALID_PAYMENT_METHODreceipt_mode not in [mobile_money, wallet]Fix the field
1109 MISSING_REQUIRED_FIELDE.g. phone_number missing for mobile_moneyValidate per beneficiary
1207 BENEFICIARY_LIMIT_EXCEEDEDMore than 100 beneficiariesSplit into multiple batches