Checkout Session
Base URL: https://apinexgate.glueauth.com/api/v1/
Short Description: The Checkout Session API manages the complete checkout process for both e-commerce and event transactions. It handles creatingsession checkoutcreation sessions(with fromupfront cartwallet orbalance directvalidation), purchase,inventory managingholds, payment intents, processing paymentsvia through multiple payment methods (Wallet, Cash on Delivery, Cards, Mobile Money),Cash, and supportsFree advanced features likeflows, group purchasingpurchasing, and installment payments. Each session maintains state, inventory holds, and payment attempt tracking with automatic expiration handling.
Hints:
- Wallet balance is validated at session creation time — if insufficient, no session is created and a rich balance response is returned so the frontend can guide the user to top up
- All checkout sessions expire after 15 minutes by default
- Inventory is automatically held during active sessions and released upon expiration or cancellation
- Maximum 5 payment retry attempts allowed per session
- Group purchase sessions require WALLET payment method only
- Sessions in PAYMENT_PROCESSING status cannot be modified
- Installment payment
typeonlyischargesplannedthefordownfuturepaymentreleaseat(placeholdercheckout;only)monthly payments are handled by the scheduler - All monetary values are in TZS (Tanzanian Shillings)
- Use ISO 8601 format for all datetime fields
- Sessions can only be updated when in PENDING_PAYMENT or PAYMENT_FAILED status
Full Checkout Flow Diagram
CLIENT BACKEND SYSTEMS
| | |
| POST /checkout-sessions | |
|------------------------------>| |
| |-- Validate request |
| |-- Calculate pricing |
| | |
| |-- assertSufficientBalance() |
| | | |
| | |-- GET wallet balance -|-> Ledger
| | | |
| | ....................... |
| | . BALANCE INSUFFICIENT . |
| | ....................... |
| 422 + rich balance data | | |
|<------------------------------|<-------' |
| { | |
| walletBalance: 5000, | |
| sessionTotal: 12000, | |
| shortfall: 7000, | |
| recommendedTopUp: 7000 | |
| } | |
| | |
| | ....................... |
| | . BALANCE SUFFICIENT . |
| | ....................... |
| | | |
| |-- Hold inventory ------------>|-> Inventory
| |-- Save session |
| |-- Schedule expiry job ------->|-> JobRunr
| | |
| 201 + session data | |
|<------------------------------| |
| { sessionId, status: | |
| PENDING_PAYMENT, ... } | |
| | |
| ...15 min window... | |
| | |
| POST /{sessionId}/payment | |
|------------------------------>| |
| |-- Validate status |
| |-- Check expiry |
| | |
| | ....................... |
| | . FREE checkout . |
| | ....................... |
| | | |
| |-- Create booking/order |
| |-- Track free transaction |
| 200 SUCCESS | |
|<------------------------------| |
| | |
| | ....................... |
| | . CASH checkout . |
| | ....................... |
| | | |
| |-- Create booking/order |
| |-- Track cash transaction |
| 200 SUCCESS | |
|<------------------------------| |
| | |
| | ....................... |
| | . WALLET checkout . |
| | ....................... |
| | | |
| |-- Set PAYMENT_PROCESSING |
| |-- holdMoney() --------------->|-> Escrow
| | |
| | ....................... |
| | . SUCCESS . |
| | ....................... |
| | | |
| |-- Set PAYMENT_COMPLETED |
| |-- Create order/booking |
| |-- Commit inventory hold ----->|-> Inventory
| |-- Publish payment event ----->|-> Notifications
| 200 SUCCESS | |
|<------------------------------| |
| { orderId, escrowId, | |
| amountPaid, ... } | |
| | |
| | ....................... |
| | . FAILED . |
| | ....................... |
| | | |
| |-- recordFailedAttempt() |
| |-- Release reservation |
| | (events only) |
| 200 FAILED | |
|<------------------------------| |
| { success: false, | |
| canRetry: true/false } | |
| | |
| POST /{sessionId}/retry | |
|------------------------------>| |
| |-- Check status = FAILED |
| |-- Check attempts < 5 |
| |-- Re-validate inventory |
| |-- Check wallet balance |
| |-- Re-hold inventory |
| |-- Reset to PENDING_PAYMENT |
| |-- processPayment() ... |
| | (same wallet flow above) |
Session Type Routing
POST /checkout-sessions
sessionType?
.
├─ REGULAR_DIRECTLY ──> validate 1 item ──> balance check ──> hold inventory ──> session
|
├─ REGULAR_CART ──────> validate cart ───> balance check ──> hold inventory ──> session
|
├─ GROUP_PURCHASE ────> validate group ──> balance check ──> session (no hold, group-level)
|
└─ INSTALLMENT ───────> calculate down payment ──> balance check ──> hold inventory ──> session
POST /e-events/checkout
ticketPricingType?
.
├─ PAID ──> balance check ──> create payment intent ──> reserve ticket ──> session
|
└─ FREE ──> (no balance check) ──> reserve ticket ──> session
Standard Response Format
All API responses follow a consistent structure using our Globe Response Builder pattern:
Success Response Structure
{
"success": true,
"httpStatus": "OK",
"message": "Operation completed successfully",
"action_time": "2025-10-02T10:30:45",
"data": {
// Actual response data goes here
}
}
Error Response Structure
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Error description",
"action_time": "2025-10-02T10:30:45",
"data": "Error description"
}
Insufficient Balance Error Structure (422)
This is a special structured error returned when wallet balance is insufficient at session creation time. The data field contains rich balance details so the frontend can guide the user to top up.
{
"success": false,
"httpStatus": "UNPROCESSABLE_ENTITY",
"message": "Insufficient wallet balance to complete checkout",
"action_time": "2025-10-02T10:30:45",
"data": {
"walletBalance": 5000.00,
"sessionTotal": 12000.00,
"shortfall": 7000.00,
"hasSufficientBalance": false,
"recommendedTopUp": 7000.00,
"pspMinimum": 500.00,
"currency": "TZS"
}
}
| Field | Description |
|---|---|
walletBalance |
Current wallet balance of the user |
sessionTotal |
Total amount required for this checkout |
shortfall |
How much is missing (sessionTotal - walletBalance) |
hasSufficientBalance |
Always false when this error is returned |
recommendedTopUp |
Suggested top-up amount (at least shortfall, rounded up to PSP minimum) |
pspMinimum |
Minimum top-up amount accepted by the payment provider |
currency |
Always TZS |
Standard Response Fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true for successful operations, false for errors |
httpStatus |
string | HTTP status name (OK, CREATED, BAD_REQUEST, NOT_FOUND, etc.) |
message |
string | Human-readable message describing the operation result |
action_time |
string | ISO 8601 timestamp of when the response was generated |
data |
object/string | Response payload for success, error details for failures |
HTTP Method Badge Standards
For better visual clarity, all endpoints use colored badges for HTTP methods with the following standard colors:
- GET - GET - Green (Safe, read-only operations)
- POST - POST - Blue (Create new resources)
- PATCH - PATCH - Orange (Partial updates)
- DELETE - DELETE - Red (Remove resources)
Endpoints
1. Create Checkout Session
Purpose: Creates a new checkout session for processing a purchase. Wallet balance is validated upfront — if insufficient, no session is created and the caller receives rich balance data to guide the user. Supports multiple checkout types: direct product purchase, cart checkout, group purchasing, and installment payments (future).payments.
Endpoint: POST {base_url}/checkout-sessions
Access Level: 🔒 Protected (Requires Authentication)
Authentication: Bearer Token required in Authorization header
Request Headers:
| Header | Type | Required | Description |
|---|---|---|---|
| Authorization | string | Yes | Bearer token for authenticated user |
| Content-Type | string | Yes | Must be application/json |
Request JSON Sample:
{
"sessionType": "REGULAR_DIRECTLY",
"items": [
{
"productId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"quantity": 2
}
],
"shippingAddressId": "f1e2d3c4-b5a6-7890-cdef-123456789abc",
"shippingMethodId": "standard-shipping",
"metadata": {
"couponCode": "SAVE20",
"referralCode": "REF123",
"notes": "Please handle with care"
},
"installmentPlanId": null,
"groupInstanceId": null,
"downPaymentPercent": 20,20
}
Request Body Parameters:
| Parameter | Type | Required | Description | Validation |
|---|---|---|---|---|
| sessionType | string | Yes | Type of checkout session | enum: REGULAR_DIRECTLY, REGULAR_CART, GROUP_PURCHASE, INSTALLMENT |
| items | array | Conditional | Array of items to checkout. Required for REGULAR_DIRECTLY and GROUP_PURCHASE | For REGULAR_DIRECTLY: exactly 1 item. For GROUP_PURCHASE: exactly 1 item. Not used for REGULAR_CART |
| items[].productId | string (UUID) | Yes (if items provided) | Product identifier | Valid UUID format |
| items[].quantity | integer | Yes (if items provided) | Quantity to purchase | Min: 1, must not exceed product constraints |
| shippingAddressId | string (UUID) | Yes | User's shipping address identifier | Valid UUID format, must belong to authenticated user |
| shippingMethodId | string | Yes | Selected shipping method identifier | Must be valid shipping method |
| metadata | object | No | Additional metadata for the session | Key-value pairs for coupons, referrals, notes, etc. |
| installmentPlanId | string (UUID) | Installment plan identifier ( |
Valid UUID format | |
| downPaymentPercent | integer | Conditional | Down payment percentage (INSTALLMENT type only) | Must satisfy plan's min/max constraints |
| groupInstanceId | string (UUID) | No | Group instance to join ( |
Valid UUID format, group must be |
| groupName | string | Conditional | Name for new group (GROUP_PURCHASE, groupInstanceId null) | Must be unique per product |
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK"CREATED",
"message": "Checkout session created successfully",
"action_time": "2025-10-02T14:30:45",
"data": {
"sessionId": "c1d2e3f4-a5b6-7890-cdef-123456789abc",
"sessionType": "REGULAR_DIRECTLY",
"status": "PENDING_PAYMENT",
"customerId": "u1s2e3r4-i5d6-7890-abcd-ef1234567890",
"customerUserName": "john_doe",
"items": [
{
"productId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"productName": "Premium Wireless Headphones",
"productSlug": "premium-wireless-headphones",
"productImage": "https://cdn.nextgate.com/products/headphones-001.jpg",
"quantity": 2,
"unitPrice": 150000.00,
"discountAmount": 20000.00,
"subtotal": 300000.00,
"tax": 0.00,
"total": 280000.00,
"shopId": "s1h2o3p4-i5d6-7890-abcd-ef1234567890",
"shopName": "TechWorld Electronics",
"shopLogo": "https://cdn.nextgate.com/shops/techworld-logo.jpg",
"availableForCheckout": true,
"availableQuantity": 50
}
],
"pricing": {
"subtotal": 300000.00,
"discount": 20000.00,
"shippingCost": 5000.00,
"tax": 0.00,
"total": 285000.00,
"currency": "TZS"
},
"shippingAddress": {
"fullName": "John Doe",
"addressLine1": "123 Main Street",
"addressLine2": "Apartment 4B",
"city": "Dar es Salaam",
"state": "Dar es Salaam Region",
"postalCode": "12345",
"country": "Tanzania",
"phone": "+255123456789"
},
"billingAddress": {
"sameAsShipping": false,
"fullName": "John Doe",
"addressLine1": "456 Business Ave",
"city": "Dar es Salaam",
"state": "Dar es Salaam Region",
"postalCode": "12346",
"country": "Tanzania"
},
"shippingMethod": {
"id": "standard-shipping",
"name": "Standard Shipping",
"carrier": "DHL",
"cost": 5000.00,
"estimatedDays": "3-5 business days",
"estimatedDelivery": "2025-10-07T14:30:45"
},
"paymentIntent": {
"provider": "WALLET",
"clientSecret": null,
"paymentMethods": ["WALLET"],
"status": "READY"
},
"paymentAttempts": [],
"inventoryHeld": true,
"inventoryHoldExpiresAt": "2025-10-02T14:45:45",
"metadata": {
"couponCode": "SAVE20",
"referralCode": "REF123",
"notes": "Please handle with care"
},
"expiresAt": "2025-10-02T14:45:45",
"createdAt": "2025-10-02T14:30:45",
"updatedAt": "2025-10-02T14:30:45",
"completedAt": null,
"createdOrderId": null,
"cartId": null
}
}
Success Response Fields:
| Field | Description |
|---|---|
| sessionId | Unique identifier for the checkout session |
| sessionType | Type of checkout (REGULAR_DIRECTLY, REGULAR_CART, GROUP_PURCHASE, INSTALLMENT) |
| status | Current status of the session ( |
| customerId | User ID who created the session |
| customerUserName | Username of the customer |
| items | Array of checkout items with product details, pricing, and availability |
| pricing | Summary of all pricing calculations |
| pricing. | |
| Final amount to be |
|
| pricing.currency | |
| shippingAddress | Complete shipping address details |
| shippingMethod | Selected shipping method details |
| paymentIntent | Payment processing details |
| paymentAttempts | |
| inventoryHeld | Whether inventory is currently held (false for |
| inventoryHoldExpiresAt | When the inventory hold will be released |
| expiresAt | When this checkout session expires |
| createdOrderId | |
| cartId | Cart ID if session was created from |
Error Response JSON SampleResponses:
Insufficient Wallet Balance (422) — includes rich top-up data:
{
"success": false,
"httpStatus": "BAD_REQUEST"UNPROCESSABLE_ENTITY",
"message": "ValidationInsufficient failed"wallet balance to complete checkout",
"action_time": "2025-10-02T14:30:45",
"data": {
"sessionType"walletBalance": 150000.00,
"sessionTotal": 285000.00,
"shortfall": 135000.00,
"hasSufficientBalance": false,
"recommendedTopUp": 135000.00,
"pspMinimum": 500.00,
"currency": "must not be null",
"items": "Items are required for checkout",
"shippingAddressId": "must not be null"TZS"
}
}
Standard Error Types:
Application-Level Exceptions (400-499)
400 BAD_REQUEST: Invalid request data, validation errors, business rule violations401 UNAUTHORIZED: Missing, invalid, or expired authentication token403 FORBIDDEN: Insufficient permissions or verification required404 NOT_FOUND: Product, payment method, shipping address, or other resource not found422 UNPROCESSABLE_ENTITY: Validation errors with detailed field information
Server-Level Exceptions (500+)
500 INTERNAL_SERVER_ERROR: Unexpected server errors
Error Response Examples:
Bad Request - Invalid Session Type (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "REGULAR_DIRECTLY checkout supports only 1 item. Use REGULAR_CART for multiple items.",
"action_time": "2025-10-02T14:30:45",
"data": "REGULAR_DIRECTLY checkout supports only 1 item. Use REGULAR_CART for multiple items."
}
Bad Request - Insufficient Inventory (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Insufficient stock. Available: 3, Requested: 5",
"action_time": "2025-10-02T14:30:45",
"data": "Insufficient stock. Available: 3, Requested: 5"
}
Bad Request - Insufficient Wallet Balance (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Insufficient wallet balance. Required: 285000 TZS, Available: 150000 TZS",
"action_time": "2025-10-02T14:30:45",
"data": "Insufficient wallet balance. Required: 285000 TZS, Available: 150000 TZS"
}
{
"success": false,
"httpStatus": "UNAUTHORIZED",
"message": "Authentication token is required",
"action_time": "2025-10-02T14:30:45",
"data": "Authentication token is required"
}
Not Found - Product Not Found (404):
{
"success": false,
"httpStatus": "NOT_FOUND",
"message": "Product not found",
"action_time": "2025-10-02T14:30:45",
"data": "Product not found"
}
Not Found - Payment Method Not Found (404):
{
"success": false,
"httpStatus": "NOT_FOUND",
"message": "Payment method not found or does not belong to you",
"action_time": "2025-10-02T14:30:45",
"data": "Payment method not found or does not belong to you"
}
Validation Error (422):
{
"success": false,
"httpStatus": "UNPROCESSABLE_ENTITY",
"message": "Validation failed",
"action_time": "2025-10-02T14:30:45",
"data": {
"sessionType": "must not be null",
"items[0].quantity": "must be greater than or equal to 1",
"shippingAddressId": "must not be null"
}
}
Not Found - Product Not Found (404):
{
"success": false,
"httpStatus": "NOT_FOUND",
"message": "Product not found",
"action_time": "2025-10-02T14:30:45",
"data": "Product not found"
}
{
"success": false,
"httpStatus": "UNAUTHORIZED",
"message": "Authentication token is required",
"action_time": "2025-10-02T14:30:45",
"data": "Authentication token is required"
}
2. Get Checkout Session by ID
Purpose: Retrieves detailed information about a specific checkout session by its ID. Only the session owner can access their session.
Endpoint: GET {base_url}/checkout-sessions/{sessionId}
Access Level: 🔒 Protected (Requires Authentication and Ownership)
Authentication: Bearer Token required in Authorization header
Request Headers:
Path Parameters:
| Parameter | Type | Required | Description | Validation |
|---|---|---|---|---|
| sessionId | string (UUID) | Yes | Unique identifier of the checkout session | Valid UUID format |
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Checkout session retrieved successfully",
"action_time": "2025-10-02T14:35:45",
"data": {
"sessionId": "c1d2e3f4-a5b6-7890-cdef-123456789abc",
"sessionType": "REGULAR_DIRECTLY",
"status": "PENDING_PAYMENT",
"customerId": "u1s2e3r4-i5d6-7890-abcd-ef1234567890",
"customerUserName": "john_doe",
"items": [
{
"productId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"productName": "Premium Wireless Headphones",
"productSlug": "premium-wireless-headphones",
"productImage": "https://cdn.nextgate.com/products/headphones-001.jpg",
"quantity": 2,
"unitPrice": 150000.00,
"discountAmount": 20000.00,
"subtotal": 300000.00,
"tax": 0.00,
"total": 280000.00,
"shopId": "s1h2o3p4-i5d6-7890-abcd-ef1234567890",
"shopName": "TechWorld Electronics",
"shopLogo": "https://cdn.nextgate.com/shops/techworld-logo.jpg",
"availableForCheckout": true,
"availableQuantity": 50
}
],
"pricing": {
"subtotal": 300000.00,
"discount": 20000.00,
"shippingCost": 5000.00,
"tax": 0.00,
"total": 285000.00,
"currency": "TZS"
},
"shippingAddress": {
"fullName": "John Doe",
"addressLine1": "123 Main Street",
"addressLine2": "Apartment 4B",
"city": "Dar es Salaam",
"state": "Dar es Salaam Region",
"postalCode": "12345",
"country": "Tanzania",
"phone": "+255123456789"
},
"billingAddress": {
"sameAsShipping": false,
"fullName": "John Doe",
"addressLine1": "456 Business Ave",
"city": "Dar es Salaam",
"state": "Dar es Salaam Region",
"postalCode": "12346",
"country": "Tanzania"
},
"shippingMethod": {
"id": "standard-shipping",
"name": "Standard Shipping",
"carrier": "DHL",
"cost": 5000.00,
"estimatedDays": "3-5 business days",
"estimatedDelivery": "2025-10-07T14:30:45"
},
"paymentIntent": {
"provider": "WALLET",
"clientSecret": null,
"paymentMethods": ["WALLET"],
"status": "READY"
},
"paymentAttempts": [],
"inventoryHeld": true,
"inventoryHoldExpiresAt": "2025-10-02T14:45:45",
"metadata": { "couponCode": "SAVE20" },
"expiresAt": "2025-10-02T14:45:45",
"createdAt": "2025-10-02T14:30:45",
"updatedAt": "2025-10-02T14:30:45",
"completedAt": null,
"createdOrderId": null,
"cartId": null
}
}
Success Response Fields:
Error Response JSON Sample:
{
"success": false,
"httpStatus": "NOT_FOUND",
"message": "Checkout session not found or you don't have permission to access it",
"action_time": "2025-10-02T14:35:45",
"data": "Checkout session not found or you don't have permission to access it"
}
Error Response ExamplesResponses:
Not Found - Session Not Found or No Permission (404):
{
"success": false,
"httpStatus": "NOT_FOUND",
"message": "Checkout session not found or you don't have permission to access it",
"action_time": "2025-10-02T14:35:45",
"data": "Checkout session not found or you don't have permission to access it"
}
{
"success": false,
"httpStatus": "UNAUTHORIZED",
"message": "Authentication token is required",
"action_time": "2025-10-02T14:35:45",
"data": "Authentication token is required"
}
3. Get My Checkout Sessions
Purpose: Retrieves all checkout sessions belonging to the authenticated user, ordered by creation date (newest first).
Endpoint: GET {base_url}/checkout-sessions
Access Level: 🔒 Protected (Requires Authentication)
Authentication: Bearer Token required in Authorization header
Request Headers:
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Checkout sessions retrieved successfully",
"action_time": "2025-10-02T14:40:45",
"data": [
{
"sessionId": "c1d2e3f4-a5b6-7890-cdef-123456789abc",
"sessionType": "REGULAR_DIRECTLY",
"status": "PENDING_PAYMENT",
"itemCount": 1,
"totalAmount": 285000.00,
"currency": "TZS",
"expiresAt": "2025-10-02T14:45:45",
"createdAt": "2025-10-02T14:30:45",
"isExpired": false,
"canRetryPayment": false,
"itemPreviews": [
{
"productId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"productName": "Premium Wireless Headphones",
"productImage": "https://cdn.nextgate.com/products/headphones-001.jpg",
"quantity": 2,
"unitPrice": 150000.00,
"total": 280000.00,
"shopName": "TechWorld Electronics"
}
]
},
{
"sessionId": "d2e3f4a5-b6c7-8901-def0-234567890abc",
"sessionType": "REGULAR_CART",
"status": "COMPLETED",
"itemCount": 3,
"totalAmount": 500000.00,
"currency": "TZS",
"expiresAt": "2025-10-01T10:15:30",
"createdAt": "2025-10-01T10:00:30",
"isExpired": false,
"canRetryPayment": false,
"itemPreviews": [
{
"productId": "p1r2o3d4-u5c6-7890-abcd-ef1234567890",
"productName": "Smart Watch Series 5",
"productImage": "https://cdn.nextgate.com/products/watch-005.jpg",
"quantity": 1,
"unitPrice": 350000.00,
"total": 350000.00,
"shopName": "Gadget Hub"
},
{
"productId": "p2r3o4d5-u6c7-8901-bcde-f12345678901",
"productName": "Wireless Mouse",
"productImage": "https://cdn.nextgate.com/products/mouse-003.jpg",
"quantity": 2,
"unitPrice": 45000.00,
"total": 90000.00,
"shopName": "TechWorld Electronics"
}
]
},
{
"sessionId": "e3f4a5b6-c7d8-9012-ef01-345678901bcd",
"sessionType": "PAYMENT_FAILED",
"status": "PAYMENT_FAILED",
"itemCount": 1,
"totalAmount": 120000.00,
"currency": "TZS",
"expiresAt": "2025-10-02T15:00:00",
"createdAt": "2025-10-02T14:45:00",
"isExpired": false,
"canRetryPayment": true,
"itemPreviews": [
{
"productId": "p3r4o5d6-u7c8-9012-cdef-234567890123",
"productName": "USB-C Cable 2m",
"productImage": "https://cdn.nextgate.com/products/cable-002.jpg",
"quantity": 5,
"unitPrice": 15000.00,
"total": 75000.00,
"shopName": "Accessories World"
}
]
}
]
}
Success Response Fields:
| Field | Description |
|---|---|
| sessionId | Unique identifier for the checkout session |
| sessionType | Type of checkout session |
| status | Current status of the session |
| itemCount | Number of items in the checkout |
| totalAmount | Total amount to be paid in TZS |
| currency | Currency code (TZS) |
| expiresAt | When this session expires |
| createdAt | When this session was created |
| isExpired | Whether the session has expired |
| canRetryPayment | |
| itemPreviews | Array of preview information for items |
Error Response JSON Sample:
{
"success": false,
"httpStatus": "UNAUTHORIZED",
"message": "Authentication token is required",
"action_time": "2025-10-02T14:40:45",
"data": "Authentication token is required"
}
Error Response Examples:
{
"success": false,
"httpStatus": "UNAUTHORIZED",
"message": "Authentication token is required",
"action_time": "2025-10-02T14:40:45",
"data": "Authentication token is required"
}
4. Get My Active Checkout Sessions
Purpose: Retrieves only active checkout sessions (PENDING_PAYMENT or PAYMENT_FAILED status) that haven't expired yet, ordered by creation date (newest first).
Endpoint: GET {base_url}/checkout-sessions/active
Access Level: 🔒 Protected (Requires Authentication)
AuthenticationNotes: Bearer Token required in Authorization header
Request Headers:
Success Response JSONstructure Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Active checkout sessions retrieved successfully",
"action_time": "2025-10-02T14:42:45",
"data": [
{
"sessionId": "c1d2e3f4-a5b6-7890-cdef-123456789abc",
"sessionType": "REGULAR_DIRECTLY",
"status": "PENDING_PAYMENT",
"itemCount": 1,
"totalAmount": 285000.00,
"currency": "TZS",
"expiresAt": "2025-10-02T14:45:45",
"createdAt": "2025-10-02T14:30:45",
"isExpired": false,
"canRetryPayment": false,
"itemPreviews": [
{
"productId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"productName": "Premium Wireless Headphones",
"productImage": "https://cdn.nextgate.com/products/headphones-001.jpg",
"quantity": 2,
"unitPrice": 150000.00,
"total": 280000.00,
"shopName": "TechWorld Electronics"
}
]
},
{
"sessionId": "e3f4a5b6-c7d8-9012-ef01-345678901bcd",
"sessionType": "GROUP_PURCHASE",
"status": "PAYMENT_FAILED",
"itemCount": 1,
"totalAmount": 120000.00,
"currency": "TZS",
"expiresAt": "2025-10-02T15:00:00",
"createdAt": "2025-10-02T14:45:00",
"isExpired": false,
"canRetryPayment": true,
"itemPreviews": [
{
"productId": "p3r4o5d6-u7c8-9012-cdef-234567890123",
"productName": "USB-C Cable 2m",
"productImage": "https://cdn.nextgate.com/products/cable-002.jpg",
"quantity": 5,
"unitPrice": 15000.00,
"total": 75000.00,
"shopName": "Accessories World"
}
]
}
]
}
Success Response Fields:
Erroronly. Response JSON Sample:
is{ "success": false, "httpStatus": "UNAUTHORIZED", "message": "Authentication tokenisExpiredrequired",always"action_time":false"2025-10-02T14:42:45",in"data":this"Authentication token is required" }
Error Response Examples:response.
{
"success": false,
"httpStatus": "UNAUTHORIZED",
"message": "Authentication token is required",
"action_time": "2025-10-02T14:42:45",
"data": "Authentication token is required"
}
5. Update Checkout Session
Purpose: Updates an existing checkout session. Can modify shipping address, shipping method, payment method, or metadata. Only sessions in PENDING_PAYMENT or PAYMENT_FAILED status can be updated.
Endpoint: PATCH {base_url}/checkout-sessions/{sessionId}
Access Level: 🔒 Protected (Requires Authentication and Ownership)
Authentication: Bearer Token required in Authorization header
Request Headers:
|
Path Parameters:
| Parameter | Type | Required | Description | |
|---|---|---|---|---|
| sessionId | string (UUID) | Yes | Unique identifier of the checkout session |
Request JSON Sample:
{
"shippingAddressId": "f9e8d7c6-b5a4-3210-fedc-ba9876543210",
"shippingMethodId": "express-shipping",
"paymentMethodId": "p9a8y7m6-e5n4-3210-tdef-ba9876543210",
"metadata": {
"giftWrapping": true,
"giftMessage": "Happy Birthday!"
}
}
Request Body Parameters:
| Parameter | Type | Required | Description | |
|---|---|---|---|---|
| shippingAddressId | string (UUID) | No | New shipping address identifier | |
| shippingMethodId | string | No | New shipping method | (triggers |
| metadata | object | No | Key-value pairs, merged with existing metadata |
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Checkout session updated successfully",
"action_time": "2025-10-02T14:50:45",
"data": {
"sessionId": "c1d2e3f4-a5b6-7890-cdef-123456789abc",
"sessionType": "REGULAR_DIRECTLY",
"status": "PENDING_PAYMENT",
"customerId": "u1s2e3r4-i5d6-7890-abcd-ef1234567890",
"customerUserName": "john_doe",
"items": [
{
"productId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"productName": "Premium Wireless Headphones",
"productSlug": "premium-wireless-headphones",
"productImage": "https://cdn.nextgate.com/products/headphones-001.jpg",
"quantity": 2,
"unitPrice": 150000.00,
"discountAmount": 20000.00,
"subtotal": 300000.00,
"tax": 0.00,
"total": 280000.00,
"shopId": "s1h2o3p4-i5d6-7890-abcd-ef1234567890",
"shopName": "TechWorld Electronics",
"shopLogo": "https://cdn.nextgate.com/shops/techworld-logo.jpg",
"availableForCheckout": true,
"availableQuantity": 50
}
],
"pricing": {
"subtotal": 300000.00,
"discount": 20000.00,
"shippingCost": 8000.00,
"tax": 0.00,
"total": 288000.00,
"currency": "TZS"
},
"shippingAddress": {
"fullName": "John Doe",
"addressLine1": "789 New Address Street",
"addressLine2": null,
"city": "Dar es Salaam",
"state": "Dar es Salaam Region",
"postalCode": "12347",
"country": "Tanzania",
"phone": "+255987654321"
},
"billingAddress": {
"sameAsShipping": false,
"fullName": "John Doe",
"addressLine1": "321 Payment Ave",
"city": "Dar es Salaam",
"state": "Dar es Salaam Region",
"postalCode": "12348",
"country": "Tanzania"
},
"shippingMethod": {
"id": "express-shipping",
"name": "Express Shipping",
"carrier": "DHL",
"cost": 8000.00,
"estimatedDays": "1-2 business days",
"estimatedDelivery": "2025-10-04T14:50:45"
},
"paymentIntent": {
"provider": "CREDIT_CARD",
"clientSecret": "pi_1234567890abcdef",
"paymentMethods": ["CREDIT_CARD", "DEBIT_CARD"],
"status": "READY"
},
"paymentAttempts": [],
"inventoryHeld": true,
"inventoryHoldExpiresAt": "2025-10-02T15:05:45",
"metadata": {
"couponCode": "SAVE20",
"giftWrapping": true,
"giftMessage": "Happy Birthday!"
},
"expiresAt": "2025-10-02T15:05:45",
"createdAt": "2025-10-02T14:30:45",
"updatedAt": "2025-10-02T14:50:45",
"completedAt": null,
"createdOrderId": null,
"cartId": null
}
}
Success Response Fields:
Error Response JSON Sample:
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Cannot update - payment has been completed",
"action_time": "2025-10-02T14:50:45",
"data": "Cannot update - payment has been completed"
}
Error Response ExamplesResponses:
Bad Request - Cannot Update Completed Session (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Cannot update a completed checkout session",
"action_time": "2025-10-02T14:50:45",
"data": "Cannot update a completed checkout session"
}
Bad Request - Cannot Update Cancelled Session (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Cannot update a cancelled checkout session",
"action_time": "2025-10-02T14:50:45",
"data": "Cannot update a cancelled checkout session"
}
Bad Request - Cannot Update Expired Session (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Cannot update an expired checkout session",
"action_time": "2025-10-02T14:50:45",
"data": "Cannot update an expired checkout session"
}
Not Found - Session Not Found (404):
{
"success": false,
"httpStatus": "NOT_FOUND",
"message": "Checkout session not found or you don't have permission to access it",
"action_time": "2025-10-02T14:50:45",
"data": "Checkout session not found or you don't have permission to access it"
}
Not Found - Payment Method Not Found (404):
{
"success": false,
"httpStatus": "NOT_FOUND",
"message": "Payment method not found or does not belong to you",
"action_time": "2025-10-02T14:50:45",
"data": "Payment method not found or does not belong to you"
}
6. Cancel Checkout Session
Purpose: Cancels an existing checkout session and releases held inventory. Cannot cancel sessions that are completed or have successful payment.
Endpoint: DELETE {base_url}/checkout-sessions/{sessionId}/cancel
Access Level: 🔒 Protected (Requires Authentication and Ownership)
Authentication: Bearer Token required in Authorization header
Request Headers:
Path Parameters:
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Checkout session cancelled successfully",
"action_time": "2025-10-02T14:55:45",
"data": null
}
Success Response Fields:
Error Response JSON Sample:
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Cannot cancel a completed checkout session",
"action_time": "2025-10-02T14:55:45",
"data": "Cannot cancel a completed checkout session"
}
Error Response ExamplesResponses:
Bad Request - Cannot Cancel Completed Session (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Cannot cancel a completed checkout session",
"action_time": "2025-10-02T14:55:45",
"data": "Cannot cancel a completed checkout session"
}
Bad Request - Cannot Cancel with Successful Payment (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Cannot cancel - payment has been completed. Please contact support.",
"action_time": "2025-10-02T14:55:45",
"data": "Cannot cancel - payment has been completed. Please contact support."
}
Bad Request - Already Cancelled (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Checkout session is already cancelled",
"action_time": "2025-10-02T14:55:45",
"data": "Checkout session is already cancelled"
}
Not Found - Session Not Found (404):
{
"success": false,
"httpStatus": "NOT_FOUND",
"message": "Checkout session not found or you don't have permission to access it",
"action_time": "2025-10-02T14:55:45",
"data": "Checkout session not found or you don't have permission to access it"
}
7. Process Payment
Purpose: Initiates payment processing for a checkout session. Validates session status,in inventoryPENDING_PAYMENT availability,status. and payment method before processing. DelegatesRoutes to the appropriate payment providerprocessor (WALLET, CASH, FREE) based on the session amount and payment method type.method.
Endpoint: POST {base_url}/checkout-sessions/{sessionId}/process-payment
Access Level: 🔒 Protected (Requires Authentication and Ownership)
Authentication: Bearer Token required in Authorization header
Request Headers:
Path Parameters:
| Parameter | Type | Required | Description | |
|---|---|---|---|---|
| sessionId | string (UUID) | Yes | Unique identifier of the checkout session |
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Payment processedcompleted successfully"successfully. Your order is being processed.",
"action_time": "2025-10-02T15:00:45",
"data": {
"success": true,
"paymentProvider": "WALLET",
"transactionId": "txn_1234567890abcdef",
"amount": 285000.00,
"currency": "TZS",
"status": "COMPLETED"SUCCESS",
"message": "Payment successful"completed successfully. Your order is being processed.",
"checkoutSessionId": "c1d2e3f4-a5b6-7890-cdef-123456789abc",
"escrowId": "esc-uuid",
"escrowNumber": "ESC-20251002-001",
"orderId": "ord-uuid",
"paymentMethod": "WALLET",
"processedAt"amountPaid": 285000.00,
"platformFee": 5700.00,
"sellerAmount": 279300.00,
"currency": "2025-10-02T15:00:45",
"orderId": "ord_9876543210fedcba",
"receiptUrl": nullTZS"
}
}
Success Response Fields:
| Field | Description |
|---|---|
| success | Whether the payment was successful |
| Human-readable | |
| orderId | Order or booking ID created after |
| amountPaid | Total |
| platformFee | Platform fee deducted |
| sellerAmount | Amount the seller receives |
| currency | Always TZS |
Error Response JSON Sample:
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Cannot process payment - session status: PAYMENT_COMPLETED",
"action_time": "2025-10-02T15:00:45",
"data": "Cannot process payment - session status: PAYMENT_COMPLETED"
}
Error Response ExamplesResponses:
Bad Request - Invalid Session StatusNot in PENDING_PAYMENT status (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Cannot process payment - session status:is not pending: PAYMENT_COMPLETED",
"action_time": "2025-10-02T15:00:45",
"data": "Cannot process payment - session status:is not pending: PAYMENT_COMPLETED"
}
Bad Request - Session Expired (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Checkout session has expired",
"action_time": "2025-10-02T15:00:45",
"data": "Checkout session has expired"
}
Bad Request - Insufficient Wallet Balance (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Insufficient wallet balance. Required: 285000 TZS, Available: 150000 TZS",
"action_time": "2025-10-02T15:00:45",
"data": "Insufficient wallet balance. Required: 285000 TZS, Available: 150000 TZS"
}
Not Found - Session Not Found (404):
{
"success": false,
"httpStatus": "NOT_FOUND",
"message": "Checkout session not found or you don't have permission to access it",
"action_time": "2025-10-02T15:00:45",
"data": "Checkout session not found or you don't have permission to access it"
}
8. Retry Payment
Purpose: Retries payment for a failed checkout session. Validates that the session is in PAYMENT_FAILED status, hasn't exceeded maximum retry attempts (5), and hasn't expired.status. Re-validates inventory availabilityavailability, checks wallet balance, re-holds inventory, and extends session expiration before retrying. Maximum 5 total attempts.
Endpoint: POST {base_url}/checkout-sessions/{sessionId}/retry-payment
Access Level: 🔒 Protected (Requires Authentication and Ownership)
Authentication: Bearer Token required in Authorization header
Request Headers:
Path Parameters:
Success Response JSON Sample:
{
"success": true,
"httpStatus": "OK",
"message": "Payment retry successful",
"action_time": "2025-10-02T15:10:45",
"data": {
"success": true,
"paymentProvider": "WALLET",
"transactionId": "txn_retry_1234567890abcdef",
"amount": 285000.00,
"currency": "TZS",
"status": "COMPLETED",
"message": "Payment successful on retry",
"paymentMethod": "WALLET",
"processedAt": "2025-10-02T15:10:45",
"orderId": "ord_retry_9876543210fedcba",
"receiptUrl": null
}
}
Success Response Fields:
Error Response JSON Sample:
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Cannot retry payment - session status: PENDING_PAYMENT. Expected: PAYMENT_FAILED",
"action_time": "2025-10-02T15:10:45",
"data": "Cannot retry payment - session status: PENDING_PAYMENT. Expected: PAYMENT_FAILED"
}
Error Response ExamplesResponses:
Bad Request - Invalid Status (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Cannot retry payment - session status: PENDING_PAYMENT. Expected: PAYMENT_FAILED",
"action_time": "2025-10-02T15:10:45",
"data": "Cannot retry payment - session status: PENDING_PAYMENT. Expected: PAYMENT_FAILED"
}
Bad Request - Session Expired (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Checkout session has expired. Please create a new checkout session.",
"action_time": "2025-10-02T15:10:45",
"data": "Checkout session has expired. Please create a new checkout session."
}
Bad Request - Max Retry Attempts Exceeded (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Maximum payment attempts (5) exceeded. Please create a new checkout session.",
"action_time": "2025-10-02T15:10:45",
"data": "Maximum payment attempts (5) exceeded. Please create a new checkout session."
}
BadInsufficient RequestWallet -Balance on Retry (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Insufficient wallet balance. Required: 285000 TZS, Available: 150000 TZS. Please top up your wallet.",
"action_time": "2025-10-02T15:10:45",
"data": "Insufficient wallet balance. Required: 285000 TZS, Available: 150000 TZS. Please top up your wallet."
}
Product No Longer Available (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Product 'Premium Wireless Headphones' is no longer available in requested quantity. Please create a new checkout session.",
"action_time": "2025-10-02T15:10:45",
"data": "Product 'Premium Wireless Headphones' is no longer available in requested quantity. Please create a new checkout session."
}
Bad Request - Insufficient Wallet Balance (400):
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Insufficient wallet balance. Required: 285000 TZS, Available: 150000 TZS. Please top up your wallet or update your payment method.",
"action_time": "2025-10-02T15:10:45",
"data": "Insufficient wallet balance. Required: 285000 TZS, Available: 150000 TZS. Please top up your wallet or update your payment method."
}
Not Found - Session Not Found (404):
{
"success": false,
"httpStatus": "NOT_FOUND",
"message": "Checkout session not found or you don't have permission to access it",
"action_time": "2025-10-02T15:10:45",
"data": "Checkout session not found or you don't have permission to access it"
}
Checkout Session Types
REGULAR_DIRECTLY
Direct product purchase without using a cart. Must include exactly 1 item in the request.
Characteristics:item.
Single item purchase flowItems array must contain exactly 1 productDoes not link to any cartcartId field will be null in response- Best for "Buy Now" buttons
- Balance
quickischeckoutcheckedflowsagainstpricing.total(includes shipping) - Inventory is held immediately on session creation
Example Use Case:
User clicks "Buy Now" on a product detail page and proceeds directly to checkout.
REGULAR_CART
Checkout from existing shopping cart. Items are retrievedfetched automatically from the user's active cart.
Characteristics:
- Multi-item purchase flow
- Items array not required in request
- Balance is checked against
pricing.total(fetchedincludesfromshipping) - Inventory is held for all cart
automatically) Links to user's cart via cartIdCart is validated before checkout creationcartId field will be populated in responseitems
Example Use Case:
User adds multiple products to cart, reviews cart, and clicks "Proceed to Checkout".
GROUP_PURCHASE
SpecialGroup buying checkout type for group buying where multiple users purchase the same product at a discounted group price.
Characteristics:
- Single item
purchaseatgroup priceproduct.groupPrice ItemsBalancearrayismustcheckedcontainagainstexactlygroupPrice1×productquantityPaymentWALLET payment methodMUST be WALLET (other methods not supported)only- Can join existing group
via(providegroupInstanceId) or create new group (providegroupName) UsesNoproduct'ssession-levelgroupPriceinventoryinsteadholdof—regularinventorypriceis RequiresheldproductattothehavegroupgroupBuyingEnabledlevel=aftertrueQuantity cannot exceed product's groupMaxSizeGroup has time limit defined by product's groupTimeLimitHourspayment
Example Use Case:
User sees a product available for group buying at 80,000 TZS (regular price: 150,000 TZS). User can either start a new group or join an existing group with available seats.
Request Example (Create New Group):Group:
{
"sessionType": "GROUP_PURCHASE",
"items": [{ "productId": "prod-uuid", "quantity": 2 }],
"shippingAddressId": "addr-uuid",
"groupName":"This is my winning group",
"shippingMethodId": "standard",
"paymentMethodId"groupName": null,"My "groupInstanceId":Winning nullGroup"
}
Request Example (Join Existing Group):Group:
{
"sessionType": "GROUP_PURCHASE",
"items": [{ "productId": "prod-uuid", "quantity": 3 }],
"shippingAddressId": "addr-uuid",
"shippingMethodId": "standard",
"paymentMethodId": null,
"groupInstanceId": "group-uuid-to-join"
}
INSTALLMENT
Status: PLACEHOLDER - Not Yet Implemented
Future checkout type for installmentSplit payment plans.over Willmultiple allowmonths. usersOnly tothe splitdown payment is charged at checkout; remaining monthly payments intoare multipleprocessed installments.
Plannedby Characteristics:the scheduler.
WillBalancerequireis checked againstdownPaymentAmountonly (not the full product price)installmentPlanIdanddownPaymentPercentare requiredpricing.totalinrequestthe Paymentsessionspreadresponseoverreflectsmultiple periodsMay requirethe down payment onlyInterestInventoryratesismayheldapply basedimmediately onplansession Credit check may be requiredcreation
Current Behavior:
Returns error:
{
"INSTALLMENTsessionType": checkout"INSTALLMENT",
not"items": implemented[{ yet""productId": "prod-uuid", "quantity": 1 }],
"shippingAddressId": "addr-uuid",
"shippingMethodId": "standard",
"installmentPlanId": "plan-uuid",
"downPaymentPercent": 20
}
Checkout Session Status Flow
Status Definitions
| Status | Description | Can Update? | Can Cancel? | Can Pay? | Can Retry? |
|---|---|---|---|---|---|
| PENDING_PAYMENT | Session created, awaiting payment | Yes | Yes | Yes | No |
| PAYMENT_PROCESSING | Payment in progress | No | No | No | No |
| PAYMENT_FAILED | Payment failed, can retry | Yes | Yes | No | Yes |
| PAYMENT_COMPLETED | Payment successful | No | No | No | No |
| EXPIRED | Session expired | No | No | No | No |
| CANCELLED | User cancelled | No | No | No | No |
| COMPLETED | No | No | No | No |
Status Transition Flow
[Session Creation]
|
| balance check passes
v
PENDING_PAYMENT
├|
|-- user cancels ──────────────────> PAYMENT_PROCESSINGCANCELLED
| (wheninventory paymentreleased)
initiated)|
│|-- ├15 min timeout ────────────────> PAYMENT_COMPLETEDEXPIRED
| (oninventory success)released)
│|
│|-- └processPayment()
|
|-- amount = 0 ────────────────> COMPLETED (afterfree)
order|
creation)|-- │CASH └──────────────────────> COMPLETED (cash)
|
|-- WALLET ────────────────────> PAYMENT_PROCESSING
|
|-- success ──> PAYMENT_COMPLETED
| (order/booking created,
| inventory committed)
|
|-- failure ──> PAYMENT_FAILED
(oninventory failure,released canfor retryevents,
max 5 times)retries)
│|
├|-- retryPayment() ──> PENDING_PAYMENT
| (wheninventory retryre-held)
initiated)|
│|-- └5 attempts ──────> EXPIRED
(after
Wallet orBalance Check Endpoint
For cases where the frontend wants to proactively check balance against an existing session timeout)(e.g., ├─>before CANCELLEDshowing (userthe cancels)"Pay └─>Now" EXPIREDbutton), (15use:
Endpoint: timeout)GET {base_url}/wallet/checkout-balance-check?sessionId={id}&domain={PRODUCT|EVENT}
Success Response:
{
"success": true,
"httpStatus": "OK",
"message": "Checkout balance check completed",
"data": {
"walletBalance": 150000.00,
"sessionTotal": 285000.00,
"shortfall": 135000.00,
"hasSufficientBalance": false,
"recommendedTopUp": 135000.00,
"pspMinimum": 500.00,
"currency": "TZS"
}
}
Note: This endpoint always returns 200 — it never throws. Use hasSufficientBalance to determine if the user can pay. This is the "soft check" for an existing session; the "hard check" (which blocks session creation) happens automatically inside POST /checkout-sessions.
Payment Methods Supported
WALLET (Default)
Internal wallet systemsystem. forDefault storingif andno usingpayment funds.
Requirements:is specified.
User must have active walletSufficient balance required- Balance
checkedvalidatedbeforeat session creation (hard block) and again at paymentprocessingtime (safety net) - Instant
paymentprocessingprocessingvia escrow NoFundsadditionalheldfeesin escrow until order is confirmed/delivered
Payment Flow:
Validate wallet is activeCheck sufficient balanceDeduct amount from walletCreate transaction recordCreate order
Default Behavior:
If no paymentMethodId provided in request, WALLET is used as default.
CASH_ON_DELIVERYCASH
Pay in cash whenon orderdelivery isor delivered.
Requirements:the point of event check-in.
- No pre-payment required
Payment collected by delivery agentOrderOrder/booking created immediatelyMayApplicablehavetogeographicbothrestrictionsproduct and event checkouts
FREE
PaymentZero-amount Flow:checkout (free products or free event tickets).
CreateHandled automatically whenpricing.total = 0- No payment
intentmethodwith status "PENDING"required CreateOrder/bookingordercreated immediatelyPayment marked as "COD"Delivery agent collects payment on delivery
CREDIT_CARD / DEBIT_CARDMOBILE_MONEY
Status: Planned -— Notnot Yetyet Implemented
Future support for credit and debit card payments.
Planned Features:
Card tokenization for securityPCI compliance3D Secure authenticationSaved cards supportInternational cards support
MNO_PAYMENT (Mobile Money)
Status: Planned - Not Yet Implemented
Future support for mobile money payments (M-Pesa, Tigo Pesa, Airtel Money, etc.).
Planned Features:
USSD push notificationsCallback confirmationTransaction reconciliationMultiple operators support
Other Payment Methods
Additional payment methods (PayPal, Bank Transfer, Cryptocurrency, Gift Card) are placeholders for future implementation.implemented.
Inventory Management
Inventory Hold Mechanism
| Session Type | Hold Created At | Hold Released At |
|---|---|---|
| REGULAR_DIRECTLY | Session creation | Expiry, cancellation, or payment success (committed) |
| REGULAR_CART | Session creation | Expiry, cancellation, or payment success (committed) |
| GROUP_PURCHASE | After payment, at group level | Group expiry or group failure |
| INSTALLMENT | Session creation | Expiry, cancellation, or payment success (committed) |
WhenOn asuccessful checkoutpayment, sessionholds isare created,committed inventory(stock ispermanently automaticallydeducted). heldOn failure/expiry/cancellation, holds are released (stock returned to prevent overselling.
Hold Behavior:
Inventory held for 15 minutes (matches session expiration)Held quantity deducted from available stockOther users cannot purchase held inventoryHold automatically released on:Session expirationSession cancellationPayment failure (after 5 retry attempts)
Hold converted to permanent deduction on successful payment
Hold Fields:
inventoryHeld: Boolean indicating if inventory is currently heldinventoryHoldExpiresAt: Timestamp when hold will be released
Example:
{
"inventoryHeld": true,
"inventoryHoldExpiresAt": "2025-10-02T14:45:45"
}
Inventory Validation
Before processing payment or retry, system validates:
Product still exists and is activeProduct still in stockRequested quantity still availableProduct hasn't been deleted
If validation fails, user must create new checkout session with current availability.available).
Session Expiration
Expiration Rules
Default Expiration:Default: 15 minutes from creationcreation.
Expiration Extended When:when:
- Payment retry is initiated (adds 15 minutes)
Session updated successfully (adds 15 minutes)
WhatOn Happens on Expiration:expiry:
SessionStatusstatus changes to→ EXPIRED- Held inventory released
back to available stock - Session cannot be
updatedupdated, paid, orpaid Session cannot becancelled(already effectively ended)- User must create
new checkout session
Checking Expiration:
expiresAtfield shows expiration timestampisExpiredfield (in summary responses) shows if session expired
Preventing Expiration
To prevent session expiration:
Complete payment before expirationUpdate session if needed (extends timer)If expired, createa new checkout session
Best Practice:
Display countdown timer to users showing time remaining before expiration.
Payment Attempts Tracking
Attempt Limits
Maximum Attempts: 5 attempts per session
Attempt Tracking:session. Each payment attempt recorded with:records:
- Attempt number (
1-1–5) - Payment method used
StatusStatus:(SUCCESS, FAILED,RETRY_INITIATED)or RETRY_INITIATED- Error message (if failed)
- Timestamp
Transactionand transaction ID(if available)
Example Payment Attempts:
{
"paymentAttempts": [
{
"attemptNumber": 1,
"paymentMethod": "WALLET",
"status": "FAILED",
"errorMessage": "Insufficient wallet balance",
"attemptedAt": "2025-10-02T14:35:00",
"transactionId": null
},
{
"attemptNumber": 2,
"paymentMethod": "WALLET",
"status": "RETRY_INITIATED",
"errorMessage": null,
"attemptedAt": "2025-10-02T14:40:00",
"transactionId": null
},
{
"attemptNumber": 3,
"paymentMethod": "WALLET",
"status": "SUCCESS",
"errorMessage": null,
"attemptedAt": "2025-10-02T14:42:00",
"transactionId": "txn_1234567890abcdef"
}
]
}
After Max Attempts
When 5 attemptsfailed exceeded:
Sessionsession statussetmoves to EXPIREDInventoryandreleasedinventory Cannotisretry paymentUser must create new checkout session
Metadata Usage
Purpose
Metadata allows storing custom key-value data with checkout sessions for business-specific needs.released.
Common Use Cases
Coupons & Discounts:
{
"metadata": {
"couponCode": "SAVE20",
"couponDiscount": 20000,
"couponAppliedAt": "2025-10-02T14:30:00"
}
}
Referral Tracking:
{
"metadata": {
"referralCode": "REF123",
"referredBy": "user-uuid",
"referralBonus": 5000
}
}
Gift Options:
{
"metadata": {
"isGift": true,
"giftWrapping": true,
"giftMessage": "Happy Birthday!",
"giftRecipientName": "Jane Doe"
}
}
Delivery Instructions:
{
"metadata": {
"deliveryInstructions": "Leave package at front desk",
"deliveryTimePreference": "morning",
"contactOnArrival": true
}
}
Group Purchase:
{
"metadata": {
"groupInstanceId": "group-uuid",
"isGroupLeader": true,
"groupCreatedAt": "2025-10-02T14:30:00"
}
}
Marketing Attribution:
{
"metadata": {
"source": "facebook_ad",
"campaign": "summer_sale_2025",
"medium": "social_media"
}
}
Metadata Rules
Stored as JSON objectKey-value pairs with string keysValues can be strings, numbers, booleans, or nested objectsNo size limit enforced at API level (reasonable usage expected)Merged with existing metadata on update (not replaced)Persisted with session throughout lifecycleAccessible in order after completion
Error Handling Best Practices
Client-SideFrontend HandlingChecklist
Before Creatingcalling Checkout:POST /checkout-sessions:
ValidateEnsure the user has a shipping address savedCheckNoproductneedavailabilityto pre-check balance — the API returns rich balance data if insufficient- Read
data.shortfallto show how much the user is short VerifyReadpaymentdata.recommendedTopUpmethodtoexistspre-fill(ifa top-up amount- Navigate the user to the wallet top-up screen
- Once topped up, retry
POST /checkout-sessions— do notusingstorewallet)the failed session Display clear pricing breakdown
On 422 Insufficient Balance response:
During Checkout:active session (PENDING_PAYMENT):
- Show
expirationa countdown timer usingexpiresAt HandleOn expiry, prompt user to create a new sessionexpiration gracefullyProvide clear error messagesSuggest actions (e.g., "Top up wallet" if insufficient balance)
PaymentOn Failures:payment failure:
DisplayShowspecificcanRetryPaymenterrortoreasondecide whether to show a retry button- Show remaining
retryattemptsattempts(5 - paymentAttemptCount) OfferOn retry, callPOST /{sessionId}/retry-payment— no need toupdate payment methodSuggest alternative payment methods
Common Error Scenarios
Insufficient Inventory:
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Insufficient stock. Available: 3, Requested: 5"
}
Action: Reduce quantity or create new session with available quantity.
Insufficient Wallet Balance:
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Insufficient wallet balance. Required: 285000 TZS, Available: 150000 TZS"
}
Action: Top up wallet or change payment method.
Session Expired:
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Checkout session has expired"
}
Action: Create new checkout session.
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Product is not available for purchase"
}
Action: Remove product from cart or select alternative product.
Max Retries Exceeded:
{
"success": false,
"httpStatus": "BAD_REQUEST",
"message": "Maximum payment attempts (5) exceeded. Please create a new checkoutsession
session."
}
Action: Create new checkout session, possibly with different payment method.
Integration Examples
Example 1: Direct Product Purchase Flow
Step 1: Create Checkout Session
1. POST /api/v1/checkout-sessions
Authorization:→ Bearer422 {token}if Content-Type:balance application/jsoninsufficient {(show "sessionType":top-up "REGULAR_DIRECTLY",screen "items":with [{data.recommendedTopUp)
"productId":→ "prod-uuid",201 "quantity":with 1sessionId }],if "shippingAddressId":balance "addr-uuid",OK
"shippingMethodId":2. "standard",
"paymentMethodId": null
}
Step 2: Process Payment
POST /api/v1/checkout-sessions/{sessionId}/process-payment
Authorization:→ Bearer200 {token}with orderId on success
Step 3: Check Order Created
Response will include orderId field after successful payment.
Example 2: Cart Checkout Flow
Step 1: Create Checkout from Cart
1. POST /api/v1/checkout-sessions Authorization: Bearer {token}
Content-Type: application/json
{ "sessionType":sessionType: "REGULAR_CART",REGULAR_CART, "shippingAddressId": "addr-uuid",
"shippingMethodId": "express",
"metadata": {
"couponCode": "SAVE20"... }
}→ 422 Stepor 2:201
Review2. Session
GETPATCH /api/v1/checkout-sessions/{sessionId} Authorization: Bearer {token}
Step 3: Update if Needed
PATCH /api/v1/checkout-sessions/{sessionId}
Authorization: Bearer {token}
Content-Type: application/json
{ "shippingMethodId":shippingMethodId: "standard",
"metadata": {
"giftWrapping": trueexpress" }
}3. Step 4: Process Payment
POST /api/v1/checkout-sessions/{sessionId}/process-payment
Authorization: Bearer {token}
Example 3: Group Purchase Flow
Step 1: Create Group Purchase Session
1. POST /api/v1/checkout-sessions Authorization: Bearer {token}
Content-Type: application/json
{ "sessionType":sessionType: GROUP_PURCHASE, groupName: "GROUP_PURCHASE"...", "items": [{
"productId": "prod-uuid",
"quantity": 2
}],
"shippingAddressId": "addr-uuid",
"shippingMethodId": "standard",
"groupInstanceId": null... }
→ Step422 2:if Processbalance Payment< (WALLETgroupPrice only)
qty
→ 201 with sessionId
2. POST /api/v1/checkout-sessions/{sessionId}/process-payment
Authorization:(WALLET Bearer {token}only)
Example 4: Installment
1. POST /checkout-sessions { sessionType: INSTALLMENT, installmentPlanId: "...", downPaymentPercent: 20 }
→ 422 if balance < downPaymentAmount
→ 201 with sessionId (pricing.total = down payment only)
2. POST /checkout-sessions/{sessionId}/process-payment
→ charges down payment only; monthly payments handled by scheduler
Example 5: Payment Retry Flow
Step 1: Get Active Sessions
1. GET /api/v1/checkout-sessions/active
Authorization:→ Bearer {token}
Step 2: Identify Failed Session
Look forfind session with status: PAYMENT_FAILED, "PAYMENT_FAILED"and canRetryPayment: true
Step2. 3: Update Payment Method (Optional)
PATCH /api/v1/checkout-sessions/{sessionId}
Authorization: Bearer {token}
Content-Type: application/json
{
"paymentMethodId": "new-payment-method-uuid"
}
Step 4: Retry Payment
POST /api/v1/checkout-sessions/{sessionId}/retry-payment
Authorization:→ Bearerre-validates {token}inventory + balance
→ re-holds inventory
→ processes payment
Rate Limiting
Rate
Limits:
Endpoint
Limit
Create
Checkout:Checkout20
requests per minutereq/min per user
Get
Sessions:Sessions60
requests per minutereq/min per userProcess/
Process / Retry
Payment:Payment10
requests per minutereq/min per userUpdate/Cancel:
Update / Cancel
30
requests per minutereq/min per userRateLimit Headers:
X-RateLimit-Limit: 20
X-RateLimit-Remaining: 15
X-RateLimit-Reset: 1696258800
Rate Limit Exceeded:
{
"success": false,
"httpStatus": "TOO_MANY_REQUESTS",
"message": "Rate limit exceeded. Please try again later.",
"action_time": "2025-10-02T15:30:45",
"data": "Rate limit exceeded. Please try again later."
}