Order Reorder API
Reorder items from a previous delivered order by adding them to the customer's active cart.
Audience: Mobile/web frontend developers
Scope:POST /api/orders/:orderId/reorder
Order Reorder - API and Integration Guide
1. How to Read / Quick Metadata
- Module: Order -> Reorder
- Auth: Customer JWT (
JwtAuthGuard) - Permission:
ORDERS_REORDER - Primary API path:
/api/orders/:orderId/reorder - Mobile-composed path:
/api/mobile/orders/:orderId/reorder - Response envelope:
ResponseDto<ReorderResponseDto> - Swagger tag:
Orders (Mobile)
2. High-Level Overview
Reorder lets a customer add items from a past delivered order back into the active cart.
Behavior summary:
- Validates order exists, belongs to the authenticated user, and is delivered.
- Supports full reorder or partial reorder by
productIds. - Ensures selected products are still sellable and physical.
- Aggregates duplicate product rows before cart writes.
- Adds items via
CartCustomerService.addItemso existing cart merge behavior is preserved. - Returns cart summary and list of items added by this reorder operation.
3. Core Concepts
- Reorder: Copy eligible past-order items into active cart.
- Eligible item: Product from order that is still sellable and physical.
- Digital-only block: If selected items are all non-physical, reorder fails.
- Quantity merge: Existing cart quantity + reorder quantity.
- Active cart: Cart record with
status = "active".
4. Route Summary
| Method | Path | Description |
|---|---|---|
POST | /api/orders/:orderId/reorder | Reorder all or selected items into active cart |
Mobile-composed equivalent:
POST /api/mobile/orders/:orderId/reorder
5. Route Detail
5.1 Request Contract
| Field | Type | Required | Description |
|---|---|---|---|
orderId (path) | number | Yes | Source order ID |
productIds (body) | number[] | No | Optional subset of products to reorder |
If productIds is omitted, the endpoint attempts reorder for all eligible order items.
5.2 Request Example (partial reorder)
{
"productIds": [101, 102]
}5.3 Response Contract (200 OK)
{
"message": "Items added to cart",
"data": {
"cartId": 1,
"addedItems": [
{
"productId": 101,
"productTitle": "Hand-Painted Green Tara",
"quantity": 2,
"unitSp": 12000
}
],
"totalCartItems": 5
}
}| Field | Type | Description |
|---|---|---|
cartId | number | Active cart ID |
addedItems | ReorderItemDto[] | Items added by this reorder operation |
totalCartItems | number | Total cart item count after reorder |
5.4 ReorderItemDto
| Field | Type | Description |
|---|---|---|
productId | number | Product ID |
productTitle | string | Product title at reorder time |
quantity | number | Quantity added to cart |
unitSp | number | Unit selling price from original order item |
6. Error Responses
Standard error envelope:
{
"statusCode": 404,
"errorCode": "ORDER_NOT_FOUND",
"message": "Order not found",
"timestamp": "2026-04-23T10:00:00.000Z",
"path": "/api/orders/123/reorder"
}| HTTP | errorCode | Scenario |
|---|---|---|
400 | ORDER_NOT_DELIVERED | Order exists but fulfillment status is not delivered |
400 | ORDER_HAS_DIGITAL_ONLY | Selected items are all non-physical |
400 | CART_INSUFFICIENT_STOCK | Stock reserve failed while adding one of the reorder items to cart |
400 | CART_QUANTITY_EXCEEDED | Reorder quantity for a cart item exceeds cart max quantity rules |
403 | ORDER_ACCESS_DENIED | Order belongs to a different user |
404 | ORDER_NOT_FOUND | Order ID does not exist |
404 | ORDER_PRODUCT_NOT_FOUND | Requested product not in order, product missing, or not sellable |
7. Behavioral Details
7.1 Order Eligibility
Reorder is allowed only when fulfillmentStatus = "delivered".
7.2 Product Filtering
- If
productIdsis provided, only those IDs are considered. - If any requested product ID is not in the order selection, request fails with
ORDER_PRODUCT_NOT_FOUND.
7.3 Product Eligibility
Each selected product must:
- Exist in
products. - Have
isSellable = true. - Be physical (
isPhysicalProduct(productType) = true).
7.4 Digital-Only Block
If no physical reorderable entries remain after filtering/validation, request fails with ORDER_HAS_DIGITAL_ONLY.
7.5 Quantity Aggregation
Duplicate order lines for the same productId are aggregated before cart writes.
Example:
- Product 101 quantity 2
- Product 101 quantity 3
- Final add call: product 101 quantity 5
7.6 Cart Merge Behavior
CartCustomerService.addItem handles merge into existing cart state.
Resulting rule:
newCartQuantity = existingCartQuantity + reorderQuantity7.7 Cart Cache
Reorder relies on existing cart service cache invalidation behavior through cart mutations and final cart fetch.
7.8 Stock Enforcement (Normal Add-to-Cart and Reorder)
Stock is enforced in backend cart mutations, not only on product-page UI state.
- Normal add-to-cart:
CartCustomerService.addItemperforms inventory reserve checks. - Reorder:
OrderReorderCustomerServicecallsCartCustomerService.addItemfor each aggregated product, so the same reserve checks run.
7.9 Important: Partial Success Semantics
Reorder currently processes products sequentially.
- If a failure happens before the first cart write, no items are added.
- If a failure happens after some successful cart writes, those earlier items remain in cart.
- The API does not currently return a per-item failure list in this error case.
This means reorder is not all-or-nothing transactional at the whole-request level.
8. Request Variations
8.1 Reorder All Eligible Items
POST /api/orders/101/reorder
Authorization: Bearer <customer_jwt>No body required.
8.2 Reorder Selected Items Only
POST /api/orders/101/reorder
Authorization: Bearer <customer_jwt>
Content-Type: application/json
{
"productIds": [101, 102]
}8.3 Merge With Existing Cart Product
- Existing cart: product 101 quantity 1
- Reorder payload adds product 101 quantity 2
- Final cart quantity for 101 becomes 3
8.4 Duplicate Order Item Lines
If an order has multiple rows for same product, reorder returns a single aggregated entry per product in addedItems and performs one add call per distinct product.
9. Frontend Integration Flow
- User opens delivered order detail/history.
- User taps reorder action (all items or selected items).
- Frontend calls:
POST /api/orders/{orderId}/reorder- Or mobile path:
POST /api/mobile/orders/{orderId}/reorder
- Frontend handles responses:
200: show success, update or refetch cart.ORDER_NOT_DELIVERED: show delivered-only message.ORDER_HAS_DIGITAL_ONLY: show non-reorderable message.CART_INSUFFICIENT_STOCK: show stock-changed message and prompt user to review cart.CART_QUANTITY_EXCEEDED: show quantity-limit message.ORDER_ACCESS_DENIED: show unauthorized access message.ORDER_NOT_FOUND: show missing order message.ORDER_PRODUCT_NOT_FOUND: show unavailable product message.
9.1 Frontend Handling Contract (Recommended)
For predictable UX, treat reorder as a cart-mutating operation that may partially succeed.
Recommended handling:
- Disable reorder button and show loading while request is in flight.
- Call reorder endpoint.
- On
200: show success usingaddedItemsand navigate/refetch cart. - On
4xx/5xx: always refetch cart before showing final UI state. - If error is
CART_INSUFFICIENT_STOCK, show message like:- "Some items could not be added because stock changed. Your cart has been refreshed."
- Re-render order/cart UI from fresh backend cart data after refetch.
9.2 Why Mandatory Cart Refetch on Error
Because partial success is possible, frontend must not assume "all failed" when reorder returns an error.
Always refetch cart after any reorder error to synchronize UI with actual persisted cart state.
9.3 Suggested UX Copy for Stock Cases
CART_INSUFFICIENT_STOCK:- "Some reorder items are out of stock right now. We updated your cart with what was available."
ORDER_PRODUCT_NOT_FOUND:- "One or more requested items are no longer available for reorder."
ORDER_HAS_DIGITAL_ONLY:- "This order contains only non-physical items and cannot be added to cart."
10. Backend Architecture
10.1 Module Structure
OrderModule (aggregate)
-> OrderReorderCustomerModule (leaf)
-> OrderReorderCustomerController
-> OrderReorderCustomerService10.2 Service Flow
1. Fetch order by id
2. Validate ownership
3. Validate delivered fulfillment status
4. Fetch order items (full set or requested subset)
5. Validate selected product coverage
6. Fetch product records and validate sellable/physical
7. Aggregate quantity by productId
8. Call CartCustomerService.addItem per aggregated item
9. Fetch final cart and return ReorderResponseDto10.3 File Map
| File | Purpose |
|---|---|
apps/api/src/modules/order/reorder/order-reorder-customer.module.ts | Reorder leaf module |
apps/api/src/modules/order/reorder/order-reorder-customer.controller.ts | Reorder endpoint |
apps/api/src/modules/order/reorder/order-reorder-customer.service.ts | Reorder business logic |
apps/api/src/modules/order/reorder/dto/reorder-request.dto.ts | Request DTO |
apps/api/src/modules/order/reorder/dto/reorder-response.dto.ts | Response DTO |
apps/api/src/modules/order/__tests__/unit/services/order-reorder-customer.service.unit.spec.ts | Service unit tests |
apps/api/src/modules/order/__tests__/unit/controllers/order-reorder-customer.controller.unit.spec.ts | Controller unit tests |
11. Caching
No dedicated reorder cache namespace is introduced in this feature. Reorder relies on existing cart service cache lifecycle.
12. Rate Limiting
No reorder-specific rate limiter is implemented in this subphase. Rate-limit work is deferred.
13. Validation and Test Scenarios
Recommended scenarios for QA/frontend validation:
- Delivered order, reorder all -> success.
- Delivered order, reorder subset -> success.
- Reorder where first item is out of stock -> fail with
CART_INSUFFICIENT_STOCK, no item added. - Reorder where later item is out of stock -> fail with
CART_INSUFFICIENT_STOCK, earlier item(s) may already be added. - Reorder error path always followed by cart refetch -> UI matches backend cart state.
- Order not delivered ->
ORDER_NOT_DELIVERED. - Different user order ->
ORDER_ACCESS_DENIED. - Missing order ->
ORDER_NOT_FOUND. - Selected product not in order ->
ORDER_PRODUCT_NOT_FOUND. - Product became unsellable ->
ORDER_PRODUCT_NOT_FOUND. - Digital-only selection ->
ORDER_HAS_DIGITAL_ONLY. - Existing cart quantity merge observed after reorder.