Some checks failed
- Add Development URL Quick Reference section to url-routing overview with all login URLs, entry points, and full examples - Replace /shop/ path segments with /storefront/ across 50 docs files - Update file references: shop_pages.py → storefront_pages.py, templates/shop/ → templates/storefront/, api/v1/shop/ → api/v1/storefront/ - Preserve domain references (orion.shop) and /store/ staff dashboard paths - Archive docs left unchanged (historical) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
912 lines
19 KiB
Markdown
912 lines
19 KiB
Markdown
# Storefront API Reference
|
||
|
||
**Last Updated:** 2026-01-29
|
||
**API Version:** v1
|
||
**Base Path:** `/api/v1/storefront`
|
||
|
||
---
|
||
|
||
## Overview
|
||
|
||
The Storefront API provides customer-facing endpoints for browsing products, managing cart, placing orders, and customer authentication. All endpoints use **middleware-based store context** - no store ID in URLs!
|
||
|
||
### Key Features
|
||
|
||
✅ **Automatic Store Detection** - Store extracted from Referer header via middleware
|
||
✅ **Multi-Tenant** - Each store has isolated customer data
|
||
✅ **Session-Based Cart** - No authentication required for browsing/cart
|
||
✅ **Secure Authentication** - JWT tokens with HTTP-only cookies (path=/storefront)
|
||
✅ **RESTful Design** - Standard HTTP methods and status codes
|
||
|
||
---
|
||
|
||
## How Store Context Works
|
||
|
||
All Storefront API endpoints automatically receive store context from the `StoreContextMiddleware`:
|
||
|
||
1. **Browser makes API call** from storefront page (e.g., `/platforms/oms/storefront/ORION/products`)
|
||
2. **Browser automatically sends Referer header**: `http://localhost:8000/platforms/oms/storefront/ORION/products`
|
||
3. **Middleware extracts store** from Referer path/subdomain/domain
|
||
4. **Middleware sets** `request.state.store = <Store: ORION>`
|
||
5. **API endpoint accesses store**: `store = request.state.store`
|
||
6. **No store_id needed in URL!**
|
||
|
||
### Supported Store Detection Methods
|
||
|
||
- **Path-based (dev)**: `/platforms/oms/storefront/ORION/products` → extracts `ORION`
|
||
- **Subdomain**: `orion.platform.com` → extracts `orion`
|
||
- **Custom domain**: `customshop.com` → looks up store by domain
|
||
|
||
---
|
||
|
||
## Authentication
|
||
|
||
### Public Endpoints (No Auth Required)
|
||
|
||
- Product catalog
|
||
- Product details
|
||
- Product search
|
||
- Cart operations
|
||
- CMS content pages
|
||
|
||
### Authenticated Endpoints (Customer Token Required)
|
||
|
||
- Place order
|
||
- Order history
|
||
- Order details
|
||
|
||
### Authentication Headers
|
||
|
||
For authenticated requests, include the JWT token:
|
||
|
||
```http
|
||
Authorization: Bearer <customer_token>
|
||
```
|
||
|
||
Or use the HTTP-only cookie (automatically sent by browser):
|
||
|
||
```http
|
||
Cookie: customer_token=<jwt_token>
|
||
```
|
||
|
||
---
|
||
|
||
## Products
|
||
|
||
### Get Product Catalog
|
||
|
||
Get paginated list of products for current store.
|
||
|
||
**Endpoint:** `GET /api/v1/storefront/products`
|
||
|
||
**Query Parameters:**
|
||
|
||
| Parameter | Type | Default | Description |
|
||
|-----------|------|---------|-------------|
|
||
| `skip` | integer | 0 | Number of products to skip (pagination) |
|
||
| `limit` | integer | 100 | Maximum products to return (max 1000) |
|
||
| `search` | string | null | Search products by name/description |
|
||
| `is_featured` | boolean | null | Filter by featured products only |
|
||
|
||
**Request Example:**
|
||
|
||
```http
|
||
GET /api/v1/storefront/products?skip=0&limit=20&is_featured=true
|
||
Referer: http://localhost:8000/storefront/orion/products
|
||
```
|
||
|
||
**Response (200 OK):**
|
||
|
||
```json
|
||
{
|
||
"products": [
|
||
{
|
||
"id": 1,
|
||
"store_id": 1,
|
||
"product_id": "PROD-001",
|
||
"price": 29.99,
|
||
"sale_price": null,
|
||
"currency": "EUR",
|
||
"availability": "in stock",
|
||
"is_featured": true,
|
||
"is_active": true,
|
||
"marketplace_product": {
|
||
"title": "Sample Product",
|
||
"description": "Product description...",
|
||
"image_link": "https://example.com/image.jpg",
|
||
"brand": "Brand Name"
|
||
}
|
||
}
|
||
],
|
||
"total": 50,
|
||
"skip": 0,
|
||
"limit": 20
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### Get Product Details
|
||
|
||
Get detailed information for a specific product.
|
||
|
||
**Endpoint:** `GET /api/v1/storefront/products/{product_id}`
|
||
|
||
**Path Parameters:**
|
||
|
||
| Parameter | Type | Description |
|
||
|-----------|------|-------------|
|
||
| `product_id` | integer | Product ID |
|
||
|
||
**Request Example:**
|
||
|
||
```http
|
||
GET /api/v1/storefront/products/1
|
||
Referer: http://localhost:8000/storefront/orion/products
|
||
```
|
||
|
||
**Response (200 OK):**
|
||
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"store_id": 1,
|
||
"product_id": "PROD-001",
|
||
"price": 29.99,
|
||
"sale_price": 24.99,
|
||
"currency": "EUR",
|
||
"availability": "in stock",
|
||
"condition": "new",
|
||
"is_featured": true,
|
||
"is_active": true,
|
||
"min_quantity": 1,
|
||
"max_quantity": 10,
|
||
"total_inventory": 100,
|
||
"available_inventory": 95,
|
||
"marketplace_product": {
|
||
"title": "Sample Product",
|
||
"description": "Full product description...",
|
||
"image_link": "https://example.com/image.jpg",
|
||
"brand": "Brand Name",
|
||
"gtin": "1234567890123"
|
||
}
|
||
}
|
||
```
|
||
|
||
**Error Responses:**
|
||
|
||
- `404 Not Found` - Product not found or not active
|
||
- `404 Not Found` - Store not found (missing/invalid Referer)
|
||
|
||
---
|
||
|
||
## Shopping Cart
|
||
|
||
Cart operations use session-based tracking (no authentication required).
|
||
|
||
### Get Cart
|
||
|
||
Retrieve cart contents for a session.
|
||
|
||
**Endpoint:** `GET /api/v1/storefront/cart/{session_id}`
|
||
|
||
**Path Parameters:**
|
||
|
||
| Parameter | Type | Description |
|
||
|-----------|------|-------------|
|
||
| `session_id` | string | Unique session identifier |
|
||
|
||
**Request Example:**
|
||
|
||
```http
|
||
GET /api/v1/storefront/cart/session-abc-123
|
||
Referer: http://localhost:8000/storefront/orion/cart
|
||
```
|
||
|
||
**Response (200 OK):**
|
||
|
||
```json
|
||
{
|
||
"store_id": 1,
|
||
"session_id": "session-abc-123",
|
||
"items": [
|
||
{
|
||
"product_id": 1,
|
||
"product_name": "Sample Product",
|
||
"quantity": 2,
|
||
"price": 29.99,
|
||
"line_total": 59.98,
|
||
"image_url": "https://example.com/image.jpg"
|
||
}
|
||
],
|
||
"subtotal": 59.98,
|
||
"total": 59.98,
|
||
"item_count": 1
|
||
}
|
||
```
|
||
|
||
**Response Schema:** `CartResponse`
|
||
|
||
| Field | Type | Description |
|
||
|-------|------|-------------|
|
||
| `store_id` | integer | Store ID |
|
||
| `session_id` | string | Shopping session ID |
|
||
| `items` | array | List of cart items (see CartItemResponse below) |
|
||
| `subtotal` | float | Subtotal of all items |
|
||
| `total` | float | Total amount (currently same as subtotal) |
|
||
| `item_count` | integer | Total number of unique items in cart |
|
||
|
||
**CartItemResponse Schema:**
|
||
|
||
| Field | Type | Description |
|
||
|-------|------|-------------|
|
||
| `product_id` | integer | Product ID |
|
||
| `product_name` | string | Product name |
|
||
| `quantity` | integer | Quantity in cart |
|
||
| `price` | float | Price per unit (captured when added to cart) |
|
||
| `line_total` | float | Total for this line (price × quantity) |
|
||
| `image_url` | string \| null | Product image URL |
|
||
|
||
---
|
||
|
||
### Add to Cart
|
||
|
||
Add a product to the cart. If the product already exists in the cart, the quantity will be incremented.
|
||
|
||
**Endpoint:** `POST /api/v1/storefront/cart/{session_id}/items`
|
||
|
||
**Path Parameters:**
|
||
|
||
| Parameter | Type | Description |
|
||
|-----------|------|-------------|
|
||
| `session_id` | string | Unique session identifier |
|
||
|
||
**Request Body Schema:** `AddToCartRequest`
|
||
|
||
| Field | Type | Required | Description |
|
||
|-------|------|----------|-------------|
|
||
| `product_id` | integer | Yes | Product ID to add (must be > 0) |
|
||
| `quantity` | integer | No | Quantity to add (default: 1, must be >= 1) |
|
||
|
||
**Request Example:**
|
||
|
||
```json
|
||
{
|
||
"product_id": 1,
|
||
"quantity": 2
|
||
}
|
||
```
|
||
|
||
**Response (200 OK):** `CartOperationResponse`
|
||
|
||
```json
|
||
{
|
||
"message": "Product added to cart",
|
||
"product_id": 1,
|
||
"quantity": 2
|
||
}
|
||
```
|
||
|
||
**Response Schema:**
|
||
|
||
| Field | Type | Description |
|
||
|-------|------|-------------|
|
||
| `message` | string | Operation result message |
|
||
| `product_id` | integer | Product ID affected |
|
||
| `quantity` | integer | New quantity in cart |
|
||
|
||
**Error Responses:**
|
||
|
||
- `404 Not Found` - Product not found or store not found
|
||
```json
|
||
{
|
||
"error_code": "PRODUCT_NOT_FOUND",
|
||
"message": "Product with ID '123' not found in store 1 catalog",
|
||
"status_code": 404,
|
||
"details": {
|
||
"product_id": 123,
|
||
"store_id": 1
|
||
}
|
||
}
|
||
```
|
||
|
||
- `400 Bad Request` - Insufficient inventory
|
||
```json
|
||
{
|
||
"error_code": "INSUFFICIENT_INVENTORY_FOR_CART",
|
||
"message": "Insufficient inventory for product 'Sample Product'. Requested: 10, Available: 5",
|
||
"status_code": 400,
|
||
"details": {
|
||
"product_id": 1,
|
||
"product_name": "Sample Product",
|
||
"requested_quantity": 10,
|
||
"available_quantity": 5
|
||
}
|
||
}
|
||
```
|
||
|
||
- `422 Unprocessable Entity` - Validation error
|
||
```json
|
||
{
|
||
"error_code": "INVALID_CART_QUANTITY",
|
||
"message": "Quantity must be at least 1",
|
||
"status_code": 422,
|
||
"details": {
|
||
"field": "quantity",
|
||
"quantity": 0,
|
||
"min_quantity": 1
|
||
}
|
||
}
|
||
```
|
||
|
||
**Implementation Notes:**
|
||
|
||
- Cart items are stored in the database with persistent storage
|
||
- Price is captured at time of adding to cart (uses `sale_price` if available, otherwise `price`)
|
||
- If product already exists in cart, quantity is incremented (duplicate prevention)
|
||
- Inventory is validated before adding items
|
||
|
||
---
|
||
|
||
### Update Cart Item
|
||
|
||
Update the quantity of an existing item in the cart.
|
||
|
||
**Endpoint:** `PUT /api/v1/storefront/cart/{session_id}/items/{product_id}`
|
||
|
||
**Path Parameters:**
|
||
|
||
| Parameter | Type | Description |
|
||
|-----------|------|-------------|
|
||
| `session_id` | string | Unique session identifier |
|
||
| `product_id` | integer | Product ID to update (must be > 0) |
|
||
|
||
**Request Body Schema:** `UpdateCartItemRequest`
|
||
|
||
| Field | Type | Required | Description |
|
||
|-------|------|----------|-------------|
|
||
| `quantity` | integer | Yes | New quantity (must be >= 1) |
|
||
|
||
**Request Example:**
|
||
|
||
```json
|
||
{
|
||
"quantity": 3
|
||
}
|
||
```
|
||
|
||
**Response (200 OK):** `CartOperationResponse`
|
||
|
||
```json
|
||
{
|
||
"message": "Cart updated",
|
||
"product_id": 1,
|
||
"quantity": 3
|
||
}
|
||
```
|
||
|
||
**Error Responses:**
|
||
|
||
- `404 Not Found` - Cart item not found
|
||
```json
|
||
{
|
||
"error_code": "CART_ITEM_NOT_FOUND",
|
||
"message": "Product 123 not found in cart",
|
||
"status_code": 404,
|
||
"details": {
|
||
"product_id": 123,
|
||
"session_id": "session-abc-123"
|
||
}
|
||
}
|
||
```
|
||
|
||
- `400 Bad Request` - Insufficient inventory for new quantity
|
||
- `422 Unprocessable Entity` - Invalid quantity (less than 1)
|
||
|
||
---
|
||
|
||
### Remove from Cart
|
||
|
||
Remove a specific item from the cart.
|
||
|
||
**Endpoint:** `DELETE /api/v1/storefront/cart/{session_id}/items/{product_id}`
|
||
|
||
**Path Parameters:**
|
||
|
||
| Parameter | Type | Description |
|
||
|-----------|------|-------------|
|
||
| `session_id` | string | Unique session identifier |
|
||
| `product_id` | integer | Product ID to remove (must be > 0) |
|
||
|
||
**Response (200 OK):** `CartOperationResponse`
|
||
|
||
```json
|
||
{
|
||
"message": "Item removed from cart",
|
||
"product_id": 1
|
||
}
|
||
```
|
||
|
||
**Error Responses:**
|
||
|
||
- `404 Not Found` - Cart item not found (product not in cart)
|
||
|
||
---
|
||
|
||
### Clear Cart
|
||
|
||
Remove all items from the cart.
|
||
|
||
**Endpoint:** `DELETE /api/v1/storefront/cart/{session_id}`
|
||
|
||
**Path Parameters:**
|
||
|
||
| Parameter | Type | Description |
|
||
|-----------|------|-------------|
|
||
| `session_id` | string | Unique session identifier |
|
||
|
||
**Response (200 OK):** `ClearCartResponse`
|
||
|
||
```json
|
||
{
|
||
"message": "Cart cleared",
|
||
"items_removed": 3
|
||
}
|
||
```
|
||
|
||
**Response Schema:**
|
||
|
||
| Field | Type | Description |
|
||
|-------|------|-------------|
|
||
| `message` | string | Operation result message |
|
||
| `items_removed` | integer | Number of items that were removed from cart |
|
||
|
||
---
|
||
|
||
## Orders
|
||
|
||
Order endpoints require customer authentication.
|
||
|
||
### Place Order
|
||
|
||
Create a new order (authenticated).
|
||
|
||
**Endpoint:** `POST /api/v1/storefront/orders`
|
||
|
||
**Authentication:** Required (customer token)
|
||
|
||
**Request Body:**
|
||
|
||
```json
|
||
{
|
||
"session_id": "session-abc-123",
|
||
"shipping_address": {
|
||
"street": "123 Main St",
|
||
"city": "City",
|
||
"postal_code": "12345",
|
||
"country": "US"
|
||
},
|
||
"billing_address": {
|
||
"street": "123 Main St",
|
||
"city": "City",
|
||
"postal_code": "12345",
|
||
"country": "US"
|
||
},
|
||
"payment_method": "stripe",
|
||
"notes": "Please deliver before 5pm"
|
||
}
|
||
```
|
||
|
||
**Response (201 Created):**
|
||
|
||
```json
|
||
{
|
||
"id": 123,
|
||
"order_number": "ORD-2025-001",
|
||
"store_id": 1,
|
||
"customer_id": 456,
|
||
"total": 59.98,
|
||
"status": "pending",
|
||
"created_at": "2025-11-22T10:00:00Z",
|
||
"items": [...],
|
||
"shipping_address": {...},
|
||
"billing_address": {...}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### Get Order History
|
||
|
||
Get list of customer's orders (authenticated).
|
||
|
||
**Endpoint:** `GET /api/v1/storefront/orders`
|
||
|
||
**Authentication:** Required
|
||
|
||
**Query Parameters:**
|
||
|
||
| Parameter | Type | Default | Description |
|
||
|-----------|------|---------|-------------|
|
||
| `skip` | integer | 0 | Pagination offset |
|
||
| `limit` | integer | 20 | Max orders to return |
|
||
|
||
**Response (200 OK):**
|
||
|
||
```json
|
||
{
|
||
"orders": [
|
||
{
|
||
"id": 123,
|
||
"order_number": "ORD-2025-001",
|
||
"total": 59.98,
|
||
"status": "completed",
|
||
"created_at": "2025-11-22T10:00:00Z"
|
||
}
|
||
],
|
||
"total": 5,
|
||
"skip": 0,
|
||
"limit": 20
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### Get Order Details
|
||
|
||
Get details of a specific order (authenticated).
|
||
|
||
**Endpoint:** `GET /api/v1/storefront/orders/{order_id}`
|
||
|
||
**Authentication:** Required
|
||
|
||
**Response (200 OK):**
|
||
|
||
```json
|
||
{
|
||
"id": 123,
|
||
"order_number": "ORD-2025-001",
|
||
"store_id": 1,
|
||
"customer_id": 456,
|
||
"total": 59.98,
|
||
"status": "completed",
|
||
"created_at": "2025-11-22T10:00:00Z",
|
||
"items": [...],
|
||
"shipping_address": {...},
|
||
"billing_address": {...},
|
||
"tracking_number": "TRACK-123"
|
||
}
|
||
```
|
||
|
||
**Error Responses:**
|
||
|
||
- `404 Not Found` - Order not found or doesn't belong to customer
|
||
|
||
---
|
||
|
||
## Authentication
|
||
|
||
### Register Customer
|
||
|
||
Create a new customer account.
|
||
|
||
**Endpoint:** `POST /api/v1/storefront/auth/register`
|
||
|
||
**Request Body:**
|
||
|
||
```json
|
||
{
|
||
"email": "customer@example.com",
|
||
"password": "SecurePass123!",
|
||
"first_name": "John",
|
||
"last_name": "Doe",
|
||
"phone": "+1234567890"
|
||
}
|
||
```
|
||
|
||
**Response (201 Created):**
|
||
|
||
```json
|
||
{
|
||
"id": 456,
|
||
"email": "customer@example.com",
|
||
"first_name": "John",
|
||
"last_name": "Doe",
|
||
"phone": "+1234567890",
|
||
"is_active": true,
|
||
"store_id": 1
|
||
}
|
||
```
|
||
|
||
**Error Responses:**
|
||
|
||
- `400 Bad Request` - Email already registered
|
||
- `422 Unprocessable Entity` - Validation errors
|
||
|
||
---
|
||
|
||
### Customer Login
|
||
|
||
Authenticate a customer and receive JWT token.
|
||
|
||
**Endpoint:** `POST /api/v1/storefront/auth/login`
|
||
|
||
**Request Body:**
|
||
|
||
```json
|
||
{
|
||
"email_or_username": "customer@example.com",
|
||
"password": "SecurePass123!"
|
||
}
|
||
```
|
||
|
||
**Response (200 OK):**
|
||
|
||
```json
|
||
{
|
||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
"token_type": "bearer",
|
||
"expires_in": 86400,
|
||
"user": {
|
||
"id": 456,
|
||
"email": "customer@example.com",
|
||
"first_name": "John",
|
||
"last_name": "Doe"
|
||
}
|
||
}
|
||
```
|
||
|
||
**Cookie Set:**
|
||
|
||
The endpoint also sets an HTTP-only cookie:
|
||
|
||
```http
|
||
Set-Cookie: customer_token=<jwt>; Path=/storefront; HttpOnly; SameSite=Lax; Secure
|
||
```
|
||
|
||
**Error Responses:**
|
||
|
||
- `401 Unauthorized` - Invalid credentials
|
||
- `404 Not Found` - Customer not found for this store
|
||
|
||
---
|
||
|
||
### Customer Logout
|
||
|
||
Clear customer session.
|
||
|
||
**Endpoint:** `POST /api/v1/storefront/auth/logout`
|
||
|
||
**Response (200 OK):**
|
||
|
||
```json
|
||
{
|
||
"message": "Logged out successfully"
|
||
}
|
||
```
|
||
|
||
The endpoint clears the `customer_token` cookie.
|
||
|
||
---
|
||
|
||
## Content Pages (CMS)
|
||
|
||
### Get Navigation Links
|
||
|
||
Get CMS pages for header/footer navigation.
|
||
|
||
**Endpoint:** `GET /api/v1/storefront/content-pages/navigation`
|
||
|
||
**Response (200 OK):**
|
||
|
||
```json
|
||
[
|
||
{
|
||
"slug": "about",
|
||
"title": "About Us",
|
||
"show_in_header": true,
|
||
"show_in_footer": true,
|
||
"display_order": 1
|
||
},
|
||
{
|
||
"slug": "contact",
|
||
"title": "Contact Us",
|
||
"show_in_header": true,
|
||
"show_in_footer": true,
|
||
"display_order": 2
|
||
}
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
### Get Content Page
|
||
|
||
Get full content for a specific page.
|
||
|
||
**Endpoint:** `GET /api/v1/storefront/content-pages/{slug}`
|
||
|
||
**Path Parameters:**
|
||
|
||
| Parameter | Type | Description |
|
||
|-----------|------|-------------|
|
||
| `slug` | string | Page slug (e.g., "about", "faq") |
|
||
|
||
**Response (200 OK):**
|
||
|
||
```json
|
||
{
|
||
"slug": "about",
|
||
"title": "About Us",
|
||
"content": "<p>Welcome to our store...</p>",
|
||
"meta_description": "Learn about our story",
|
||
"is_published": true,
|
||
"show_in_header": true,
|
||
"show_in_footer": true,
|
||
"display_order": 1
|
||
}
|
||
```
|
||
|
||
**Error Responses:**
|
||
|
||
- `404 Not Found` - Page not found
|
||
|
||
---
|
||
|
||
## Error Handling
|
||
|
||
All endpoints follow standard HTTP error responses:
|
||
|
||
### Common Error Response Format
|
||
|
||
```json
|
||
{
|
||
"error_code": "VALIDATION_ERROR",
|
||
"message": "Request validation failed",
|
||
"status_code": 422,
|
||
"details": {
|
||
"validation_errors": [
|
||
{
|
||
"loc": ["body", "email"],
|
||
"msg": "Invalid email format",
|
||
"type": "value_error.email"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
### HTTP Status Codes
|
||
|
||
| Code | Meaning | When Used |
|
||
|------|---------|-----------|
|
||
| 200 | OK | Successful GET/PUT/DELETE |
|
||
| 201 | Created | Successful POST (resource created) |
|
||
| 400 | Bad Request | Invalid request data |
|
||
| 401 | Unauthorized | Authentication required/failed |
|
||
| 403 | Forbidden | Insufficient permissions |
|
||
| 404 | Not Found | Resource not found (product, store, order) |
|
||
| 422 | Unprocessable Entity | Validation errors |
|
||
| 500 | Internal Server Error | Server error |
|
||
|
||
---
|
||
|
||
## Rate Limiting
|
||
|
||
All Storefront API endpoints are rate limited:
|
||
|
||
- **Public endpoints**: 100 requests/minute per IP
|
||
- **Authenticated endpoints**: 200 requests/minute per customer
|
||
- **Search endpoints**: 20 requests/minute per IP
|
||
|
||
Rate limit headers included in responses:
|
||
|
||
```http
|
||
X-RateLimit-Limit: 100
|
||
X-RateLimit-Remaining: 95
|
||
X-RateLimit-Reset: 1700000000
|
||
```
|
||
|
||
---
|
||
|
||
## Migration from Old API
|
||
|
||
**Old Pattern (Deprecated):**
|
||
|
||
```http
|
||
GET /api/v1/platform/stores/{store_id}/products
|
||
POST /api/v1/platform/stores/auth/{store_id}/customers/login
|
||
```
|
||
|
||
**New Pattern (Current):**
|
||
|
||
```http
|
||
GET /api/v1/storefront/products
|
||
POST /api/v1/storefront/auth/login
|
||
```
|
||
|
||
**Key Changes:**
|
||
|
||
- ✅ Removed `{store_id}` from URLs
|
||
- ✅ Store extracted from Referer header automatically
|
||
- ✅ Cleaner URLs (~40% shorter)
|
||
- ✅ Same functionality, better architecture
|
||
|
||
**See:** [API Migration Status](../architecture/api-migration-status.md)
|
||
|
||
---
|
||
|
||
## Examples
|
||
|
||
### Complete Add to Cart Flow
|
||
|
||
```javascript
|
||
// 1. Get session ID (generate or retrieve from localStorage)
|
||
const sessionId = localStorage.getItem('session_id') || crypto.randomUUID();
|
||
localStorage.setItem('session_id', sessionId);
|
||
|
||
// 2. Add product to cart
|
||
const response = await fetch(`/api/v1/storefront/cart/${sessionId}/items`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
product_id: 1,
|
||
quantity: 2
|
||
})
|
||
});
|
||
|
||
const result = await response.json();
|
||
console.log('Cart updated:', result.cart);
|
||
```
|
||
|
||
### Complete Checkout Flow
|
||
|
||
```javascript
|
||
// 1. Customer logs in
|
||
const loginResponse = await fetch('/api/v1/storefront/auth/login', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
email_or_username: 'customer@example.com',
|
||
password: 'password123'
|
||
})
|
||
});
|
||
|
||
const { access_token } = await loginResponse.json();
|
||
localStorage.setItem('customer_token', access_token);
|
||
|
||
// 2. Place order
|
||
const orderResponse = await fetch('/api/v1/storefront/orders', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': `Bearer ${access_token}`
|
||
},
|
||
body: JSON.stringify({
|
||
session_id: sessionId,
|
||
shipping_address: {...},
|
||
billing_address: {...},
|
||
payment_method: 'stripe'
|
||
})
|
||
});
|
||
|
||
const order = await orderResponse.json();
|
||
console.log('Order created:', order.order_number);
|
||
```
|
||
|
||
---
|
||
|
||
## Interactive Documentation
|
||
|
||
For live API testing and exploration:
|
||
|
||
- **Swagger UI**: [http://localhost:8000/docs](http://localhost:8000/docs)
|
||
- **ReDoc**: [http://localhost:8000/redoc](http://localhost:8000/redoc)
|
||
- **OpenAPI Spec**: [http://localhost:8000/openapi.json](http://localhost:8000/openapi.json)
|
||
|
||
---
|
||
|
||
**Questions?** See the [API Migration Status](../architecture/api-migration-status.md) or [Storefront Architecture Guide](../frontend/storefront/architecture.md).
|