API Reference
E-Commerce Agents exposes 20 REST endpoints through the orchestrator service (FastAPI, port 8080). All endpoints are prefixed with /api/.
Route Overview
graph LR
accTitle: Route Overview
subgraph Public
style Public fill:#10b981,stroke:#059669,color:#fff
A1[POST /auth/signup]
A2[POST /auth/login]
A3[POST /auth/refresh]
end
subgraph Authenticated
style Authenticated fill:#0ea5e9,stroke:#0284c7,color:#fff
C1[POST /chat]
CV1[GET /conversations]
CV2[GET /conversations/:id]
CV3[DELETE /conversations/:id]
P1[GET /products]
P2[GET /products/:id]
O1[GET /orders]
O2[GET /orders/:id]
PR1[GET /profile]
M1[GET /marketplace/agents]
M2[POST /marketplace/request]
M3[GET /marketplace/my-agents]
end
subgraph Admin Only
style Admin fill:#f59e0b,stroke:#d97706,color:#fff
AD1[GET /admin/requests]
AD2[POST /admin/requests/:id/approve]
AD3[POST /admin/requests/:id/deny]
AD4[GET /admin/usage]
AD5[GET /admin/audit]
end
Client([Client]) --> Public
Client --> Authenticated
Client --> Admin
style Client fill:#6366f1,stroke:#4f46e5,color:#fff
Authentication
All authenticated endpoints require a Bearer token in the Authorization header:
Authorization: Bearer <access_token>
Tokens are JWTs signed with JWT_SECRET (PyJWT + bcrypt). Access tokens contain sub (email), role, user_id, and type: "access". Refresh tokens contain sub and type: "refresh".
Admin endpoints additionally verify role == "admin" and return 403 if the check fails.
Auth (Public)
POST /api/auth/signup
Create a new user account and receive tokens.
| Field | Value |
|---|---|
| Auth | Public |
Request Body
{
"email": "alice.johnson@gmail.com",
"password": "securepassword",
"name": "Alice Johnson"
}
Response 200
{
"access_token": "eyJhbGciOi...",
"refresh_token": "eyJhbGciOi...",
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "alice.johnson@gmail.com",
"name": "Alice Johnson",
"role": "customer",
"loyalty_tier": "bronze",
"total_spend": 0.0
}
}
Errors
409Email already registered
POST /api/auth/login
Authenticate an existing user and receive tokens.
| Field | Value |
|---|---|
| Auth | Public |
Request Body
{
"email": "alice.johnson@gmail.com",
"password": "securepassword"
}
Response 200
{
"access_token": "eyJhbGciOi...",
"refresh_token": "eyJhbGciOi...",
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "alice.johnson@gmail.com",
"name": "Alice Johnson",
"role": "customer",
"loyalty_tier": "gold",
"total_spend": 4200.0
}
}
Errors
401Invalid email or password403Account is deactivated
POST /api/auth/refresh
Exchange a refresh token for a new access token.
| Field | Value |
|---|---|
| Auth | Public (requires valid refresh token in body) |
Request Body
{
"refresh_token": "eyJhbGciOi..."
}
Response 200
{
"access_token": "eyJhbGciOi..."
}
Errors
401Refresh token expired / invalid / wrong type403Account is deactivated
Chat
POST /api/chat
Send a message to the orchestrator agent. The orchestrator routes to specialist agents as needed and returns the consolidated response.
| Field | Value |
|---|---|
| Auth | JWT Required |
Request Body
{
"message": "What are the best noise-cancelling headphones under $350?",
"conversation_id": null
}
conversation_id is optional. Omit or pass null to start a new conversation. Pass an existing ID to continue a conversation (loads the last 50 messages as context).
Response 200
{
"response": "I found several great options for noise-cancelling headphones under $350...",
"conversation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"agents_involved": ["orchestrator", "product-discovery", "pricing-promotions"]
}
Errors
401Missing/invalid token404Conversation not found (ifconversation_idis provided but doesn’t belong to the user)
Conversations
GET /api/conversations
List the authenticated user’s conversations, ordered by most recent activity.
| Field | Value |
|---|---|
| Auth | JWT Required |
Response 200
[
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title": "What are the best noise-cancelling headphones under $350?",
"message_count": 4,
"created_at": "2026-04-01T10:30:00+00:00",
"last_message_at": "2026-04-01T10:35:22+00:00"
}
]
Returns up to 50 active conversations. Soft-deleted conversations are excluded.
GET /api/conversations/{conversation_id}
Get a single conversation with its full message history.
| Field | Value |
|---|---|
| Auth | JWT Required |
Response 200
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title": "What are the best noise-cancelling headphones under $350?",
"created_at": "2026-04-01T10:30:00+00:00",
"last_message_at": "2026-04-01T10:35:22+00:00",
"messages": [
{
"id": "msg-uuid-1",
"role": "user",
"content": "What are the best noise-cancelling headphones under $350?",
"agent_name": null,
"agents_involved": [],
"metadata": {},
"tokens_in": 0,
"tokens_out": 0,
"created_at": "2026-04-01T10:30:00+00:00"
},
{
"id": "msg-uuid-2",
"role": "assistant",
"content": "I found several great options...",
"agent_name": "orchestrator",
"agents_involved": ["orchestrator", "product-discovery"],
"metadata": {},
"tokens_in": 150,
"tokens_out": 320,
"created_at": "2026-04-01T10:30:05+00:00"
}
]
}
Errors
404Conversation not found or doesn’t belong to the user
DELETE /api/conversations/{conversation_id}
Soft-delete a conversation (sets is_active = FALSE). Messages are preserved in the database.
| Field | Value |
|---|---|
| Auth | JWT Required |
Response 200
{
"status": "deleted"
}
Errors
404Conversation not found or doesn’t belong to the user
Products
GET /api/products
Browse and search the product catalog with filtering and sorting.
| Field | Value |
|---|---|
| Auth | JWT Required |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
category | string | - | Filter by category (Electronics, Clothing, Home, Sports, Books) |
min_price | float | - | Minimum price filter |
max_price | float | - | Maximum price filter |
search | string | - | ILIKE search against product name and description |
sort | string | rating | Sort order: rating, price_asc, price_desc, newest, name |
limit | int | 50 | Page size |
offset | int | 0 | Pagination offset |
Response 200
{
"products": [
{
"id": "prod-uuid-1",
"name": "Sony WH-1000XM5",
"description": "Premium wireless noise-cancelling headphones with 30-hour battery...",
"category": "Electronics",
"brand": "Sony",
"price": 299.99,
"original_price": 349.99,
"image_url": "/images/products/sony-wh1000xm5.jpg",
"rating": 4.7,
"review_count": 12
}
],
"total": 50,
"categories": ["Books", "Clothing", "Electronics", "Home", "Sports"]
}
Product descriptions are truncated to 200 characters in the list view.
GET /api/products/{product_id}
Get full product details including specs, stock levels, reviews, and rating distribution.
| Field | Value |
|---|---|
| Auth | JWT Required |
Response 200
{
"id": "prod-uuid-1",
"name": "Sony WH-1000XM5",
"description": "Premium wireless noise-cancelling headphones with 30-hour battery life...",
"category": "Electronics",
"brand": "Sony",
"price": 299.99,
"original_price": 349.99,
"image_url": "/images/products/sony-wh1000xm5.jpg",
"rating": 4.7,
"review_count": 12,
"specs": {
"type": "Over-ear",
"battery": "30 hours",
"noise_cancelling": true,
"weight": "250g",
"connectivity": "Bluetooth 5.2"
},
"in_stock": true,
"total_stock": 145,
"warehouses": [
{ "name": "East", "region": "east", "quantity": 50 },
{ "name": "Central", "region": "central", "quantity": 65 },
{ "name": "West", "region": "west", "quantity": 30 }
],
"reviews": [
{
"id": "review-uuid-1",
"rating": 5,
"title": "Best headphones I've owned",
"body": "The noise cancellation is incredible...",
"verified": true,
"reviewer": "Alice Johnson",
"date": "2026-03-15T14:20:00+00:00"
}
],
"rating_distribution": {
"1": 1,
"2": 0,
"3": 2,
"4": 3,
"5": 6
}
}
Errors
404Product not found
Orders
GET /api/orders
List the authenticated user’s orders. Filterable by status.
| Field | Value |
|---|---|
| Auth | JWT Required |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
status | string | - | Filter by status: placed, confirmed, shipped, out_for_delivery, delivered, cancelled, returned |
limit | int | 20 | Page size |
offset | int | 0 | Pagination offset |
Response 200
{
"orders": [
{
"id": "order-uuid-1",
"status": "delivered",
"total": 349.98,
"carrier": "Express",
"tracking": "EXP-12345-US",
"item_count": 2,
"date": "2026-03-20T09:15:00+00:00"
}
],
"total": 8
}
GET /api/orders/{order_id}
Get full order details including line items, status history, shipping address, and return info.
| Field | Value |
|---|---|
| Auth | JWT Required |
Response 200
{
"id": "order-uuid-1",
"status": "delivered",
"total": 349.98,
"shipping_address": {
"street": "123 Main St",
"city": "New York",
"state": "NY",
"zip": "10001",
"country": "US"
},
"carrier": "Express",
"tracking": "EXP-12345-US",
"coupon": "SAVE10",
"discount": 35.0,
"date": "2026-03-20T09:15:00+00:00",
"items": [
{
"product_id": "prod-uuid-1",
"name": "Sony WH-1000XM5",
"category": "Electronics",
"image_url": "/images/products/sony-wh1000xm5.jpg",
"quantity": 1,
"unit_price": 299.99,
"subtotal": 299.99
}
],
"status_history": [
{
"status": "placed",
"notes": "Order received",
"location": null,
"timestamp": "2026-03-20T09:15:00+00:00"
},
{
"status": "delivered",
"notes": "Delivered to front door",
"location": "New York, NY",
"timestamp": "2026-03-23T14:30:00+00:00"
}
],
"return": null
}
When a return exists, the return field contains:
{
"id": "return-uuid-1",
"reason": "Defective product",
"status": "refunded",
"refund_method": "original_payment",
"refund_amount": 299.99,
"created_at": "2026-03-25T10:00:00+00:00",
"resolved_at": "2026-03-28T16:00:00+00:00"
}
Errors
404Order not found or doesn’t belong to the user
Profile
GET /api/profile
Get the authenticated user’s profile, including loyalty tier benefits and activity counts.
| Field | Value |
|---|---|
| Auth | JWT Required |
Response 200
{
"id": "user-uuid-1",
"email": "alice.johnson@gmail.com",
"name": "Alice Johnson",
"role": "customer",
"loyalty_tier": "gold",
"total_spend": 4200.0,
"member_since": "2025-12-01T00:00:00+00:00",
"order_count": 15,
"review_count": 8,
"tier_benefits": {
"discount_pct": 10.0,
"free_shipping_threshold": 25.0,
"priority_support": true
}
}
Errors
404User not found
Marketplace
GET /api/marketplace/agents
List all active agents in the marketplace catalog.
| Field | Value |
|---|---|
| Auth | JWT Required |
Response 200
[
{
"id": "agent-uuid-1",
"name": "product-discovery",
"display_name": "Product Discovery",
"description": "Searches products by keyword, category, price range, and semantic similarity.",
"category": "Shopping",
"icon": "search",
"status": "active",
"version": "1.0",
"capabilities": ["search", "recommend", "compare"],
"requires_approval": true,
"allowed_roles": ["power_user", "admin"]
}
]
POST /api/marketplace/request
Submit an access request for a specific agent.
| Field | Value |
|---|---|
| Auth | JWT Required |
Request Body
{
"agent_name": "product-discovery",
"role_requested": "power_user",
"use_case": "I need advanced product search capabilities for comparison shopping."
}
Response 200 (pending approval)
{
"id": "req-uuid-1",
"agent_name": "product-discovery",
"status": "pending",
"message": "Your request has been submitted and is pending admin approval."
}
Response 200 (auto-approved, when requires_approval = false)
{
"id": "req-uuid-1",
"agent_name": "product-discovery",
"status": "approved",
"message": "Access granted automatically — no approval required."
}
Errors
404Agent not found409Pending request already exists for this agent409User already has access to this agent
GET /api/marketplace/my-agents
List agents the authenticated user has been granted access to.
| Field | Value |
|---|---|
| Auth | JWT Required |
Response 200
[
{
"agent_name": "product-discovery",
"display_name": "Product Discovery",
"description": "Searches products by keyword, category, price range, and semantic similarity.",
"category": "Shopping",
"icon": "search",
"role": "power_user",
"granted_at": "2026-03-01T12:00:00+00:00"
}
]
Admin
All admin endpoints require role: "admin" in the JWT. Non-admin users receive 403 Admin access required.
GET /api/admin/requests
List all pending access requests across all users.
| Field | Value |
|---|---|
| Auth | Admin Only |
Response 200
[
{
"id": "req-uuid-1",
"agent_name": "product-discovery",
"role_requested": "power_user",
"use_case": "I need advanced product search capabilities.",
"status": "pending",
"created_at": "2026-04-01T08:00:00+00:00",
"user_email": "bob.smith@gmail.com",
"user_name": "Bob Smith",
"user_role": "customer"
}
]
POST /api/admin/requests/{request_id}/approve
Approve a pending access request. Creates the corresponding agent_permissions record in a transaction.
| Field | Value |
|---|---|
| Auth | Admin Only |
Request Body
{
"admin_notes": "Approved for trial period."
}
admin_notes is optional (defaults to empty string).
Response 200
{
"status": "approved",
"request_id": "req-uuid-1"
}
Errors
404Request not found409Request already approved/denied
POST /api/admin/requests/{request_id}/deny
Deny a pending access request.
| Field | Value |
|---|---|
| Auth | Admin Only |
Request Body
{
"admin_notes": "Insufficient justification."
}
Response 200
{
"status": "denied",
"request_id": "req-uuid-1"
}
Errors
404Request not found409Request already approved/denied
GET /api/admin/usage
Get aggregate usage statistics for the last 30 days, with per-agent breakdowns and a 7-day daily trend.
| Field | Value |
|---|---|
| Auth | Admin Only |
Response 200
{
"period": "last_30_days",
"overall": {
"total_requests": 1250,
"unique_users": 18,
"total_tokens_in": 450000,
"total_tokens_out": 680000,
"avg_duration_ms": 2300,
"total_tool_calls": 3400
},
"by_agent": [
{
"agent_name": "orchestrator",
"request_count": 500,
"unique_users": 18,
"tokens_in": 180000,
"tokens_out": 250000,
"avg_duration_ms": 2100,
"error_count": 5
},
{
"agent_name": "product-discovery",
"request_count": 320,
"unique_users": 15,
"tokens_in": 95000,
"tokens_out": 150000,
"avg_duration_ms": 1800,
"error_count": 2
}
],
"daily_trend": [
{
"day": "2026-04-04",
"request_count": 85,
"unique_users": 12
},
{
"day": "2026-04-03",
"request_count": 92,
"unique_users": 14
}
]
}
GET /api/admin/audit
Get a detailed audit log from usage_logs with associated agent_execution_steps for each entry.
| Field | Value |
|---|---|
| Auth | Admin Only |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | int | 50 | Page size (max 200) |
offset | int | 0 | Pagination offset |
Response 200
{
"entries": [
{
"id": "log-uuid-1",
"agent_name": "orchestrator",
"user_email": "alice.johnson@gmail.com",
"user_name": "Alice Johnson",
"input_summary": "What are the best headphones?",
"tokens_in": 150,
"tokens_out": 420,
"tool_calls_count": 2,
"duration_ms": 2450,
"status": "success",
"error_message": null,
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"created_at": "2026-04-04T10:15:00+00:00",
"steps": [
{
"step_index": 0,
"tool_name": "call_specialist_agent",
"tool_input": { "agent_name": "product-discovery" },
"tool_output": { "result": "Found 3 matching products..." },
"status": "success",
"duration_ms": 1200
}
]
}
],
"total": 1250,
"limit": 50,
"offset": 0
}
The trace_id field correlates with OpenTelemetry traces in the Aspire Dashboard, allowing drill-down from audit log to distributed traces.
Error Response Format
All error responses follow FastAPI’s standard format:
{
"detail": "Description of the error"
}
| Status Code | Meaning |
|---|---|
401 | Missing, expired, or invalid JWT |
403 | Insufficient permissions (e.g., non-admin accessing admin routes) |
404 | Resource not found or doesn’t belong to the authenticated user |
409 | Conflict (duplicate email, duplicate access request, already resolved request) |
Related
docs/architecture.md— how requests flow from browser through orchestrator to specialist agentsdocs/database-schema.md— the tables these endpoints read and writedocs/deployment.md— running the stack so endpoints are reachabledocs/frontend.md— how the Next.js client calls these endpoints- Project README
Source: docs/api-reference.md — this page is generated from the repository.