Happy House - Ecommerce Docs
Developer ResourcesOrder

Order API Reference

Complete API contracts for the Order module, including routes, auth, DTOs, responses, errors, examples, and integration notes.

Order - API Reference

Audience: Frontend engineers, mobile engineers, backend engineers, QA, and API consumers. Scope: The 28 order routes — 8 customer, 11 order admin, 5 return admin, 4 refund admin.

1. Documentation Evidence

AreaFiles InspectedWhat Was Verified
Controllersapps/api/src/modules/order/customer/order-customer.controller.ts, admin/{order,return,refund}/*.controller.tsRoutes, methods, guards, permissions
DTOsdto/*.tsValidation
Servicescustomer/admin/return/refund servicesBehavior, transitions
Schemapackages/db/src/schema/order/*.ts12 tables, CHECKs
Error registryapps/api/src/common/types/error-codes.ts (// ORDER)ORDER_* codes

2. Module Summary

FieldValue
Module nameorder
Module slugorder
Primary actorscustomer, admin (orders/returns/refunds), worker
API surfacesmobile (customer), admin
Base route prefixes/api/mobile/orders, /api/orders, /api/order-returns, /api/order-refunds
Auth modelJwtAuthGuard (customer); JwtAuthGuard + RoleGuard (admin)
PersistencePostgreSQL (12 tables); no cache
Runtime source of truthOrder rows (snapshots) + live inventory for restock
Sibling docsBackend, Features and flows

3. Concepts and Terminology

TermMeaningSource FileUsed By
statusOne of nine order statuses — none returned/refundedschemaAll routes
Per-line labelDerived display label; quantities are the truthresponse builderOrder responses
unavailableQuantityA short order — paid for, not comingschemaShort orders
codCollectedAtCOD money actually changed handsschemaCOD flows
returnPendingQuantityUnits in a return in flightschemaReturns
pollAfterSecondsServer-set poll intervalstatus endpointPolling
refundedAmountDenormalised counter, CHECK-boundedschemaRefunds

4. API Surface Map

4.1 Customer — /api/mobile/orders

MethodPathPurpose
GET/My orders
GET/:idOne order
GET/:id/statusSmall poll payload
GET/:id/invoice.pdfReceipt PDF
POST/:id/cancelCancel before dispatch
POST/:id/returnsRequest a return
GET/:id/returnsMy returns on this order
POST/:id/returns/:returnId/cancelCancel a pending return

4.2 Admin — orders, /api/orders

MethodPathPermissionPurpose
GET/Orders_READList
GET/:idOrders_READDetail
POST/:id/confirmOrders_UPDATEConfirm
POST/:id/processingOrders_UPDATEProcessing
POST/:id/cancelOrders_UPDATECancel
POST/:id/notesOrders_UPDATEAdd note
POST/:id/cod-collectionOrders_UPDATERecord COD cash
POST/:id/shipmentsOrders_UPDATEDispatch (with serials)
POST/:id/shipments/:shipmentId/deliverOrders_UPDATEDeliver parcel
POST/:id/shipments/:shipmentId/failOrders_UPDATEFail parcel
POST/:id/refundsRefunds_UPDATECreate refund
POST/:id/ready-for-pickupOrders_UPDATETell the customer a pickup order is waiting
POST/:id/collectOrders_UPDATEHand a pickup order over — drives it to delivered

The last two are the pickup lifecycle, and they sit on the same /api/orders prefix as the rest even though they live in their own controller: readiness and collection are one lifecycle, share two error codes, and neither means anything for a delivery order. Both refuse a delivery order with ORDER_NOT_PICKUP.

/collect is the pickup counterpart of /:id/shipments and the only thing that moves a pickup order to delivered — until it runs, the customer cannot review an item or open a return, because the return window opens on delivery. It is deliberately not idempotent (ORDER_NOT_COLLECTABLE on a second press): at a counter, pressing twice is far more likely a double-tap than a retry.

/ready-for-pickup is the opposite — pressing it again re-enters the same state, and the outbox dedupe key collapses the repeats into one email.

Two operators pressing "ready" at once no longer 409s. The endpoint moves a confirmed order to processing first, and the second request lost that race: it hit ORDER_TRANSITION_NOT_ALLOWED and showed the operator a failure for an order that was, at that moment, exactly as ready as they had asked for. Two people at one counter is the normal case for this route, not an edge case.

It now tolerates precisely that code from the transition — and only that code — then re-reads the order and continues. Any other failure still propagates. The order still ends in the state the caller asked for, which is the test an idempotent endpoint has to pass; a transition genuinely refused (already collected, cancelled) is a different state and still refuses.

4.3 Admin — returns, /api/order-returns

MethodPathPermissionPurpose
GET/Returns_READList
GET/:idReturns_READDetail
POST/:id/decideReturns_UPDATEApprove/reject
POST/:id/receiveReturns_UPDATEGoods back
POST/:id/inspectReturns_UPDATEInspect (quantities + reason)

4.4 Admin — refunds, /api/order-refunds

MethodPathPermissionPurpose
GET/Refunds_READList
POST/:id/approveRefunds_UPDATEApprove (choose method)
POST/:id/rejectRefunds_UPDATEReject (pending only)
POST/:id/settleRefunds_UPDATESettle (reference required)

5. Auth, Identity, and Permissions

SurfaceGuard/DecoratorIdentity ShapePermissionGuest AllowedNotes
CustomerJwtAuthGuardreq.user.idNoOwnership-scoped: another customer's order is 404
AdminJwtAuthGuard, RoleGuardreq.userOrders_* / Returns_* / Refunds_*NoThree separate permission modules — money-back is never a side effect of dispatch rights; run permissions:sync on deploy

6. DTO and Model Reference

6.1 Create refund — POST /api/orders/:id/refunds

The caller sends lines and quantities — the server computes the money. No amount field.

{ "items": [ { "orderItemId": "…", "quantity": 1 } ] }

6.2 Approve refund

{ "method": "bank_transfer" }

The method is chosen at approval — the row has no method before this. Values: esewa_reversal / bank_transfer / cash.

6.3 Settle refund

{ "settlementReference": "BRN-12345" }

Required by constraint — 400 ORDER_REFUND_SETTLEMENT_REFERENCE_REQUIRED without it.

6.4 Return DTOs

Decide: approval state (+ reason when rejecting). Inspect: per-item quantities and, when rejecting, a reason (ORDER_RETURN_INSPECTION_INVALID names which).

6.5 Query DTOs

Order list and return/refund lists follow the standard QueryDto paging with filters (status, date range, customer, etc.); the refund list is the finance queue.

6.6 Order line item — the frozen configuration

Every order line was frozen from a checkout line that names a product_variant, not only a product. Both the customer and admin order-item response DTOs expose which configuration was bought — added because order_item had carried the columns since migration 0028 with no surface exposing either, so a customer's order history showed "iPhone 17 Pro" with no way to tell the 256GB they bought from the 1TB they did not.

SurfaceDTOIdentity fieldNotes
Customer (GET /:id, list)OrderItemResponseDtovariantPublicId (uuid, not nullable)product_variant.public_id, frozen at purchase
Admin (GET /api/orders/:id, list)OrderItemAdminDtovariantId (uuid, not nullable)Same value, different field name — the admin DTO names it variantId even though it carries the variant's PUBLIC id, not the integer PK

Both DTOs also carry variantName: string \| null. variantName is null exactly when the variant was the product's sole configuration and carried no label of its own — render the product name alone in that case, never the word "null", and never a label re-derived from the variant's CURRENT name, which would rewrite what was actually bought. Both DTOs additionally carry productPublicId/productId, productName, sku, unitPrice, mrp, quantity, lineTotal and discountAmount — all in integer minor units.

7. Enum Reference

EnumValueMeaningRuntime EffectSource
order_statuscreated / confirmed / processing / partially_shipped / shipped / partially_delivered / delivered / completed / cancelledThe orderNine values — none returned or refundedenums.ts
order_refund_methodesewa_reversal / bank_transfer / cashHow money goes backChosen at approval
per-line label (derived)unavailable / cancelled / delivered / partially_delivered / shipped / partially_shipped / processingDisplayQuantities are the truthresponse builder

8. Endpoint Reference

8.1 GET /api/mobile/orders

My purchase history. ORDER_NOT_FOUND semantics apply per row (no existence oracle).

8.2 GET /api/mobile/orders/:id

Full order: status, per-line quantities + derived label, the frozen variantPublicId/variantName per line (§6.6), pricing (minor units), shipment/return/refund summaries, the customer-visible timeline.

8.3 GET /api/mobile/orders/:id/status

Small payload for polling: order status, per-line labels, the latest customer-visible timeline entry, pollAfterSeconds. Honour pollAfterSeconds — it can be lengthened server-side under load without shipping a frontend. Reads recorded state only; cheap.

8.4 GET /api/mobile/orders/:id/invoice.pdf

Streams a receipt PDF, generated on demand, carrying verbatim and prominently: "This is a sales receipt for your records. It is NOT an official taxable invoice — no VAT or PAN registration is claimed." Never label it "Tax Invoice".

8.5 POST /api/mobile/orders/:id/cancel

Cancel before dispatch. Restock happens in the same transaction; a restock refusal rolls the cancellation back (ORDER_RESTOCK_REFUSED, 500, nothing changed). COD without codCollectedAt refunds nothing — the cancellation email says so.

Error Cases

HTTPCodeCondition
404ORDER_NOT_FOUNDUnknown or another customer's
409ORDER_TRANSITION_NOT_ALLOWEDOrder moved
409ORDER_NOT_CANCELLABLEAlready dispatched or delivered — offer a return (message says which)
500ORDER_RESTOCK_REFUSEDInventory declined; rolled back

8.6 POST /api/mobile/orders/:id/returns (+ GET, + cancel)

Request a return on delivered lines within the window. ORDER_RETURN_NOT_ELIGIBLE (409, date in message) when not delivered or past the window; ORDER_RETURN_QUANTITY_UNAVAILABLE (409) on a double-tap — units already in a return; refresh. Cancel releases the budget.

8.7 Admin order routes — POST /api/orders/:id/{confirm,processing,notes,cod-collection,shipments,shipments/:shipmentId/{deliver,fail}}

Transitions guarded by ORDER_TRANSITION_NOT_ALLOWED. Shipments take quantities + serial numbersORDER_SERIAL_COUNT_MISMATCH (more serials than units), ORDER_SERIAL_ALREADY_RECORDED (duplicate device — operator check). cod-collection is only applicable for COD, delivered, not already counted (ORDER_COD_COLLECTION_NOT_APPLICABLE). Deliver/fail close a parcel (ORDER_SHIPMENT_NOT_OPEN if already closed).

8.8 POST /api/orders/:id/refunds

Create a refund from order lines — server computes the money from the net ceilings. ORDER_REFUND_EXCEEDS_PAID (409) if it would exceed what is left to give back — reachable with no operator fault (two people approving at once); say the figure changed and refresh.

8.9 Return admin — /api/order-returns/:id/{decide,receive,inspect}

ORDER_RETURN_TRANSITION_NOT_ALLOWED on wrong-state steps; ORDER_RETURN_INSPECTION_INVALID names which quantities or the missing rejection reason.

8.10 Refund admin — /api/order-refunds/:id/{approve,reject,settle}

  • approve — choose the method (DTO per §6.2).
  • reject — pending only; an approved refund can never be rejected (ORDER_REFUND_TRANSITION_NOT_ALLOWED).
  • settle — settlement reference required (§6.3). This is where a human records that money actually moved; no gateway refund is integrated.

9. Flow Diagrams

9.1 Route Ownership

9.2 Request Sequence (cancel)

9.3 Error Branch (refund settle)

EndpointPagination TypeDefault SizeMax SizeSort FieldsFilters
GET /api/mobile/ordersoffset page/size20100standardstatus, date
GET /api/ordersoffset page/size20100standardstatus, customer, date, totals
GET /api/order-returnsoffset page/size20100standardstatus, order
GET /api/order-refundsoffset page/size20100standardstatus — the finance queue

11. Caching, Jobs, and External Integrations

IntegrationUsed?Details
Redis cacheNoStatus reads recorded state only
BullMQYesORDER queue — CREATE_ORDER from the outbox row + email jobs
EmailYes (optional key)RESEND_API_KEY optional; without it emails render/queue and are logged instead of delivered
Gateway refundNoSettlement is human; reference required by constraint

13. Mandatory Deep API Documentation Pack

13.1 Route-by-Route Completeness Matrix

RouteController MethodService MethodGuardsPermissionsDB TouchesErrorsDocumented?
GET /api/mobile/ordersfindAllOrderCustomerService.listJWTordersYes
GET /api/mobile/orders/:idfindById…findOneJWTorder + lines404Yes
GET /:id/statusstatus…statusJWTorder404Yes
GET /:id/invoice.pdfinvoice…invoiceJWTorder404Yes
POST /:id/cancelcancel…cancelJWTorder + restock404/409/500Yes
POST /:id/returnscreateReturnreturn serviceJWTorder, items404/409Yes
GET /:id/returnslistReturnsJWTreturns404Yes
POST /:id/returns/:returnId/cancelcancelReturnreturn serviceJWTreturn404/409Yes
GET /api/ordersfindAllOrderAdminService.listJWT+RoleOrders_READordersYes
GET /api/orders/:idfindById…findOneJWT+RoleOrders_READorder404Yes
POST /:id/{confirm,processing,cancel,notes,cod-collection}5 methodsadmin serviceJWT+RoleOrders_UPDATEorder + events404/409Yes
POST /:id/shipmentsshipadmin serviceJWT+RoleOrders_UPDATEshipment + serials404/409Yes
POST /:id/shipments/:shipmentId/{deliver,fail}2 methodsadmin serviceJWT+RoleOrders_UPDATEshipment404/409Yes
POST /api/orders/:id/refundscreateRefundrefund serviceJWT+RoleRefunds_UPDATErefund rows404/409Yes
GET /api/order-returns / /:id2 methodsreturn serviceJWT+RoleReturns_READreturns404Yes
POST /:id/{decide,receive,inspect}3 methodsreturn serviceJWT+RoleReturns_UPDATEreturn rows404/409Yes
GET /api/order-refundsfindAllrefund serviceJWT+RoleRefunds_READrefundsYes
POST /:id/{approve,reject,settle}3 methodsrefund serviceJWT+RoleRefunds_UPDATErefund rows400/404/409Yes

13.2 Request/Response Exhaustiveness

Covered in §8: refund-create without amount (§6.1/8.8), approve-with-method (§6.2), settle-with-reference (§6.3), the receipt disclaimer (§8.4), short-order shape (unavailableQuantity + label), domain errors per endpoint (§8 error tables), the two 409s that are not failures (RETURN_QUANTITY_UNAVAILABLE, REFUND_EXCEEDS_PAID).

13.3 API Diagram Pack

Route ownership (§9.1), sequence per endpoint family (§9.2, backend §7), error decision tree (§9.3), async flow (backend §7.1 — the outbox chain).

13.4 Consumer Integration Notes

ConsumerRequired KnowledgeFailure HandlingContract Stability
Web frontendNine statuses (no returned); derived labels; receipt ≠ tax invoice409s per §8; double-tap return = refreshStable
Mobile apppollAfterSeconds; COD refund-absence on cancelORDER_NOT_CANCELLABLE → offer returnStable
Admin panelThree permission modules; serials at dispatch; refund settle queueREFUND_EXCEEDS_PAID → refreshStable
QAQuantities-as-truth; short orders; return budgetReproduce via exact codesStable
Financeawaiting_settlement queue; reference requiredStable

13.5 API Tradeoffs and Rationale

DecisionChosen BehaviorAlternatives ConsideredWhy This TradeoffRiskMitigation
Background creationOutbox chainSynchronousPaid customer never without a recordDelayUnique index
No returned statusHistory is truthStatusesDerived badgesClient assumptionDocumented
No item statusQuantities add upLabel columnClient workLabel provided
Server computes refund moneyNo caller amountsClient amountsCeilings enforcedCHECKs
Human-settled refundsMoney controlGateway autoManual queueReference constraint
Three permission modulesLeast privilegeOne Orders moduleWarehouse can't refundDocumented

13.6 API Change Impact

ChangeAffected ConsumersBackend ImpactData ImpactMigration Needed?Compatibility Plan
Fulfillment module laterDispatch routesSplit servicesNoneNoRows shaped for takeover
Gateway refund laterSettle flowNew integrationNoneNoHuman path remains

14. Zero-Omission API Checklist

  • Every controller route is documented (§4, §8, §13.1).
  • Every parent route prefix and runtime URL is documented (§2, §4).
  • Every DTO field, enum, default, transform and validator is documented (§6, §7).
  • Every response field and nullable field is documented (§8).
  • Every auth, guard, permission and guest identity branch is documented (§5).
  • Every success, validation, not-found, conflict, rate-limit and server-error branch is documented (§8).
  • Every DB read/write, queue job and external call is documented (§11, backend §9).
  • Every route has examples for minimal request, success response and representative failures (§8).
  • Every endpoint family has route, sequence and error diagrams (§9, backend §7).
  • Every tradeoff and compatibility risk is documented (§13.5, §13.6).
  • The API doc links to backend and features/flows (§1, See Also).

15. Integration Checklist

  • Every route from controllers is documented.
  • Every DTO field is documented.
  • Every enum value is documented.
  • Every response envelope is documented.
  • Every error code is documented.
  • Every auth guard and permission is documented.
  • Every cache key, queue job and external call is documented.
  • Every diagram matches the current code.
  • The API doc links to backend and features/flows.

See Also

On this page

Order - API Reference1. Documentation Evidence2. Module Summary3. Concepts and Terminology4. API Surface Map4.1 Customer — /api/mobile/orders4.2 Admin — orders, /api/orders4.3 Admin — returns, /api/order-returns4.4 Admin — refunds, /api/order-refunds5. Auth, Identity, and Permissions6. DTO and Model Reference6.1 Create refund — POST /api/orders/:id/refunds6.2 Approve refund6.3 Settle refund6.4 Return DTOs6.5 Query DTOs6.6 Order line item — the frozen configuration7. Enum Reference8. Endpoint Reference8.1 GET /api/mobile/orders8.2 GET /api/mobile/orders/:id8.3 GET /api/mobile/orders/:id/status8.4 GET /api/mobile/orders/:id/invoice.pdf8.5 POST /api/mobile/orders/:id/cancelError Cases8.6 POST /api/mobile/orders/:id/returns (+ GET, + cancel)8.7 Admin order routes — POST /api/orders/:id/{confirm,processing,notes,cod-collection,shipments,shipments/:shipmentId/{deliver,fail}}8.8 POST /api/orders/:id/refunds8.9 Return admin — /api/order-returns/:id/{decide,receive,inspect}8.10 Refund admin — /api/order-refunds/:id/{approve,reject,settle}9. Flow Diagrams9.1 Route Ownership9.2 Request Sequence (cancel)9.3 Error Branch (refund settle)10. Pagination, Sorting, Filtering, and Search11. Caching, Jobs, and External Integrations13. Mandatory Deep API Documentation Pack13.1 Route-by-Route Completeness Matrix13.2 Request/Response Exhaustiveness13.3 API Diagram Pack13.4 Consumer Integration Notes13.5 API Tradeoffs and Rationale13.6 API Change Impact14. Zero-Omission API Checklist15. Integration ChecklistSee Also