Shop It Docs
Developer Resourcesorder

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.addItem so 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

MethodPathDescription
POST/api/orders/:orderId/reorderReorder all or selected items into active cart

Mobile-composed equivalent:

  • POST /api/mobile/orders/:orderId/reorder

5. Route Detail

5.1 Request Contract

FieldTypeRequiredDescription
orderId (path)numberYesSource order ID
productIds (body)number[]NoOptional 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
  }
}
FieldTypeDescription
cartIdnumberActive cart ID
addedItemsReorderItemDto[]Items added by this reorder operation
totalCartItemsnumberTotal cart item count after reorder

5.4 ReorderItemDto

FieldTypeDescription
productIdnumberProduct ID
productTitlestringProduct title at reorder time
quantitynumberQuantity added to cart
unitSpnumberUnit 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"
}
HTTPerrorCodeScenario
400ORDER_NOT_DELIVEREDOrder exists but fulfillment status is not delivered
400ORDER_HAS_DIGITAL_ONLYSelected items are all non-physical
400CART_INSUFFICIENT_STOCKStock reserve failed while adding one of the reorder items to cart
400CART_QUANTITY_EXCEEDEDReorder quantity for a cart item exceeds cart max quantity rules
403ORDER_ACCESS_DENIEDOrder belongs to a different user
404ORDER_NOT_FOUNDOrder ID does not exist
404ORDER_PRODUCT_NOT_FOUNDRequested 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 productIds is 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:

  1. Exist in products.
  2. Have isSellable = true.
  3. 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 + reorderQuantity

7.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.addItem performs inventory reserve checks.
  • Reorder: OrderReorderCustomerService calls CartCustomerService.addItem for 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

  1. User opens delivered order detail/history.
  2. User taps reorder action (all items or selected items).
  3. Frontend calls:
    • POST /api/orders/{orderId}/reorder
    • Or mobile path: POST /api/mobile/orders/{orderId}/reorder
  4. 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.

For predictable UX, treat reorder as a cart-mutating operation that may partially succeed.

Recommended handling:

  1. Disable reorder button and show loading while request is in flight.
  2. Call reorder endpoint.
  3. On 200: show success using addedItems and navigate/refetch cart.
  4. On 4xx/5xx: always refetch cart before showing final UI state.
  5. If error is CART_INSUFFICIENT_STOCK, show message like:
    • "Some items could not be added because stock changed. Your cart has been refreshed."
  6. 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
     -> OrderReorderCustomerService

10.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 ReorderResponseDto

10.3 File Map

FilePurpose
apps/api/src/modules/order/reorder/order-reorder-customer.module.tsReorder leaf module
apps/api/src/modules/order/reorder/order-reorder-customer.controller.tsReorder endpoint
apps/api/src/modules/order/reorder/order-reorder-customer.service.tsReorder business logic
apps/api/src/modules/order/reorder/dto/reorder-request.dto.tsRequest DTO
apps/api/src/modules/order/reorder/dto/reorder-response.dto.tsResponse DTO
apps/api/src/modules/order/__tests__/unit/services/order-reorder-customer.service.unit.spec.tsService unit tests
apps/api/src/modules/order/__tests__/unit/controllers/order-reorder-customer.controller.unit.spec.tsController 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.

See Also