- the financial state machine (
order_status) - the shipping status field and its bilingual custom labels
- which webhook fires on each transition
The state machine
Financial statuses (order_status)
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
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:
Update with
POST /v1/orders/{uuid}/status. Each call fires a shipping_status_updated webhook.
Keep shipping status separate from financial status in your own system.
order_status tells you whether the order was approved, captured, cancelled, or refunded; status tells you where fulfilment stands.Custom shipping labels
Different fulfilment platforms (Salla, Zid, custom WMS, …) use status names that don’t map cleanly onto the six built-in shipping stages above.POST /v1/orders/{uuid}/status accepts two optional fields alongside the canonical status enum so you can attach your own bilingual label to an order without us having to extend the enum:
*At least one of
status, name_ar, or name_en must be supplied — a fully blank payload returns 422. All three can be sent together; the canonical enum and the custom label update atomically.Auto-translation
When only one ofname_ar / name_en is supplied, the missing locale is auto-filled via Google Translate so custom_status always has both locales. Translations are cached server-side for 30 days keyed on (target, text) — sending the same label across 100 orders only hits Google once.
If the translator is unreachable (quota / network), the supplied locale is copied into the missing slot rather than leaving the row half-populated.
Examples
Response fields
EveryOrder response exposes the resolved label so consumers don’t have to duplicate the fallback logic client-side:
Timeline example — redeem checkout with full refund
- Customer clicks Pay → you call
POST /orders/checkout/{publicKey}→ order isnew. - Customer completes payment on
business.papp.sa→ order transitions toapproved, webhookapprovedfires. - 7 days later, customer requests a refund → you call
POST /orders/{uuid}/refund→ order moves tofully_refunded, redeemed points are returned, earned points reversed.
Timeline example — authorize-capture flow
POST /orders/checkout/{publicKey}→ order isnew.POST /orders/{uuid}/authorizeafter your PSP authorises →authorized.POST /orders/{uuid}/captureafter you ship →captured.- Later: partial refund for one returned item →
POST /orders/{uuid}/refundwithamount→partially_refunded.
Invalid transitions
The API enforces the state machine. Examples that return400:
POST /orders/{uuid}/authorizeon acancelledor already-refunded order.POST /orders/{uuid}/captureon an order that is notauthorized.POST /orders/{uuid}/refundon an order that has not yet beenapprovedorcaptured, or outside the allowed refund window.POST /orders/{uuid}/completeon an order that is alreadyapproved/captured.
message field for the specific reason before retrying.
Webhooks per transition
See Webhook events for payload schemas.
Practical advice
Store the UUID, not the numeric ID
Store the UUID, not the numeric ID
All endpoints take
{order:uuid} — the integer id is internal and may change between environments.Reconcile nightly against GET /orders/{uuid}
Reconcile nightly against GET /orders/{uuid}
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.
Refunds reverse earned points too
Refunds reverse earned points too
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.
Cancellation vs refund
Cancellation vs refund
Cancel only while the order is
new or authorized. Once funds are captured or the order is approved, use refund instead.Next
Refunds & cancellations
Rules, windows, and partial refund behaviour.
Webhook events
Per-event payload schemas and sample bodies.

