> ## Documentation Index
> Fetch the complete documentation index at: https://developer.klikit.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Event catalogue

> What each webhook means, when it fires, what the payload looks like.

Three event types are surfaced to partners today. They all share the same
JSON envelope — `{ brand_id, branch_id, orders }` — and the same headers.
What changes is **why klikit is calling you** and **which field in the order
matters most**.

<h2 id="order-created">
  klikit.order.created.v2
</h2>

### When it fires

A customer placed an order through one of klikit's surfaces (aggregator
marketplace, direct ordering web, kiosk) and the order has been confirmed.
This is the trigger for "ring the kitchen / send the ticket to the POS".

### What you receive

```json theme={null}
{
  "brand_id":  123,
  "branch_id": 456,
  "orders": [
    {
      "id":          7821,
      "status":      2,          // see OrderStatus reference
      "placed_at":   "2026-06-25T09:14:11Z",
      "currency":    "AED",
      "total":       "84.50",
      "cart":        [ /* line items */ ],
      "customer":    { /* ... */ },
      "branch_id":   456,
      "brand_id":    123
      /* ...same shape as GET /v1/partner/orders/{id} */
    }
  ]
}
```

`orders` is an array. Today it's almost always length 1, but klikit reserves
the right to batch several brand-new orders into a single delivery if they
land in the same tick.

### What to do

1. Verify `x-klikit-signature` ([recipe](/partner-api/webhooks/verify)).
2. Dedupe on `x-klikit-event-id`.
3. Return `200` within 10 seconds.
4. Push to your POS / kitchen display on a background worker.

***

<h2 id="status-updated">
  klikit.order.status.updated
</h2>

### When it fires

An existing order moved to a new state. That includes the forward path
(`PLACED → ACCEPTED → PREPARING → READY → DISPATCHED → DELIVERED`) **and**
the cancellation path (any → `CANCELLED`). Use this to keep your own order
view in sync with klikit's source of truth without polling.

### What you receive

The same envelope. The `status` field on each order reflects the **new**
state — decode via the
[OrderStatus reference dictionary](/partner-api/api-reference/reference-dictionaries#order-status).

```json theme={null}
{
  "brand_id":  123,
  "branch_id": 456,
  "orders": [
    {
      "id":     7821,
      "status": 5,                // READY
      "updated_at": "2026-06-25T09:21:04Z",
      /* full order body */
    }
  ]
}
```

### What to do

Verify, dedupe, reply 200 fast, then update your own order record.

<Warning>
  `klikit.order.status.updated` is **not** guaranteed to be ordered. A `READY`
  event can in theory arrive before the `PREPARING` event it followed. If your
  state machine needs strict ordering, compare `updated_at` and ignore events
  that move the timestamp backwards.
</Warning>

***

<h2 id="cart-updated">
  klikit.order.cart.updated
</h2>

### When it fires

A customer or operator edited the items / quantities on an in-progress order
**before** it was finalised — added a topping, removed an item, swapped a
modifier. Subscribe to this only if you mirror live cart state into your POS
(e.g. for a kitchen display that wants to prep ahead of the final `ACCEPTED`
event).

### What you receive

The same envelope. The `cart` array on each order reflects the **new**
line-item state — treat it as the replacement, not as a delta.

```json theme={null}
{
  "brand_id":  123,
  "branch_id": 456,
  "orders": [
    {
      "id":   7821,
      "cart": [ /* new full cart contents */ ],
      "updated_at": "2026-06-25T09:18:33Z",
      /* full order body */
    }
  ]
}
```

### What to do

Verify, dedupe, reply 200 fast, then replace your local cart state.

<Note>
  If you don't preview baskets in your POS, you don't need this event. Skip it
  and consume only `klikit.order.created.v2` + `klikit.order.status.updated`.
</Note>
