Skip to main content

Checkout ReqSample Senarials

JikoXpress — Checkout Session API Scenarios

Version 1.0 | April 2026 | QBIT SPARK CO LIMITED
Reference guide for all checkout session creation scenarios


Overview

A checkout session is a temporary stepping stone to an order. Once confirmed, the session creates an order and its job is done. Sessions are never refunded — orders are.

Session Types

Type Description
IMMEDIATE Pay now, right at this terminal
SLIP Generate slip, customer goes to cashier
TAB Pay later, dine-in rounds

Session Statuses

Status Description
PENDING_PAYMENT Waiting for payment — USSD webhook or cashier confirmation
CONFIRMED Payment done, order created
EXPIRED Slip timed out, inventory released
CANCELLED Manually cancelled, inventory released
FAILED Payment failed, inventory released

Payment Methods

Method Description
CASH Physical money
MOBILE_MONEY USSD — M-Pesa, Tigo, Airtel
CARD Visa, Mastercard
PLATFORM_WALLET JikoXpress app wallet
KITCHEN_WALLET Kitchen issued prepaid balance
KITCHEN_CHANNEL Kitchen configured channel — Lipa Voda, HaloPesa etc

IDs Resolved Server Side

These are never passed in request — resolved from context:

Field Resolved From
staffId Authenticated staff session token
accountId Authenticated JikoXpress user token
Kitchen (POS/Kiosk) Staff session — staff belongs to a kitchen
Kitchen (App direct) Passed in request
Kitchen (App cart) Derived from cart items grouped by kitchen

Payment Split Model

All payments are a list. Single payment = list of one. Amounts must sum to session total.

{
  "payments": [
    {
      "paymentMethod": "KITCHEN_WALLET",
      "kitchenCustomerId": "uuid",
      "amount": 3000
    },
    {
      "paymentMethod": "KITCHEN_CHANNEL",
      "kitchenPaymentMethodId": "uuid",
      "amount": 1500
    },
    {
      "paymentMethod": "MOBILE_MONEY",
      "amount": 1000
    },
    {
      "paymentMethod": "CASH",
      "amount": 500
    },
    {
      "paymentMethod": "CARD",
      "amount": 500
    },
    {
      "paymentMethod": "PLATFORM_WALLET",
      "amount": 500
    }
  ]
}

kitchenCustomerId required only for KITCHEN_WALLET
kitchenPaymentMethodId required only for KITCHEN_CHANNEL


Scenarios


1. POS — Pay Now, Cash

Staff takes order at counter. Customer pays cash immediately.

{
  "sessionType": "IMMEDIATE",
  "channel": "POS",
  "fulfillmentType": "PICKUP",
  "tag": "John",
  "orderInstructions": null,
  "items": [
    {"menuId": "uuid", "quantity": 2, "itemInstructions": null},
    {"menuId": "uuid", "quantity": 1, "itemInstructions": "no salt"}
  ],
  "payments": [
    {
      "paymentMethod": "CASH",
      "amount": 5000
    }
  ]
}

2. POS — Pay Now, Split Payment

Customer pays part cash, part mobile money.

{
  "sessionType": "IMMEDIATE",
  "channel": "POS",
  "fulfillmentType": "PICKUP",
  "tag": "Sarah",
  "items": [
    {"menuId": "uuid", "quantity": 1, "itemInstructions": null}
  ],
  "payments": [
    {
      "paymentMethod": "CASH",
      "amount": 2000
    },
    {
      "paymentMethod": "MOBILE_MONEY",
      "amount": 3000
    }
  ]
}

3. POS — Pay Now, Kitchen Wallet

Loyal customer pays using their prepaid kitchen wallet.

{
  "sessionType": "IMMEDIATE",
  "channel": "POS",
  "fulfillmentType": "PICKUP",
  "tag": "Mama Fatuma",
  "items": [
    {"menuId": "uuid", "quantity": 2, "itemInstructions": null}
  ],
  "payments": [
    {
      "paymentMethod": "KITCHEN_WALLET",
      "kitchenCustomerId": "uuid",
      "amount": 5000
    }
  ]
}

4. POS — Pay Now, Kitchen Channel (Lipa Voda)

Customer pays via kitchen configured channel e.g. Vodacom Lipa.

{
  "sessionType": "IMMEDIATE",
  "channel": "POS",
  "fulfillmentType": "PICKUP",
  "tag": "James",
  "items": [
    {"menuId": "uuid", "quantity": 1, "itemInstructions": null}
  ],
  "payments": [
    {
      "paymentMethod": "KITCHEN_CHANNEL",
      "kitchenPaymentMethodId": "uuid",
      "amount": 5000
    }
  ]
}

5. POS — Generate Slip (Human Kiosk)

Staff takes order, generates slip. Customer walks to cashier to pay.

{
  "sessionType": "SLIP",
  "channel": "POS",
  "fulfillmentType": "PICKUP",
  "tag": "John",
  "orderInstructions": null,
  "items": [
    {"menuId": "uuid", "quantity": 1, "itemInstructions": "no salt"}
  ]
}

No payments — cashier will collect when customer brings slip


6. POS — Tab, Round 1 (New Bill)

Dine-in customer. Staff opens new tab/bill for the table.

{
  "sessionType": "TAB",
  "channel": "POS",
  "fulfillmentType": "DINE_IN",
  "tableNumber": "05",
  "tag": "Family ya Mbeya",
  "items": [
    {"menuId": "uuid", "quantity": 2, "itemInstructions": null},
    {"menuId": "uuid", "quantity": 1, "itemInstructions": "extra spicy"}
  ]
}

No billId — server creates new KitchenBillsEntity automatically
No payments — customer pays at end


7. POS — Tab, Round 2 (Existing Bill)

Same table orders more. Cashier picks existing open bill, adds new round.

{
  "sessionType": "TAB",
  "channel": "POS",
  "fulfillmentType": "DINE_IN",
  "tableNumber": "05",
  "billId": "existing-bill-uuid",
  "items": [
    {"menuId": "uuid", "quantity": 2, "itemInstructions": null}
  ]
}

8. Kiosk Machine — Cash Slip

Customer self-orders on kiosk machine. Chooses to pay cash. Slip prints. Customer walks to cashier.

{
  "sessionType": "SLIP",
  "channel": "KIOSK",
  "fulfillmentType": "PICKUP",
  "items": [
    {"menuId": "uuid", "quantity": 2, "itemInstructions": null},
    {"menuId": "uuid", "quantity": 1, "itemInstructions": null}
  ]
}

kitchenId derived from kiosk device registration
Slip expires after configured time (default 15 min)


9. Kiosk Machine — Mobile Money (Immediate)

Customer self-orders on kiosk, pays via USSD immediately.

{
  "sessionType": "IMMEDIATE",
  "channel": "KIOSK",
  "fulfillmentType": "PICKUP",
  "items": [
    {"menuId": "uuid", "quantity": 1, "itemInstructions": null}
  ],
  "payments": [
    {
      "paymentMethod": "MOBILE_MONEY",
      "amount": 5000
    }
  ]
}

Session stays PENDING_PAYMENT until USSD webhook confirms


10. Table QR — Pay on Phone

Customer scans QR at table, orders, pays via USSD on their own phone.

{
  "sessionType": "IMMEDIATE",
  "channel": "TABLE_QR",
  "fulfillmentType": "DINE_IN",
  "tableNumber": "05",
  "items": [
    {"menuId": "uuid", "quantity": 1, "itemInstructions": null}
  ],
  "payments": [
    {
      "paymentMethod": "MOBILE_MONEY",
      "amount": 5000
    }
  ]
}

kitchenId embedded in QR code, resolved server side
Needs cashier approval before going to kitchen


11. Table QR — Pay at Cashier (Slip)

Customer scans QR, orders, chooses to pay cash at counter.

{
  "sessionType": "SLIP",
  "channel": "TABLE_QR",
  "fulfillmentType": "DINE_IN",
  "tableNumber": "05",
  "items": [
    {"menuId": "uuid", "quantity": 1, "itemInstructions": null}
  ]
}

12. App — Checkout from Cart, Delivery

App user checks out all items from their cart. One payment, orders split per kitchen automatically.

{
  "sessionType": "IMMEDIATE",
  "channel": "APP",
  "fulfillmentType": "DELIVERY",
  "fromCart": true,
  "deliveryAddress": {
    "street": "Lumumba St",
    "area": "Mbeya",
    "city": "Mbeya",
    "notes": "Green gate",
    "latitude": -8.9,
    "longitude": 33.4
  },
  "payments": [
    {
      "paymentMethod": "MOBILE_MONEY",
      "amount": 15000
    }
  ]
}

accountId from auth token
kitchenId derived from cart items — one session created per kitchen
fromCart: true — no items needed in request


13. App — Direct Buy, No Cart

App user buys directly from a kitchen without going through cart.

{
  "sessionType": "IMMEDIATE",
  "channel": "APP",
  "fulfillmentType": "DELIVERY",
  "kitchenId": "uuid",
  "fromCart": false,
  "items": [
    {"menuId": "uuid", "quantity": 1, "itemInstructions": null}
  ],
  "deliveryAddress": {
    "street": "Lumumba St",
    "area": "Mbeya",
    "city": "Mbeya",
    "notes": "Green gate",
    "latitude": -8.9,
    "longitude": 33.4
  },
  "payments": [
    {
      "paymentMethod": "PLATFORM_WALLET",
      "amount": 5000
    }
  ]
}

fromCart: false — items passed directly in request
kitchenId required since not derived from cart


14. WhatsApp — Delivery

Customer orders via WhatsApp chatbot. Not a JikoXpress user — identified by phone number only.

{
  "sessionType": "IMMEDIATE",
  "channel": "WHATSAPP",
  "fulfillmentType": "DELIVERY",
  "kitchenId": "uuid",
  "customerPhone": "+255700000000",
  "items": [
    {"menuId": "uuid", "quantity": 1, "itemInstructions": null},
    {"menuId": "uuid", "quantity": 2, "itemInstructions": "extra sauce"}
  ],
  "deliveryAddress": {
    "street": "Lumumba St",
    "area": "Mbeya",
    "city": "Mbeya",
    "notes": "Green gate",
    "latitude": -8.9,
    "longitude": 33.4
  },
  "payments": [
    {
      "paymentMethod": "MOBILE_MONEY",
      "amount": 8000
    }
  ]
}

kitchenId from chatbot — each kitchen has their own WhatsApp number
customerPhone identifies customer — no JikoXpress account needed
No accountId — WhatsApp customer is anonymous to platform


Edge Cases


Kitchen Wallet — Insufficient Balance, Split with Cash

Customer's kitchen wallet has 3000 but total is 5000. Pays difference with cash.

{
  "sessionType": "IMMEDIATE",
  "channel": "POS",
  "fulfillmentType": "PICKUP",
  "items": [
    {"menuId": "uuid", "quantity": 2, "itemInstructions": null}
  ],
  "payments": [
    {
      "paymentMethod": "KITCHEN_WALLET",
      "kitchenCustomerId": "uuid",
      "amount": 3000
    },
    {
      "paymentMethod": "CASH",
      "amount": 2000
    }
  ]
}

Three-Way Split

Customer splits across cash, kitchen channel, and mobile money.

{
  "sessionType": "IMMEDIATE",
  "channel": "POS",
  "fulfillmentType": "PICKUP",
  "items": [
    {"menuId": "uuid", "quantity": 3, "itemInstructions": null}
  ],
  "payments": [
    {
      "paymentMethod": "CASH",
      "amount": 2000
    },
    {
      "paymentMethod": "KITCHEN_CHANNEL",
      "kitchenPaymentMethodId": "uuid",
      "amount": 2000
    },
    {
      "paymentMethod": "MOBILE_MONEY",
      "amount": 1000
    }
  ]
}

Tab — Pay Bill with Split

Customer finishes eating, pays open tab with card and cash.

This happens at bill close time, not session creation.
Separate endpoint: POST /bills/{billId}/pay

{
  "payments": [
    {
      "paymentMethod": "CARD",
      "amount": 10000
    },
    {
      "paymentMethod": "CASH",
      "amount": 5000
    }
  ]
}

Cashier Confirms Slip Payment

Customer arrives at counter with slip. Cashier scans barcode or finds slip by number. Confirms cash collected. Order created and sent to kitchen.

Endpoint: POST /checkout-sessions/{sessionId}/confirm-slip

{
  "payments": [
    {
      "paymentMethod": "CASH",
      "amount": 5000
    }
  ]
}

Cashier can also split payment at this point — customer may pay slip with mobile money instead of cash


Cashier Confirms Slip — Split Payment

Customer brought slip but wants to pay part cash, part mobile money.

Endpoint: POST /checkout-sessions/{sessionId}/confirm-slip

{
  "payments": [
    {
      "paymentMethod": "CASH",
      "amount": 3000
    },
    {
      "paymentMethod": "MOBILE_MONEY",
      "amount": 2000
    }
  ]
}

After confirmation → session CONFIRMED → order created → kitchen notified → inventory deducted


QBIT SPARK CO LIMITED | JikoXpress | April 2026
Internal development reference — confidential