Documentation Index Fetch the complete documentation index at: https://docs.papp.sa/llms.txt
Use this file to discover all available pages before exploring further.
Every webhook event shares the same envelope. This page documents each event, when it fires, and any additional fields in the payload.
Envelope
{
"event" : "<event-name>" ,
"order" : { /* OrderResource plus per-event extras */ },
"timestamp" : "2026-04-18T10:05:12Z"
}
The order object always contains at least:
Field Type Example idstring (UUID) 550e8400-e29b-41d4-a716-446655440000reference_numberstring | null REF-2024-001234order_numberstring ORD-2024-0001typestring earning or replacingtotal_pricenumber (SAR) 150.75total_pointsnumber 500payment_statusstring fully_paid or partially_paidorder_statusstring approved, authorized, captured, cancelled, fully_refunded, partially_refunded, newmetadataobject | null { "source": "web" }created_atISO 8601 string 2026-04-18T10:00:00Zupdated_atISO 8601 string 2026-04-18T10:05:12Z
Headers on every delivery:
Header Example Content-Typeapplication/jsonX-Webhook-Secretabc123def456... (the secret you registered)X-Webhook-EventSame as event in the body
approved
Fires when: an order is fully settled — a paid checkout completes, or an earning order is awarded.
Use it to: mark the order as confirmed in your system, send the customer a receipt, trigger fulfilment.
{
"event" : "approved" ,
"order" : {
"id" : "550e8400-e29b-41d4-a716-446655440000" ,
"reference_number" : "REF-2024-001234" ,
"order_number" : "ORD-2024-0001" ,
"type" : "replacing" ,
"total_price" : 150.75 ,
"total_points" : 500 ,
"payment_status" : "fully_paid" ,
"order_status" : "approved" ,
"metadata" : { "source" : "web" },
"created_at" : "2026-04-18T10:00:00Z" ,
"updated_at" : "2026-04-18T10:05:12Z"
},
"timestamp" : "2026-04-18T10:05:12Z"
}
authorized
Fires when: funds are authorised on a two-step (auth → capture) payment flow. No money has moved yet.
Use it to: reserve inventory, start fulfilment if your flow permits it before capture.
{
"event" : "authorized" ,
"order" : {
"id" : "550e8400-e29b-41d4-a716-446655440000" ,
"order_number" : "ORD-2024-0001" ,
"type" : "replacing" ,
"order_status" : "authorized" ,
"total_price" : 150.75 ,
"total_points" : 500 ,
"payment_status" : "fully_paid" ,
"created_at" : "2026-04-18T10:00:00Z" ,
"updated_at" : "2026-04-18T10:01:00Z"
},
"timestamp" : "2026-04-18T10:01:00Z"
}
captured
Fires when: previously-authorised funds are captured.
Use it to: finalise the order, release inventory holds, run post-sale automation.
{
"event" : "captured" ,
"order" : {
"id" : "550e8400-e29b-41d4-a716-446655440000" ,
"order_number" : "ORD-2024-0001" ,
"order_status" : "captured" ,
"total_price" : 150.75 ,
"total_points" : 500 ,
"payment_status" : "fully_paid" ,
"created_at" : "2026-04-18T10:00:00Z" ,
"updated_at" : "2026-04-18T10:10:00Z"
},
"timestamp" : "2026-04-18T10:10:00Z"
}
cancelled
Fires when: an order is cancelled via POST /v1/orders/{uuid}/cancel.
Use it to: release inventory, notify the customer, stop fulfilment.
{
"event" : "cancelled" ,
"order" : {
"id" : "550e8400-e29b-41d4-a716-446655440000" ,
"order_number" : "ORD-2024-0001" ,
"order_status" : "cancelled" ,
"total_price" : 150.75 ,
"total_points" : 0 ,
"payment_status" : "fully_paid" ,
"reason" : "Customer requested cancellation" ,
"created_at" : "2026-04-18T10:00:00Z" ,
"updated_at" : "2026-04-18T10:30:00Z"
},
"timestamp" : "2026-04-18T10:30:00Z"
}
The reason field, if supplied on the cancel request, is echoed in the payload.
completed
Fires when: a replacing (checkout) order is marked complete via POST /v1/orders/{uuid}/complete — typically after the customer’s payment is confirmed by the PSP.
Use it to: close out the order on your side if your flow distinguishes “approved” from “completed”.
{
"event" : "completed" ,
"order" : {
"id" : "550e8400-e29b-41d4-a716-446655440000" ,
"order_number" : "ORD-2024-0001" ,
"order_status" : "approved" ,
"total_price" : 150.75 ,
"total_points" : 500 ,
"payment_status" : "fully_paid" ,
"created_at" : "2026-04-18T10:00:00Z" ,
"updated_at" : "2026-04-18T10:05:12Z"
},
"timestamp" : "2026-04-18T10:05:12Z"
}
shipping_status_updated
Fires when: you update a physical-goods order’s shipping status via POST /v1/orders/{uuid}/status.
Additional fields (inside order):
Field Type Example statusstring One of new, license_in_progress, ready_shipping, delivery_is_in_progress, delivered, cancelled status_labelstring Human-readable label (Arabic/English) shown on the customer’s transaction history
{
"event" : "shipping_status_updated" ,
"order" : {
"id" : "550e8400-e29b-41d4-a716-446655440000" ,
"order_number" : "ORD-2024-0001" ,
"order_status" : "approved" ,
"status" : "ready_shipping" ,
"status_label" : "Ready for shipping" ,
"total_price" : 150.75 ,
"total_points" : 500 ,
"payment_status" : "fully_paid" ,
"created_at" : "2026-04-18T10:00:00Z" ,
"updated_at" : "2026-04-18T14:00:00Z"
},
"timestamp" : "2026-04-18T14:00:00Z"
}
refunded
Fires when: a refund is created through POST /v1/orders/{uuid}/refund.
Use it to: reverse fulfilment-side accounting, return value in your ERP, and mark the order as fully or partially refunded on your side.
Additional fields (inside order):
Field Type Example refund_amountnumber 25.00reasonstring One line item returnedtypestring earning or replacingrefund_pointsnumber 500left_pointsnumber 1500left_amountnumber 75.00
Not every refund payload includes every optional field. For example, refund_points, left_points, and left_amount are especially relevant for earning-order reversals.
{
"event" : "refunded" ,
"order" : {
"id" : "550e8400-e29b-41d4-a716-446655440000" ,
"order_number" : "ORD-2024-0001" ,
"type" : "earning" ,
"order_status" : "partially_refunded" ,
"total_price" : 150.75 ,
"total_points" : 3000 ,
"payment_status" : "fully_paid" ,
"refund_amount" : 25.00 ,
"refund_points" : 500 ,
"left_points" : 2500 ,
"left_amount" : 125.75 ,
"reason" : "One line item returned" ,
"created_at" : "2026-04-18T10:00:00Z" ,
"updated_at" : "2026-04-18T15:00:00Z"
},
"timestamp" : "2026-04-18T15:00:00Z"
}
auto_refunded
Fires when: Points automatically reverses a replacing order internally, for example when a required transaction record is missing during backend reconciliation.
Use it to: treat the order as refund-class terminal state and stop assuming the checkout remained successful.
Additional fields (inside order):
Field Type Example refund_amountnumber 150.75refund_pointsnumber 3000reasonstring auto_refund_missing_transactiontypestring replacing
{
"event" : "auto_refunded" ,
"order" : {
"id" : "550e8400-e29b-41d4-a716-446655440000" ,
"order_number" : "ORD-2024-0001" ,
"type" : "replacing" ,
"order_status" : "fully_refunded" ,
"total_price" : 150.75 ,
"total_points" : 3000 ,
"payment_status" : "fully_paid" ,
"refund_amount" : 150.75 ,
"refund_points" : 3000 ,
"reason" : "auto_refund_missing_transaction" ,
"created_at" : "2026-04-18T10:00:00Z" ,
"updated_at" : "2026-04-18T16:00:00Z"
},
"timestamp" : "2026-04-18T16:00:00Z"
}
Testing events
The fastest way to trigger an event end-to-end is to issue the corresponding API call against a sandbox order:
Event API call approvedPOST /v1/orders/earning or complete a checkoutauthorizedPOST /v1/orders/{uuid}/authorizecapturedPOST /v1/orders/{uuid}/capturecancelledPOST /v1/orders/{uuid}/cancelcompletedPOST /v1/orders/{uuid}/completerefundedPOST /v1/orders/{uuid}/refundauto_refundedInternal event; not normally merchant-triggered shipping_status_updatedPOST /v1/orders/{uuid}/status
Delivery semantics
Points sends webhook deliveries over HTTPS
each attempt uses a 10 second HTTP timeout
failed deliveries may be retried up to 3 times
order is not guaranteed across different events, so your consumer must be idempotent
Next
Overview How delivery works, secret verification, and the recommended consumer pattern.
Management Register, update, rotate, and delete webhooks.