Endpoints
All paths are relative to https://sales.api.kushi.ng. API-key endpoints need authentication; storefront endpoints use your store slug.
Integrator API — Orders board (API key)
Create an order
POST /public/v1/orders
Creates an order on your Orders board. Each item either links a catalog product by productId (price and name come from the catalog) or is a free-text line with your own name and unitPrice. A line without productId is still linked if its sku, or its name (ignoring case), matches a product, or if you've linked that name under Order links in Stock. An unknown productId returns 400.
Linking by productId is what lets the order affect inventory — but stock moves when the order reaches Delivered, not when it's created, because the goods are still yours until then. Set the status with PATCH /public/v1/orders/{id} and the deduction happens then, taking from the assigned agent if there is one, otherwise the office. Combos deduct their constituents; a quantity bundle deducts its free gifts.
Request
{
"customerName": "Ada Obi",
"phone": "08012345678",
"address": "12 Marina, Lagos",
"codAmount": 27500,
"deliveryFee": 1500,
"courier": "GIG",
"source": "shopify",
"items": [
{ "productId": "3f9c…", "qty": 2 },
{ "name": "Gift wrap", "qty": 1, "unitPrice": 500 }
]
}
Only customerName and a non-empty items array are required. New orders start in Pending. codAmount defaults to the order total.
Retries — send your own order reference as externalId. A second request with the same externalId returns the existing order (200, with "duplicate": true) instead of creating another.
Response — 201 Created
{ "id": "a1b2…", "reference": "A1B2C3D4", "status": "Pending", "total": 55500 }
Duplicate guard — the same phone + total within 6 hours returns the existing order instead of creating another:
{ "id": "a1b2…", "duplicate": true }
List orders
GET /public/v1/orders?status=Pending&limit=50
Recent orders, newest first. status (optional) filters to one status; limit defaults to 50 (max 200).
Response — 200 OK
{ "orders": [
{ "id": "a1b2…", "reference": "A1B2C3D4", "customerName": "Ada Obi", "phone": "08012345678",
"status": "Pending", "paymentStatus": "unpaid", "total": 55500, "source": "shopify",
"createdAt": "2026-07-21T10:00:00Z", "items": [ { "name": "…", "qty": 2, "unitPrice": 27500 } ] }
] }
Update an order
PATCH /public/v1/orders/{id}
Send status and/or paymentStatus. Statuses: Pending, In Transit, Delivered, Rescheduled, Call Back, Rejected, Follow Up.
This does what the status change in the app does: reaching Delivered moves stock and adds the cash to the agent's balance, moving out of Delivered puts them back, and an order.status_changed webhook is sent.
{ "status": "In Transit", "paymentStatus": "paid" }
Response — 200 OK → { "ok": true, "status": "In Transit" }
List products
GET /public/v1/products
{ "products": [
{ "id": "3f9c…", "name": "Magic Brush", "sku": null, "unit": "pack", "type": "simple",
"price": 27500, "cost": 4700, "stock": 98, "isActive": true }
] }
Live stock
GET /public/v1/stock
{ "stock": [
{ "productId": "3f9c…", "name": "Magic Brush", "office": 98, "withAgents": 31, "total": 129 }
] }
Storefront — customer checkout (no key)
Store details
GET /public/v1/store/{slug}
Returns the store name/branding and its active products (with offer tiers) — enough to render a store page.
Place an order
POST /public/v1/store/{slug}/orders
A pay-on-delivery order from a customer. Prices are computed server-side from the catalog. Body: customerName, phone, address, optional email/note, and items: [{ productId, qty }]. Returns 201 with { "orderId": "…", "ref": "A1B2C3D4", "total": 27500 }. The same phone and total within 6 hours returns 200 with { "id": "…", "duplicate": true } instead.
Track an order
GET /public/v1/orders/{id}
Public status timeline for one order — the full order id acts as the token. No key required.