A seller on OrderPage can have every new order sent to their own software the moment it arrives. They paste your web address in the app (Settings › Send orders to your software) and send you a secret key. This page is everything you need to receive the orders.
https:// address that accepts a POST.
IP addresses, http:// and local network names are refused.osk_. Keep it on your server (an
environment variable or secret store), never in a browser, app or repository.One POST for each new order, with a JSON body and these headers:
| Header | Value |
|---|---|
Content-Type | application/json; charset=utf-8 |
X-OrderPage-Event | order.created, or test when the seller taps Connect or Send a test order |
X-OrderPage-Timestamp | When we sent it, in Unix seconds |
X-OrderPage-Signature | v1= + hex HMAC-SHA256 of timestamp + "." + body, with the secret key |
{
"event": "order.created",
"orderId": "a8Kq2LmZ0pRtY7wX",
"ref": "165729",
"createdAt": "2026-09-28T11:27:12.000Z",
"status": "pending",
"mode": "delivery",
"store": { "id": "GI87Kq7Y", "name": "Surmai Seafood" },
"customer": { "name": "Asha", "phone": "+919800000000", "address": "Flat 4, Example Road, Dadar",
"landmark": "Opposite the post office", "area": "Dadar West", "city": "Mumbai", "postcode": "400028" },
"items": [ { "name": "Pomfret (Large)", "qty": 2, "price": 650, "lineTotal": 1300 } ],
"fields": [ { "label": "Preparation", "value": "Curry cut" }, { "label": "Delivery time", "value": "Morning" } ],
"dueDate": "2026-09-29",
"note": "Please call before coming",
"subtotal": 1300, "deliveryFee": 0, "charges": [], "total": 1300,
"currency": "INR"
}
| Field | Meaning |
|---|---|
orderId | Unique for the order. Use this as your key. |
ref | The number the customer sees. It is made from the time of day and repeats on other days, so never use it as a key. |
items[].name | The item, with the chosen option in brackets, e.g. Pomfret (Large). |
items[].addons | Only when the customer picked add-ons for a dish, e.g. Spice: Hot, Extra cheese. Their price is already in price and lineTotal. |
customer | Name, phone and the typed address. landmark, area, city and postcode are filled when the customer shared their location or typed a landmark, and are empty strings otherwise. The map location itself is not sent. |
fields | The seller's own questions and the customer's answers, as label and value. |
dueDate | The first date the customer filled (delivery or booking date), yyyy-MM-dd, or null. |
mode | delivery, pickup or inquiry. |
booking, stay, table | Only for appointment, stay or rental stores, and table orders. |
Amounts are numbers in the store's currency. New fields may be added; ignore ones you don't know.
X-OrderPage-Timestamp is more than 5 minutes from your clock (a replay).v1= + hex HMAC-SHA256 of timestamp + "." + rawBody with the key, and compare with
X-OrderPage-Signature in constant time. Refuse it if they differ (401).orderId you have already saved. The same order can very occasionally arrive twice.event: "test", answer 200 and save nothing.const crypto = require("crypto");
function isFromOrderPage(headers, rawBody) {
const ts = Number(headers["x-orderpage-timestamp"]);
if (!ts || Math.abs(Date.now() / 1000 - ts) > 300) return false;
const want = "v1=" + crypto.createHmac("sha256", process.env.ORDERPAGE_KEY)
.update(ts + "." + rawBody).digest("hex");
const got = String(headers["x-orderpage-signature"] || "");
return got.length === want.length && crypto.timingSafeEqual(Buffer.from(got), Buffer.from(want));
}
// Express: app.post("/orderpage", express.raw({ type: "application/json" }), (req, res) => {
// const raw = req.body.toString("utf8");
// if (!isFromOrderPage(req.headers, raw)) return res.sendStatus(401);
// const order = JSON.parse(raw);
// if (order.event === "order.created") saveOnce(order.orderId, order);
// res.sendStatus(200);
// });
$raw = file_get_contents('php://input');
$ts = (int)($_SERVER['HTTP_X_ORDERPAGE_TIMESTAMP'] ?? 0);
$want = 'v1=' . hash_hmac('sha256', $ts . '.' . $raw, getenv('ORDERPAGE_KEY'));
if (!$ts || abs(time() - $ts) > 300 || !hash_equals($want, $_SERVER['HTTP_X_ORDERPAGE_SIGNATURE'] ?? '')) {
http_response_code(401); exit;
}
$order = json_decode($raw, true);
if ($order['event'] === 'order.created') { /* save once per orderId */ }
http_response_code(200);
import hashlib, hmac, os, time
def is_from_orderpage(headers, raw: bytes) -> bool:
ts = headers.get("X-OrderPage-Timestamp", "")
if not ts.isdigit() or abs(time.time() - int(ts)) > 300:
return False
want = "v1=" + hmac.new(os.environ["ORDERPAGE_KEY"].encode(), ts.encode() + b"." + raw,
hashlib.sha256).hexdigest()
return hmac.compare_digest(want, headers.get("X-OrderPage-Signature", ""))
Key osk_testkey_0123456789abcdef, timestamp 1790678232, body
{"event":"test","ref":"TEST01"} must give:
v1=4e3f5b97bc6cdbc88fe334ec69b5dfb80870768eb574c05bfcaa8f5117985eff
Email nk92.iit@gmail.com with the store's link.