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:

  • Physical product types (thangka, singing_bowl, statue, jewellery) are supported and create orderType: "physical".

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

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 payment success
  • 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/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

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
RequestpaymentMethod: "esewa" or "khalti" + paymentId: string
ResponseResponseDto<OrderConfirmationDto>
Errors400 invalid cart, 400 payment failed

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 | failedoptional
orderTypeenum(order_type)optional
searchstringoptional
sortcreatedAt | updatedAtcreatedAt
orderasc | descdesc

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

  • digital
  • physical

7.2 order_payment_method

  • online

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
  • admin_manual

7.6 refund_status

  • requested
  • pending
  • approved
  • rejected

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 (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: "esewa"|"khalti", returnUrl: string ""PaymentInitResponseDtoCreates order from active cart, initiates payment; idempotency via header
GET/api/ordersUser JWTQueryOrdersDto "" page?, size?, pagination?, status?, sort?, order? ""OrderListItemResponseDto[] paginatedReturns current user's order history; filters by status
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/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/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
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?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=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": "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

FieldValueNotes
initiationTypeform_postForm submission required
initiationTyperedirectURL redirect with query params
gatewayesewaeSewa gateway
gatewaykhaltiKhalti gateway
paymentId9001Internal payment reference
gatewayTransactionId9001-1774884775940Gateway-specific transaction ID
orderStatuspayment_pendingInitial order status after creation
paymentStatuspendingPayment awaiting completion

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 payment
paidcompletedrefund_requested, cancelledPayment successful
payment_failedfailedcancelledPayment not received
cancelledfailed- (terminal)Order cancelled
refund_requestedcompletedrefund_approved, refund_rejectedCustomer requested refund
refund_approvedcompleted- (terminal)Refund approved
refund_rejectedcompleted- (terminal)Refund rejected

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

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_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_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

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"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

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 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
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

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[]Payment verified as completed
stock.releaseorderId, items[]Payment failed, cancelled, or timed out

10.1.14 DTO Field Reference

CheckoutDto

FieldTypeRequiredValidationNotes
gatewayenumYes"esewa"|"khalti"Payment gateway selection
returnUrlstringYesValid URLFrontend return destination

BuyNowCheckoutDto

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

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

11. Testing Scenarios

11.1 Customer Checkout Flow

Test Case: Successful checkout via esewa

  1. User has items in active cart
  2. POST /api/orders/checkout with "" "gateway": "esewa", "returnUrl": "https://app.com/payment/return" ""
  3. Expect 200 with PaymentInitResponseDto containing redirectUrl and gatewayPayload
  4. Submit form to esewa redirect 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": "khalti", "returnUrl": "https://app.com/payment/return", "promoCode": "SUMMER2026" ""
  3. Expect 200 with payment initiation payload
  4. Complete payment via Khalti
  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": "esewa", "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_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)7. Enums7.1 order_type7.2 order_payment_method7.3 order_status7.4 order_status_actor_type7.5 order_source7.6 refund_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 Job/Queue Payloads10.1.12 Transactional Notification Events10.1.13 Inventory Outbox Events (Post-Payment Lifecycle)10.1.14 DTO Field ReferenceCheckoutDtoBuyNowCheckoutDtoCancelOrderDto / CancelOrderAdminDtoRequestRefundDtoProcessRefundDtoAddNoteDto11. 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