Payment Object

You can expect the below object when you register a webhook for the following events:

  • payment.failed
  • payment.succeeded
  • payment.refund_initiated
  • payment.refunded
  • payment.refund_failed
  • payment.card_verified

Raw sample

{
  "status": "captured",
  "id": "PAY-D65B203ABD",
  "amount": 33.99,
  "amount_currency": "AED",
  "refund_amount": 0,
  "refund_status": "No refund",
  "refunds": [],
  "max_refund_amount": 33.99,
  "billing_descriptor": "Mamo*Merchant",
  "custom_data": {},
  "created_date": "2023-12-25-14-38-53",
  "subscription_id": null,
  "settlement_amount": "31.99",
  "settlement_currency": "AED",
  "settlement_date": "2024-01-01",
  "customer_details": {
    "name": "",
    "email": "[email protected]",
    "phone_number": "-",
    "comment": "-"
  },
  "payment_method": {
    "card_id": null,
    "type": "CREDIT VISA",
    "card_holder_name": "John Doe",
    "card_last4": "1111",
    "card_expiry_month": "12",
    "card_expiry_year": "2028",
    "origin": "International card"
  },
  "settlement_fee": "AED 1.90",
  "settlement_vat": "AED 0.10",
  "payment_link_id": "MB-LINK-1EC52247EE",
  "payment_link_url": "https://staging.business.mamopay.com/pay/mamosandbox-8acfdf",
  "external_id": null,
  "error_code": null,
  "error_message": null,
  "next_payment_date": null,
  "event_type": "payment.succeeded"
}

Field Descriptions

FieldTypeDescription
statusStringStatus of the payment (confirmation_required-captured-refund_initiated-processing-failed-refunded)
idStringMamo payment ID
amountNumberAmount
amount_currencyStringCurrency
refund_amountNumberRefund Amount (for a refund payment)
refund_statusStringRefund Status (for a refund payment)
refundsArrayBreakdown of each individual refund issued (id-amount-amount_currency-billing_amount-billing_amount_currency)
max_refund_amountNumberThe maximum amount that can still be refunded on this payment
custom_dataDictionaryCustom Data sent upon creation
created_dateString (Format: YYYY-MM-DD-HH-MM-SS)payment creation time
subscription_idStringSubscription ID (in case of a subscription payment)
settlement_amountStringSettlement Amount
settlement_currencyStringSettlement Currency
settlement_dateString (Format: YYYY-MM-DD)Settlement Date
customer_detailsDictionaryCustomer Details (name-email-phone_number-comment)
external_idStringExternal ID if sent
payment_methodStringPayment Method (card_id-type-card_holder_name-card_last4-card_expiry_month-card_expiry_year-origin)
settlement_feeStringSettlement Fee
settlement_vatStringSettlement VAT
payment_link_idStringID of payment link used
payment_link_urlStringPayment Link Used
error_codeStringError Code (In case of failure)
error_messageStringError Message (In case of failure)
next_payment_dateStringNext Payment Date (In case of failure)
event_typeStringCorresponding Webhook Event

Payment status lifecycle

The status field tells you where a payment is in its lifecycle and, crucially, whether money has actually been received. On webhooks the status is reported raw — it is never remapped — so an authorized hold arrives as authorized (not captured) and a released hold arrives as voided (not failed). Note that confirmation_required and processing do not trigger a webhook, so you will not receive this object for those states; a payment you hear about via webhook has reached captured, failed, authorized, card_verified, or voided (refund events carry refund_initiated / refunded).

StatusFunds received?Meaning
confirmation_requiredNoInitial state. The payment is waiting on the customer to complete authentication / confirmation (for example 3-D Secure or a redirect). No money has moved. Does not trigger a webhook, so it does not arrive via this object.
processingNo (pending)The payment has been submitted to the gateway and the outcome is not yet known. Do not treat this as success. Does not trigger a webhook, so it does not arrive via this object.
authorizedHeld, not capturedFunds have been authorized (placed on hold on the customer's card) but not captured. This happens on hold_and_charge_later links, and on future-dated subscription links — see the note below.
capturedYesThe payment succeeded and funds were captured. This is the terminal success state and the amount will be settled to you.
card_verifiedNo (no charge)The card was successfully verified (for example a card-saving or verification flow). No amount was captured.
refund_initiatedYes, originally — refund pendingThe payment was captured and a refund (full or partial) has been started but not yet completed.
refundedReturned to customerThe payment was captured and has since been refunded back to the customer.
failedNoThe payment attempt failed. Inspect error_code / error_message for the reason.
voidedNo (hold released)An authorization that was released/cancelled before capture. Always reported as voided on webhooks (the raw status is sent, so it is never remapped to failed).
📘

Authorize vs. capture (hold_and_charge_later)

On a normal payment link the charge is captured immediately, so a successful payment goes straight to captured and the funds are received.

On a payment link configured with hold_and_charge_later, the payment is only authorized first: the amount is placed on hold on the customer's card and the charge sits in authorized until you capture it later. The hold can be released, which moves the charge to voided. On webhooks these states are reported raw — an authorized hold is sent as authorized (not captured) and a released hold as voided (not failed) — so rely on the status together with the link configuration to know whether a given payment is a hold or a completed capture.

What differs per event

The raw sample above is a payment.succeeded payload. Other events carry the same object shape — only these fields change:

EventstatusNotable fields
payment.failedfailederror_code / error_message populated; settlement_date is the placeholder string "-" and settlement_amount reports 0 — these fields are always present, never actually null
payment.authorizedauthorizedSame settlement_date/settlement_amount placeholders as above until captured
payment.voidedvoidedSame as authorized, but the hold has been released — no further action possible on this payment
payment.card_verifiedcard_verifiedamount reflects the verification amount (if any); settlement_* fields are still present with the same placeholder values, since no revenue has been recorded
payment.refund_initiatedrefund_initiatedrefund_amount > 0, refunds has at least one entry, max_refund_amount reduced accordingly
payment.refundedrefundedSame as refund_initiated, with the refund entry's state resolved
📘

Marketplace / split payments

This object does not include payouts_share — the split amount is available on the payment link object instead. For a split payment, the recipient's share is credited to their recipient ledger when the payment is captured; it is paid out to their bank account later on a schedule (by default monthly). Use Fetch Recipient Balance to check a recipient's accrued ledger balance.