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(...)
- Customer/mobile routes:
- 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
- Customer:
- 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:
- Physical product types (
thangka,singing_bowl,statue,jewellery) are supported and createorderType: "physical".
3. Core Concepts and Terminology
- order: primary transaction entity (
ordertable) - order item: line-level monetary snapshot (
order_itemtable) - 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, andgatewayPayload
Current async order jobs:
order.payment_successorder.payment_failedorder.payment_retryorder.cancelorder.process_refundorder.auto_cancel
Current queue payload contracts:
| Job | Payload 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_BUYNOWORDER_PAYMENT_RECEIVED_CHECKOUT,ORDER_PAYMENT_RECEIVED_BUYNOWORDER_PAYMENT_FAILED,ORDER_CANCELLEDORDER_REFUND_REQUESTED,ORDER_REFUND_APPROVED,ORDER_REFUND_REJECTED
Order-to-inventory outbox events emitted by lifecycle stage:
stock.reserveafter checkout/buy-now order creationstock.finalizeafter verified payment successstock.releaseafter payment failure, cancellation, or expiry
Outbox/queue lifecycle for inventory coupling:
- Order service writes
outbox_eventswithtargetQueuefor inventory processing. - Outbox dispatcher claims pending inventory-target rows only from its owned queue set.
- Dispatcher enqueues reserve/finalize/release inventory jobs.
- 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
| Method | Path |
|---|---|
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
| Method | Path | Permission |
|---|---|---|
GET | /api/admin/orders | Orders_READ |
GET | /api/admin/orders/:id | Orders_READ |
GET | /api/admin/orders/requests/:requestId | Orders_READ |
POST | /api/admin/orders/:id/cancel | Orders_UPDATE |
POST | /api/admin/orders/:id/process-refund | Orders_UPDATE |
POST | /api/admin/orders/:id/notes | Orders_UPDATE |
4.3 Payment Redirect and Result
| Method | Path | Owner |
|---|---|---|
GET | /api/payments/redirect/:paymentId/success | PaymentRedirectController |
POST | /api/payments/redirect/:paymentId/success | PaymentRedirectController |
GET | /api/payments/redirect/:paymentId/failure | PaymentRedirectController |
POST | /api/payments/redirect/:paymentId/failure | PaymentRedirectController |
GET | /api/payments/result | PaymentResultController |
Route Details
Checkout
| Aspect | Details |
|---|---|
| Endpoint | POST /api/orders/checkout or /api/mobile/orders/checkout |
| Auth | JwtAuthGuard |
| Request | paymentMethod: "esewa" or "khalti" + paymentId: string |
| Response | ResponseDto<OrderConfirmationDto> |
| Errors | 400 invalid cart, 400 payment failed |
Get Orders
| Aspect | Details |
|---|---|
| Endpoint | GET /api/orders or /api/mobile/orders |
| Auth | JwtAuthGuard |
| Request | pagination, status filter |
| Response | ResponseDto<OrderDto[]> |
| Errors | - |
5. Query Parameters
5.1 Customer list (GET /api/orders)
| Param | Type | Default |
|---|---|---|
page | number | 1 |
size | number | 20 |
pagination | boolean | true |
status | enum(order_status) | optional |
sort | createdAt | updatedAt | createdAt |
order | asc | desc | desc |
5.2 Admin list (GET /api/admin/orders)
| Param | Type | Default |
|---|---|---|
page | number | 1 |
size | number | 20 |
pagination | boolean | true |
status | enum(order_status) | optional |
paymentMethod | enum(order_payment_method) | optional |
paymentStatus | pending | completed | failed | optional |
orderType | enum(order_type) | optional |
search | string | optional |
sort | createdAt | updatedAt | createdAt |
order | asc | desc | desc |
6. Response Shape Examples
6.1 Checkout request
"
"gateway": "esewa",
"returnUrl": "https://example.com/payment/return"
"6.2 Buy-now request
"
"productId": 101,
"gateway": "esewa",
"returnUrl": "https://example.com/payment/return",
"promoCode": "SUMMER2026"
"6.3 Payment-init response (200 OK)
"
"orderId": 101,
"status": "payment_pending",
"paymentId": 9001,
"gatewayTransactionId": "9001-1774884775940",
"initiationType": "form_post",
"redirectUrl": "https://rc-epay.esewa.com.np/api/epay/main/v2/form",
"gatewayPayload": "
"amount": "1300.00",
"tax_amount": "0.00",
"total_amount": "1300.00",
"transaction_uuid": "9001-1774884775940",
"product_code": "EPAYTEST",
"product_service_charge": "0.00",
"product_delivery_charge": "0.00",
"success_url": "https://api.example.com/api/payments/redirect/9001/success",
"failure_url": "https://api.example.com/api/payments/redirect/9001/failure",
"signed_field_names": "total_amount,transaction_uuid,product_code",
"signature": "Tgk0luEqSxFj7qTrTs4w2zT61P1oM8oq+cm289bwgtU="
""
"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"
"7. Enums
7.1 order_type
digitalphysical
7.2 order_payment_method
online
7.3 order_status
createdpayment_pendingpaidpayment_failedcancelledrefund_requestedrefund_pendingrefund_approvedrefund_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
customeradminsystem
7.5 order_source
checkoutbuy_nowadmin_manual
7.6 refund_status
requestedpendingapprovedrejected
Current manual refund flow uses requested -> approved|rejected; pending remains a legacy enum value.
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(default120)ORDER_ADMIN_CACHE_TTL_SECONDS(default60)
Invalidation triggers:
- customer/admin mutation services invalidate related prefixes after accepted commands
10. Endpoint Reference + Payload Cheatsheet
10.1 Payload Cheatsheet Table (Every Endpoint)
| Method | Path | Auth / Permission | Request DTO / Params | Success DTO | Notes |
|---|---|---|---|---|---|
| POST | /api/orders/checkout | User JWT | CheckoutDto "" gateway: "esewa"|"khalti", returnUrl: string "" | PaymentInitResponseDto | Creates order from active cart, initiates payment; idempotency via header |
| GET | /api/orders | User JWT | QueryOrdersDto "" page?, size?, pagination?, status?, sort?, order? "" | OrderListItemResponseDto[] paginated | Returns current user's order history; filters by status |
| GET | /api/orders/:id | User JWT | path: id (int) | OrderDetailResponseDto | Fetches single order detail; validates ownership |
| GET | /api/orders/requests/:requestId | User JWT | path: requestId (string) | AsyncRequestResponseDto | Polls async operation status (cancel/refund processing) |
| POST | /api/orders/:id/cancel | User JWT | path: id (int), body: CancelOrderDto "" reason?: string "" | AsyncRequestResponseDto | Async cancellation; returns requestId for polling |
| POST | /api/orders/:id/request-refund | User JWT | path: id (int), body: RequestRefundDto "" reason: string, remarks?: string "" | OrderResponseDto | Synchronous refund request; checks order eligibility |
| GET | /api/admin/orders | Admin + Orders_READ | QueryOrdersAdminDto "" page?, size?, pagination?, status?, paymentMethod?, paymentStatus?, orderType?, search?, sort?, order? "" | OrderAdminListItemDto[] paginated | Admin order list with filters; search by order number/customer |
| GET | /api/admin/orders/:id | Admin + Orders_READ | path: id (int) | OrderAdminDetailDto | Admin order detail with status history and items |
| GET | /api/admin/orders/requests/:requestId | Admin + Orders_READ | path: requestId (string) | AsyncRequestResponseDto | Admin polls async operation status |
| POST | /api/admin/orders/:id/cancel | Admin + Orders_UPDATE | path: id (int), body: CancelOrderAdminDto "" reason?: string "" | AsyncRequestResponseDto | Admin-triggered order cancellation |
| POST | /api/admin/orders/:id/process-refund | Admin + Orders_UPDATE | path: id (int), body: ProcessRefundDto "" action: "approve"|"reject", remarks: string "" | AsyncRequestResponseDto | Admin approves/rejects refund request |
| POST | /api/admin/orders/:id/notes | Admin + Orders_UPDATE | path: id (int), body: AddNoteDto "" note: string "" | OrderAdminNoteResponseDto | Adds internal admin note to order |
| GET | /api/payments/redirect/:paymentId/success | Public | path: paymentId (int), query: gateway response params | HTTP 302 redirect | Processes payment success callback; queues verification job |
| POST | /api/payments/redirect/:paymentId/success | Public | path: paymentId (int), body: gateway response params | HTTP 302 redirect | Handles form-post payment success callback |
| GET | /api/payments/redirect/:paymentId/failure | Public | path: paymentId (int), query: gateway response params | HTTP 302 redirect | Processes payment failure callback |
| POST | /api/payments/redirect/:paymentId/failure | Public | path: paymentId (int), body: gateway response params | HTTP 302 redirect | Handles form-post payment failure callback |
| GET | /api/payments/result | Public | query: payment_status, payment_id, reference_type, reference_id, next | HTML page | Renders payment result page with redirect to frontend |
10.1.1 Customer List Endpoint Query Variations
| Method | Path | Query Parameters | Notes |
|---|---|---|---|
| GET | /api/orders | (no params) | Default: page=1, size=20, sort=createdAt, order=desc |
| GET | /api/orders | ?page=2&size=10 | Custom page and size |
| GET | /api/orders | ?status=paid | Filter by order status |
| GET | /api/orders | ?status=payment_pending&sort=updatedAt&order=asc | Filter + sort combo |
| GET | /api/orders | ?pagination=false | Returns all records (no pagination) |
10.1.2 Admin List Endpoint Query Variations
| Method | Path | Query Parameters | Notes |
|---|---|---|---|
| GET | /api/admin/orders | (no params) | Default: page=1, size=20, sort=createdAt, order=desc |
| GET | /api/admin/orders | ?page=3&size=50 | Custom pagination |
| GET | /api/admin/orders | ?status=paid&paymentStatus=completed | Filter by order + payment status |
| GET | /api/admin/orders | ?paymentMethod=online&orderType=physical | Filter by payment method + order type |
| GET | /api/admin/orders | ?search=ORD123 | Search by order number, customer name/email/phone |
| GET | /api/admin/orders | ?status=cancelled&sort=updatedAt&order=desc | Filter + custom sort |
| GET | /api/admin/orders | ?paymentStatus=failed | Filter by failed payment |
| GET | /api/admin/orders | ?refundStatus=requested | Filter by refund status (admin view) |
10.1.3 Checkout/Buy-now Request Variations
| Method | Path | Request Body | Notes |
|---|---|---|---|
| POST | /api/orders/checkout | "" "gateway": "esewa", "returnUrl": "https://example.com/return" "" | Full cart checkout with esewa |
| POST | /api/orders/checkout | "" "gateway": "khalti", "returnUrl": "https://example.com/return" "" | Full cart checkout with khalti |
| POST | /api/orders/buy-now | "" "productId": 101, "gateway": "esewa", "returnUrl": "https://example.com/return" "" | Single product buy-now |
| POST | /api/orders/buy-now | "" "productId": 101, "gateway": "khalti", "returnUrl": "https://example.com/return", "promoCode": "SUMMER2026" "" | Buy-now with promo code |
10.1.4 Payment Init Response Variations
| Field | Value | Notes |
|---|---|---|
| initiationType | form_post | Form submission required |
| initiationType | redirect | URL redirect with query params |
| gateway | esewa | eSewa gateway |
| gateway | khalti | Khalti gateway |
| paymentId | 9001 | Internal payment reference |
| gatewayTransactionId | 9001-1774884775940 | Gateway-specific transaction ID |
| orderStatus | payment_pending | Initial order status after creation |
| paymentStatus | pending | Payment awaiting completion |
10.1.5 Async Request Status Response Variations
| Field | Value | Notes |
|---|---|---|
| status | pending | Operation in progress |
| status | completed | Operation finished successfully |
| status | failed | Operation failed |
| result.orderStatus | cancelled | Order cancelled |
| result.paymentStatus | failed | Payment marked failed |
10.1.6 Order Status Flow States
| Status | Payment Status | Next Possible States | Notes |
|---|---|---|---|
created | pending | payment_pending | Initial state |
payment_pending | pending | paid, payment_failed, cancelled | Awaiting payment |
paid | completed | refund_requested, cancelled | Payment successful |
payment_failed | failed | cancelled | Payment not received |
cancelled | failed | - (terminal) | Order cancelled |
refund_requested | completed | refund_approved, refund_rejected | Customer requested refund |
refund_approved | completed | - (terminal) | Refund approved |
refund_rejected | completed | - (terminal) | Refund rejected |
10.1.7 Admin Action Variations
| Method | Path | Body | Notes |
|---|---|---|---|
| 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 |
10.1.8 Error Response Variations
| HTTP | errorCode | Message | Scenario |
|---|---|---|---|
| 400 | ORDER_CART_EMPTY | Cart has no items. | Checkout with empty cart |
| 400 | ORDER_PRODUCT_NOT_AVAILABLE | Product is not available for purchase. | Buy-now unavailable product |
| 400 | ORDER_PAYMENT_METHOD_NOT_SUPPORTED | Only online payment is supported. | Invalid payment method |
| 400 | ORDER_CANCEL_NOT_ALLOWED | Order cannot be cancelled in current status. | Cancel non-cancellable order |
| 400 | ORDER_NOT_PENDING_REFUND | Order is not pending refund processing. | Process refund on non-pending order |
| 404 | ORDER_NOT_FOUND | Order not found. | Invalid order ID |
| 404 | ORDER_ACTIVE_CART_NOT_FOUND | Active cart not found. | Checkout without cart |
| 404 | ORDER_ASYNC_REQUEST_NOT_FOUND | Async request not found. | Invalid request ID |
| 409 | ORDER_IDEMPOTENCY_MISMATCH | Request with this idempotency key is already in progress. | Duplicate request |
| 409 | ORDER_PAYMENT_FAILED | Previous request with this idempotency key has failed. | Retry failed checkout |
| 429 | RATE_LIMIT_EXCEEDED | Too many requests. Please try again later. | Rate limit hit |
| 503 | ORDER_ASYNC_REQUEST_CREATION_FAILED | Failed to create async order request. | Queue failure |
10.1.9 Cache Key Patterns
| Cache Key | Pattern | TTL (seconds) | Invalidation |
|---|---|---|---|
| Customer order list | order:customer:list:pagination:"page"-size:"size"-sort:"sort"-order:"order"-status:"status" | 120 | Order mutation (cancel, refund) |
| Customer order detail | order:detail:"orderId" | 120 | Order status change |
| Admin order list | order:admin:list:pagination:"page"-size:"size"-sort:"sort"-order:"order"-filters... | 60 | Admin order mutations |
| Admin order detail | order:admin:detail:"orderId" | 60 | Admin status changes |
10.1.10 Rate Limit Patterns
| Route Family | Key Pattern | Limit |
|---|---|---|
| Customer checkout | rl:orders:customer:action:checkout-key:"userId" | 10 req/min |
| Customer buy-now | rl:orders:customer:action:buynow-key:"userId" | 10 req/min |
| Customer list | rl:orders:customer:action:list-key:"userId" | 60 req/min |
| Customer cancel | rl:orders:customer:action:cancel-key:"userId" | 5 req/min |
| Admin orders | rl:orders:admin:action:list-key:"adminId" | 60 req/min |
| Admin mutations | rl:orders:admin:action:mutate-key:"adminId" | 20 req/min |
10.1.11 Job/Queue Payloads
| Job Name | Payload | Trigger |
|---|---|---|
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 |
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 (unpaid orders) |
10.1.12 Transactional Notification Events
| Event | Payload Highlights | Channels |
|---|---|---|
ORDER_PLACED_CHECKOUT | orderId, orderNumber, total, items | Push, Email |
ORDER_PLACED_BUYNOW | orderId, orderNumber, product, price | Push, Email |
ORDER_PAYMENT_RECEIVED_CHECKOUT | orderId, orderNumber, paymentReference | Push, Email |
ORDER_PAYMENT_RECEIVED_BUYNOW | orderId, orderNumber, paymentReference | Push, Email |
ORDER_PAYMENT_FAILED | orderId, orderNumber, reason | Push, Email |
ORDER_CANCELLED | orderId, orderNumber, cancelledBy, reason | Push, Email |
ORDER_REFUND_REQUESTED | orderId, orderNumber, reason, amount | Push, Email (admin) |
ORDER_REFUND_APPROVED | orderId, orderNumber, amount | Push, Email |
ORDER_REFUND_REJECTED | orderId, orderNumber, reason | Push, Email |
10.1.13 Inventory Outbox Events (Post-Payment Lifecycle)
| Event | Payload | Conditions |
|---|---|---|
stock.reserve | orderId, items[] | Order created from checkout/buy-now |
stock.finalize | orderId, items[] | Payment verified as completed |
stock.release | orderId, items[] | Payment failed, cancelled, or timed out |
10.1.14 DTO Field Reference
CheckoutDto
| Field | Type | Required | Validation | Notes |
|---|---|---|---|---|
| gateway | enum | Yes | "esewa"|"khalti" | Payment gateway selection |
| returnUrl | string | Yes | Valid URL | Frontend return destination |
BuyNowCheckoutDto
| Field | Type | Required | Validation | Notes |
|---|---|---|---|---|
| productId | number | Yes | Positive integer | Product to purchase |
| gateway | enum | Yes | "esewa"|"khalti" | Payment gateway |
| returnUrl | string | Yes | Valid URL | Frontend return destination |
| promoCode | string | No | 3-50 chars | Optional promo code |
CancelOrderDto / CancelOrderAdminDto
| Field | Type | Required | Validation | Notes |
|---|---|---|---|---|
| reason | string | No | Max 500 chars | Cancellation reason |
RequestRefundDto
| Field | Type | Required | Validation | Notes |
|---|---|---|---|---|
| reason | string | Yes | 1-500 chars | Refund reason |
| remarks | string | No | Max 1000 chars | Additional details |
ProcessRefundDto
| Field | Type | Required | Validation | Notes |
|---|---|---|---|---|
| action | enum | Yes | "approve"|"reject" | Refund decision |
| remarks | string | Yes | 1-500 chars | Admin remarks |
AddNoteDto
| Field | Type | Required | Validation | Notes |
|---|---|---|---|---|
| note | string | Yes | 1-1000 chars | Admin note content |
11. Testing Scenarios
11.1 Customer Checkout Flow
Test Case: Successful checkout via esewa
- User has items in active cart
- POST
/api/orders/checkoutwith"" "gateway": "esewa", "returnUrl": "https://app.com/payment/return" "" - Expect
200withPaymentInitResponseDtocontainingredirectUrlandgatewayPayload - Submit form to esewa redirect URL
- Verify user redirected back to
/api/payments/redirect/:paymentId/success - Verify order status becomes
paidafter queue processing
11.2 Customer Buy-now Flow
Test Case: Buy-now with promo code
- User selects single product
- POST
/api/orders/buy-nowwith"" "productId": 101, "gateway": "khalti", "returnUrl": "https://app.com/payment/return", "promoCode": "SUMMER2026" "" - Expect
200with payment initiation payload - Complete payment via Khalti
- Verify promo discount applied to finalPayable
11.3 Customer Order List with Filters
Test Case: Filter orders by status
- Authenticated user with multiple orders
- GET
/api/orders?status=paid&page=1&size=10 - Expect
200with paginated list of paid orders only - Verify pagination metadata accurate
11.4 Customer Cancel Order
Test Case: Cancel order in valid status
- User has order with status
payment_pending - POST
/api/orders/101/cancelwith"" "reason": "Changed my mind" "" - Expect
202withAsyncRequestResponseDtocontainingrequestId - Poll GET
/api/orders/requests/:requestIduntilstatus: "completed" - Verify order status changed to
cancelled
11.5 Customer Request Refund
Test Case: Request refund on paid order
- User has order with status
paid - POST
/api/orders/101/request-refundwith"" "reason": "Product not as described", "remarks": "Please check with seller" "" - Expect
200with order detail showingrefundStatus: "requested" - Verify refund reason stored in order
11.6 Admin Process Refund
Test Case: Admin approves refund request
- Admin retrieves order with
refundStatus: "requested" - POST
/api/admin/orders/101/process-refundwith"" "action": "approve", "remarks": "Approved after verification" "" - Expect
202with async request response - Poll until completion
- Verify order
refundStatusbecomesapproved
11.7 Admin Order Search
Test Case: Search orders by order number
- Admin wants to find specific order
- GET
/api/admin/orders?search=ORD12345678 - Expect
200with matching orders - Verify search matches order number, customer name, email, or phone
11.8 Payment Failure Handling
Test Case: Payment gateway returns failure
- User initiates checkout
- User cancels/aborts at gateway
- Gateway redirects to
/api/payments/redirect/:paymentId/failure - Backend processes failure callback
- Order status changes to
payment_failedorcancelled - User sees payment failure page with retry option
12. Integration Flow Recipes
12.1 Mobile App: Complete Purchase Flow
- Initialize cart: Ensure user has items in cart via Cart module
- Initiate checkout:
- POST
/api/mobile/orders/checkoutwith"" "gateway": "esewa", "returnUrl": "https://yourapp.com/payment-result" "" - Capture returned
paymentId,redirectUrl,gatewayPayload
- POST
- Redirect to gateway:
- If
initiationType === "form_post", auto-submit form withgatewayPayloadtoredirectUrl - If
initiationType === "redirect", navigate browser toredirectUrlwith query params
- If
- Handle callback:
- Gateway redirects to
/api/payments/redirect/:paymentId/success(or failure) - Backend processes and redirects to payment result page with
nextparam
- Gateway redirects to
- Poll for status:
- After redirect, call GET
/api/orders/:orderIdto verify status - Or GET
/api/orders/requests/:requestIdif used async flow
- After redirect, call GET
- Show result:
- If
orderStatus === "paid", show success, unlock access - If
orderStatus === "payment_failed", show failure, offer retry
- If
12.2 Admin: Handle Customer Refund Request
- Receive refund request: Customer submits via app
- Review order:
- GET
/api/admin/orders/:orderIdto view full order details - Check payment reference, transaction history
- Verify product not already consumed (for digital: check access grants)
- GET
- Make decision:
- Approve: POST
/api/admin/orders/:orderId/process-refundwith"" "action": "approve", "remarks": "Refund approved" "" - Reject: POST
/api/admin/orders/:orderId/process-refundwith"" "action": "reject", "remarks": "Reason for rejection" ""
- Approve: POST
- Track async operation:
- Poll GET
/api/admin/orders/requests/:requestIduntil completed - Verify final order state reflects decision
- Poll GET
- Add admin note:
- POST
/api/admin/orders/:orderId/noteswith note for audit trail
- POST
12.3 Webhook: Payment Gateway Callback Processing
- Receive callback:
- Payment gateway POSTs to
/api/payments/redirect/:paymentId/success(or/failure) - Request contains gateway-specific fields (transaction_uuid, total_amount, etc.)
- Payment gateway POSTs to
- Validate payload:
- Backend verifies signature if provided
- Matches paymentId with internal records
- Queue processing job:
order.payment_successororder.payment_failedjob added to queue
- Async processing:
- Worker updates order status
- Worker creates/entitles product access (on success)
- Worker emits transactional notifications
- Redirect to frontend:
- Backend redirects to
/api/payments/resultwith status params - Frontend shows result page and redirects to app deep link
- Backend redirects to
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:
| HTTP | errorCode | Message |
|---|---|---|
| 400 | ORDER_CART_EMPTY | Cart has no items. |
| 400 | ORDER_PRODUCT_NOT_AVAILABLE | Product is not available for purchase. |
| 400 | ORDER_PAYMENT_METHOD_NOT_SUPPORTED | Only online payment is supported. |
| 400 | ORDER_CANCEL_NOT_ALLOWED | Order cannot be cancelled in current status. |
| 400 | ORDER_NOT_PENDING_REFUND | Order is not pending refund processing. |
| 400 | ORDER_IDEMPOTENCY_KEY_TOO_LONG | Idempotency key must be 200 characters or less. |
| 404 | ORDER_ACTIVE_CART_NOT_FOUND | Active cart not found. |
| 404 | ORDER_ASYNC_REQUEST_NOT_FOUND | Async request not found. |
| 404 | ORDER_NOT_FOUND | Order not found. |
| 409 | ORDER_IDEMPOTENCY_MISMATCH | Request with this idempotency key is already in progress. |
| 409 | ORDER_PAYMENT_FAILED | Previous request with this idempotency key has failed. |
| 429 | RATE_LIMIT_EXCEEDED | Too many requests. Please try again later. |
| 503 | ORDER_ASYNC_REQUEST_CREATION_FAILED | Failed to create async order request. |
| 503 | ERR_CONFIG_INVALID | Configuration 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
- Feature Guide: See Order - Feature List Section 6 (State Models) for order lifecycle diagram.
- Backend Reference: See Order - Backend Documentation Section 9 for system architecture diagram.