MoneyHash Payouts lets you send funds directly to customers, beneficiaries, or third parties — whether that's a withdrawal, a refund, an affiliate commission, or a marketplace settlement. This guide covers the full individual payout lifecycle: creating a payout, tracking it, cancelling it, and closing it cleanly.

Need to pay many recipients at once? See Bulk Payouts — a single request can schedule up to 1,000 payouts simultaneously.


Core concepts

Understanding payouts in MoneyHash requires familiarity with three layered entities: Intent, Transaction, and Operation. Each maps to a distinct role.

Intent

A Payout Intent is the top-level container for the entire payout lifecycle. It holds metadata about the payout (amount, currency, customer) and tracks the overall outcome.

intent_statusDescription
unprocessedDefault state. The payout is in progress or has failed but can be retried. It remains unprocessed until the transaction succeeds or the intent is closed.
processedTerminal state. A disburse or void operation completed successfully.
closedTerminal state. You explicitly closed the intent — no further actions possible.

Transaction

A Transaction is an execution attempt within an intent. It is created automatically when you create a payout and becomes the primary reference entity once a disburse operation succeeds.

Operations

Operations are the financial actions that move (or cancel) money. Two types exist:

Disburse — executes the payout. Created automatically on payout creation.

disburse_statusTerminal?Description
pendingNoQueued for processing
pending_verificationNoProvider is awaiting verification
pending_approvalNoAwaiting approval before execution
successfulYesFunds disbursed successfully
failedYesDisbursement failed

Void — cancels an in-progress payout. Initiated by you.

void_statusTerminal?Description
pendingNoCancellation in progress
successfulYesPayout cancelled — no funds moved
failedYesCancellation failed — disburse continues

Payout status

payout_status is a high-level summary of money movement — independent of intent_status. Use it to answer "did money move?" without reasoning through intent and operation states.

payout_statusWhen
no_disburse_attemptsPayout created, disburse not yet started
disburse_attempt_pendingDisburse is in progress
disbursedFunds sent successfully
disburse_attempt_failedDisburse failed
voidedPayout cancelled before funds moved
abortedIntent closed without a successful disburse

Quick reference

  • intent_status = lifecycle state (is this intent open or done?)
  • payout_status = money movement outcome (did funds move?)

Payout lifecycle

Main flow

Every payout follows the same flow: intent created → provider processes the disburse → terminal outcome.

The key states to watch:

Stageintent_statuspayout_status
Just createdunprocessedno_disburse_attempts
Provider processingunprocesseddisburse_attempt_pending
Funds sentprocesseddisbursed
Disburse failedunprocesseddisburse_attempt_failed

Void and close paths

Two optional actions let you intervene before or after a disburse completes.

ActionWhenOutcome on success
VoidDisburse is pending, pending_verification, or pending_approvalpayout: voided · intent: processed
CloseDisburse failed, no retry plannedpayout: aborted · intent: closed

Creating a payout

POST /api/v1.4/payout/intent/

{
  "amount_currency": "ngn",
  "amount": 100,
  "customer_id": "8c91204b-5a5b-4496-9904-76a6b72bc15d",
  "webhook_url": "https://yourapp.com/webhooks/payout"
}

What happens automatically:

  1. A Payout Intent is created with intent_status: UNPROCESSED.
  2. A Transaction is created inside the intent.
  3. A Disburse operation is created with status pending.
  4. Provider processing begins.
  5. Webhooks are sent as status changes occur.

Example response:

{
  "status": {
    "code": 200,
    "message": "success",
    "errors": []
  },
  "data": {
    "embed_url": "https://embed.moneyhash.io/embed/payout/ZAlyR3g",
    "id": "ZAlyR3g",
    "type": "Payout",
    "amount": "100.00",
    "amount_currency": "NGN",
    "status": "UNPROCESSED",
    "payout_status": {
      "status": "NO_DISBURSE_ATTEMPTS"
    },
    "active_transaction": null,
    "transactions_history": [],
    "state": "INTENT_FORM",
    "state_details": {
      "embed_url": "https://yourapp.com/webhooks/payout"
    },
    "billing_data": null,
    "created": "today"
  },
  "count": 1,
  "next": null,
  "previous": null
}

Monitor via webhooks. After creation, listen for webhook events as MoneyHash processes the payout with the provider.


Using saved payout methods

Instead of submitting raw beneficiary data on every payout, you can save a payout method to a customer and reference it by token. This reduces repeated data entry, minimises errors, and limits exposure of sensitive details.

Supported method types:

  • Bank account
  • Card (via Vault, for PCI compliance)
  • Mobile wallet
  • Mobile money

To use a saved method, provide the payout method token in your payout request instead of raw beneficiary fields. The token must belong to the customer_id in the same request.

Important: Saved payout methods only change how beneficiary data is sourced. The disburse/void lifecycle, status transitions, and webhooks behave identically to payouts using raw data.

Validation on save: When a method is saved, MoneyHash performs format validation only (IBAN structure, Luhn check for cards, MSISDN format for wallets). No provider calls are made and no funds are moved.

Customer billing requirement: The customer linked to a saved payout method must have complete billing information — full name, phone, email, and billing address — before payouts using that method can execute successfully.


Cancelling a payout (void)

POST /api/v1.4/payout/transactions/{transaction_id}/void/

A void cancels an in-progress payout before funds are disbursed.

Void is only available when the disburse status is:

  • pending
  • pending_verification
  • pending_approval

If void succeeds:

  • payout_statusvoided
  • intent_statusprocessed
  • No funds are moved.

If void fails:

  • The disburse operation continues.
  • payout_status reflects the eventual disburse outcome.
  • Funds may still be disbursed.

Note: Void availability depends on the provider. Some providers do not support cancelling a payout once it is in progress. Contact MoneyHash support to confirm void availability for your integration.


Closing a payout intent

POST /api/v1.4/payout/intent/{intent_id}/close

Closing permanently terminates a payout intent. Use this when a disburse has failed and you do not intend to retry, or when a payout is no longer needed.

What closing does:

  • Sets intent_statusclosed
  • Sets payout_statusaborted
  • Locks the intent — no further operations possible

When you cannot close:

  • After a successful disburse (intent_status is already processed)
  • After a successful void (intent_status is already processed)

Best practice: Explicitly close failed intents rather than leaving them open. This keeps your system state clean, avoids orphaned intents, and makes it unambiguous that no further money movement will occur.

Close vs. void: Void is for cancelling money movement. Close is for ending the intent lifecycle. They serve different purposes and are not interchangeable.


Webhooks

MoneyHash sends webhooks for every significant payout status change — intent updates, disburse transitions, and void outcomes. Configure your webhook_url when creating the payout intent.

See Webhooks and Webhook Types for payload structure and event types.


API reference summary

MethodEndpointDescription
POST/api/v1.4/payout/intent/Create a payout intent
POST/api/v1.4/payout/transactions/{transaction_id}/void/Cancel an in-progress payout
POST/api/v1.4/payout/intent/{intent_id}/close/Close a payout intent

For complete parameter documentation, see the API Reference.