Shop It Docs
Developer Resourcesorder

Order Module API & Integration Guide

Order API contracts for mobile/customer and admin surfaces with synchronous payment initiation.

Audience: Mobile/web frontend developers Scope: Checkout, payment, order endpoints

Order Module - API & Integration Guide

1. How to Read / Quick Metadata

  • Module: Order
  • Auth models:
    • Customer/mobile routes: JwtAuthGuard
    • Admin routes: JwtAuthGuard + RoleGuard + @Permissions(...)
  • Primary base URLs:
    • Customer: /api/orders
    • Mobile-composed customer: /api/mobile/orders
    • Admin: /api/admin/orders
    • Payment redirect callbacks: /api/payments/redirect/:paymentId/success|failure
  • Response envelope: successful endpoints return ResponseDto<T>
  • Swagger tags used by controllers:
    • Orders (Mobile)
    • Orders (Admin)

2. High-Level Overview

Order API is split into:

  • synchronous payment-initiation endpoints (checkout, buy-now) returning gateway payload immediately
  • synchronous read endpoints (list/detail/request-status)
  • async command endpoints for cancellation and admin refund processing

Payment verification is completed through redirect callbacks, then finalized by queue workers.

Buy-now product behavior:

  • productKind determines orderType: physicalphysical, digitaldigital, care_packagecare_package.
  • All three product kinds are supported for buy-now.

Checkout order type:

  • Order type resolves from the cart's items. Single-kind carts inherit that type; mixed-kind carts produce orderType: "mixed".
  • Digital-only and care-package-only checkouts skip shipping (no shippingDistrict required, shippingFee = 0).

3. Core Concepts and Terminology

  • order: primary transaction entity (order table)
  • order item: line-level monetary snapshot (order_item table)
  • status history: append-only transition log with actor provenance (order_status_history)
  • async request: command-tracking record for async mutations (async_request)
  • outbox event: durable dispatch record for background jobs (outbox_event)
  • payment-init response: payload containing initiationType, redirectUrl, and gatewayPayload
  • final payable (physical): totalSp - couponDiscount + shippingFee

Current async order jobs:

  • order.payment_success
  • order.payment_failed
  • order.payment_retry
  • order.cancel
  • order.process_refund
  • order.auto_cancel

Current queue payload contracts:

JobPayload shape
order.payment_success"" orderId, paymentReference, transactionId? ""
order.payment_failed"" orderId, reason? ""
order.payment_retry"" orderId, paymentId, attempt, maxAttempts ""
order.cancel"" orderId, reason?, cancelledBy, cancelledByActorType ""
order.process_refund"" orderId, adminId, action, amount?, remarks ""
order.auto_cancel"" orderId, reason ""

Transactional notification routing events used by order flow:

  • ORDER_PLACED_CHECKOUT, ORDER_PLACED_BUYNOW
  • ORDER_PAYMENT_RECEIVED_CHECKOUT, ORDER_PAYMENT_RECEIVED_BUYNOW
  • ORDER_PAYMENT_FAILED, ORDER_CANCELLED
  • ORDER_REFUND_REQUESTED, ORDER_REFUND_APPROVED, ORDER_REFUND_REJECTED

Order-to-inventory outbox events emitted by lifecycle stage:

  • stock.reserve after checkout/buy-now order creation
  • stock.finalize after verified online payment success, or after COD reservation succeeds and the order enters paymentStatus = "cod_pending"
  • stock.release after payment failure, cancellation, or expiry

Outbox/queue lifecycle for inventory coupling:

  1. Order service writes outbox_events with targetQueue for inventory processing.
  2. Outbox dispatcher claims pending inventory-target rows only from its owned queue set.
  3. Dispatcher enqueues reserve/finalize/release inventory jobs.
  4. Inventory processors mutate stock state and acknowledge job completion.

Delivery channels for transactional events:

  • push (mobile_push, in-app targets)
  • email (template-based renderer output)

4. Route Summary

4.1 Customer / Mobile

MethodPath
POST/api/orders/checkout
POST/api/orders/buy-now
GET/api/orders
GET/api/orders/:id
GET/api/orders/requests/:requestId
POST/api/orders/:id/cancel
POST/api/orders/:id/request-refund

Mobile-composed equivalents are available under /api/mobile/orders/.... GET /api/orders/requests/:requestId is for async operations (for example cancel/refund processing), not for checkout/buy-now initiation.

4.2 Admin

MethodPathPermission
GET/api/admin/ordersOrders_READ
GET/api/admin/orders/:idOrders_READ
GET/api/admin/orders/analyticsOrders_READ
GET/api/admin/orders/analytics/districtsOrders_READ
GET/api/admin/orders/:id/invoice-downloadOrders_READ
GET/api/admin/orders/requests/:requestIdOrders_READ
POST/api/admin/orders/:id/cancelOrders_UPDATE
POST/api/admin/orders/:id/process-refundOrders_UPDATE
POST/api/admin/orders/:id/notesOrders_UPDATE
POST/api/admin/orders/:id/activate-care-packageCarePackageSubscriptions_UPDATE
PATCH/api/admin/orders/:id/items/:orderItemId/serialOrders_UPDATE

4.3 Payment Redirect and Result

MethodPathOwner
GET/api/payments/redirect/:paymentId/successPaymentRedirectController
POST/api/payments/redirect/:paymentId/successPaymentRedirectController
GET/api/payments/redirect/:paymentId/failurePaymentRedirectController
POST/api/payments/redirect/:paymentId/failurePaymentRedirectController
GET/api/payments/resultPaymentResultController

Route Details

Checkout

AspectDetails
EndpointPOST /api/orders/checkout or /api/mobile/orders/checkout
AuthJwtAuthGuard
Requestgateway: `"stripe"
ResponseResponseDto<PaymentInitResponseDto>
Errors400 invalid cart, 400 payment initiation/validation failure

Validation rule:

  • Checkout and buy-now require shipping district to be selected on the active cart (ORDER_SHIPPING_DISTRICT_REQUIRED).
  • Order creation sets orderStatus=payment_pending and does not clear cart immediately.
  • Cart clear is executed only after verified payment success (order.payment_success -> cart clear worker).
  • COD is the exception to online payment finalization: after reservation succeeds, checkout sets paymentStatus=cod_pending, keeps orderStatus=payment_pending, clears the cart through the confirmed-order cart clear job, and does not emit order.payment_success.

Get Orders

AspectDetails
EndpointGET /api/orders or /api/mobile/orders
AuthJwtAuthGuard
Requestpagination, status filter
ResponseResponseDto<OrderDto[]>
Errors-

5. Query Parameters

5.1 Customer list (GET /api/orders)

ParamTypeDefault
pagenumber1
sizenumber20
paginationbooleantrue
statusenum(order_status)optional
sortcreatedAt | updatedAtcreatedAt
orderasc | descdesc

5.2 Admin list (GET /api/admin/orders)

ParamTypeDefault
pagenumber1
sizenumber20
paginationbooleantrue
statusenum(order_status)optional
paymentMethodenum(order_payment_method)optional
paymentStatuspending | completed | failed | cod_pending | cod_collectedoptional
orderTypeenum(order_type)optional
searchstringoptional
sortcreatedAt | updatedAtcreatedAt
orderasc | descdesc

6. Response Shape Examples

6.1 Checkout request

"
  "gateway": "stripe",
  "returnUrl": "https://example.com/payment/return"
"

6.2 Buy-now request

"
  "productId": 101,
  "gateway": "stripe",
  "returnUrl": "https://example.com/payment/return",
  "promoCode": "SUMMER2026"
"

6.3 Payment-init response (200 OK)

"
  "orderId": 101,
  "status": "payment_pending",
  "paymentId": 9001,
  "gatewayTransactionId": "cs_test_a1b2c3d4e5",
  "initiationType": "redirect",
  "redirectUrl": "https://checkout.stripe.com/c/pay/cs_test_a1b2c3d4e5",
  "gatewayPayload": "
    "sessionId": "cs_test_a1b2c3d4e5"
  ""
"

6.4 Async request status response

"
  "requestId": "cancel_9f67c1bc67694347b6509e1ee1277f49",
  "status": "completed",
  "result": "
    "orderId": 101,
    "orderStatus": "cancelled",
    "paymentStatus": "failed",
    "correlationId": "order_cancel_user_abc_79f9c2fa11a7"
  "",
  "createdAt": "2026-03-10T10:00:00.000Z",
  "completedAt": "2026-03-10T10:00:05.000Z"
"

6.5 Admin status history item (actor provenance)

"
  "status": "cancelled",
  "notes": "Cancelled by support",
  "actorType": "admin",
  "createdByCustomerId": null,
  "createdByAdminId": "019d2c3e-3ca0-76ae-83ba-53e81e74eed1",
  "createdBy": "019d2c3e-3ca0-76ae-83ba-53e81e74eed1",
  "createdAt": "2026-03-30T12:00:00.000Z"
"

6.6 Order response (with shipping)

"
  "id": 101,
  "orderNumber": "ORD-20260417-001",
  "orderType": "physical",
  "orderStatus": "payment_pending",
  "paymentStatus": "pending",
  "totalSp": 12000,
  "couponDiscount": 1000,
  "shippingDistrict": "Kathmandu",
  "shippingMobileNum": "+977-9801234567",
  "shippingFee": 500,
  "shippingAddressLine1": "Boudha Stupa Road",
  "shippingAddressLine2": "House 12, Floor 2",
  "shippingCity": "Kathmandu",
  "shippingState": "Bagmati",
  "shippingPostalCode": "44600",
  "shippingLandmark": "Near main gate",
  "shippingLatitude": 27.7172,
  "shippingLongitude": 85.324,
  "receiver": "Kunga Lama",
  "contactNumber": "+61 7 4720 9931",
  "fulfillmentStatus": "in_transit",
  "fulfillmentTimeline": [
    { "status": "received", "label": "Received", "completed": true, "current": false },
    { "status": "ready", "label": "Ready", "completed": true, "current": false },
    { "status": "picked_up", "label": "Picked Up", "completed": true, "current": false },
    { "status": "in_transit", "label": "In Transit", "completed": true, "current": true },
    { "status": "delivered", "label": "Delivered", "completed": false, "current": false }
  ],
  "fulfillmentTimeline (care_package order)": [
    { "status": "received", "label": "Received", "completed": true, "current": false },
    { "status": "activated", "label": "Activated", "completed": false, "current": false }
  ],
  "fulfillmentTimeline (digital order)": [
    { "status": "received", "label": "Received", "completed": true, "current": false },
    { "status": "key_sent", "label": "Key Sent", "completed": false, "current": false }
  ],
  "orderThumbnails": [
    "https://cdn.example.com/products/101-thumb.jpg",
    "https://cdn.example.com/products/102-thumb.jpg"
  ],
  "items": [
    {
      "id": 1,
      "productId": 101,
      "quantity": 1,
      "unitMrp": 12000,
      "unitSp": 11500,
      "discount": 500,
      "finalValue": 11500,
      "thumbnailUrl": "https://cdn.example.com/products/101-thumb.jpg",
      "productTitle": "Green Tara Thangka",
      "productSlug": "green-tara-thangka",
      "serialNumber": "SN-2024-ABC123",
      "subscriptionInfo": null
    }
  ],
  "finalPayable": 11500
"

For physical orders, finalPayable includes shipping fee.

7. Enums

7.1 order_type

  • digital
  • physical
  • care_package
  • mixed

7.2 order_payment_method

  • online
  • cod
  • pos

7.3 order_status

  • created
  • payment_pending
  • paid
  • payment_failed
  • cancelled
  • refund_requested
  • refund_pending
  • refund_approved
  • refund_rejected

Current manual refund flow does not transition through refund_pending; approvals/rejections are applied directly by admin action.

7.4 order_status_actor_type

  • customer
  • admin
  • system

7.5 order_source

  • checkout
  • buy_now
  • training_enroll
  • admin_manual

7.6 refund_status

  • requested
  • pending
  • approved
  • rejected

Current manual refund flow uses requested -> approved|rejected; pending remains a legacy enum value.

7.7 order_fulfillment_status

  • received — default initial state
  • ready — physical/mixed only
  • picked_up — physical/mixed only
  • in_transit — physical/mixed only
  • delivered — physical/mixed terminal
  • key_sent — digital terminal
  • activated — care_package terminal

8. Integration Diagram

9. Caching

Cache keyspaces:

  • order:customer:list:
  • order:detail:
  • order:admin:list:
  • order:admin:detail:
  • order: (detail-specific state key)

TTL envs:

  • ORDER_HISTORY_CACHE_TTL_SECONDS (default 120)
  • ORDER_ADMIN_CACHE_TTL_SECONDS (default 60)

Invalidation triggers:

  • customer/admin mutation services invalidate related prefixes after accepted commands

10. Endpoint Reference + Payload Cheatsheet

10.1 Payload Cheatsheet Table (Every Endpoint)

MethodPathAuth / PermissionRequest DTO / ParamsSuccess DTONotes
POST/api/orders/checkoutUser JWTCheckoutDto "" gateway: "stripe"|"esewa"|"fonepay"|"connect_ips"|"cod", returnUrl: string ""PaymentInitResponseDtoCreates order from active cart, initiates payment; idempotency via header
GET/api/ordersUser JWTQueryOrdersDto "" page?, size?, pagination?, status?, fulfillmentStatus?, sort?, order? ""OrderListItemResponseDto[] paginatedReturns current user's order history; filters by order status and fulfillment status; includes orderThumbnails (max 2)
GET/api/orders/:idUser JWTpath: id (int)OrderDetailResponseDtoFetches single order detail; validates ownership
GET/api/orders/requests/:requestIdUser JWTpath: requestId (string)AsyncRequestResponseDtoPolls async operation status (cancel/refund processing)
POST/api/orders/:id/cancelUser JWTpath: id (int), body: CancelOrderDto "" reason?: string ""AsyncRequestResponseDtoAsync cancellation; returns requestId for polling
POST/api/orders/:id/request-refundUser JWTpath: id (int), body: RequestRefundDto "" reason: string, remarks?: string ""OrderResponseDtoSynchronous refund request; checks order eligibility
GET/api/admin/orders/analyticsAdmin + Orders_READQueryOrderAnalyticsAdminDto "" range?, bucket?, fromDate?, toDate?, district? ""OrderAdminAnalyticsDtoOrder analytics summary with optional district filter
GET/api/admin/orders/analytics/districtsAdmin + Orders_READQueryOrderAnalyticsAdminDto "" range?, bucket?, fromDate?, toDate?, district? ""OrderDistrictAggregationDto[]Full district aggregation for map/heatmap; optional district filter
GET/api/admin/ordersAdmin + Orders_READQueryOrdersAdminDto "" page?, size?, pagination?, status?, paymentMethod?, paymentStatus?, orderType?, search?, sort?, order? ""OrderAdminListItemDto[] paginatedAdmin order list with filters; search by order number/customer
GET/api/admin/orders/:idAdmin + Orders_READpath: id (int)OrderAdminDetailDtoAdmin order detail with status history and items
GET/api/admin/orders/:id/invoice-downloadAdmin + Orders_READpath: id (int)application/pdfAdmin downloads fresh invoice PDF for any order
GET/api/admin/orders/requests/:requestIdAdmin + Orders_READpath: requestId (string)AsyncRequestResponseDtoAdmin polls async operation status
POST/api/admin/orders/:id/cancelAdmin + Orders_UPDATEpath: id (int), body: CancelOrderAdminDto "" reason?: string ""AsyncRequestResponseDtoAdmin-triggered order cancellation
POST/api/admin/orders/:id/process-refundAdmin + Orders_UPDATEpath: id (int), body: ProcessRefundDto "" action: "approve"|"reject", remarks: string ""AsyncRequestResponseDtoAdmin approves/rejects refund request
POST/api/admin/orders/:id/notesAdmin + Orders_UPDATEpath: id (int), body: AddNoteDto "" note: string ""OrderAdminNoteResponseDtoAdds internal admin note to order
POST/api/admin/orders/:id/send-digital-deliveryAdmin + DigitalKeys_SEND_DELIVERYpath: id (int)SendDigitalDeliveryResponseDtoAssigns digital keys and emails delivery to customer
POST/api/admin/orders/:id/activate-care-packageAdmin + CarePackageSubscriptions_UPDATEpath: id (int)ActivateCarePackageResponseDtoManually activates pending care package subscriptions on the order
PATCH/api/admin/orders/:id/items/:orderItemId/serialAdmin + Orders_UPDATEpath: orderId (int), orderItemId (int); body: AssignSerialNumberDto { serialNumber: string }AssignSerialNumberResponseDtoAssigns a serial number to a physical order item
PUT/api/admin/orders/:id/cod-collectAdmin + Orders_UPDATEpath: id (int); body: CollectCodDto { remarks: string }CollectCodResponseDtoRecords physical COD cash collection. Idempotent: returns existing data if already collected.
GET/api/admin/orders/:id/digital-keysAdmin + Orders_READpath: id (int)OrderDigitalKeysResponseDtoReturns digital keys assigned to order items
GET/api/payments/redirect/:paymentId/successPublicpath: paymentId (int), query: gateway response paramsHTTP 302 redirectProcesses payment success callback; queues verification job
POST/api/payments/redirect/:paymentId/successPublicpath: paymentId (int), body: gateway response paramsHTTP 302 redirectHandles form-post payment success callback
GET/api/payments/redirect/:paymentId/failurePublicpath: paymentId (int), query: gateway response paramsHTTP 302 redirectProcesses payment failure callback
POST/api/payments/redirect/:paymentId/failurePublicpath: paymentId (int), body: gateway response paramsHTTP 302 redirectHandles form-post payment failure callback
GET/api/payments/resultPublicquery: payment_status, payment_id, reference_type, reference_id, nextHTML pageRenders payment result page with redirect to frontend

10.1.1 Customer List Endpoint Query Variations

MethodPathQuery ParametersNotes
GET/api/orders(no params)Default: page=1, size=20, sort=createdAt, order=desc
GET/api/orders?page=2&size=10Custom page and size
GET/api/orders?status=paidFilter by order status
GET/api/orders?fulfillmentStatus=deliveredFilter by fulfillment status
GET/api/orders?status=paid&fulfillmentStatus=in_transitFilter by order + fulfillment status
GET/api/orders?status=payment_pending&sort=updatedAt&order=ascFilter + sort combo
GET/api/orders?pagination=falseReturns all records (no pagination)

10.1.2 Admin List Endpoint Query Variations

MethodPathQuery ParametersNotes
GET/api/admin/orders(no params)Default: page=1, size=20, sort=createdAt, order=desc
GET/api/admin/orders?page=3&size=50Custom pagination
GET/api/admin/orders?status=paid&paymentStatus=completedFilter by order + payment status
GET/api/admin/orders?paymentMethod=cod&paymentStatus=cod_pendingFilter uncollected COD orders
GET/api/admin/orders?paymentMethod=online&orderType=physicalFilter by payment method + order type
GET/api/admin/orders?search=ORD123Search by order number, customer name/email/phone
GET/api/admin/orders?status=cancelled&sort=updatedAt&order=descFilter + custom sort
GET/api/admin/orders?paymentStatus=failedFilter by failed payment
GET/api/admin/orders?refundStatus=requestedFilter by refund status (admin view)

10.1.3 Checkout/Buy-now Request Variations

MethodPathRequest BodyNotes
POST/api/orders/checkout"" "gateway": "stripe", "returnUrl": "https://example.com/return" ""Full cart checkout (preferred)
POST/api/orders/checkout"" "gateway": "esewa", "returnUrl": "https://example.com/return" ""Legacy cart checkout
POST/api/orders/checkout"" "gateway": "cod", "returnUrl": "https://example.com/return" ""COD checkout for physical or mixed carts; returns status=payment_pending
POST/api/orders/buy-now"" "productId": 101, "gateway": "stripe", "returnUrl": "https://example.com/return" ""Single product buy-now (preferred)
POST/api/orders/buy-now"" "productId": 101, "gateway": "fonepay", "returnUrl": "https://example.com/return", "promoCode": "SUMMER2026" ""Legacy gateway with promo code

10.1.4 Payment Init Response Variations

FieldValueNotes
initiationTypeform_postForm submission required
initiationTyperedirectURL redirect with query params
initiationTypecodNo gateway redirect; frontend navigates to returned redirectUrl
gatewaystripePreferred gateway
gatewayesewa / fonepay / connect_ipsLegacy gateways still supported
gatewaycodCash on delivery; payment row remains pending until admin collection
paymentId9001Internal payment reference
gatewayTransactionIdcs_test_a1b2c3d4e5Gateway-specific transaction ID
orderStatuspayment_pendingInitial order status after creation
paymentStatuspendingPayment awaiting completion
paymentStatuscod_pendingCOD order confirmed for fulfillment, cash not collected
paymentStatuscod_collectedAdmin recorded COD cash and completed the payment row

10.1.5 Async Request Status Response Variations

FieldValueNotes
statuspendingOperation in progress
statuscompletedOperation finished successfully
statusfailedOperation failed
result.orderStatuscancelledOrder cancelled
result.paymentStatusfailedPayment marked failed

10.1.6 Order Status Flow States

StatusPayment StatusNext Possible StatesNotes
createdpendingpayment_pendingInitial state
payment_pendingpendingpaid, payment_failed, cancelledAwaiting online payment
payment_pendingcod_pendingcancelled; payment status later changes to cod_collectedCOD confirmed for fulfillment, cash uncollected; warranty remains blocked
payment_pendingcod_collectedcancelledCOD cash collected; order status remains unchanged by collection; warranty becomes eligible
paidcompletedrefund_requested, cancelledPayment successful
payment_failedfailedcancelledPayment not received; warranty blocked
cancelledfailed- (terminal)Order cancelled; warranty blocked
refund_requestedcompletedrefund_approved, refund_rejectedCustomer requested refund; warranty still allowed until approval
refund_approvedcompleted- (terminal)Refund approved; warranty blocked
refund_rejectedcompleted- (terminal)Refund rejected; warranty remains allowed

10.1.7 Admin Action Variations

MethodPathBodyNotes
POST/api/admin/orders/101/cancel"" "reason": "Customer request" ""Cancel with reason
POST/api/admin/orders/101/cancel""Cancel without reason
POST/api/admin/orders/101/process-refund"" "action": "approve", "remarks": "Verified with payment team" ""Approve with remarks
POST/api/admin/orders/101/process-refund"" "action": "reject", "remarks": "Duplicate charge not confirmed" ""Reject refund
POST/api/admin/orders/101/notes"" "note": "Customer called, order will ship tomorrow" ""Add note
POST/api/admin/orders/101/activate-care-package(no body)Activate all pending subscriptions on care package order
PATCH/api/admin/orders/101/items/5/serial{ "serialNumber": "SN-2024-ABC123" }Assign serial number to item
PUT/api/admin/orders/101/cod-collect{ "remarks": "Collected at door by rider #12, cash NPR 3500" }Record COD cash collection

10.1.8 Error Response Variations

HTTPerrorCodeMessageScenario
400ORDER_CART_EMPTYCart has no items.Checkout with empty cart
400ORDER_PRODUCT_NOT_AVAILABLEProduct is not available for purchase.Buy-now unavailable product
400ORDER_SHIPPING_DISTRICT_REQUIREDShipping district is required before checkout or buy-now.Checkout/buy-now without selected shipping district
400ORDER_COD_PHYSICAL_ONLYCOD checkout attempted on digital-only or care-package-only cart/productCOD checkout on non-physical cart
400ORDER_NOT_COD_METHODAdmin COD cash collection attempted on a non-COD orderAdmin collect on non-COD order
400ORDER_PAYMENT_METHOD_NOT_SUPPORTEDOnly online payment is supported.Invalid payment method
400ORDER_CANCEL_NOT_ALLOWEDOrder cannot be cancelled in current status.Cancel non-cancellable order
400ORDER_DIGITAL_NOT_REFUNDABLEDigital product orders are non-refundable.Request refund on digital-only order
400ORDER_NOT_PENDING_REFUNDOrder is not pending refund processing.Process refund on non-pending order
404ORDER_NOT_FOUNDOrder not found.Invalid order ID
404ORDER_ACTIVE_CART_NOT_FOUNDActive cart not found.Checkout without cart
404ORDER_ASYNC_REQUEST_NOT_FOUNDAsync request not found.Invalid request ID
409ORDER_IDEMPOTENCY_MISMATCHRequest with this idempotency key is already in progress.Duplicate request
409ORDER_PAYMENT_FAILEDPrevious request with this idempotency key has failed.Retry failed checkout
429RATE_LIMIT_EXCEEDEDToo many requests. Please try again later.Rate limit hit
503ORDER_ASYNC_REQUEST_CREATION_FAILEDFailed to create async order request.Queue failure
400ORDER_FULFILLMENT_NOT_PHYSICAL_TYPEOrder type does not support fulfillment advance.Advance physical fulfillment on digital order
400ORDER_ACTIVATE_CARE_PACKAGE_NOT_APPLICABLEOrder is not a care package type.Activate care package on physical order
400ORDER_NOT_PAIDOrder must be in paid status.Serial assignment on unpaid order
409ORDER_SERIAL_ALREADY_ASSIGNEDSerial number already assigned to this item.Duplicate serial assign
409ORDER_SERIAL_DUPLICATESerial number already in use.Same serial on different item
422ORDER_BUYNOW_CARE_PACKAGE_NOT_ALLOWEDCare package products do not support buy-now.Buy-now with care_package productKind
422ORDER_SERIAL_ITEM_NOT_PHYSICALSerial number can only be assigned to physical items.Serial on digital item
422ORDER_SERIAL_AFTER_DELIVEREDCannot assign serial after order is delivered.Serial on delivered order

10.1.9 Cache Key Patterns

Cache KeyPatternTTL (seconds)Invalidation
Customer order listorder:customer:list:pagination:"page"-size:"size"-sort:"sort"-order:"order"-status:"status"-fulfillmentStatus:"fulfillmentStatus"120Order mutation (cancel, refund)
Customer order detailorder:detail:"orderId"120Order status change
Admin order listorder:admin:list:pagination:"page"-size:"size"-sort:"sort"-order:"order"-filters...60Admin order mutations
Admin order detailorder:admin:detail:"orderId"60Admin status changes
Admin analyticsorder:admin:analytics:admin:"adminId"-range:"range"-bucket:"bucket"-from:"from"-to:"to"-district:"district"60 (env ORDER_ADMIN_CACHE_TTL_SECONDS)Order mutation
Admin district aggregationorder:admin:analytics:districts:admin:"adminId"-range:"range"-from:"from"-to:"to"-district:"district"60 (env ORDER_ADMIN_CACHE_TTL_SECONDS)Order mutation

10.1.10 Rate Limit Patterns

Route FamilyKey PatternLimit
Customer checkoutrl:orders:customer:action:checkout-key:"userId"10 req/min
Customer buy-nowrl:orders:customer:action:buynow-key:"userId"10 req/min
Customer listrl:orders:customer:action:list-key:"userId"60 req/min
Customer cancelrl:orders:customer:action:cancel-key:"userId"5 req/min
Admin ordersrl:orders:admin:action:list-key:"adminId"60 req/min
Admin mutationsrl:orders:admin:action:mutate-key:"adminId"20 req/min

10.1.11 Digital Delivery Endpoints

POST /api/admin/orders/:id/send-digital-delivery

PropertyValue
AuthJWT + DigitalKeys_SEND_DELIVERY permission
Path paramid — order ID (integer)

Success response (HTTP 200):

{
  "orderId": 101,
  "deliveredItems": [
    {
      "orderItemId": 1,
      "productTitle": "Microsoft Office 365 Home — Annual",
      "keyValue": "N7TV2-2WY7D-MXV8T-P3D9R-6K4FB",
      "licenseType": "annual",
      "duration": 12,
      "durationUnit": "months"
    }
  ],
  "emailSentTo": "customer@example.com",
  "fulfillmentStatus": "key_sent"
}
ErrorHTTPCondition
ORDER_NOT_PAID400Order is not in paid status
ORDER_NOT_DIGITAL400Order has no digital items
ORDER_DIGITAL_ALREADY_DELIVERED409Digital keys already sent for this order
DIGITAL_KEY_NOT_FOUND422Insufficient available keys in pool for one or more products

GET /api/admin/orders/:id/digital-keys

PropertyValue
AuthJWT + Orders_READ permission
Path paramid — order ID (integer)

Success response (HTTP 200):

{
  "orderId": 101,
  "items": [
    {
      "orderItemId": 1,
      "productId": 42,
      "productTitle": "Microsoft Office 365 Home — Annual",
      "keyValue": "N7TV2-2WY7D-MXV8T-P3D9R-6K4FB",
      "status": "assigned",
      "assignedAt": "2026-06-11T12:00:00.000Z"
    }
  ]
}

10.1.12 Job/Queue Payloads

Job NamePayloadTrigger
order.payment_success"" orderId: number, paymentReference: string, transactionId?: string ""Payment gateway success callback
order.payment_failed"" orderId: number, reason?: string ""Payment gateway failure callback
order.payment_retry"" orderId: number, paymentId: number, attempt: number, maxAttempts: number ""Retry logic for online payments; skips COD cod_pending orders
order.cancel"" orderId: number, reason?: string, cancelledBy: string, cancelledByActorType: "customer"|"admin" ""Cancel endpoint
order.process_refund"" orderId: number, adminId: string, action: "approve"|"reject", amount?: number, remarks: string ""Admin refund processing
order.auto_cancel"" orderId: number, reason: string ""Scheduled auto-cancel for unpaid online orders; skips COD

10.1.12 Transactional Notification Events

EventPayload HighlightsChannels
ORDER_PLACED_CHECKOUTorderId, orderNumber, total, itemsPush, Email
ORDER_PLACED_BUYNOWorderId, orderNumber, product, pricePush, Email
ORDER_PAYMENT_RECEIVED_CHECKOUTorderId, orderNumber, paymentReferencePush, Email
ORDER_PAYMENT_RECEIVED_BUYNOWorderId, orderNumber, paymentReferencePush, Email
ORDER_PAYMENT_FAILEDorderId, orderNumber, reasonPush, Email
ORDER_CANCELLEDorderId, orderNumber, cancelledBy, reasonPush, Email
ORDER_REFUND_REQUESTEDorderId, orderNumber, reason, amountPush, Email (admin)
ORDER_REFUND_APPROVEDorderId, orderNumber, amountPush, Email
ORDER_REFUND_REJECTEDorderId, orderNumber, reasonPush, Email

10.1.13 Inventory Outbox Events (Post-Payment Lifecycle)

EventPayloadConditions
stock.reserveorderId, items[]Order created from checkout/buy-now
stock.finalizeorderId, items[]Online payment verified as completed, or COD reservation confirmed with paymentStatus=cod_pending
stock.releaseorderId, items[]Payment failed, timed out, or cancelled before finalize
stock.adjustorderId, items[]Cancellation after finalized stock deduction (restock compensation)

10.1.14 DTO Field Reference

CheckoutDto

FieldTypeRequiredValidationNotes
gatewayenumYes"stripe"|"esewa"|"fonepay"|"connect_ips"|"cod"Payment gateway selection
returnUrlstringYesValid URLFrontend return destination

BuyNowCheckoutDto

FieldTypeRequiredValidationNotes
productIdnumberYesPositive integerProduct to purchase
gatewayenumYes"stripe"|"esewa"|"fonepay"|"connect_ips"|"cod"Payment gateway
returnUrlstringYesValid URLFrontend return destination
promoCodestringNo3-50 charsOptional promo code

QueryOrderAnalyticsAdminDto

FieldTypeRequiredValidationNotes
rangeenumNo"daily" | "weekly" | "monthly" | "yearly" | "custom"Preset range. Use fromDate/toDate for custom range. Default: "monthly"
bucketenumNo"day" | "week" | "month"Trend bucket granularity for chart data
fromDatestringNoISO date (YYYY-MM-DD)Start date. Required when range=custom
toDatestringNoISO date (YYYY-MM-DD)End date. Required when range=custom
districtstringNoNon-empty stringFilter analytics by shipping district. Omitting returns all districts

CancelOrderDto / CancelOrderAdminDto

FieldTypeRequiredValidationNotes
reasonstringNoMax 500 charsCancellation reason

RequestRefundDto

FieldTypeRequiredValidationNotes
reasonstringYes1-500 charsRefund reason
remarksstringNoMax 1000 charsAdditional details

ProcessRefundDto

FieldTypeRequiredValidationNotes
actionenumYes"approve"|"reject"Refund decision
remarksstringYes1-500 charsAdmin remarks

AddNoteDto

FieldTypeRequiredValidationNotes
notestringYes1-1000 charsAdmin note content

OrderItemResponseDto (customer)

FieldTypeRequiredValidationNotes
serialNumberstring | nullNoAssigned serial number (physical items only)
subscriptionInfoobject | nullNoCare package subscription info (care_package items only); shape: { status, startDate, expiryDate, durationMonths, carePackageName }

OrderAdminItemResponseDto (admin)

FieldTypeNotes
idnumberOrder item ID
productIdnumber | nullProduct ID
quantitynumber
unitMrpnumber
unitSpnumber
discountnumber
finalValuenumber
productKindstring | nullphysical, digital, care_package
serialNumberstring | nullAdmin-assigned serial (physical only)
subscriptionDetailobject | null{ status, startDate, expiryDate, durationMonths, carePackageName } — care_package items only
digitalKeyValuestring | nullAssigned key value — admin view only, NOT exposed to customer

AssignSerialNumberDto

FieldTypeRequiredValidation
serialNumberstringYesNon-empty, max 100 chars

OrderAdminDetailDto (admin detail) — updated fields

  • fulfillmentStatus: string — current fulfillment status
  • eligibleFulfillmentActions: string[] — available actions based on orderType + fulfillmentStatus
  • items: OrderAdminItemResponseDto[] — replaces generic OrderItemResponseDto[]

11. Testing Scenarios

11.1 Customer Checkout Flow

Test Case: Successful checkout via stripe

  1. User has items in active cart
  2. POST /api/orders/checkout with "" "gateway": "stripe", "returnUrl": "https://app.com/payment/return" ""
  3. Expect 200 with PaymentInitResponseDto containing redirectUrl and gatewayPayload
  4. Redirect user to Stripe checkout URL
  5. Verify user redirected back to /api/payments/redirect/:paymentId/success
  6. Verify order status becomes paid after queue processing

11.2 Customer Buy-now Flow

Test Case: Buy-now with promo code

  1. User selects single product
  2. POST /api/orders/buy-now with "" "productId": 101, "gateway": "stripe", "returnUrl": "https://app.com/payment/return", "promoCode": "SUMMER2026" ""
  3. Expect 200 with payment initiation payload
  4. Complete payment via Stripe Checkout
  5. Verify promo discount applied to finalPayable

11.3 Customer Order List with Filters

Test Case: Filter orders by status

  1. Authenticated user with multiple orders
  2. GET /api/orders?status=paid&page=1&size=10
  3. Expect 200 with paginated list of paid orders only
  4. Verify pagination metadata accurate

11.4 Customer Cancel Order

Test Case: Cancel order in valid status

  1. User has order with status payment_pending
  2. POST /api/orders/101/cancel with "" "reason": "Changed my mind" ""
  3. Expect 202 with AsyncRequestResponseDto containing requestId
  4. Poll GET /api/orders/requests/:requestId until status: "completed"
  5. Verify order status changed to cancelled

11.5 Customer Request Refund

Test Case: Request refund on paid order

  1. User has order with status paid
  2. POST /api/orders/101/request-refund with "" "reason": "Product not as described", "remarks": "Please check with seller" ""
  3. Expect 200 with order detail showing refundStatus: "requested"
  4. Verify refund reason stored in order

11.6 Admin Process Refund

Test Case: Admin approves refund request

  1. Admin retrieves order with refundStatus: "requested"
  2. POST /api/admin/orders/101/process-refund with "" "action": "approve", "remarks": "Approved after verification" ""
  3. Expect 202 with async request response
  4. Poll until completion
  5. Verify order refundStatus becomes approved

Test Case: Search orders by order number

  1. Admin wants to find specific order
  2. GET /api/admin/orders?search=ORD12345678
  3. Expect 200 with matching orders
  4. Verify search matches order number, customer name, email, or phone

11.8 Payment Failure Handling

Test Case: Payment gateway returns failure

  1. User initiates checkout
  2. User cancels/aborts at gateway
  3. Gateway redirects to /api/payments/redirect/:paymentId/failure
  4. Backend processes failure callback
  5. Order status changes to payment_failed or cancelled
  6. User sees payment failure page with retry option

12. Integration Flow Recipes

12.1 Mobile App: Complete Purchase Flow

  1. Initialize cart: Ensure user has items in cart via Cart module
  2. Initiate checkout:
    • POST /api/mobile/orders/checkout with "" "gateway": "stripe", "returnUrl": "https://yourapp.com/payment-result" ""
    • Capture returned paymentId, redirectUrl, gatewayPayload
  3. Redirect to gateway:
    • If initiationType === "form_post", auto-submit form with gatewayPayload to redirectUrl
    • If initiationType === "redirect", navigate browser to redirectUrl with query params
  4. Handle callback:
    • Gateway redirects to /api/payments/redirect/:paymentId/success (or failure)
    • Backend processes and redirects to payment result page with next param
  5. Poll for status:
    • After redirect, call GET /api/orders/:orderId to verify status
    • Or GET /api/orders/requests/:requestId if used async flow
  6. Show result:
    • If orderStatus === "paid", show success, unlock access
    • If orderStatus === "payment_failed", show failure, offer retry

12.2 Admin: Handle Customer Refund Request

  1. Receive refund request: Customer submits via app
  2. Review order:
    • GET /api/admin/orders/:orderId to view full order details
    • Check payment reference, transaction history
    • Verify product not already consumed (for digital: check access grants)
  3. Make decision:
    • Approve: POST /api/admin/orders/:orderId/process-refund with "" "action": "approve", "remarks": "Refund approved" ""
    • Reject: POST /api/admin/orders/:orderId/process-refund with "" "action": "reject", "remarks": "Reason for rejection" ""
  4. Track async operation:
    • Poll GET /api/admin/orders/requests/:requestId until completed
    • Verify final order state reflects decision
  5. Add admin note:
    • POST /api/admin/orders/:orderId/notes with note for audit trail

12.3 Webhook: Payment Gateway Callback Processing

  1. Receive callback:
    • Payment gateway POSTs to /api/payments/redirect/:paymentId/success (or /failure)
    • Request contains gateway-specific fields (transaction_uuid, total_amount, etc.)
  2. Validate payload:
    • Backend verifies signature if provided
    • Matches paymentId with internal records
  3. Queue processing job:
    • order.payment_success or order.payment_failed job added to queue
  4. Async processing:
    • Worker updates order status
    • Worker creates/entitles product access (on success)
    • Worker emits transactional notifications
  5. Redirect to frontend:
    • Backend redirects to /api/payments/result with status params
    • Frontend shows result page and redirects to app deep link

13. Error Handling

All order API errors return the standard error envelope:

"
  "statusCode": 404,
  "errorCode": "ORDER_NOT_FOUND",
  "message": "Order not found.",
  "timestamp": "2026-03-20T10:00:00.000Z",
  "path": "/api/orders/123"
"

Representative error map:

HTTPerrorCodeMessage
400ORDER_CART_EMPTYCart has no items.
400ORDER_PRODUCT_NOT_AVAILABLEProduct is not available for purchase.
400ORDER_PAYMENT_METHOD_NOT_SUPPORTEDOnly online payment is supported.
400ORDER_CANCEL_NOT_ALLOWEDOrder cannot be cancelled in current status.
400ORDER_DIGITAL_NOT_REFUNDABLEDigital product orders are non-refundable.
400ORDER_NOT_PENDING_REFUNDOrder is not pending refund processing.
400ORDER_IDEMPOTENCY_KEY_TOO_LONGIdempotency key must be 200 characters or less.
404ORDER_ACTIVE_CART_NOT_FOUNDActive cart not found.
404ORDER_ASYNC_REQUEST_NOT_FOUNDAsync request not found.
404ORDER_NOT_FOUNDOrder not found.
409ORDER_IDEMPOTENCY_MISMATCHRequest with this idempotency key is already in progress.
409ORDER_PAYMENT_FAILEDPrevious request with this idempotency key has failed.
429RATE_LIMIT_EXCEEDEDToo many requests. Please try again later.
503ORDER_ASYNC_REQUEST_CREATION_FAILEDFailed to create async order request.
503ERR_CONFIG_INVALIDConfiguration validation failed.

Time fields in this module are stored as timezone-aware values and should be handled as ISO-8601 instants by API consumers.


See Also

On this page

Order Module - API & Integration Guide1. How to Read / Quick Metadata2. High-Level Overview3. Core Concepts and Terminology4. Route Summary4.1 Customer / Mobile4.2 Admin4.3 Payment Redirect and ResultRoute DetailsCheckoutGet Orders5. Query Parameters5.1 Customer list (GET /api/orders)5.2 Admin list (GET /api/admin/orders)6. Response Shape Examples6.1 Checkout request6.2 Buy-now request6.3 Payment-init response (200 OK)6.4 Async request status response6.5 Admin status history item (actor provenance)6.6 Order response (with shipping)7. Enums7.1 order_type7.2 order_payment_method7.3 order_status7.4 order_status_actor_type7.5 order_source7.6 refund_status7.7 order_fulfillment_status8. Integration Diagram9. Caching10. Endpoint Reference + Payload Cheatsheet10.1 Payload Cheatsheet Table (Every Endpoint)10.1.1 Customer List Endpoint Query Variations10.1.2 Admin List Endpoint Query Variations10.1.3 Checkout/Buy-now Request Variations10.1.4 Payment Init Response Variations10.1.5 Async Request Status Response Variations10.1.6 Order Status Flow States10.1.7 Admin Action Variations10.1.8 Error Response Variations10.1.9 Cache Key Patterns10.1.10 Rate Limit Patterns10.1.11 Digital Delivery EndpointsPOST /api/admin/orders/:id/send-digital-deliveryGET /api/admin/orders/:id/digital-keys10.1.12 Job/Queue Payloads10.1.12 Transactional Notification Events10.1.13 Inventory Outbox Events (Post-Payment Lifecycle)10.1.14 DTO Field ReferenceCheckoutDtoBuyNowCheckoutDtoQueryOrderAnalyticsAdminDtoCancelOrderDto / CancelOrderAdminDtoRequestRefundDtoProcessRefundDtoAddNoteDtoOrderItemResponseDto (customer)OrderAdminItemResponseDto (admin)AssignSerialNumberDtoOrderAdminDetailDto (admin detail) — updated fields11. Testing Scenarios11.1 Customer Checkout Flow11.2 Customer Buy-now Flow11.3 Customer Order List with Filters11.4 Customer Cancel Order11.5 Customer Request Refund11.6 Admin Process Refund11.7 Admin Order Search11.8 Payment Failure Handling12. Integration Flow Recipes12.1 Mobile App: Complete Purchase Flow12.2 Admin: Handle Customer Refund Request12.3 Webhook: Payment Gateway Callback Processing13. Error HandlingSee Also