Skip to main content
Every Points order moves through a small set of states, driven by either merchant API calls or internal Points events. Understanding the state machine is essential for building a correct refund/fulfilment/reconciliation pipeline.

The state machine

States explained

order_statusMeaningTypical trigger
newOrder created, not yet settled. Customer may still be on checkout.POST /orders/checkout/{publicKey} or POST /orders/earning (pre-lock release).
approvedOrder settled. Points credited or redeemed. This is the happy-path terminal state for earning and fully-paid checkouts.POST /orders/{uuid}/complete (after payment) or the earning path on POST /orders/earning.
authorizedFunds reserved but not captured. Used when your PSP runs a two-step auth→capture flow.POST /orders/{uuid}/authorize.
capturedAuthorized funds captured. Terminal state before any refund.POST /orders/{uuid}/capture.
cancelledOrder cancelled. Any reserved points are released back to the customer.POST /orders/{uuid}/cancel.
fully_refundedFull amount refunded. All redeemed points returned; earned points reversed.POST /orders/{uuid}/refund (no amount, or amount equals total).
partially_refundedA portion of the order refunded.POST /orders/{uuid}/refund with a partial amount.
order_status is a string enum in every webhook payload. The OpenAPI spec reflects a legacy numeric field — prefer the string values above.

Two order types

type (numeric)type (webhook string)Description
1earningSingle-step order created via POST /orders/earning. Awards points on a purchase the customer has already paid for on your side.
2replacingFull Points checkout — customer redeems + pays remainder on pay.papp.sa.
The state machine above applies to both, but earning orders typically move new → approved in a single step with no intermediate authorized/captured.

Shipping status (separate field)

order_status tracks the financial state of the order. Physical-goods orders also have a separate shipping status that you update as you fulfil:
Shipping statusMeaning
newOrder received, not yet processed.
license_in_progressPaperwork / licensing in progress (where applicable).
ready_shippingPackaged, handed to carrier.
delivery_is_in_progressIn transit.
deliveredReceived by customer.
cancelledShipping cancelled (not the same as a financial cancellation).
Update with POST /v1/orders/{uuid}/status. See Order statuses for the full enum + transitions.

Timeline example — redeem checkout with full refund

  1. Customer clicks Pay → you call POST /orders/checkout/{publicKey} → order is new.
  2. Customer completes payment on pay.papp.sa → order transitions to approved, webhook approved fires.
  3. 7 days later, customer requests a refund → you call POST /orders/{uuid}/refund → order moves to fully_refunded, redeemed points are returned, earned points reversed.

Timeline example — authorize-capture flow

  1. POST /orders/checkout/{publicKey} → order is new.
  2. POST /orders/{uuid}/authorize after your PSP authorises → authorized.
  3. POST /orders/{uuid}/capture after you ship → captured.
  4. Later: partial refund for one returned item → POST /orders/{uuid}/refund with amountpartially_refunded.

Invalid transitions

The API enforces the state machine. Examples that return 400:
  • POST /orders/{uuid}/authorize on a cancelled or already-refunded order.
  • POST /orders/{uuid}/capture on an order that is not authorized.
  • POST /orders/{uuid}/refund on an order that has not yet been approved or captured, or outside the allowed refund window.
  • POST /orders/{uuid}/complete on an order that is already approved / captured.
Always check the response message field for the specific reason before retrying.

Webhooks per transition

TransitionEvent delivered
new → approved (earning or complete)approved (then also completed for replacing orders that hit the complete endpoint)
new → authorizedauthorized
authorized → capturedcaptured
any → cancelledcancelled
any → fully_refunded / partially_refunded(handled by PSP/refund integration)
shipping status changeshipping_status_updated
See Webhook events for payload schemas.

Practical advice

All endpoints take {order:uuid} — the integer id is internal and may change between environments.
Don’t rely solely on webhooks. Run a nightly job that fetches the authoritative state of any order you believe is still live, to catch the rare missed delivery.
A full refund returns redeemed points to the customer and reverses points earned on the refunded portion. Mirror this in your own loyalty calculations if you double-book rewards.
Cancel only while the order is new or authorized. Once funds are captured or the order is approved, use refund instead.

Next

Order statuses

Full enum reference for financial and shipping statuses.

Refunds & cancellations

Rules, windows, and partial refund behaviour.