Jiffoo Docs

Orders API

Complete guide to order management and lifecycle in Jiffoo Mall

Orders API

The Orders API manages the complete order lifecycle from creation through fulfillment, including payment processing, shipment tracking, and cancellations.

Order Lifecycle

sequenceDiagram
    Customer->>API: POST /orders (Create Order)
    API->>API: Validate items & inventory
    API->>Customer: Return order (PENDING)
    Customer->>Payment: Process payment
    Payment->>API: Webhook: Payment confirmed
    API->>API: Update order status (PAID)
    Note over API,Admin: Order ready for fulfillment
    Admin->>API: POST /admin/orders/:id/ship
    API->>Customer: Order shipped (SHIPPED)
    Carrier->>Customer: Delivery complete
    Admin->>API: Update status (DELIVERED)
    Note over Customer,API: Optional: Cancellation or Refund

Order Status Flow

stateDiagram-v2
    [*] --> PENDING: Order Created
    PENDING --> PAID: Payment Success
    PENDING --> CANCELLED: Payment Failed/Timeout
    PAID --> SHIPPED: Admin Ships Order
    PAID --> CANCELLED: Customer Cancels
    SHIPPED --> DELIVERED: Delivery Confirmed
    PAID --> REFUNDED: Admin Refunds
    SHIPPED --> REFUNDED: Return & Refund
    DELIVERED --> COMPLETED: Order Complete
    CANCELLED --> [*]
    REFUNDED --> [*]
    COMPLETED --> [*]

User Endpoints

Create Order

Create a new order from cart items or direct product selection.

Endpoint: POST /orders

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Request Body:

{
  "items": [
    {
      "productId": "cm52kg0000001qv0akj8r9w3e",
      "variantId": "cm52kg0000002qv0akj8r9w3f",
      "quantity": 2
    },
    {
      "productId": "cm52kg0000003qv0akj8r9w3g",
      "variantId": "cm52kg0000004qv0akj8r9w3h",
      "quantity": 1
    }
  ],
  "shippingAddress": {
    "firstName": "John",
    "lastName": "Doe",
    "address": "123 Main St, Apt 4B",
    "city": "New York",
    "postalCode": "10001",
    "country": "United States"
  },
  "customerEmail": "[email protected]"
}

Response: 201 Created

{
  "success": true,
  "data": {
    "id": "cm52kg0000010qv0akj8r9w3i",
    "userId": "cm52kg0000000qv0akj8r9w3d",
    "status": "PENDING",
    "paymentStatus": "PENDING",
    "totalAmount": 15999,
    "currency": "USD",
    "shippingAddress": {
      "firstName": "John",
      "lastName": "Doe",
      "address": "123 Main St, Apt 4B",
      "city": "New York",
      "postalCode": "10001",
      "country": "United States"
    },
    "items": [
      {
        "id": "cm52kg0000011qv0akj8r9w3j",
        "productId": "cm52kg0000001qv0akj8r9w3e",
        "productName": "Premium Wireless Headphones",
        "variantId": "cm52kg0000002qv0akj8r9w3f",
        "variantName": "Black - Large",
        "quantity": 2,
        "unitPrice": 5999,
        "totalPrice": 11998
      },
      {
        "id": "cm52kg0000012qv0akj8r9w3k",
        "productId": "cm52kg0000003qv0akj8r9w3g",
        "productName": "USB-C Charging Cable",
        "variantId": "cm52kg0000004qv0akj8r9w3h",
        "variantName": "2m - White",
        "quantity": 1,
        "unitPrice": 1999,
        "totalPrice": 1999
      }
    ],
    "createdAt": "2024-01-15T10:30:00.000Z",
    "updatedAt": "2024-01-15T10:30:00.000Z"
  }
}

Error Response: 400 Bad Request

{
  "success": false,
  "error": {
    "code": "BAD_REQUEST",
    "message": "Product cm52kg0000001qv0akj8r9w3e is out of stock"
  }
}

Validation Rules:

  • items: Required, minimum 1 item
  • productId: Required for each item
  • variantId: Required for each item
  • quantity: Required, must be positive integer
  • shippingAddress: Optional, required fields if provided
  • customerEmail: Optional, must be valid email format

Get User Orders

Retrieve all orders for the authenticated user with pagination and filtering.

Endpoint: GET /orders

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Query Parameters:

ParameterTypeDefaultDescription
pageinteger1Page number
limitinteger10Items per page
statusstring-Filter by order status

Example Request:

GET /orders?page=1&limit=10&status=PAID

Response: 200 OK

{
  "success": true,
  "data": {
    "items": [
      {
        "id": "cm52kg0000010qv0akj8r9w3i",
        "userId": "cm52kg0000000qv0akj8r9w3d",
        "status": "PAID",
        "paymentStatus": "PAID",
        "totalAmount": 15999,
        "currency": "USD",
        "items": [
          {
            "id": "cm52kg0000011qv0akj8r9w3j",
            "productName": "Premium Wireless Headphones",
            "quantity": 2,
            "unitPrice": 5999,
            "totalPrice": 11998
          }
        ],
        "createdAt": "2024-01-15T10:30:00.000Z",
        "updatedAt": "2024-01-15T10:35:00.000Z"
      }
    ],
    "page": 1,
    "limit": 10,
    "total": 15,
    "totalPages": 2
  }
}

Error Response: 500 Internal Server Error

{
  "success": false,
  "error": {
    "code": "INTERNAL_SERVER_ERROR",
    "message": "Failed to retrieve orders"
  }
}

Get Order by ID

Retrieve detailed information about a specific order.

Endpoint: GET /orders/:id

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Response: 200 OK

{
  "success": true,
  "data": {
    "id": "cm52kg0000010qv0akj8r9w3i",
    "userId": "cm52kg0000000qv0akj8r9w3d",
    "status": "SHIPPED",
    "paymentStatus": "PAID",
    "totalAmount": 15999,
    "currency": "USD",
    "shippingAddress": {
      "firstName": "John",
      "lastName": "Doe",
      "address": "123 Main St, Apt 4B",
      "city": "New York",
      "postalCode": "10001",
      "country": "United States"
    },
    "items": [
      {
        "id": "cm52kg0000011qv0akj8r9w3j",
        "productId": "cm52kg0000001qv0akj8r9w3e",
        "productName": "Premium Wireless Headphones",
        "variantId": "cm52kg0000002qv0akj8r9w3f",
        "variantName": "Black - Large",
        "quantity": 2,
        "unitPrice": 5999,
        "totalPrice": 11998
      }
    ],
    "shipments": [
      {
        "id": "cm52kg0000020qv0akj8r9w3l",
        "carrier": "FedEx",
        "trackingNumber": "1Z999AA10123456784",
        "shippedAt": "2024-01-16T14:20:00.000Z"
      }
    ],
    "createdAt": "2024-01-15T10:30:00.000Z",
    "updatedAt": "2024-01-16T14:20:00.000Z"
  }
}

Error Response: 404 Not Found

{
  "success": false,
  "error": {
    "code": "NOT_FOUND",
    "message": "Order not found"
  }
}

Cancel Order

Cancel a pending or paid order before shipment.

Endpoint: POST /orders/:id/cancel

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Request Body:

{
  "cancelReason": "Changed my mind about the purchase"
}

Response: 200 OK

{
  "success": true,
  "data": {
    "id": "cm52kg0000010qv0akj8r9w3i",
    "userId": "cm52kg0000000qv0akj8r9w3d",
    "status": "CANCELLED",
    "paymentStatus": "REFUNDED",
    "totalAmount": 15999,
    "currency": "USD",
    "cancelReason": "Changed my mind about the purchase",
    "cancelledAt": "2024-01-15T11:00:00.000Z",
    "createdAt": "2024-01-15T10:30:00.000Z",
    "updatedAt": "2024-01-15T11:00:00.000Z"
  }
}

Error Response: 400 Bad Request

{
  "success": false,
  "error": {
    "code": "BAD_REQUEST",
    "message": "Cannot cancel order that has already been shipped"
  }
}

Validation Rules:

  • cancelReason: Required, minimum 1 character
  • Order must be in PENDING or PAID status
  • Order cannot be already shipped

Admin Endpoints

Get All Orders (Admin)

Retrieve all orders across all users with pagination and filtering.

Endpoint: GET /admin/orders

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Required Role: ADMIN

Query Parameters:

ParameterTypeDefaultDescription
pageinteger1Page number
limitinteger10Items per page
statusstring-Filter by order status

Response: 200 OK

{
  "success": true,
  "data": {
    "items": [
      {
        "id": "cm52kg0000010qv0akj8r9w3i",
        "userId": "cm52kg0000000qv0akj8r9w3d",
        "status": "PAID",
        "paymentStatus": "PAID",
        "totalAmount": 15999,
        "currency": "USD",
        "items": [
          {
            "productName": "Premium Wireless Headphones",
            "quantity": 2
          }
        ],
        "createdAt": "2024-01-15T10:30:00.000Z"
      }
    ],
    "page": 1,
    "limit": 10,
    "total": 150,
    "totalPages": 15
  }
}

Get Order by ID (Admin)

Retrieve detailed information about any order.

Endpoint: GET /admin/orders/:id

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Required Role: ADMIN

Response: Same structure as user endpoint GET /orders/:id

Error Response: 404 Not Found

{
  "success": false,
  "error": {
    "code": "NOT_FOUND",
    "message": "Order not found"
  }
}

Update Order Status (Admin)

Manually update an order's status.

Endpoint: PUT /admin/orders/:id/status

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Required Role: ADMIN

Request Body:

{
  "status": "COMPLETED"
}

Valid Status Values:

  • PENDING
  • PAID
  • COMPLETED
  • SHIPPED
  • DELIVERED
  • CANCELLED
  • REFUNDED

Response: 200 OK

{
  "success": true,
  "data": {
    "id": "cm52kg0000010qv0akj8r9w3i",
    "status": "COMPLETED",
    "updatedAt": "2024-01-20T15:45:00.000Z"
  }
}

Error Response: 500 Internal Server Error

{
  "success": false,
  "error": {
    "code": "INTERNAL_SERVER_ERROR",
    "message": "Failed to update order status"
  }
}

Ship Order (Admin)

Mark an order as shipped with tracking information.

Endpoint: POST /admin/orders/:id/ship

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Required Role: ADMIN

Request Body:

{
  "carrier": "FedEx",
  "trackingNumber": "1Z999AA10123456784",
  "items": [
    {
      "orderItemId": "cm52kg0000011qv0akj8r9w3j",
      "quantity": 2
    }
  ]
}

Response: 200 OK

{
  "success": true,
  "data": {
    "shipment": {
      "id": "cm52kg0000020qv0akj8r9w3l",
      "orderId": "cm52kg0000010qv0akj8r9w3i",
      "carrier": "FedEx",
      "trackingNumber": "1Z999AA10123456784",
      "status": "SHIPPED",
      "shippedAt": "2024-01-16T14:20:00.000Z"
    },
    "order": {
      "id": "cm52kg0000010qv0akj8r9w3i",
      "status": "SHIPPED",
      "updatedAt": "2024-01-16T14:20:00.000Z"
    }
  }
}

Error Response: 400 Bad Request

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Order must be in PAID status to ship"
  }
}

Validation Rules:

  • carrier: Required
  • trackingNumber: Required
  • items: Optional, defaults to all items
  • Order must be in PAID status

Refund Order (Admin)

Process a full refund for an order.

Endpoint: POST /admin/orders/:id/refund

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Required Role: ADMIN

Request Body:

{
  "reason": "Customer requested refund due to defective product",
  "idempotencyKey": "refund_cm52kg0000010qv0akj8r9w3i_20240115"
}

Response: 200 OK

{
  "success": true,
  "data": {
    "refund": {
      "id": "cm52kg0000030qv0akj8r9w3m",
      "orderId": "cm52kg0000010qv0akj8r9w3i",
      "amount": 15999,
      "currency": "USD",
      "reason": "Customer requested refund due to defective product",
      "status": "SUCCEEDED",
      "processedAt": "2024-01-17T09:15:00.000Z"
    },
    "order": {
      "id": "cm52kg0000010qv0akj8r9w3i",
      "status": "REFUNDED",
      "paymentStatus": "REFUNDED",
      "updatedAt": "2024-01-17T09:15:00.000Z"
    }
  }
}

Error Response: 400 Bad Request

{
  "success": false,
  "error": {
    "code": "REFUND_ERROR",
    "message": "Order has already been refunded"
  }
}

Validation Rules:

  • idempotencyKey: Required, ensures refund is not processed twice
  • reason: Optional
  • Order must be in PAID or SHIPPED status
  • Full refund only (Alpha version limitation)

Cancel Order (Admin)

Cancel an order on behalf of a customer or due to fulfillment issues.

Endpoint: POST /admin/orders/:id/cancel

Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Required Role: ADMIN

Request Body:

{
  "cancelReason": "Out of stock - unable to fulfill order"
}

Response: 200 OK

{
  "success": true,
  "data": {
    "id": "cm52kg0000010qv0akj8r9w3i",
    "status": "CANCELLED",
    "paymentStatus": "REFUNDED",
    "cancelReason": "Out of stock - unable to fulfill order",
    "cancelledAt": "2024-01-16T10:00:00.000Z",
    "updatedAt": "2024-01-16T10:00:00.000Z"
  }
}

Error Response: 400 Bad Request

{
  "success": false,
  "error": {
    "code": "CANCEL_ERROR",
    "message": "Cannot cancel delivered orders"
  }
}

Validation Rules:

  • cancelReason: Required
  • Order cannot be in DELIVERED or REFUNDED status

Order Statuses

Status Definitions

StatusDescriptionNext Possible States
PENDINGOrder created, awaiting paymentPAID, CANCELLED
PAIDPayment successful, ready for fulfillmentSHIPPED, CANCELLED, REFUNDED
COMPLETEDOrder completed successfully-
SHIPPEDOrder dispatched with trackingDELIVERED, REFUNDED
DELIVEREDOrder delivered to customerCOMPLETED
CANCELLEDOrder cancelled before shipment-
REFUNDEDPayment refunded to customer-

Payment Statuses

StatusDescription
PENDINGPayment not yet processed
PAIDPayment successful
FAILEDPayment failed
REFUNDEDPayment refunded

Complete Order Lifecycle Example

Step 1: Create Order

const createOrderResponse = await fetch('http://localhost:3001/orders', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    items: [
      {
        productId: 'prod_123',
        variantId: 'var_456',
        quantity: 2
      }
    ],
    shippingAddress: {
      firstName: 'John',
      lastName: 'Doe',
      address: '123 Main St',
      city: 'New York',
      postalCode: '10001',
      country: 'United States'
    }
  }),
});

const { data: order } = await createOrderResponse.json();
// Order status: PENDING

Step 2: Process Payment (External Payment Gateway)

// Integrate with Stripe, PayPal, or other payment provider
const paymentIntent = await stripe.paymentIntents.create({
  amount: order.totalAmount,
  currency: order.currency,
  metadata: {
    orderId: order.id
  }
});

// After successful payment, webhook updates order to PAID status

Step 3: Fulfill Order (Admin)

// Admin ships the order
const shipResponse = await fetch(`http://localhost:3001/admin/orders/${order.id}/ship`, {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${adminToken}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    carrier: 'FedEx',
    trackingNumber: '1Z999AA10123456784'
  }),
});
// Order status: SHIPPED

Step 4: Mark as Delivered

// Update order status when delivery is confirmed
const statusResponse = await fetch(`http://localhost:3001/admin/orders/${order.id}/status`, {
  method: 'PUT',
  headers: {
    'Authorization': `Bearer ${adminToken}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    status: 'DELIVERED'
  }),
});
// Order status: DELIVERED

Step 5: Complete Order

// Mark order as completed
const completeResponse = await fetch(`http://localhost:3001/admin/orders/${order.id}/status`, {
  method: 'PUT',
  headers: {
    'Authorization': `Bearer ${adminToken}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    status: 'COMPLETED'
  }),
});
// Order status: COMPLETED

Usage Examples

JavaScript/TypeScript (Fetch API)

Create Order with Error Handling

async function createOrder(items: any[], shippingAddress: any) {
  const token = localStorage.getItem('access_token');

  try {
    const response = await fetch('http://localhost:3001/orders', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ items, shippingAddress }),
    });

    const result = await response.json();

    if (!result.success) {
      throw new Error(result.error.message);
    }

    return result.data;
  } catch (error) {
    console.error('Order creation failed:', error);
    throw error;
  }
}

// Usage
const order = await createOrder(
  [
    { productId: 'prod_123', variantId: 'var_456', quantity: 2 }
  ],
  {
    firstName: 'John',
    lastName: 'Doe',
    address: '123 Main St',
    city: 'New York',
    postalCode: '10001',
    country: 'United States'
  }
);

Get Orders with Pagination

async function getUserOrders(page = 1, limit = 10, status?: string) {
  const token = localStorage.getItem('access_token');

  const params = new URLSearchParams({
    page: page.toString(),
    limit: limit.toString(),
    ...(status && { status })
  });

  const response = await fetch(`http://localhost:3001/orders?${params}`, {
    headers: {
      'Authorization': `Bearer ${token}`,
    },
  });

  const result = await response.json();
  return result.data;
}

// Usage
const orders = await getUserOrders(1, 10, 'PAID');

Track Order Status

async function trackOrder(orderId: string) {
  const token = localStorage.getItem('access_token');

  const response = await fetch(`http://localhost:3001/orders/${orderId}`, {
    headers: {
      'Authorization': `Bearer ${token}`,
    },
  });

  const result = await response.json();

  if (result.success) {
    console.log('Order Status:', result.data.status);
    console.log('Payment Status:', result.data.paymentStatus);

    if (result.data.shipments?.length > 0) {
      const shipment = result.data.shipments[0];
      console.log(`Tracking: ${shipment.carrier} - ${shipment.trackingNumber}`);
    }
  }

  return result.data;
}

Cancel Order

async function cancelOrder(orderId: string, reason: string) {
  const token = localStorage.getItem('access_token');

  const response = await fetch(`http://localhost:3001/orders/${orderId}/cancel`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ cancelReason: reason }),
  });

  const result = await response.json();

  if (!result.success) {
    throw new Error(result.error.message);
  }

  return result.data;
}

// Usage
await cancelOrder('order_123', 'Changed my mind');

cURL Examples

Create Order

curl -X POST http://localhost:3001/orders \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {
        "productId": "cm52kg0000001qv0akj8r9w3e",
        "variantId": "cm52kg0000002qv0akj8r9w3f",
        "quantity": 2
      }
    ],
    "shippingAddress": {
      "firstName": "John",
      "lastName": "Doe",
      "address": "123 Main St",
      "city": "New York",
      "postalCode": "10001",
      "country": "United States"
    }
  }'

Get User Orders

curl -X GET "http://localhost:3001/orders?page=1&limit=10&status=PAID" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Get Order by ID

curl -X GET http://localhost:3001/orders/cm52kg0000010qv0akj8r9w3i \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Cancel Order

curl -X POST http://localhost:3001/orders/cm52kg0000010qv0akj8r9w3i/cancel \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "cancelReason": "Changed my mind about the purchase"
  }'

Ship Order (Admin)

curl -X POST http://localhost:3001/admin/orders/cm52kg0000010qv0akj8r9w3i/ship \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "carrier": "FedEx",
    "trackingNumber": "1Z999AA10123456784"
  }'

Refund Order (Admin)

curl -X POST http://localhost:3001/admin/orders/cm52kg0000010qv0akj8r9w3i/refund \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Defective product",
    "idempotencyKey": "refund_cm52kg0000010qv0akj8r9w3i_20240115"
  }'

Error Handling

Common Error Codes

CodeStatusDescriptionSolution
BAD_REQUEST400Invalid request dataCheck request format and validation rules
UNAUTHORIZED401Missing or invalid tokenLogin and provide valid token
NOT_FOUND404Order not foundVerify order ID exists
VALIDATION_ERROR400Invalid order state transitionCheck order status requirements
REFUND_ERROR400Refund processing failedVerify order is eligible for refund
CANCEL_ERROR400Cancellation not allowedCheck order status and rules
INTERNAL_SERVER_ERROR500Server errorRetry or contact support

Error Response Format

All errors follow this format:

{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error message"
  }
}

Handling Order State Errors

try {
  await cancelOrder(orderId, reason);
} catch (error: any) {
  const response = await error.response.json();

  if (response.error.code === 'BAD_REQUEST') {
    if (response.error.message.includes('shipped')) {
      alert('Cannot cancel order - it has already been shipped');
    } else {
      alert('Invalid cancellation request');
    }
  }
}

Best Practices

Order Creation

✅ Recommended:

  • Validate inventory before creating orders
  • Always provide complete shipping address
  • Store order ID for tracking and reference
  • Handle payment processing asynchronously
  • Implement idempotency for payment webhooks

❌ Avoid:

  • Creating orders without stock validation
  • Proceeding without proper error handling
  • Assuming immediate payment success
  • Duplicate payment processing

Order Management

✅ Recommended:

  • Poll order status for updates
  • Provide tracking information to customers
  • Implement webhook handlers for payment events
  • Use idempotency keys for refunds
  • Validate order state before transitions

❌ Avoid:

  • Changing order status without validation
  • Processing refunds without idempotency
  • Shipping orders before payment confirmation

Security

  • Always use HTTPS in production
  • Validate user ownership for order access
  • Require admin role for management endpoints
  • Implement rate limiting on order creation
  • Log all order state changes for audit trail

Webhooks & Events

Payment Webhook

When integrating with payment providers, implement webhooks to update order status:

// Example webhook handler
app.post('/webhooks/payment', async (req, res) => {
  const { orderId, status, paymentId } = req.body;

  if (status === 'succeeded') {
    await OrderService.updatePaymentStatus(orderId, 'PAID');
    await OrderService.updateOrderStatus(orderId, 'PAID');
  } else if (status === 'failed') {
    await OrderService.updatePaymentStatus(orderId, 'FAILED');
    await OrderService.cancelOrder(orderId, null, 'Payment failed');
  }

  res.json({ received: true });
});

Order Status Notifications

Send email or push notifications on status changes:

const ORDER_STATUS_EVENTS = {
  PAID: 'Order Confirmed',
  SHIPPED: 'Order Shipped',
  DELIVERED: 'Order Delivered',
  CANCELLED: 'Order Cancelled',
  REFUNDED: 'Refund Processed'
};

// Notify customer on status change
async function notifyCustomer(order: Order) {
  const event = ORDER_STATUS_EVENTS[order.status];

  await emailService.send({
    to: order.customerEmail,
    subject: `${event} - Order #${order.id}`,
    template: 'order-status-update',
    data: { order, event }
  });
}

Rate Limiting

Order endpoints are rate limited to prevent abuse:

EndpointLimit
POST /orders10 requests/minute per user
GET /orders60 requests/minute per user
GET /orders/:id100 requests/minute per user
POST /orders/:id/cancel5 requests/hour per user
POST /admin/orders/:id/ship30 requests/minute per admin
POST /admin/orders/:id/refund10 requests/hour per admin

Exceeding rate limits returns:

{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many order creation requests. Please try again later.",
    "retryAfter": 60
  }
}

Next Steps

On this page