Orders
Customers place orders in WhatsApp; you read them here and receive them as events.
The order object
{
"id": "ord_…",
"object": "order",
"number": 128,
"status": "confirmed",
"source": "whatsapp",
"currency": "KES",
"subtotal": 28000,
"delivery_fee": 3000,
"total": 31000,
"payment": {
"mode": "pay_now",
"status": "paid",
"amount_paid": 31000,
"amount_due": 0,
"upfront_due": 31000,
"upfront_required_by": null,
"paid_at": 1792716000,
"attempts": [{ "id": "pay_…", "method": "mpesa", "amount": 31000, "status": "paid", "receipt": "TJK3H2K9LP", "created": 1792715950 }]
},
"items": [{ "product": "pr_…", "product_external_id": "SKU-1001", "name": "Unga 2kg", "quantity": 1, "unit_price": 25000, "amount": 25000 }],
"customer": { "id": "ct_…", "object": "customer", "name": "Achieng Otieno", "phone": "+254712345678", "external_id": "res.partner/4211", … },
"fulfilment": "delivery",
"delivery": {
"location": { "lat": -1.2921, "lng": 36.7856 },
"landmark": "Blue gate opposite the church",
"instructions": "Call when you're at the gate",
"distance_km": 3.4,
"status": "picked_up",
"rider": { "id": "rd_…", "name": "Kevin" },
"eta_minutes": 14,
"failure_reason": null
},
"pickup": null,
"attribution": { "source": "ad", "sourceId": "120211…", "headline": "Unga deal", "ctwaClid": "ARAk…" },
"rating": null,
"cancel_reason": null,
"external_id": null,
"metadata": {},
"created": 1792715900,
"updated": 1792716000
}
Status
status |
|
|---|---|
awaiting_payment |
Pay-now order waiting for payment. |
confirmed |
Paid, or pay-on-delivery accepted. The shop should prepare it. |
dispatched |
With a rider (see delivery.status: assigned → picked_up → arrived). |
delivered |
Done. |
ready / collected |
Pickup orders. |
failed |
Delivery failed; stock returned. |
cancelled |
See cancel_reason. |
payment.status is separate: unpaid, pending (a prompt is out), partial (a deposit is in), paid. upfront_due is what must be paid before the order goes ahead — see payment terms. A pay-on-delivery order can be delivered and paid with method: "cash".
Retrieve and list
GET /v1/orders/{id}GET /v1/orders— filters:status,payment_status,customer(a customer id),number,source(see Ads & attribution),external_id,created_gte,created_lt.GET /v1/orders/{id}/events— the order's full history (who did what, when).
Link to your system
POST /v1/orders/{id} accepts only external_id and metadata — e.g. after creating the sale order in Odoo:
curl $KIBANDA_API/v1/orders/ord_123 -H "Authorization: Bearer $KIBANDA_KEY" \
-H "Content-Type: application/json" -d '{"external_id": "SO0042", "metadata": {"odoo_id": "42"}}'
Ask for payment first
POST /v1/orders/{id}/require_payment with {"amount": "full"} (default) or {"amount": "deposit"} — the shop's call on a confirmed order that hasn't left. The customer is asked on WhatsApp; the order waits until it's paid.
Cancel
POST /v1/orders/{id}/cancel with an optional reason (shown to the customer). Stock is returned and a rider who's on it is told to bring it back. Paid orders and orders with a payment in progress return 409 order_not_cancellable.