Two POST endpoints under /api/webhook/order use the Webhook token. See the Webhooks/Pushers tab.
Get orders: /order/details
| Field | Required | Meaning |
|---|
from_date | No | Start, in the form 2026-01-31 00:00:00 |
to_date | No | End, same form. Must be after from_date |
state | No | One of new, approved, processing, delivered, cancel |
With both dates you get every order created or changed in the range. Otherwise you get the 20 most recent. Demo-store orders are never listed.
state | Orders it filters to |
|---|
new | Placed |
approved | Accepted, being prepared |
processing | Picked up |
delivered | Delivered |
cancel | Cancelled |
The state you read back is broader: ready, assigned to a driver, picked up and modified all read as processing.
The answer wraps the list in result:
{ "result": { "status": true, "message": "Success", "data": [ { "order_id": 5123, "order_name": "OD-…", "order_line": [] } ] } }
Keys of each order:
| Group | Keys |
|---|
| Identity | order_id (numeric), order_name (the order number), cart_no, branch_id, branch |
| Customer | customer, customer_phone, customer_email, customer_delivery_address, address_line, city, area |
| Timing | date, last_update_date, delivery_date, delivery_time |
| Delivery and payment | delivery_methdod_id, delivery_methdod_name, delivery_charge, purchase_type, payment_type |
| Status and total | state, amount_total |
| Lines | order_line[] with line_id, product_id, product_name, unit_price, quantity, price, varient_id, varient_name, varient_safari_id |
The key names are spelt as shown. product_id is your external id for the product. varient_safari_id is its barcode.
Each order ends with one extra line whose product_id is delivery_charge. Its line_id is random on every call. Do not send it back in an update.
Update order lines: /order/updates
Sets the issued quantity and unit price of order lines. Totals and tax are recalculated.
| Field | Required | Meaning |
|---|
username | Yes | Any name for your system |
password | Yes | Your Webhook token. Required in the body on this call, even when you also send the header |
order_info | Yes | A list with at least one order |
order_info[].order_id | Yes | The numeric order_id from /order/details |
order_info[].order_line[].line_id | Yes | The line_id from /order/details |
order_info[].order_line[].quantity | Yes | Issued quantity, 0 or more |
order_info[].order_line[].price_unit | Yes | Issued unit price, 0 or more |
The call answers HTTP 200 even when orders are skipped:
result.message begins | Meaning |
|---|
| "SUCCESS" | Every order was updated |
| "PARTIAL SUCCESS" | Some were updated. skipped_orders gives a reason for each of the others |
| "No orders were updated" | result.status is false |
updated_orders returns new_total, new_payable, tax_amount and sub_total for each order.
Reasons you may see in skipped_orders or skipped_lines:
- "Order not found or does not belong to this shop"
- "Empty order_line array - no items to update"
- "Line item not found or does not belong to this order"
- "quantity and price_unit must be numeric values"
- "Order cannot be re-priced: …"
- "The order was being changed at the same moment — nothing was applied, send this order again". This one carries
retryable: true.
Within one order, a line with a problem is listed under skipped_lines. The valid lines and new totals are saved together.