View as Markdown

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

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.