Webhooks
How you find out that a transaction reached a final state.
When a payment or payout reaches a final state, we send an HTTP POST to your configured webhook URL. This is the recommended way to be notified of outcomes.
Headers#
X-Maly-Event: payment.succeeded
X-Maly-Signature: t=1751020200,v1=<signature>
Content-Type: application/jsonBody#
{
"event": "payment.succeeded",
"payment_id": "550e8400-...",
"reference": "ORDER-123",
"status": "success",
"failure_reason": null,
"amount": { "value": "11800", "currency": "XAF" },
"method": "mobile_money_mtn",
"metadata": { "order_id": "ORDER-123" },
"timestamp": "2026-06-27T09:01:42Z"
}Events#
| Event | Fires when |
|---|---|
payment.succeeded | A payment reaches success |
payment.failed | A payment reaches failed |
payment.expired | A payment reaches expired |
payout.succeeded | A payout reaches success |
payout.failed | A payout reaches failed |
Handling them well#
- Verify the signature on every webhook before acting on it. See Verifying webhooks.
- Reject events older than 5 minutes, using the
t=timestamp, to protect against replays. - Respond
200quickly and do any heavy processing asynchronously. - Make your handler idempotent. A delivery can arrive more than once.
Deduplicating deliveries#
Delivery is at least once, so the same event can reach you more than once. A webhook fires only when a transaction reaches its single final state, so the transaction id is a sufficient dedupe key on its own: once you have processed a final outcome for a given payment_id, treat any further delivery for it as a no-op. There is no earlier state a later delivery could arrive before, so ordering is not a concern.
Which source wins. If a webhook and the status endpoint ever disagree, the status endpoint is authoritative.
Pending confirmation Payment webhooks carry payment_id. The identifier field on a payout webhook is being confirmed from a live payout event; dedupe payouts on that id once published.
Retries We retry delivery for up to 24 hours with exponential backoff on any non-2xx response.
Webhooks are not the only truth. If a delivery is missed entirely, the status endpoint still holds the final state. Run a periodic sweep for transactions your side still has as non-final.
Maly Tech Ltd. This guide is provided for information. Where it differs from your signed agreement, the agreement applies.