Quickstart
In about 10 minutes, your sandbox will mark an item sold out on Laayo and receive a test order. You need your key ID and secret from the console.
#1Sign every request
Join the timestamp, the method, the path and the exact body you send, with a dot between each. HMAC it with your secret. Send all three headers. We refuse anything more than 5 minutes off, and the same signature twice: identical requests in the same second are refused as replays, so retry after 1 second with a new timestamp.
const crypto = require('crypto');
const method = 'PUT';
const path = '/v1/stores/27/items/availability';
const body = JSON.stringify({ items: [ { external_item_id: 'MOMO-C-10', available: false } ] });
const ts = Math.floor(Date.now() / 1000).toString();
const sig = crypto.createHmac('sha256', process.env.LAAYO_SECRET)
.update(ts + '.' + method + '.' + path + '.' + body).digest('hex');
await fetch('https://posconnect.laayo.com.np' + path, {
method,
headers: {
'Content-Type': 'application/json',
'X-Laayo-Key': process.env.LAAYO_KEY_ID,
'X-Laayo-Timestamp': ts,
'X-Laayo-Signature': sig,
},
body,
});#2Link the test restaurant
Real restaurants read you a 6 digit code from the Laayo vendor app. Your sandbox has one ready on the keys page, and the console shows a fresh one when it expires. Send it once with your own ID for that store.
POST /v1/stores/link
{ "code": "731058", "external_store_id": "TK-01" }
200
{ "data": { "store_id": 9001, "store_name": "Laayo Test Kitchen",
"external_store_id": "TK-01", "link_id": 41, "linked_at": "2026-11-01T12:30:04+05:45" } }#3Match your items
Fetch the Laayo menu with GET /v1/stores/9001/menu, then send your item IDs next to ours. You can also do it by hand in the console, which suggests matches by name.
PUT /v1/stores/9001/item-map
{ "mappings": [
{ "external_item_id": "MOMO-C-10", "laayo_item_id": 55102 },
{ "external_item_id": "MOMO-V-10", "laayo_item_id": 55101 }
] }
200
{ "data": { "saved": 2, "removed": 0 } }#4Receive orders
Pick one. Cloud POS: set a webhook URL in the console and we POST each event to it. Desktop POS: call GET /v1/events?after=cursor and we hold the call open for up to 25 seconds until something happens. Then press Send test order on the Go-live page.
{
"event": "order.created",
"idempotency_key": "order.created:104812",
"occurred_at": "2026-11-01T12:41:11+05:45",
"data": {
"laayo_order_id": "104812",
"laayo_store_id": 9001,
"external_store_id": "TK-01",
"status": "pending",
"order_type": "delivery",
"payment_method": "cash_on_delivery",
"order_amount": 545,
"note": "Less spicy",
"customer": { "name": "Sita", "phone": "+977*******521", "address": "Near Birtamod chowk" },
"items": [
{ "external_item_id": "MOMO-C-10", "name": "Chicken momo", "quantity": 2, "price": 180,
"addons": [ { "name": "Extra achar", "quantity": 1, "price": 20 } ], "note": null }
]
}
}#5Check our signature
Webhooks are signed with your secret too, over the timestamp, a dot and the raw body (no method or path: you own that URL). Check it before you trust the body, and drop an X-Laayo-Idempotency-Key you have already handled.
app.post('/laayo/webhook', express.raw({ type: '*/*' }), (req, res) => {
const ts = req.get('X-Laayo-Timestamp');
const expected = crypto.createHmac('sha256', process.env.LAAYO_SECRET)
.update(ts + '.' + req.body).digest('hex');
const given = req.get('X-Laayo-Signature') || '';
if (expected.length !== given.length ||
!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(given))) {
return res.sendStatus(401);
}
res.sendStatus(200);
});#6Run the checklist
Open Go-live in the console. It ticks itself as your sandbox does each thing: a signed call, a test store linked, the store status set, an item sold out and back, a test order taken from accept to ready, and order events received. Then you ask for a pilot.