Skip to main content
ScanSewaby Lacspace
Developer API

Build on top of ScanSewa

A read-only REST API for orders, menu, tables, inventory, customers and analytics — with real-time webhooks and inbound order channels. Scoped keys, an OpenAPI spec, and a live explorer to try it in your browser.

Overview

The ScanSewa Developer API is a read-only REST API that lets partners and your own apps read a restaurant's live data — orders, menu, tables, inventory, customers and sales analytics — plus receive real-time webhooks and push orders in from external channels. Responses are JSON; every request is authenticated with a scoped API key.

Scoped API keysGrant only what each integration needs.
120 requests / minPer key, with RateLimit-* headers.
Real-time webhooksSigned order.created / order.updated.
Inbound channelsPush aggregator orders straight into the POS.

Base URL

https://api.scansewa.com/api/public/v1

Quickstart

  1. 1 In your ERP dashboard, open Developer API and create a key. Copy it — it's shown once.
  2. 2 Send it as a Bearer token on every request.
  3. 3 Call an endpoint — or try it live in the API Explorer.
Your first request
curl "https://api.scansewa.com/api/public/v1/orders?status=Completed&limit=10" \
  -H "Authorization: Bearer ssk_live_…"

Authentication

Pass your key as a Bearer token, or use the x-api-key header. Keys are read-only and scoped to a single restaurant's data — keep them server-side.

Header
Authorization: Bearer ssk_live_…

Scopes

Each key is limited to the scopes you grant it. Calling an endpoint outside the key's scopes returns 403.

orders:read
List & fetch orders
menu:read
Menu items, categories & offers
tables:read
Table list & occupancy
inventory:read
Stock levels & low-stock flags
customers:read
Customer list & search (personal data)
analytics:read
Sales summary & top items

Rate limits

Every key is limited to 120 requests per minute. Standard RateLimit-* headers are returned on each response; exceeding the cap returns 429. List endpoints are paginated — pass ?limit= (1–100) and ?page=; the response includes total and hasMore.

Errors

Errors use standard HTTP status codes with a JSON { success: false, message } body.

401
Missing, invalid or revoked API key
403
Key lacks the required scope
404
Resource not found (or not yours)
429
Rate limit exceeded (120 req/min per key)

Endpoints

All endpoints are GET and relative to the base URL above.

Orders

orders:read
GET
/ordersList orders, newest first.
GET
/orders/:idFetch a single order by id.

Catalog

menu:read
GET
/menuList menu items.
GET
/menu/:idFetch a single menu item.
GET
/categoriesList menu categories.
GET
/offersList offers / promotions.

Tables

tables:read
GET
/tablesList tables with occupancy.

Inventory

inventory:read
GET
/inventoryList stock items.

Customers

customers:read
GET
/customersList & search customers (contains personal data).

Analytics

analytics:read
GET
/analytics/summaryRevenue, by-status, by-source and top items for a date range.
Sample — GET /orders
{
  "success": true,
  "page": 1,
  "limit": 50,
  "total": 128,
  "hasMore": true,
  "data": [
    {
      "id": "665f…",
      "status": "Completed",
      "paymentStatus": "Paid",
      "items": [
        { "menuItemId": "M-101", "name": "Margherita", "quantity": 2, "unitPrice": 450, "itemTotal": 900 }
      ],
      "subtotal": 900,
      "grandTotal": 1017,
      "table": "T4",
      "source": "dine-in",
      "customerName": "Asha",
      "createdAt": "2026-06-11T08:20:00.000Z"
    }
  ]
}
Sample — GET /analytics/summary
{
  "success": true,
  "data": {
    "orders": 128,
    "revenue": 184560,
    "averageOrderValue": 1441.88,
    "byStatus": [ { "status": "Completed", "count": 110, "revenue": 170200 } ],
    "bySource": [ { "source": "dine-in", "count": 80, "revenue": 120300 } ],
    "topItems": [ { "menuItemId": "M-101", "name": "Margherita", "quantity": 212, "revenue": 95400 } ]
  }
}

API Explorer

Try any endpoint against the live API with one of your keys, then copy the request as cURL, JavaScript or Python.

Live API Explorer

Paste one of your API keys and call the real API — nothing is stored, the key stays in your browser.

Create a key in your ERP dashboard → Developer API.

GET
https://api.scansewa.com/api/public/v1/orders
Copy as code
curl "https://api.scansewa.com/api/public/v1/orders" \
  -H "Authorization: Bearer YOUR_API_KEY"

Webhooks

Register an endpoint in your ERP dashboard to receive signed event POSTs instead of polling. Each delivery carries X-ScanSewa-Event, X-ScanSewa-Delivery and X-ScanSewa-Signature headers. Failed deliveries retry with backoff (30s → 2h, 6 attempts).

order.created
A new order was placed (POS, QR or an inbound channel).
order.updated
An order changed — status, payment or items.
Event payload
{
  "id": "evt_9f2c…",            // unique — use for idempotency
  "type": "order.created",
  "createdAt": "2026-06-11T08:20:00.000Z",
  "data": { "id": "665f…", "status": "Pending", "grandTotal": 1017, "items": [ … ] }
}
Verify the signature (Node)
import crypto from "crypto";

app.post("/webhooks/scansewa", express.raw({ type: "application/json" }), (req, res) => {
  const header = req.header("X-ScanSewa-Signature") || "";   // "t=...,v1=..."
  const parts = Object.fromEntries(header.split(",").map(p => p.split("=")));
  const expected = crypto
    .createHmac("sha256", process.env.WEBHOOK_SECRET)         // whsec_...
    .update(`${parts.t}.${req.body.toString()}`)
    .digest("hex");

  if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1 || "")))
    return res.status(400).send("bad signature");

  const event = JSON.parse(req.body.toString());             // { id, type, createdAt, data }
  // handle event.type; dedupe on event.id
  res.sendStatus(200);
});

Respond 2xx within 10s to acknowledge, and dedupe on event.id — the same event may arrive more than once.

Inbound channels

Channels let an external system — a delivery aggregator or your own app — push orders into ScanSewa. They land in the kitchen display, billing and reports like any other order. Create a channel in your ERP dashboard to get a signing secret and a unique URL, then POST signed orders:

Endpoint
POST https://api.scansewa.com/api/inbound/<channelId>/orders
Send a signed order (Node)
import crypto from "crypto";

const secret = process.env.SCANSEWA_CHANNEL_SECRET;          // chsec_...
const body = JSON.stringify(order);
const t = Math.floor(Date.now() / 1000);
const v1 = crypto.createHmac("sha256", secret).update(`${t}.${body}`).digest("hex");

await fetch("https://api.scansewa.com/api/inbound/<channelId>/orders", {
  method: "POST",
  headers: { "Content-Type": "application/json", "X-ScanSewa-Signature": `t=${t},v1=${v1}` },
  body,
});

Items resolve to your menu by id, a mapping table or name. To get status changes back, register an order.updated webhook.

OpenAPI & SDKs

The whole API is described by an OpenAPI 3.0 spec — import it into Postman, Insomnia or Swagger UI, or generate a typed client. No key needed to fetch it.

https://api.scansewa.com/api/public/v1/openapi.json Download openapi.json

Ready to build?

Create an API key from your ERP dashboard in under a minute.

Talk to us
Start building

Your data, your integrations

Create a scoped API key from your ScanSewa dashboard and connect the tools you already use — or let us help you build a custom integration.