REST API
Complete REST API documentation for the e-commerce platform, including cart management, order processing, and payment handling.
E-Commerce REST API
Complete REST API documentation for Jose Madrid Salsa's e-commerce platform. This API provides endpoints for cart management, order processing, and payment handling.
Overview
Base URL: https://josemadrid.net/api (Production) or http://localhost:3000/api (Development)
Content Type: application/json
API Version: 1.0
All endpoints return JSON responses with a consistent structure and use standard HTTP status codes.
Authentication
Most endpoints require authentication using NextAuth session cookies. Users must be logged in to access protected endpoints.
Protected Endpoints:
- All cart endpoints (
/api/cart/*) - All order endpoints (
/api/orders/*) - Payment processing (
/api/payment)
Authentication Method: Session-based authentication via NextAuth
How to Authenticate:
- User logs in through the web interface
- NextAuth creates a secure session
- Session cookie is automatically included in subsequent requests
Unauthenticated Response:
{
"error": "Unauthorized - authentication required"
}Status Code: 401 Unauthorized
Error Handling
All API endpoints follow a standardized error response format:
{
"error": "Error message description",
"details": {
// Optional detailed error information (validation errors, etc.)
}
}Common HTTP Status Codes:
200 OK- Request succeeded201 Created- Resource created successfully400 Bad Request- Invalid request data401 Unauthorized- Authentication required403 Forbidden- Insufficient permissions404 Not Found- Resource not found429 Too Many Requests- Rate limit exceeded500 Internal Server Error- Server error
Rate Limiting
API endpoints are protected by rate limiting to prevent abuse:
Default Limits:
- 100 requests per 15-minute window per IP address
- Limits apply per endpoint
Rate Limit Headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640995200Rate Limit Exceeded Response:
{
"error": "Rate limit exceeded. Please try again later."
}Status Code: 429 Too Many Requests
Header: Retry-After: 900 (seconds until reset)
Cart Management
Get Cart
Retrieve the authenticated user's shopping cart with all items and totals.
Endpoint: GET /api/cart
Authentication: Required
Response (200 OK):
{
"items": [
{
"id": "cm5abc123xyz",
"productId": "cm5prod456def",
"quantity": 2,
"product": {
"id": "cm5prod456def",
"name": "Jalapeño Hot Sauce",
"slug": "jalapeno-hot-sauce",
"price": 8.99,
"compareAtPrice": 10.99,
"featuredImage": "https://cdn.josemadrid.net/products/jalapeno.jpg",
"heatLevel": 3,
"inventory": 50
}
}
],
"itemCount": 1,
"totalQuantity": 2,
"subtotal": 17.98
}Error Responses:
401 Unauthorized- User not authenticated500 Internal Server Error- Database error
Example Request:
curl -X GET https://josemadrid.net/api/cart \
-H "Cookie: next-auth.session-token=..." \
-H "Content-Type: application/json"Add to Cart
Add a product to the authenticated user's cart. If the product already exists in the cart, the quantity is incremented.
Endpoint: POST /api/cart
Authentication: Required
Request Body:
{
"productId": "cm5prod456def",
"quantity": 2
}Field Validation:
productId(required): Valid CUID stringquantity(required): Positive integer (minimum 1)
Response (200 OK):
{
"success": true,
"cartItem": {
"id": "cm5cart789ghi",
"productId": "cm5prod456def",
"quantity": 2,
"product": {
"id": "cm5prod456def",
"name": "Jalapeño Hot Sauce",
"price": 8.99,
"featuredImage": "https://cdn.josemadrid.net/products/jalapeno.jpg"
}
}
}Error Responses:
400 Bad Request- Invalid request payload or validation error401 Unauthorized- User not authenticated404 Not Found- Product not found500 Internal Server Error- Database error
Example Request:
curl -X POST https://josemadrid.net/api/cart \
-H "Cookie: next-auth.session-token=..." \
-H "Content-Type: application/json" \
-d '{
"productId": "cm5prod456def",
"quantity": 2
}'Update Cart Item
Update the quantity of an existing cart item.
Endpoint: PUT /api/cart/{id}
Authentication: Required
Path Parameters:
id(required): Cart item ID (CUID string)
Request Body:
{
"quantity": 3
}Field Validation:
quantity(required): Positive integer (minimum 1)
Response (200 OK):
{
"success": true,
"cartItem": {
"id": "cm5cart789ghi",
"productId": "cm5prod456def",
"quantity": 3,
"product": {
"id": "cm5prod456def",
"name": "Jalapeño Hot Sauce",
"price": 8.99,
"featuredImage": "https://cdn.josemadrid.net/products/jalapeno.jpg"
}
}
}Error Responses:
400 Bad Request- Invalid quantity or insufficient inventory401 Unauthorized- User not authenticated403 Forbidden- Cart item belongs to another user404 Not Found- Cart item not found500 Internal Server Error- Database error
Example Request:
curl -X PUT https://josemadrid.net/api/cart/cm5cart789ghi \
-H "Cookie: next-auth.session-token=..." \
-H "Content-Type: application/json" \
-d '{
"quantity": 3
}'Remove Cart Item
Remove an item from the authenticated user's cart.
Endpoint: DELETE /api/cart/{id}
Authentication: Required
Path Parameters:
id(required): Cart item ID (CUID string)
Response (200 OK):
{
"success": true,
"message": "Cart item removed successfully"
}Error Responses:
401 Unauthorized- User not authenticated403 Forbidden- Cart item belongs to another user404 Not Found- Cart item not found500 Internal Server Error- Database error
Example Request:
curl -X DELETE https://josemadrid.net/api/cart/cm5cart789ghi \
-H "Cookie: next-auth.session-token=..." \
-H "Content-Type: application/json"Order Management
Create Order
Create a new order from cart items. This endpoint:
- Validates inventory availability
- Calculates tax using Stripe Tax API
- Calculates shipping costs
- Creates the order and order items
- Removes cart items after successful order creation
- Creates a Stripe payment intent
- Queues Shopify sync
Endpoint: POST /api/orders
Authentication: Required
Request Body:
{
"cartItemIds": ["cm5cart123abc", "cm5cart456def"],
"shippingAddress": {
"address1": "123 Main Street",
"address2": "Apt 4B",
"city": "Austin",
"state": "TX",
"postalCode": "78701",
"country": "US"
},
"billingAddress": {
"address1": "123 Main Street",
"city": "Austin",
"state": "TX",
"postalCode": "78701",
"country": "US"
},
"notes": "Please ring doorbell"
}Field Validation:
cartItemIds(required): Array of cart item IDs (minimum 1 item)shippingAddress(required): Object with address fieldsaddress1(required): Street addressaddress2(optional): Apartment, suite, etc.city(required): City namestate(required): State/province codepostalCode(required): ZIP/postal codecountry(optional): Country code (defaults to "US")
billingAddress(optional): Same structure as shipping addressnotes(optional): Customer notes
Response (200 OK):
{
"clientSecret": "pi_3ABC123xyz_secret_DEF456uvw",
"orderId": "cm5order789ghi",
"orderNumber": "JMS-20260301-1234",
"amount": 42.57
}Response Fields:
clientSecret: Stripe payment intent client secret for frontend payment processingorderId: Unique order ID for trackingorderNumber: Human-readable order number (format:JMS-YYYYMMDD-XXXX)amount: Total order amount in USD
Error Responses:
400 Bad Request- Invalid payload, cart items not found, or insufficient inventory401 Unauthorized- User not authenticated500 Internal Server Error- Order creation failed
Example Request:
curl -X POST https://josemadrid.net/api/orders \
-H "Cookie: next-auth.session-token=..." \
-H "Content-Type: application/json" \
-d '{
"cartItemIds": ["cm5cart123abc"],
"shippingAddress": {
"address1": "123 Main Street",
"city": "Austin",
"state": "TX",
"postalCode": "78701",
"country": "US"
}
}'List Orders
Retrieve a paginated list of orders for the authenticated user with optional filtering.
Endpoint: GET /api/orders
Authentication: Required
Query Parameters:
status(optional): Filter by order status (PENDING,CONFIRMED,PROCESSING,SHIPPED,DELIVERED,CANCELLED,REFUNDED, orall)paymentStatus(optional): Filter by payment status (PENDING,PAID,FAILED,REFUNDED, orall)skip(optional): Number of orders to skip (default: 0)take(optional): Number of orders to return (no default, returns all if not specified)sortOrder(optional): Sort order by creation date (ascordesc, default:desc)
Response (200 OK):
[
{
"id": "cm5order789ghi",
"orderNumber": "JMS-20260301-1234",
"status": "CONFIRMED",
"paymentStatus": "PAID",
"subtotal": 35.96,
"shippingCost": 5.99,
"tax": 3.42,
"discountAmount": 0,
"total": 45.37,
"shippingMethod": "123 Main Street, Apt 4B\nAustin, TX 78701",
"trackingNumber": null,
"customerNotes": "Please ring doorbell",
"stripePaymentIntentId": "pi_3ABC123xyz",
"createdAt": "2026-03-01T10:30:00.000Z",
"updatedAt": "2026-03-01T10:35:00.000Z",
"items": [
{
"id": "cm5item123abc",
"productId": "cm5prod456def",
"productName": "Jalapeño Hot Sauce",
"productSku": "JHS-001",
"productImage": "https://cdn.josemadrid.net/products/jalapeno.jpg",
"quantity": 4,
"unitPrice": 8.99,
"totalPrice": 35.96,
"product": {
"id": "cm5prod456def",
"name": "Jalapeño Hot Sauce",
"slug": "jalapeno-hot-sauce",
"featuredImage": "https://cdn.josemadrid.net/products/jalapeno.jpg",
"heatLevel": 3
}
}
]
}
]Error Responses:
401 Unauthorized- User not authenticated500 Internal Server Error- Database error
Example Request:
# Get all orders
curl -X GET https://josemadrid.net/api/orders \
-H "Cookie: next-auth.session-token=..." \
-H "Content-Type: application/json"
# Get paid orders with pagination
curl -X GET "https://josemadrid.net/api/orders?paymentStatus=PAID&skip=0&take=10" \
-H "Cookie: next-auth.session-token=..." \
-H "Content-Type: application/json"Get Order Details
Retrieve detailed information about a specific order.
Endpoint: GET /api/orders/{id}
Authentication: Required
Path Parameters:
id(required): Order ID (CUID string)
Response (200 OK):
{
"id": "cm5order789ghi",
"orderNumber": "JMS-20260301-1234",
"status": "CONFIRMED",
"paymentStatus": "PAID",
"subtotal": 35.96,
"shippingCost": 5.99,
"tax": 3.42,
"discountAmount": 0,
"total": 45.37,
"shippingMethod": "123 Main Street, Apt 4B\nAustin, TX 78701",
"trackingNumber": "1Z999AA10123456784",
"customerNotes": "Please ring doorbell",
"stripePaymentIntentId": "pi_3ABC123xyz",
"createdAt": "2026-03-01T10:30:00.000Z",
"updatedAt": "2026-03-01T10:35:00.000Z",
"items": [
{
"id": "cm5item123abc",
"productId": "cm5prod456def",
"productName": "Jalapeño Hot Sauce",
"productSku": "JHS-001",
"productImage": "https://cdn.josemadrid.net/products/jalapeno.jpg",
"quantity": 4,
"unitPrice": 8.99,
"totalPrice": 35.96,
"product": {
"id": "cm5prod456def",
"name": "Jalapeño Hot Sauce",
"slug": "jalapeno-hot-sauce",
"featuredImage": "https://cdn.josemadrid.net/products/jalapeno.jpg",
"heatLevel": 3
}
}
]
}Error Responses:
401 Unauthorized- User not authenticated403 Forbidden- Order belongs to a different user404 Not Found- Order not found500 Internal Server Error- Database error
Example Request:
curl -X GET https://josemadrid.net/api/orders/cm5order789ghi \
-H "Cookie: next-auth.session-token=..." \
-H "Content-Type: application/json"Payment Processing
Process Payment
Process payment for an existing order using Stripe. This endpoint:
- Validates order ownership and status
- Prevents duplicate payments
- Confirms the existing Stripe PaymentIntent created by
POST /api/orders - Updates order payment and status
- Logs audit events
Endpoint: POST /api/payment
Authentication: Required
Request Body:
{
"orderId": "cm5order789ghi",
"paymentMethodId": "pm_1ABC123xyz456"
}Field Validation:
orderId(required): Valid order ID (CUID string)paymentMethodId(required): Stripe payment method ID
Response (200 OK):
{
"success": true,
"paymentIntent": {
"id": "pi_3ABC123xyz",
"status": "succeeded",
"clientSecret": "pi_3ABC123xyz_secret_DEF456uvw"
},
"order": {
"id": "cm5order789ghi",
"orderNumber": "JMS-20260301-1234",
"paymentStatus": "PAID",
"status": "CONFIRMED"
}
}Payment Intent Status Values:
succeeded- Payment completed successfully (order status → CONFIRMED, payment status → PAID)requires_action- Additional authentication required (3D Secure, etc.)requires_payment_method- Payment method declined, new method neededcanceled- Payment canceled (payment status → FAILED)
Error Responses:
400 Bad Request- Invalid payload400 Bad Request- Order already paid400 Bad Request- Order in non-payable status401 Unauthorized- User not authenticated402 Payment Required- Card declined (Stripe card error)403 Forbidden- User doesn't own the order404 Not Found- Order not found500 Internal Server Error- Payment processing error
Example Request:
curl -X POST https://josemadrid.net/api/payment \
-H "Cookie: next-auth.session-token=..." \
-H "Content-Type: application/json" \
-d '{
"orderId": "cm5order789ghi",
"paymentMethodId": "pm_1ABC123xyz456"
}'Common Error Codes
| Status Code | Meaning | Common Causes |
|---|---|---|
400 | Bad Request | Invalid input, validation errors, business rule violations |
401 | Unauthorized | Not logged in, session expired |
403 | Forbidden | Insufficient permissions, accessing another user's resource |
404 | Not Found | Resource doesn't exist |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Database error, external service failure |
Complete Purchase Flow Example
This example demonstrates a complete purchase flow from adding items to cart through payment processing.
Step 1: Add Products to Cart
# Add first product
curl -X POST https://josemadrid.net/api/cart \
-H "Cookie: next-auth.session-token=..." \
-H "Content-Type: application/json" \
-d '{
"productId": "cm5prod123",
"quantity": 2
}'
# Add second product
curl -X POST https://josemadrid.net/api/cart \
-H "Cookie: next-auth.session-token=..." \
-H "Content-Type: application/json" \
-d '{
"productId": "cm5prod456",
"quantity": 1
}'Step 2: Review Cart
curl -X GET https://josemadrid.net/api/cart \
-H "Cookie: next-auth.session-token=..." \
-H "Content-Type: application/json"Step 3: Create Order
curl -X POST https://josemadrid.net/api/orders \
-H "Cookie: next-auth.session-token=..." \
-H "Content-Type: application/json" \
-d '{
"cartItemIds": ["cm5cart123", "cm5cart456"],
"shippingAddress": {
"address1": "123 Main Street",
"city": "Austin",
"state": "TX",
"postalCode": "78701",
"country": "US"
}
}'Response:
{
"clientSecret": "pi_3ABC123xyz_secret_DEF456uvw",
"orderId": "cm5order789",
"orderNumber": "JMS-20260301-1234",
"amount": 42.57
}Step 4: Process Payment
curl -X POST https://josemadrid.net/api/payment \
-H "Cookie: next-auth.session-token=..." \
-H "Content-Type: application/json" \
-d '{
"orderId": "cm5order789",
"paymentMethodId": "pm_1ABC123xyz456"
}'Response:
{
"success": true,
"paymentIntent": {
"id": "pi_3ABC123xyz",
"status": "succeeded",
"clientSecret": "pi_3ABC123xyz_secret_DEF456uvw"
},
"order": {
"id": "cm5order789",
"orderNumber": "JMS-20260301-1234",
"paymentStatus": "PAID",
"status": "CONFIRMED"
}
}Step 5: Get Order Details
curl -X GET https://josemadrid.net/api/orders/cm5order789 \
-H "Cookie: next-auth.session-token=..." \
-H "Content-Type: application/json"Cart Management Example
Managing cart items:
# Get current cart
curl -X GET https://josemadrid.net/api/cart \
-H "Cookie: next-auth.session-token=..."
# Update quantity
curl -X PUT https://josemadrid.net/api/cart/cm5cart123 \
-H "Cookie: next-auth.session-token=..." \
-H "Content-Type: application/json" \
-d '{"quantity": 5}'
# Remove item
curl -X DELETE https://josemadrid.net/api/cart/cm5cart456 \
-H "Cookie: next-auth.session-token=..."Order History Example
Retrieving order history with filtering:
# Get all orders (most recent first)
curl -X GET https://josemadrid.net/api/orders \
-H "Cookie: next-auth.session-token=..."
# Get only paid orders
curl -X GET "https://josemadrid.net/api/orders?paymentStatus=PAID" \
-H "Cookie: next-auth.session-token=..."
# Get pending orders with pagination
curl -X GET "https://josemadrid.net/api/orders?status=PENDING&skip=0&take=10&sortOrder=asc" \
-H "Cookie: next-auth.session-token=..."Security Features
Authentication
- Session-based authentication via NextAuth
- All cart, order, and payment endpoints require authentication
- User can only access their own resources (cart items, orders)
Authorization
- Row-level security: Users can only view/modify their own data
- Ownership validation on all update/delete operations
- Forbidden (403) response when attempting to access another user's resources
Input Validation
- All request payloads validated using Zod schemas
- Type-safe validation for all fields
- Detailed validation error messages
Inventory Protection
- Inventory checked before adding to cart
- Inventory re-validated during order creation
- Prevents overselling with race condition handling
Payment Security
- Stripe integration for PCI-compliant payment processing
- Payment intent validation
- Duplicate payment prevention
- Order status validation before payment
Audit Logging
- All cart, order, and payment operations are logged
- Includes user ID, action type, and changes
- IP address and user agent tracked for security
Rate Limiting
- 100 requests per 15 minutes per IP
- Prevents brute force and abuse
- Automatic rate limit headers in responses
Support
For API support or questions:
- Email: support@josemadrid.net
- Documentation: https://josemadrid.net/docs
- Status Page: https://status.josemadrid.net
How is this guide?
Last updated on