Wallet
Panel Guide
Bulk Payouts

Panel — Bulk Payouts

Who calls these endpoints?Merchant panel
Base path
/api/panel/v1/wallet
Identity
Panel session (JWT) — Authorization: Bearer <panel access token>. The token comes from panel login; an s2s signing key does NOT open these endpoints.
Authorization
RBAC permission: wallet:bulk:create · wallet:bulk:approveFour-eyes: the requester and the approver cannot be the same person — this is enforced by identity comparison, not by a role gate.
Cross-surface
MOSTLY mirrored: 9 bulk-payout endpoints also exist in the s2s API (create, list, detail, items, submit, approve, reject, process, retry-failed). Panel-only: POST bulk-payouts/:id/cancel, GET bulk-payouts/:id/preview, GET bulk-payouts/:id/statement, GET bulk-payouts/counts and GET bulk-payout-statements/period.

Runs many payouts — payroll, commissions, refund batches — from a single list.

Coming soon — non-wallet targets require a bank integration

Batches targeting wallets work today. IBAN-targeted items require a connected bank integration. Status: Roadmap.

Endpoints

GET  bulk-payouts                      # batches (filter by programId, status)
POST bulk-payouts                      # create
GET  bulk-payouts/:id                  # summary
GET  bulk-payouts/:id/preview          # preview before processing
GET  bulk-payouts/:id/items            # items
POST bulk-payouts/:id/submit           # submit for approval
POST bulk-payouts/:id/approve          # approve
POST bulk-payouts/:id/reject           # reject
POST bulk-payouts/:id/process          # process
POST bulk-payouts/:id/retry-failed     # retry failures
POST bulk-payouts/:id/cancel           # cancel
GET  bulk-payouts/:id/statement        # batch statement
GET  bulk-payout-statements/period     # period statement
GET  bulk-payouts/counts               # batch counts per status

Status counters

GET bulk-payouts/counts               # filter by programId

Returns server-side counts per status instead of making you page through the batch list.

{
  "counts": [
    { "status": "PENDING_APPROVAL", "count": 12, "exact": true },
    { "status": "PROCESSING", "count": 500, "exact": false }
  ],
  "cap": 500
}
🚫

Two fields are easy to misread, and both mislead the operator:

  • exact: false ⇒ the count hit the cap. Render it as "N+", never as an exact number.
  • counts: [] (empty array) ⇒ could not count, it does NOT mean "zero batches". Showing an empty list as "none" tells the operator they have nothing awaiting approval.

The counter endpoint uses the same permission as the list endpoint (wallet:bulk:create) and leaks nothing the list does not — it returns status and count only.

Preview

GET bulk-payouts/:id/preview
⚠️

Always preview before submitting for approval. The preview shows invalid targets and the total before anything is processed. In a 500-line batch, one mis-mapped column can turn the whole list into payments to the wrong people.

Check: total amount, item count, invalid targets, source account balance.

Approval

POST bulk-payouts/:id/submit
POST bulk-payouts/:id/approve      # { approve: true, reason? }
POST bulk-payouts/:id/reject       # { reason }
⚠️

Maker-checker: the creator cannot approve. Enforced by principal comparison, not a role gate — even as OWNER/ADMIN you cannot approve your own batch.

Processing and retries

POST bulk-payouts/:id/process
POST bulk-payouts/:id/retry-failed
⚠️

Never recreate a partially failed batch — use retry-failed. Creating a new batch pays the successful items a second time.

Item status is independent of batch status: a COMPLETED batch can still contain failed items. Build your accounting records from item statuses.

Cancellation

POST bulk-payouts/:id/cancel       # { reason }

Cancels an unprocessed batch. Processed items are not reversed.

Statements

GET bulk-payouts/:id/statement
GET bulk-payout-statements/period     # sourceWalletAccountId, date range

Batch and period statements for accounting reconciliation.

Checklist

  • Previewed; total and item count match expectations
  • No invalid targets
  • Sufficient balance on the source account
  • Approved by a different operator
  • Item statuses reviewed after processing
  • retry-failed used for failures (not a new batch)

Common mistakes

SymptomCauseFix
The same payout went twiceThe batch was recreatedUse retry-failed
Batch partially processedInsufficient balance or invalid targetsInspect the item list
Approval rejectedApprover equals creatorA different operator must approve
IBAN items rejectedNo bank integration connectedSee the roadmap box