Payout Webhook

This page walks you through how to set up and observe MoneyHash webhook notifications for payout operations. It covers both individual payout intents and bulk payout requests.

For the full list of payout webhook events, payload structures, and event descriptions, see Webhook Types.


Before you start

Payout webhooks require more setup than payment webhooks. Make sure the following are in place before testing:

  • A customer with complete billing information — full name, phone, email, and billing address. This is required when using a saved payout method, and expected by most providers when submitting raw beneficiary details directly.
  • A payout provider configured and active on your account. Contact MoneyHash support if you're unsure which providers are available for your integration.
  • A webhook URL ready to receive events. Use webhook.site to get a free URL for testing.

Testing an individual payout webhook

1. Create a payout intent

Make a POST request to /api/v1.4/payout/intent/ and include your webhook_url:

{
  "amount": 50,
  "amount_currency": "egp",
  "customer_id": "8c91204b-5a5b-4496-9904-76a6b72bc15d",
  "webhook_url": "https://webhook.site/your-unique-url"
}

As soon as the intent is created, MoneyHash begins processing the disburse operation with the provider.

2. Watch webhook.site

Open your webhook.site page and watch for incoming events. Here is what to expect:

  • If the provider requires approval before disbursing, you will first receive a transaction.disburse.pending_approval event.
  • Once the provider processes the payout, you will receive either transaction.disburse.successful or transaction.disburse.failed.

3. Identify the payout in the payload

To confirm you are looking at a payout webhook (not a payment webhook), check two fields in the payload:

  • transaction.type will be "payout" — distinguishing it from "payment" transactions
  • intent.payout_status.status reflects the current money movement outcome — for example "DISBURSED" on success

4. What if you void the payout?

If you initiate a void via POST /api/v1.4/payout/transactions/{transaction_id}/void/ while the disburse is still in progress, you will receive either transaction.void.successful (payout cancelled, no funds moved) or transaction.void.failed (void attempt failed, disburse continues).

Note: Void availability depends on the provider. Not all providers support cancelling a payout once it is in progress. See Cancelling a payout for details.


Testing a bulk payout webhook

1. Create a bulk payout request

Make a POST request to /api/v1.4/payout/bulk/requests/ with your webhook_url and at least one item:

{
  "label": "test bulk payout",
  "webhook_url": "https://webhook.site/your-unique-url",
  "items": [
    {
      "merchant_reference": "test-001",
      "scheduled_date": "2026-06-01",
      "payout_intent_details": {
        "amount": 50,
        "amount_currency": "ngn",
        "customer": "8c91204b-5a5b-4496-9904-76a6b72bc15d",
        "payout_method": "BANK_ACCOUNT",
        "webhook_url": "https://webhook.site/your-unique-url"
      }
    }
  ]
}

2. Watch webhook.site — validation phase

Immediately after submission you will receive two events in quick succession:

  • payout.bulk.active — confirms the request was created. The payload includes the full items array with each item in VALIDATION_PENDING status.
  • payout.item.validation_pending — fires per item as each one enters the validation queue.

Depending on the outcome:

  • payout.item.scheduled — validation passed, item is scheduled for its scheduled_date
  • payout.item.validation_failed — validation failed. Check validation_result.errors in the payload to see exactly which fields failed and why.

3. Watch webhook.site — execution phase

On the item's scheduled_date, execution begins. You will receive:

  • payout.item.intent_created — a payout intent was successfully created for this item. Standard payout lifecycle webhooks follow from this point.
  • payout.item.intent_creation_failed — the intent could not be created. The item moves to INTENT_CREATION_FAILED. No further webhooks fire for this item.

4. After intent creation

Once an item's payout intent is created, the same individual payout webhooks fire for that intent:

  • transaction.disburse.pending_approval (if approval is required)
  • transaction.disburse.successful or transaction.disburse.failed

Use the merchant_reference field in every payload to map each webhook event back to the correct item in your system.

5. When the batch is done

Once all items have been processed — validated, executed, or failed — you will receive payout.bulk.batch_completed. The payload includes a count breakdown showing how many items ended in each status.