Documentation

Developers

Restaurant order integration

Connect your point-of-sale or kitchen system to Sela so orders taken by the assistant reach you by webhook and you approve them through the API.

Last updated: 2026-09-29

If a restaurant takes orders through the Sela assistant, your own system (a point-of-sale, kitchen display or delivery app) can receive each order, decide whether to accept it, and report when it arrives. The integration uses two pieces described elsewhere: webhooks to hear about orders, and the REST API to act on them.

For the business-owner side of orders, see Orders and payment links.

How the flow works#

  1. A customer chats with the assistant and confirms an order.
  2. Sela records the order as pending approval and sends an order.created webhook to your endpoint. The dashboard also notifies your team.
  3. Your system verifies the signature, deduplicates on X-Sela-Delivery, and stores the order id and details.
  4. Your system calls POST /api/v1/orders/action with approve or reject, optionally attaching your own external_order_id.
  5. Sela messages the customer about the decision and sends order.approved or order.rejected.
  6. When the food is delivered or handed over, call the same endpoint with mark_arrived. Sela sends order.arrived.
  7. At any time, reconcile with GET /api/v1/orders?status=pending.

Staff can also approve or reject in the dashboard. Both paths update the same order and send the same webhook events.

Prerequisites#

  • The Scale or Enterprise plan and API and webhook access enabled for your workspace (contact support if needed). See Plans and billing.
  • The assistant's food-order tool enabled for the workspace, so orders exist to integrate.
  • An admin to create the API key and webhook endpoint.

Step 1: create an API key#

In API Keys, create a key with the orders:read and orders:write permissions. Copy it once and store it on your server as SELA_API_KEY.

Step 2: create a webhook endpoint#

In Integrations, Webhooks, add your HTTPS receiver URL and subscribe to order.*, or to the four events individually: order.created, order.approved, order.rejected and order.arrived. Save the whsec_ signing secret shown once.

Step 3: receive and verify orders#

Verify the X-Sela-Signature header as shown in Webhooks, then read the order from data.

order-webhook.mjs
import express from "express";
import { verify } from "./verify.mjs"; // see the Webhooks page

const app = express();
const seen = new Set(); // use a database in production

app.post("/sela/orders", express.raw({ type: "application/json" }), async (req, res) => {
  const raw = req.body.toString("utf8");
  if (!verify(raw, req.headers, process.env.SELA_WEBHOOK_SECRET)) return res.sendStatus(401);

  const deliveryId = req.headers["x-sela-delivery"];
  if (seen.has(deliveryId)) return res.sendStatus(200);
  seen.add(deliveryId);

  const { event, data } = JSON.parse(raw);
  if (event === "order.created") {
    await saveOrderToKitchenSystem(data); // data.id, data.orderSummary, data.customer ...
  }
  res.sendStatus(200);
});
app.listen(8080);

The order object has these fields:

FieldMeaning
idSela's order id. Use it for every API call.
statuspending, approved, arrived, rejected, failed or cancelled.
createdAt, updatedAtUnix milliseconds.
conversationIdThe chat the order came from, or null.
customerid, name, phone, email, each possibly null.
fulfillmenttype (delivery, pickup or null) and address.
orderSummaryA text summary of the items.
specialInstructionsCustomer notes, or null.
detailsThe raw order data collected by the assistant.
externalOrderIdYour reference, once you set it.

Step 4: approve, reject or complete#

bash
# Approve, and attach your own order number
curl -X POST "https://jovial-bison-730.convex.site/api/v1/orders/action" \
  -H "Authorization: Bearer $SELA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"order_id":"kx7...","action":"approve","external_order_id":"menu-123"}'

# Reject
curl -X POST "https://jovial-bison-730.convex.site/api/v1/orders/action" \
  -H "Authorization: Bearer $SELA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"order_id":"kx7...","action":"reject"}'

# Mark as arrived (only after approve)
curl -X POST "https://jovial-bison-730.convex.site/api/v1/orders/action" \
  -H "Authorization: Bearer $SELA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"order_id":"kx7...","action":"mark_arrived"}'
ActionValid fromResult
approvependingStatus approved, customer is told, order.approved is sent.
rejectpendingStatus rejected, customer is told, order.rejected is sent.
mark_arrivedapprovedStatus arrived, order.arrived is sent.

Calling mark_arrived on a pending order returns 409 invalid_state. Repeating an action that already happened returns 200 with changed: false. The full transition table is in REST API.

Step 5: reconcile#

Webhooks can be missed if your server is down for longer than the retry window. Run a periodic job that lists pending orders and processes any you do not know:

bash
curl "https://jovial-bison-730.convex.site/api/v1/orders?status=pending&limit=100" \
  -H "Authorization: Bearer $SELA_API_KEY"

Follow meta.next_cursor until meta.is_done is true. The status filter is applied per page, so a page may be short or empty before the last one.

Avoid echo loops#

When you approve an order through the API, Sela sends an order.approved webhook to your own endpoint too. Ignore events for state changes you just made, for example by comparing data.externalOrderId with the one you set, or by checking your own records. A no-op call (changed: false) sends no event.

Test the integration#

  1. Create the key and a webhook endpoint in the test environment pointing at a public tunnel to your receiver.
  2. Place an order through the assistant, for example from the web widget.
  3. Confirm order.created arrives with a valid signature.
  4. Approve it with the curl command above and confirm order.approved arrives and the customer sees the message.
  5. Mark it arrived and confirm the final event.

If you are building a receiver from scratch, a quick local option is a small server that prints headers and the raw body, then check the signature with the code in Webhooks.

Troubleshooting#

SymptomCause
No order.created arrivesThe endpoint is disabled (after 10 exhausted deliveries), not subscribed to order.*, or the plan lacks webhooks. Check the delivery log.
401 unauthorized from the APIKey revoked, expired or copied wrongly, or the plan no longer includes API access.
403 forbidden on orders/actionThe key lacks orders:write.
409 invalid_stateThe order is not in a state that allows the action, for example mark_arrived before approve.
404 not_foundThe order_id is wrong or belongs to another workspace.
Duplicate eventsDelivery is at least once. Deduplicate on X-Sela-Delivery.
Restaurant order integration | Sela docs | Sela