Skip to main content

Payout Webhooks

Payout webhook events track single payouts, payout intents, and batch payouts.

Single Payout Events

EventDescription
payout.initiatedPayout accepted by ZenPay and moved into processing (funds are reserved but the final outcome is not yet known)
payout.completedPayout processing finished successfully and funds have been fully debited from the reserved balance
payout.failedPayout processing did not complete successfully and any reserved funds are released or returned according to ZenPay rules
payout.cancelledPayout was cancelled before processing completed

Payload

{
"event_type": "payout.completed",
"payment_data": {
"payoutId": "payout_1774778823937_17298d89",
"transactionId": "po6efbc8502da51774842226226",
"intentId": "poi_mnblh1o5_e8190e32",
"amount": 100,
"currency": "INR",
"status": "completed",
"beneficiary": "Rajesh Kumar",
"payoutType": "BANK_TRANSFER",
"failureReason": null,
"metadata": {
"order_no": "ORD-2026-001",
"customer_ref": "CUST-789"
}
}
}

Payload Fields

FieldTypeDescription
payoutIdstringInternal payout ID
transactionIdstringExternal payout transaction reference — matches externalPayoutId from the confirm response
intentIdstring | nullPayout intent ID (if created via the two-step intent flow)
amountnumberPayout amount
currencystringPayout currency
statusstringinitiated, completed, failed, or cancelled
beneficiarystringBeneficiary name
payoutTypestringPayout method (e.g. BANK_TRANSFER, UPI)
failureReasonstring | nullReason for failure (only on payout.failed)
metadataobject | nullCustom key-value pairs passed when creating the payout intent — returned as-is in all webhook callbacks
Linking payouts end-to-end

When using the two-step payout intent flow:

  1. Create intent → get intentId
  2. Confirm intent → get intentId + payoutId + externalPayoutId
  3. Webhook callback → get intentId + payoutId + transactionId

The transactionId in the webhook equals externalPayoutId from the confirm response. All three IDs are present in both the confirm response and webhook, so you can always link them.


Payout Intent Events

EventDescription
payout_intent.createdPayout intent created
payout_intent.confirmedPayout intent confirmed and submitted for processing
payout_intent.succeededPayout intent completed successfully
payout_intent.failedPayout intent failed
payout_intent.cancelledPayout intent cancelled
payout_intent.expiredPayout intent expired without confirmation

Payload

Shares the same payload shape as single payout webhooks:

{
"event_type": "payout_intent.succeeded",
"payment_data": {
"intentId": "poi_mnblh1o5_e8190e32",
"payoutId": "payout_1774778823937_17298d89",
"transactionId": "po6efbc8502da51774842226226",
"amount": 500,
"currency": "INR",
"status": "succeeded",
"beneficiary": "Rajesh Kumar",
"payoutType": "BANK_TRANSFER",
"failureReason": null,
"metadata": {
"order_no": "ORD-2026-001"
}
}
}

Batch Payout Events

EventDescription
batch_payout.createdBatch payout created
batch_payout.processingBatch payout is being processed
batch_payout.completedAll payouts in the batch completed successfully
batch_payout.partially_completedSome payouts in the batch completed, others failed
batch_payout.failedBatch payout failed
batch_payout.cancelledBatch payout was cancelled

Payload

{
"event_type": "batch_payout.completed",
"payment_data": {
"batchId": "bp_abc123",
"totalPayouts": 50,
"successCount": 48,
"failedCount": 2,
"totalAmount": 25000,
"currency": "INR",
"status": "completed",
"completedAt": "2026-03-16T14:30:00.000Z"
}
}

Payload Fields

FieldTypeDescription
batchIdstringBatch payout ID
totalPayoutsnumberTotal payouts in the batch
successCountnumberNumber of successful payouts
failedCountnumberNumber of failed payouts
totalAmountnumberTotal amount across all payouts
currencystringBatch currency
statusstringcreated, processing, completed, partially_completed, failed, cancelled
completedAtstring | nullISO 8601 completion timestamp