Nunua Pro Developers
Building

Receiving orders

How an online order reaches your POS, what it contains, and how to tell us you recorded it.

When an order reaches you

An order reaches your POS only after the customer has accepted the shop's quote (status confirmed). Never earlier, while the shop is still deciding what it can supply.

The three events

EventMeansYour POS should
order.confirmedA customer committed to an order.Record the sale, send new stock, then acknowledge.
order.cancelledIt was cancelled afterwards. was is pending or accepted; pos_ref is your sale number.If you had recorded it (was: accepted), void the sale.
order.completedDelivered or collected.Nothing; it is for your records.

Events can arrive more than once. De-duplicate on event_id.

The order

order.confirmed
{
  "event_id": 1042, "type": "order.confirmed", "created_at": "2026-11-03T10:15:22+03:00",
  "order": {
    "id": 5521, "order_number": "SHP-KQ2P9X", "status": "confirmed", "type": "delivery", "currency": "TZS",
    "customer": { "name": "Asha", "phone": "+255712345678" },
    "delivery": { "address": "Sinza Mori", "instructions": "Blue gate", "latitude": -6.78, "longitude": 39.22 },
    "lines": [
      { "line_id": 9001, "external_id": "SKU-1", "variant_external_id": null, "name": "Sukari Kilombero 1kg",
        "quantity": 2, "unit_price": 3500, "addons": [], "line_total": 7000 },
      { "line_id": 9002, "external_id": "PZ-1", "variant_external_id": "PZ-1-L", "name": "Margherita (Large)",
        "quantity": 1, "unit_price": 18000, "addons": [{ "name": "Extra cheese", "price": 1500 }], "line_total": 19500 }
    ],
    "subtotal": 26500, "delivery_fee": 2000, "total": 28500,
    "payment": { "method": "cash", "status": "unpaid" },
    "pos": { "state": "pending", "pos_ref": null }
  }
}
  • Lines are matched by your external_id and variant_external_id. Lines the shop couldn't supply are left out.
  • line_total includes the add-ons.
  • type is delivery, pickup or parcel.

Getting events

Polling (works everywhere)

GET /pos/v1/events?after=<last event_id> returns events in order, with next_after for the next call. Persist the last id you processed. While a shop has paused the link you get 403; when it resumes, the feed catches up.

GET /pos/v1/orders?state=pending lists the orders still waiting for you, which is useful after downtime.

Webhooks (cloud POS)

The owner sets your HTTPS address in the Business app and we POST each event to it. The feed always has the same events, so a missed webhook is never lost. See webhooks.

Acknowledging

Tell us whether you recorded the sale with POST /pos/v1/orders/{id}/ack.

POST /pos/v1/orders/5521/ack
// Recorded
{ "status": "accepted", "pos_ref": "SALE-8841" }

// Couldn't record it
{ "status": "rejected", "reason": "out_of_stock", "message": "Last bag sold in store", "unavailable": ["SKU-1"] }

Send updated stock before you acknowledge. From confirmed until you answer, we hold the order's units back so two customers can't buy the last item while your POS catches up. Acknowledging releases that hold, so your new, lower stock must already have arrived.

  • Repeating the same answer is safe (replay: true). A different answer afterwards is 409.
  • A rejection never cancels the order, because the customer may already have paid. The shop is told and decides whether to fulfil or cancel. Products named in unavailable are taken off sale.