Event catalog
Every event you can subscribe to.
An event is emitted when a payment changes state and then fanned out to every active endpoint that subscribed to that event type. The catalog of subscribable types is served by the API, so it is always authoritative:
curl https://api.lite.shiftxpay.com/v1/merchants/me/event-types \
-H "Authorization: Bearer $SHIFTXPAY_API_KEY"{
"data": [
{ "code": "payment.succeeded", "label": "Payment Succeeded", "category": "payment" },
{ "code": "payment.refunded", "label": "Payment Refunded", "category": "payment" }
]
}Events the gateway emits today
| Event | Fires when |
|---|---|
payment.succeeded | A payment reaches a terminal authorized/captured state — on synchronous confirm and again from the PSP's signed webhook (Peach). |
payment.failed | The PSP reports the charge failed. |
payment.refunded | A refund is created or settles. status reflects the new payment state (refunded or partially_refunded). |
payment.disputed | The PSP opens a dispute / chargeback against a payment. |
test.ping | You pressed Test on an endpoint (POST /v1/merchants/me/webhooks/{id}/test). Carries no payment. |
The full catalog returned by GET /v1/merchants/me/event-types may list
additional payment.* and dispute.* codes that are reserved for future use.
Subscribe to them if you like, but only the events in the table above are
delivered by the current gateway.
Payload shape
Payment events share one compact shape. Amounts and other payment detail are not
inlined — treat the webhook as a signal and fetch the authoritative record with
GET /v1/payments/{id} using the payment_id.
payment.succeeded
{
"type": "payment.succeeded",
"payment_id": "pay_3kP9c2Xa...",
"status": "succeeded"
}payment.refunded
{
"type": "payment.refunded",
"payment_id": "pay_3kP9c2Xa...",
"status": "refunded"
}payment.failed and payment.disputed follow the same three fields, with
status carrying failed and the disputed payment's status respectively.
The type field always equals the ShiftxPay-Event header, so you can branch on
either. The body is the exact byte sequence the signature is computed over — see
Outbound webhooks.
Monetary values, wherever they appear in the API, are integer minor units (e.g.
1050isRs 10.50). Never parse them as decimals.