Docs
Start: Quickstart
Start

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.

Mark an item sold out
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,
});
Sign the bytes you actually send, and the path with its query exactly as sent. Re-encoding the JSON after signing changes the spacing, and the signature stops matching. The request log in the console shows the reason for every refused call.

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.

Request
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.

order.created
{
  "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.

Node, Express
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.

Was this page clear?Updated 1 Nov 2026