Webhook Types

MoneyHash uses a variety of webhooks to notify you regarding every action that happens on our integration side. The webhook types are listed below. Use each link to access the details regarding each existing type:

Intent Webhooks

The intent webhook will be received on your app whenever an intent changes status. These webhook types will be in the form of intent.{status}. The table below shows the events available for this webhook:

EventWebhook TypeTerminal?Description
Intent Processedintent.processedYesThe intent was processed and reached its final state. No new action can be taken on the intent.
Intent Time Expiredintent.time_expiredYesThe intent expired after the period set by expires_after_seconds. No new action can be taken on the intent.
Intent Closedintent.closedYesThe intent was closed. No new action can be taken on the intent.
Money-state changes after an intent is final

Intent webhooks fire when the intent reaches a terminal lifecycle state (processed, time_expired, or closed). Once an intent is processed, later money-state changes such as a refund will update the intent's payment_status.status, but they do not fire another intent webhook, because the intent's lifecycle status does not change. To read the latest money state after such an action, use the Get Intent Details API or rely on the corresponding transaction webhook for that operation.

Intent Payment Status

The payment_status.status field is the single high-level money state of the intent. It tells you what happened to the money, independently of the lower-level intent.status or transaction.status fields. The table below lists all possible values.

Payment StatusMeaning
NO_AUTHORIZE_ATTEMPTSThe intent was created, but no payment attempt has started yet.
AUTHORIZE_ATTEMPT_PENDINGA payment attempt is in progress, including pending 3DS authentication, redirect, or provider processing.
AUTHORIZE_ATTEMPT_FAILEDThe latest payment attempt failed. The intent may still be retryable if it has not expired or been closed.
AUTHORIZEDFunds have been authorized and reserved, but not captured yet. Capture or void depending on your flow.
CAPTUREDFunds have been captured successfully. For a standard purchase flow, this is the paid state.
REFUNDEDCaptured funds have been refunded, fully or partially. Check payment_status.balances for the refunded and remaining refundable amounts.
VOIDEDAuthorized funds have been voided and released before capture. The hold is no longer available to capture.
ABORTEDThe intent ended without a successful payment, usually because it expired or was closed.

For partial captures, refunds, or voids, payment_status.status gives the overall money state while payment_status.balances gives the exact amounts. Use balances to read the total captured, refunded, and voided amounts, and the amounts still available to capture, refund, or void.

Intent Webhook Fields

The table below explains the key fields in an intent webhook payload and what to use each one for.

FieldPurpose
intent.idUnique MoneyHash ID for the payment intent. Use it as your main order or payment session reference when storing, querying, or troubleshooting the payment.
intent.statusLifecycle state of the intent, such as UNPROCESSED, PROCESSED, TIME_EXPIRED, or CLOSED. Use it to know whether the overall payment session is still open or final. This is separate from the money state in payment_status.status.
intent_typeThe type of intent the webhook represents, such as PAYMENT. Use it to distinguish payment intents from other intent types if your system handles multiple webhook categories.
payment_status.statusThe money state of the intent. See the Intent Payment Status table above for all possible values. Use it as the main field for deciding what happened financially.
payment_status.balancesThe breakdown of amounts on the intent, including authorized, captured, refunded, and voided totals, and the amounts available to capture, refund, or void. Use it for reconciliation and to decide which follow-up operations are possible.
active_transactionThe latest transaction attempt attached to the intent. Use it to inspect the transaction, payment method, provider, and operations that produced the current state.
transactions_historyThe list of all transaction attempts under the same intent. Use it to understand retries and fallback attempts across different providers or methods.
transactions_countThe number of transaction attempts created under the intent. Use it for retry tracking, analytics, and detecting repeated failed attempts.
flow_dataRouting and flow metadata used by MoneyHash for this intent, including the flow version and sequence details. Use it when troubleshooting routing behavior with MoneyHash support.
is_liveIndicates whether the intent was processed in live or test mode. Use it to separate real payments from test activity in your backend and reporting.
createdThe timestamp when the intent was created. Use it for audit logs, event ordering, expiry calculations, and reconciliation timelines.
Sample Intent Webhook

{

"data": {

"intent": {

"id": "vE5crdN",

"ip": {

"country": {

"name": "United States of America",

"iso_code": "US"

},

"ip_address": "192.0.2.1"

},

"flow": "x7FQMzK",

"type": "Payin",

"amount": {

"value": "50.00",

"currency": "USD",

"formatted": 50,

"display_value": "50.00 USD"

},

"method": {

"id": "YK3tJ8E",

"display_name": "Provider A - Card"

},

"status": "PROCESSED",

"account": "H57BKkB",

"created": "2026-07-22T06:58:23.558890Z",

"is_live": true,

"flow_data": {

"id": "x7FQMzK",

"version": 2,

"sequence": {

"id": 88338,

"alias": "aerDx1v-Example Flow",

"alias_name": "Example Flow",

"last_action": {

"id": 261917,

"alias": "mwVT69x-Example Action",

"alias_name": "Example Action"

}

}

},

"billing_data": {

"email": "[email protected]",

"last_name": "Doe",

"first_name": "John",

"phone_number": "+10000000000"

},

"custom_fields": null,

"payment_status": {

"status": "CAPTURED",

"balances": {

"total_voided": "0.00",

"total_captured": "50.00",

"total_refunded": "0.00",

"total_authorized": "50.00",

"available_to_void": "0.00",

"available_to_refund": "50.00",

"available_to_capture": "0.00"

}

},

"amount_currency": "USD",

"active_transaction": {

"id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",

"amount": {

"value": "50.00",

"currency": "USD",

"formatted": 50,

"display_value": "50.00 USD"

},

"method": {

"id": "YK3tJ8E",

"display_name": "Provider A - Card",

"service_provider": {

"id": "aerDx1v",

"display_name": "Provider A"

}

},

"status": "SUCCESSFUL",

"account": "H57BKkB",

"created": "2026-07-22T06:58:23.692300Z",

"trx_rrn": "411545046109",

"operations": [

{

"id": "mwVT69x",

"type": "purchase",

"status": "successful",

"amount": {

"value": "50.00",

"currency": "USD",

"formatted": 50,

"display_value": "50.00 USD"

},

"statuses": [

{

"id": "XGjrXAa",

"code": "8000",

"value": "pending",

"created": "2026-07-22 06:58:23.727642+00:00",

"message": "Pending",

"localized_message": "Pending",

"provider_error_code": null,

"provider_error_message": null

},

{

"id": "rO8FLVq",

"code": "6000",

"value": "successful",

"created": "2026-07-22 06:58:25.754538+00:00",

"message": "Successful",

"localized_message": "Successful",

"provider_error_code": null,

"provider_error_message": null

}

],

"latest_status": {

"id": "rO8FLVq",

"code": "6000",

"value": "successful",

"message": "Successful",

"localized_message": "Successful",

"provider_error_code": null,

"provider_error_message": null

},

"authorization_code": "074750",

"authorization_status": null,

"acquirer_transaction_id": "817520386203251040924"

}

],

"billing_data": {

"city": "New York",

"name": "John Doe",

"email": "[email protected]",

"country": "US",

"last_name": "Doe",

"first_name": "John",

"postal_code": "10001",

"phone_number": "+10000000000"

},

"full_capture": true,

"payment_method": "CARD",

"amount_currency": "USD",

"service_provider": "aerDx1v",

"merchant_reference": "order-0001_11111",

"payment_method_name": "Card",

"payment_method_details": {

"data": {

"bin": "400000",

"type": "DEBIT",

"brand": "VISA",

"issuer": "Example Bank",

"last_4": "0002",

"country": "US",

"expiry_year": "2029",

"expiry_month": "12",

"card_holder_name": "John Doe"

},

"type": "CARD",

"provider_data": null

},

"provider_unique_reference": {

"key": "provider_reference_id",

"value": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"

},

"provider_transaction_fields": {

"scheme_id": "386203251040924",

"provider_payment_id": "pay_examplereference0001",

"provider_payment_auth_code": "074750"

}

},

"merchant_reference": "order-0001",

"transactions_count": 1,

"transactions_history": [

{

"id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",

"amount": {

"value": "50.00",

"currency": "USD",

"formatted": 50,

"display_value": "50.00 USD"

},

"method": {

"id": "YK3tJ8E",

"display_name": "Provider A - Card",

"service_provider": {

"id": "aerDx1v",

"display_name": "Provider A"

}

},

"status": "SUCCESSFUL",

"account": "H57BKkB",

"created": "2026-07-22T06:58:23.692300Z",

"trx_rrn": "411545046109",

"operations": [

{

"id": "mwVT69x",

"type": "purchase",

"status": "successful",

"latest_status": {

"id": "rO8FLVq",

"code": "6000",

"value": "successful",

"message": "Successful"

},

"authorization_code": "074750",

"acquirer_transaction_id": "817520386203251040924"

}

],

"payment_method": "CARD",

"payment_method_name": "Card",

"service_provider": "aerDx1v",

"merchant_reference": "order-0001_11111"

}

]

},

"intent_id": "vE5crdN"

},

"type": "intent.processed",

"api_version": "1.4",

"intent_type": "PAYMENT"

}

Transaction Webhooks

The transaction webhook will be received on your app whenever an operation inside the transaction changes status. Each event also carries the current money state of the intent in payment_status, so you can see where the money is at that point.

These webhook types will be in the form of transaction.{operation}.{status}. Below you will find the possible operation types, the possible statuses for these operations, and the available webhook events per operation type.

Operation types

OperationDescription
AuthorizeChecks with the card issuing bank to confirm the cardholder can pay the requested amount and that sufficient funds are available, then holds that amount so it is available when you capture it.
CaptureCaptures a previously authorized amount into your merchant account. You can capture the full amount at once or in multiple partial captures, but never more than the authorized amount.
PurchaseTakes the full amount immediately without holding it first. Use this when your business does not require the separate authorize and capture flow.
Void / CancelReleases an authorization you no longer intend to capture, giving the cardholder faster access to their funds.
RefundReturns a captured amount to the customer, in full or in part. You can perform multiple partial refunds as long as they do not exceed the captured amount.

Operation Statuses

Operation StatusDescription
PendingThe operation is awaiting processing.
Pending AuthenticationAwaiting authentication or verification, such as 3DS.
Pending External ActionAwaiting an action from an external source.
Pending Online External ActionAwaiting an online action from an external source.
SuccessfulThe operation completed successfully.
FailedThe operation encountered an error or failure during processing.

Available Webhook events per Operation type

pendingsuccessfulfailedPending AuthenticationPending External ActionPending Online External Action
Purchasetransaction.purchase.pendingtransaction.purchase.successfultransaction.purchase.failedtransaction.purchase.pending_authenticationtransaction.purchase.pending_external_actiontransaction.purchase.pending_online_external_action
Authorizetransaction.authorize.pendingtransaction.authorize.successfultransaction.authorize.failedtransaction.authorize.pending_authenticationNot ApplicableNot Applicable
Capturetransaction.capture.pendingtransaction.capture.successfultransaction.capture.failedNot ApplicableNot ApplicableNot Applicable
Voidtransaction.void.pendingtransaction.void.successfultransaction.void.failedNot ApplicableNot ApplicableNot Applicable
Refundtransaction.refund.pendingtransaction.refund.successfultransaction.refund.failedNot ApplicableNot ApplicableNot Applicable
How operations build up on a transaction

A single transaction can go through more than one operation - for example an authorize followed by a capture or a void, or a purchase followed by a refund. Each operation is added to the operations[] array, so that array is the full operation history for the transaction. The operation_id at the top level of the webhook tells you which specific operation triggered that particular event.

Transaction Webhook Fields

The table below explains the key fields in a transaction webhook payload and what to use each one for.

FieldPurpose
status_idUnique MoneyHash ID for the specific status update that triggered this webhook. Use it for webhook deduplication, logging, and support.
operation_idUnique MoneyHash ID for the operation that changed status, such as purchase, authorize, capture, refund, or void. Use it to identify which operation this webhook is about.
transaction.idUnique MoneyHash transaction ID for this payment attempt. Use it as your main MoneyHash reference for support, reconciliation, and transaction lookups.
transaction.statusThe current transaction operation status, in the form {operation}.{status}, for example purchase.successful, authorize.successful, or void.successful. Use it to understand what happened to this attempt.
transaction.typeThe transaction category, usually payment for pay-in flows. Use it to distinguish payment transactions from other transaction types.
method.service_providerThe configured MoneyHash method used for the payment, for example a self-serve Apple Pay provider configured on MoneyHash. Use it to know which configured method was selected.
method.processing_service_providerThe actual underlying provider that processed the transaction. Use it for provider-specific reconciliation, troubleshooting, and support, since this is where the money actually moved. In most cases this matches service_provider, but for methods such as self-serve wallets the two can differ.
operations[]The list of all operations under the transaction, such as purchase, authorize, capture, refund, or void. Each operation carries its own status timeline. Use it to inspect every money-moving action on the transaction.
operations[].typeThe operation type: purchase, authorize, capture, void, or refund.
statuses[]The timeline of status changes for an operation, including pending, pending authentication, successful, and failed entries. Use it to understand how the operation progressed over time.
latest_statusThe most recent status object for the operation. Use it as the quickest way to read the current result, code, message, and any provider error details without scanning the full statuses[] array.
latest_status.provider_error_codeThe provider-level error code on a failed operation. Use it together with provider_error_message to understand why a provider declined the transaction.
payment_status.statusThe money state of the intent at the time of this event. See the Intent Payment Status table in the Intent Webhooks section above for all possible values.
provider_unique_referenceThe primary provider-side transaction reference, given as a key and value pair. Use it to locate the transaction directly in the provider's dashboard or with provider support.
provider_transaction_fieldsProvider-specific metadata returned by the provider, such as payment ID, action ID, auth code, or acquirer references. Use it for advanced reconciliation and provider-level debugging.
trx_rrnThe transaction retrieval reference number when available. Use it for bank or acquirer reconciliation and customer support investigations.
ipThe customer IP and geolocation captured for the transaction. Use it for fraud review, risk checks, and debugging regional or session issues.
createdThe timestamp when the transaction was created. Use it for event ordering, audit logs, and reconciliation timelines.
Sample Transaction Webhook

{

"type": "transaction.purchase.successful",

"intent": {

"id": "qBQbdt1",

"amount": {

"value": "33.79",

"currency": "SAR",

"formatted": 33.79,

"display_value": "33.79 SAR"

},

"created": "2026-07-22 07:20:16.580248+00:00",

"aft_data": null,

"flow_data": {

"id": "yDYn8uT",

"version": 2,

"sequence": {

"id": 88338,

"alias": "pspQpvD-Example Flow SAR",

"alias_name": "Example Flow SAR",

"last_action": {

"id": 261917,

"alias": "IkQJo7G-Example Processing",

"alias_name": "Example Processing"

}

}

},

"split_data": [],

"custom_fields": {

"env": "production",

"payment_id": "00000000-0000-0000-0000-000000000000",

"autocapture": true,

"payment_type": "auto-charge",

"reference": "0000-000 000"

},

"payment_status": {

"status": "CAPTURED",

"balances": {

"total_voided": "0.00",

"total_captured": "33.79",

"total_refunded": "0.00",

"total_authorized": "33.79",

"available_to_void": "0.00",

"available_to_refund": "33.79",

"available_to_capture": "0.00"

}

},

"custom_form_answers": null

},

"account": {

"id": "wrrej60"

},

"status_id": "uES4J4p",

"api_version": "1.4",

"transaction": {

"id": "12dcf641-f731-40c6-8a3f-cf0be0169528",

"ip": {

"country": {

"name": "United States of America",

"iso_code": "US"

},

"ip_address": "192.0.2.1"

},

"type": "payment",

"method": {

"id": "4EQ1ACj",

"display_name": "Provider A - Card",

"service_provider": {

"id": "pspQpvD",

"display_name": "Provider A"

},

"processing_service_provider": {

"id": "pspQpvD",

"display_name": "Provider A"

}

},

"status": "purchase.successful",

"created": "2026-07-22 07:20:16.699835+00:00",

"trx_rrn": "215054774451",

"bin_lookup": null,

"operations": [

{

"id": "IkQJo7G",

"arn": null,

"rrn": "215054774451",

"type": "purchase",

"extra": {},

"amount": {

"value": "33.79",

"currency": "SAR",

"formatted": 33.79,

"display_value": "33.79 SAR"

},

"status": "successful",

"statuses": [

{

"id": "K2vgr0v",

"code": "8000",

"value": "pending",

"created": "2026-07-22 07:20:16.732149+00:00",

"message": "Pending",

"localized_message": "Pending",

"provider_error_code": null,

"provider_error_message": null

},

{

"id": "ODGoy6J",

"code": "6000",

"value": "successful",

"created": "2026-07-22 07:20:17.899732+00:00",

"message": "Successful",

"localized_message": "Successful",

"provider_error_code": null,

"provider_error_message": null

}

],

"refund_type": null,

"custom_fields": null,

"latest_status": {

"id": "ODGoy6J",

"code": "6000",

"value": "successful",

"message": "Successful",

"localized_message": "Successful",

"provider_error_code": null,

"provider_error_message": null

},

"authorization_code": "484116",

"authorization_status": null,

"acquirer_transaction_id": "008008497385227867437"

}

],

"billing_data": {

"city": "New York",

"name": "John Doe",

"email": "[email protected]",

"floor": null,

"state": "New York",

"street": null,

"address": "123 Example Street",

"country": "US",

"address1": null,

"building": null,

"apartment": null,

"bank_code": null,

"last_name": "Doe",

"first_name": "John",

"postal_code": "10001",

"phone_number": "+10000000000",

"mobile_wallet_number": null

},

"device_check": null,

"full_capture": true,

"shipping_data": {

"city": "New York",

"state": "New York",

"address": "123 Example Street",

"country": "US",

"postal_code": "10001"

},

"custom_message": "",

"fraud_decision": null,

"paying_card_token": {

"id": "oQCPd0J-dee9-447c-92d6-ce9f26a1a448",

"bin": "400000",

"type": "CREDIT",

"brand": "Visa",

"hashid": "1unLUDY",

"issuer": "Example Bank",

"last_4": "4233",

"country": "US",

"expiry_year": "30",

"fingerprint": "0000000000000000000000000000000000000000000000000000000000000000",

"expiry_month": "02",

"requires_cvv": false,

"vault_region": "default",

"agentic_token": null,

"custom_fields": null,

"card_holder_name": null,

"network_token_data": null,

"provider_token_data": [

{

"last_4": "4233",

"pay_in_method": "4EQ1ACj",

"service_provider_id": "pspQpvD",

"provider_specific_data": {

"token_id": "src_example00000000000000000"

}

}

]

},

"authorization_code": "484116",

"merchant_reference": "order-0001_12dcf",

"authentication_data": null,

"authorization_status": null,

"payment_method_details": {

"data": {

"bin": "26688992",

"type": "CREDIT",

"brand": "Visa",

"issuer": "Example Bank",

"last_4": "4233",

"country": "US",

"network": null,

"pan_token": null,

"eci_version": null,

"expiry_year": "2030",

"local_brand": null,

"expiry_month": "02",

"funding_method": null,

"card_holder_name": "John Doe",

"cryptogram_format": null

},

"type": "CARD",

"provider_data": null

},

"external_action_message": [],

"provider_unique_reference": {

"key": "provider_payment_id",

"value": "pay_example00000000000000000"

},

"provider_transaction_fields": {

"scheme_id": "771355294271838",

"provider_payment_id": "pay_example00000000000000000",

"provider_operation_fields": {

"IkQJo7G": {

"action_id": "act_example00000000000000000",

"auth_code": "484116",

"acquirer_transaction_id": "008008497385227867437",

"retrieval_reference_number": "215054774451"

}

},

"provider_payment_auth_code": "484116"

}

},

"operation_id": "IkQJo7G"

}

Transaction Authentication status

When a transaction goes through 3-D Secure (3DS) authentication, MoneyHash notifies you about the outcome of the authentication step separately from the final transaction status. These webhooks are sent to the webhook_url you provided when creating the intent.

Event typeDescription
transaction.{operation}.authentication_approvedThe cardholder was successfully authenticated by the issuer.
transaction.{operation}.authentication_attemptedAuthentication was attempted and proof of attempt was generated, but the cardholder was not fully authenticated.
transaction.{operation}.authentication_failedAuthentication failed or was rejected by the issuer.

The webhook includes an authentication object with details of the 3DS outcome. Fields such as eci, authentication_status, protocol_version, and ds_transaction_id are values returned by the 3DS authentication and the card scheme, not states defined by MoneyHash. MoneyHash passes them through so you can use them for your own records, risk decisions, and reconciliation. For the meaning of specific values, refer to the relevant card scheme or EMV 3DS documentation.

Note

These authentication events are informational and describe only the authentication step. They are not a payment outcome. Rely on intent.processed with payment_status.status as the signal that the payment succeeded, as described in the Payment Webhook guide.

Sample Authentication Approved Webhook

{

"type": "transaction.purchase.authentication_approved",

"status_id": "mDp9IRR",

"operation_id": "cIjIdkw",

"intent": {

"id": "JFTY0AM",

"amount": {

"value": "50.00",

"currency": "USD",

"formatted": 50,

"display_value": "50.00 USD"

},

"custom_fields": null

},

"account": {

"id": "zimO61X"

},

"transaction": {

"id": "c80af165-3aba-4de6-a8cd-f89ff4a33e6e",

"status": "authentication_approved",

"merchant_reference": null,

"authentication": {

"status": "authentication_approved",

"event_time": "2026-07-22T12:34:56Z",

"eci": "02",

"ds_transaction_id": "063bd817-132b-4433-b96a-1cb5c113cfd2",

"protocol_version": "2.2.0",

"authentication_status": "Y"

}

},

"api_version": "1.4"

}

Card Token Webhooks

The card token webhook will be received on your app whenever a card tokenization changes status. These webhook types will be in the form of card_token.{event}. The table below shows the events available for this webhook:

EventWebhook TypeDescription
Card token createdcard_token.createdA new card token has been created and associated with a customer entity.
Card token updatedcard_token.updatedA card token has been updated.
Card token deletedcard_token.deletedA card token has been removed.
Webhook delivery timing

Webhooks are delivered asynchronously and may arrive out of order due to network conditions, retries, or service timing. Your webhook handler should not depend on a specific event sequence. Instead, process each event idempotently based on its type and status, and use event deduplication via unique identifiers (such as status_id or operation_id) to handle potential duplicates or out-of-order delivery.

Card Token Fields

The table below explains the key fields in a card token payload and what to use each one for. The exact set of fields returned can vary by event, with card_token.created carrying the most complete details.

FieldPurpose
idThe MoneyHash UUID for the saved card token. Pass it as card_token when charging a saved card.
hashidThe short MoneyHash reference for the saved card token, returned on card_token.created. Pass it as card_token_id when charging a saved card. This is the value to store against your customer record for future payments.
brandThe card brand, such as Visa or Mastercard.
typeThe card type, such as credit or debit.
issuerThe bank that issued the card, when available.
countryThe card's country of issuance, when available.
binThe first digits of the card, identifying the issuing bank and card type.
last_4The last four digits of the card, useful for displaying the saved card to the customer.
expiry_month / expiry_yearThe card expiry date.
card_holder_nameThe name on the card, when available.
requires_cvvIndicates whether the customer must re-enter the CVV when paying with this saved card. Use it to decide whether to show a CVV collection step.
fingerprintA stable, provider-supplied hash that identifies the underlying physical card. It stays the same across different tokenizations of the same card, so you can use it to recognize when two different tokens represent the same card, for example for de-duplication.
custom_fieldsAny custom metadata you included when the card token was created. MoneyHash does not generate these values; they are the custom_fields you sent in the card token creation request, returned back to you.
provider_token_dataThe token records held with the underlying provider connections for this card. Each entry contains last_4 (the card's last four digits), service_provider_id (the connection ID on MoneyHash), and pay_in_method (the payment method ID under that connection). Use it for visibility and debugging.
Sample Card Token Webhook

{

"type": "card_token.created",

"data": {

"intent_id": "bVj0y6N",

"card_token": {

"id": "23ab9638-b0a2-467f-9f25-49b885997fe5",

"hashid": "v9LkA1r",

"brand": "MasterCard",

"card_holder_name": "John Doe",

"bin": "512345",

"last_4": "0008",

"issuer": "Example Bank",

"expiry_month": "01",

"expiry_year": "30",

"country": "US",

"type": "debit",

"custom_fields": null,

"provider_token_data": [

{

"last_4": "0008",

"service_provider_id": "ElXY6JS",

"pay_in_method": "NFOVLzW"

}

],

"requires_cvv": false,

"fingerprint": "3e8df60940eb9645b6fcec55b0a008ad5a898621f8bc292ce1a8661f2a7b549d06a567a6f7275db689dac965be781ec6429d165ff543324a77d3c1b03cd41446",

"vault_region": "default",

"network_token_data": null,

"agentic_token": null

}

}

}

Customer Webhooks

The customer webhook will be received on your app whenever a customer entity is created during a payment. These webhook types will be in the form of customer.{event}. The table below shows the events available for this webhook:

EventWebhook TypeDescription
Customer Createdcustomer.createdA new customer entity has been created during intent creation.
When this webhook fires

The customer.created webhook fires only when a customer is created as part of intent creation, by passing create_customer: true with customer_details in the intent request. Creating a customer directly through the customer API does not fire a webhook.

Customer Webhook Fields

The table below explains the key fields in a customer webhook payload and what to use each one for.

FieldPurpose
customer_idThe MoneyHash UUID for the customer. Use it to link the customer to your own records and to reference them in future intents.
idThe customer's MoneyHash UUID, matching customer_id.
organizationThe MoneyHash organization the customer belongs to.
first_name / last_nameThe customer's name, when provided.
emailThe customer's email address, when provided.
phone_numberThe customer's phone number, when provided.
national_idThe customer's national ID, when provided.
birth_dateThe customer's date of birth, when provided.
descriptionA free-text description of the customer, when provided.
addressThe customer's address, when provided.
is_liveIndicates whether the customer was created in live or test mode.
walletsThe customer's wallet balances, if any.
last_used_payment_methodThe customer's most recently used payment method, when available.
Sample Customer Webhook

{

"type": "customer.created",

"data": {

"customer_id": "6c80cd2c-88bb-4ce1-9234-457f7e42ee5e",

"customer": {

"id": "6c80cd2c-88bb-4ce1-9234-457f7e42ee5e",

"organization": "Example Organization",

"first_name": "John",

"last_name": "Doe",

"email": "[email protected]",

"phone_number": "+10000000000",

"national_id": null,

"birth_date": null,

"description": null,

"address": null,

"is_live": true,

"wallets": {},

"last_used_payment_method": null

}

}

}

Subscription Webhooks

Subscription webhooks are fired whenever a subscription's status changes or one of its invoices changes status. All subscription status changes trigger webhooks, so you can respond to the full subscription lifecycle in real time. For the complete lifecycle, status transitions, and management operations, see the Manage Subscriptions page.

There are two families of subscription webhook events:

  • Subscription status events take the form subscription.status.{status}, for example subscription.status.active. They fire when the subscription itself moves between lifecycle states.

  • Subscription invoice events take the form subscription.invoice.{status}, for example subscription.invoice.paid. They fire when an invoice for a billing cycle changes status.

Subscription status events

The type is subscription.status.{status}, and the current status is also available in current_status.value. The table below lists the possible statuses.

StatusDescription
NEWThe default status of a new subscription before its start date.
TRIALThe subscription is in its trial period.
INCOMPLETEThe first billing cycle is due and has not been paid yet.
ACTIVEThe subscription is paid and renewing on schedule.
PAST_DUEA billing cycle invoice is overdue and has not been paid.
PAUSEDThe subscription is temporarily suspended and no charges occur until it is resumed.
PENDING_CANCELLATIONThe subscription has been cancelled and remains active until the next billing cycle due date.
CANCELLEDA PENDING_CANCELLATION subscription that has reached its next billing date, ending access.
ENDEDThe subscription reached its final recurring cycle.
TERMINATEDThe subscription was terminated immediately, ending access at the moment of termination.
Sample Subscription Status Webhook

{

"type": "subscription.status.active",

"id": "gjb0D7g",

"account": {

"id": "YVglAZx",

"name": "Example Account"

},

"plan": {

"id": "gyXDyoL",

"name": "Example Plan"

},

"current_status": {

"id": "L5PxJk9",

"value": "ACTIVE",

"created": "2026-07-25 15:06:34.643138+00:00"

},

"statuses": [

{

"id": "ZAxXVQg",

"value": "NEW",

"created": "2026-07-25 14:59:24.514016+00:00"

},

{

"id": "ZpRznqL",

"value": "INCOMPLETE",

"created": "2026-07-25 14:59:24.534557+00:00"

},

{

"id": "L5PxJk9",

"value": "ACTIVE",

"created": "2026-07-25 15:06:34.643138+00:00"

}

],

"start_date": "2026-07-25",

"customer": {

"id": "e5d84e98-7581-42cd-baa0-e9bc712a6c2b",

"name": "John Doe",

"phone": null

},

"charge_automatically": false,

"primary_card_token": null,

"remaining_recurring_cycles": null,

"remaining_discount_cycles": null,

"configuration": {

"amount": 10.0,

"one_time_fee": null,

"trial_period": null,

"recurrency": 1,

"recurrency_unit": "MONTH",

"recurring_cycles": null,

"discount_amount": null,

"discount_percentage": null,

"discount_cycles": null

},

"webhook_url": "https://example.com/webhooks/moneyhash",

"custom_fields": {},

"due_invoices": [],

"next_recurring_cycle_invoice": {

"id": "L3vo2A9",

"subscription_id": "gjb0D7g",

"status": {

"id": "ZokbjVZ",

"value": "OPEN",

"created": "2026-07-25 15:04:56.449054+00:00"

},

"amount": 10.0,

"currency": "USD",

"due_date": "2026-08-25",

"is_live": true

},

"all_invoices": [

{

"id": "gXznN79",

"subscription_id": "gjb0D7g",

"status": {

"id": "98q61rL",

"value": "PAID",

"created": "2026-07-25 14:59:36.977296+00:00"

},

"amount": 10.0,

"currency": "USD",

"due_date": "2026-07-25",

"is_live": true,

"type": "REGULAR",

"direction": "DEBIT"

}

],

"is_live": true,

"end_date": null,

"created": "2026-07-25T14:59:24.504122Z"

}

Subscription invoice events

The type is subscription.invoice.{status}, and the current invoice status is also available in status.value. The table below lists the possible statuses.

StatusDescription
NEWThe default status of a new invoice.
OPENThe invoice is open and its due date has not passed yet.
DUEThe due date has passed and the invoice has not been paid.
PAIDThe invoice has been paid.
CANCELLEDThe invoice was cancelled.
Sample Subscription Invoice Webhook

{

"type": "subscription.invoice.paid",

"id": "gXznN79",

"subscription_id": "gjb0D7g",

"status": {

"id": "98q61rL",

"value": "PAID",

"created": "2026-07-25 14:59:36.977296+00:00"

},

"amount": 10.0,

"currency": "USD",

"due_date": "2026-07-25",

"is_live": true,

"payment_intent_url": "https://embed.moneyhash.io/embed/payment/9KWvyeM",

"statuses": [

{

"id": "ZBKQ7M9",

"value": "NEW",

"created": "2026-07-25 14:59:24.563399+00:00"

},

{

"id": "glwaNDL",

"value": "OPEN",

"created": "2026-07-25 14:59:24.571699+00:00"

},

{

"id": "9eOz72g",

"value": "DUE",

"created": "2026-07-25 14:59:24.587888+00:00"

},

{

"id": "98q61rL",

"value": "PAID",

"created": "2026-07-25 14:59:36.977296+00:00"

}

],

"payment_data": {

"intent_id": "9KWvyeM",

"intent": {

"id": "9KWvyeM",

"active_transaction": {

"id": "abd353ce-f709-452b-833e-0cc0dbc4aae3",

"status": "SUCCESSFUL",

"amount": "10.00",

"amount_currency": "USD",

"payment_method": "CARD",

"payment_method_name": "Card"

}

}

}

}

Subscription Webhook Fields

The table below explains the key fields across subscription webhooks and what to use each one for.

FieldPurpose
typeThe event type, either subscription.status.{status} or subscription.invoice.{status}.
idThe subscription ID on a status event, or the invoice ID on an invoice event.
subscription_idOn invoice events, the ID of the subscription the invoice belongs to.
current_statusOn status events, the subscription's current status and when it changed.
statusOn invoice events, the invoice's current status and when it changed.
statusesThe full history of status changes, useful for reconstructing the timeline.
planThe plan the subscription is based on.
customerThe customer the subscription belongs to.
charge_automaticallyWhether the subscription is billed automatically using a saved card, or requires manual payment each cycle.
primary_card_tokenThe saved card token used for automatic charging, when applicable.
configurationThe subscription's billing configuration, including amount, recurrency, trial period, and discount settings.
due_invoicesInvoices currently due for the subscription.
next_recurring_cycle_invoiceThe invoice generated for the next billing cycle.
all_invoicesThe full list of invoices issued for the subscription.
payment_intent_urlOn invoice events, the hosted payment URL the customer can use to pay the invoice.
payment_dataOn invoice events, the payment intent and transaction details for the invoice payment.
is_liveIndicates whether the subscription is in live or test mode.

Payout Webhooks

Payout webhooks are fired when a disburse or void operation changes status on a payout intent. These events follow the same transaction webhook pattern but are scoped to payout operations.

These webhook types take the form transaction.{operation_type}.{status}. Disburse operations may pass through intermediate states before reaching a terminal outcome.

EventWebhook TypeTerminal?Description
Disburse pending approvaltransaction.disburse.pending_approvalNoThe disburse operation is awaiting approval before execution proceeds.
Disburse successfultransaction.disburse.successfulYesFunds have been disbursed successfully. The payout intent moves to processed.
Disburse failedtransaction.disburse.failedYesThe disbursement failed. The payout intent remains unprocessed.
Void successfultransaction.void.successfulYesThe payout was cancelled before funds were disbursed. The intent moves to processed.
Void failedtransaction.void.failedYesThe void attempt failed. The disburse operation continues.
Sample Payout Webhook

{

"type": "transaction.disburse.successful",

"status_id": "v02QJad",

"operation_id": "LYp5ek0",

"intent": {

"id": "9eQVWzj",

"created": "2026-05-22 08:13:38.259170+00:00",

"custom_fields": null,

"custom_form_answers": null,

"amount": {

"value": "50.00",

"currency": "EGP",

"formatted": 50,

"display_value": "50.00 EGP"

},

"payout_status": {

"status": "DISBURSED"

}

},

"account": {

"id": "4L2W2bg"

},

"transaction": {

"type": "payout",

"id": "7ec43ca6-96ca-45b6-82ef-b6d2c1777c21",

"created": "2026-05-22 08:13:43.405692+00:00",

"status": "disburse.successful",

"billing_data": {

"issuer": "example wallet",

"last_name": "Doe",

"first_name": "John",

"phone_number": "+201111111111"

},

"external_action_message": [],

"provider_transaction_fields": {

"provider_transaction_id": null

},

"provider_unique_reference": null,

"operations": [

{

"id": "LYp5ek0",

"type": "disburse",

"status": "successful",

"amount": {

"value": "50.00",

"currency": "EGP",

"formatted": 50,

"display_value": "50.00 EGP"

},

"latest_status": {

"id": "v02QJad",

"value": "successful",

"code": "6000",

"provider_error_code": null,

"provider_error_message": null,

"message": "Successful",

"localized_message": "Successful"

},

"statuses": [

{

"id": "8jW5PGr",

"value": "pending",

"code": "8000",

"message": "Pending",

"localized_message": "Pending",

"created": "2026-05-22 08:13:43.436840+00:00"

},

{

"id": "v02QJad",

"value": "successful",

"code": "6000",

"message": "Successful",

"localized_message": "Successful",

"created": "2026-05-22 08:14:37.081263+00:00"

}

]

}

],

"method": {

"id": "gqwWO79",

"display_name": "Provider A - Mobile Wallet",

"service_provider": {

"id": "Vg6lNY9",

"display_name": "Provider A"

}

}

},

"api_version": "1.4"

}

Bulk Payout Webhooks

Bulk payout webhooks are fired at two levels: the bulk request level (status of the overall batch) and the item level (status of each individual payout). Both are delivered to the webhook_url provided when creating the bulk request.

Bulk request events

These events reflect the overall status of the bulk payout request.

EventWebhook TypeDescription
Bulk request activepayout.bulk.activeThe bulk request has been created and items are queued for validation. Payload includes the full items array with initial statuses.
Bulk request cancelledpayout.bulk.cancelledThe bulk request was cancelled. All eligible items that had not yet entered processing are moved to CANCELLED.
Bulk request batch completedpayout.bulk.batch_completedAll items in the batch have been processed — validation and execution are complete. Includes item count breakdown per status.
Sample Bulk Request Webhook

{

"type": "payout.bulk.active",

"data": {

"id": "wgjJ3wg",

"label": "test bulk payout request",

"source": "API",

"status": "ACTIVE",

"items_count": 1,

"validation_pending_items_count": 1,

"scheduled_items_count": 0,

"validation_failed_items_count": 0,

"cancelled_items_count": 0,

"intent_created_items_count": 0,

"intent_creation_failed_items_count": 0,

"active_at": "2026-05-22T09:12:33.859011Z",

"completed_at": null,

"cancelled_at": null,

"created": "2026-05-22T09:12:33.859198Z",

"items": [

{

"id": "jgxdwag",

"merchant_reference": "1234567890",

"bulk_payout_request_id": "wgjJ3wg",

"status": "VALIDATION_PENDING",

"scheduled_date": "2026-06-20T00:00:00Z",

"payout_intent_details": {

"amount": 50,

"webhook_url": "https://example.com/webhooks/moneyhash",

"payout_method": "BANK_ACCOUNT",

"amount_currency": "NGN",

"merchant_reference": "1234567890"

},

"validation_result": {},

"linked_intent_id": null,

"created": "2026-05-22T09:12:33.864169Z"

}

]

}

}

Item validation events

These events reflect the validation outcome for each individual item.

EventWebhook TypeDescription
Item validation pendingpayout.item.validation_pendingThe item is queued and waiting for validation.
Item scheduledpayout.item.scheduledValidation passed. The item is scheduled for execution on its scheduled_date.
Item validation failedpayout.item.validation_failedValidation failed. The validation_result field in the payload describes the errors.
Sample Item Validation Webhook

{

"type": "payout.item.validation_failed",

"data": {

"id": "jgxdwag",

"merchant_reference": "1234567890",

"bulk_payout_request_id": "wgjJ3wg",

"status": "VALIDATION_FAILED",

"scheduled_date": "2026-06-20T00:00:00Z",

"payout_intent_details": {

"amount": 50,

"webhook_url": "https://example.com/webhooks/moneyhash",

"payout_method": "BANK_ACCOUNT",

"amount_currency": "NGN",

"merchant_reference": "1234567890"

},

"validation_result": {

"status": "error",

"errors": {

"account_number": ["Invalid key"]

}

},

"linked_intent_id": null,

"created": "2026-05-22T09:12:33.864169Z",

"validation_failed_at": "2026-05-22T09:12:35.316634Z"

}

}

Item execution events

These events are fired on the item's scheduled_date when execution begins.

EventWebhook TypeDescription
Intent createdpayout.item.intent_createdA payout intent was successfully created for this item. Payout lifecycle webhooks will follow.
Intent creation failedpayout.item.intent_creation_failedThe payout intent could not be created. The item moves to INTENT_CREATION_FAILED. Retry in a new bulk request.
Sample Item Execution Webhook

{

"type": "payout.item.intent_created",

"data": {

"id": "L2WVlAg",

"merchant_reference": "1234567890",

"bulk_payout_request_id": "jZBnOWZ",

"status": "INTENT_CREATED",

"scheduled_date": "2026-05-24T00:00:00Z",

"payout_intent_details": {

"amount": 50,

"webhook_url": "https://example.com/webhooks/moneyhash",

"billing_data": {

"name": "John Doe",

"bank_account": "035",

"account_number": "0001234567"

},

"payout_method": "BANK_ACCOUNT",

"amount_currency": "NGN",

"merchant_reference": "1234567890"

},

"validation_result": {

"status": "success"

},

"linked_intent_id": "ZdbvNvX",

"created": "2026-05-24T13:38:25.714298Z",

"scheduled_at": "2026-05-24T13:38:26.863991Z",

"cancelled_at": null,

"validation_failed_at": null,

"intent_created_at": "2026-05-24T13:40:00.464801Z",

"intent_creation_failed_at": null

}

}

Payout intent lifecycle events

Once an item creates a payout intent, standard payout webhooks are fired for that intent's disburse and void operations:

  • transaction.disburse.pending_approval

  • transaction.disburse.successful

  • transaction.disburse.failed

  • transaction.void.successful

  • transaction.void.failed

See Payout Webhooks above for event details and payload structure.


Did this page help you?