Skip to content

API Reference

Complete API documentation for OmniStack Backend.


Table of Contents

  1. Overview
  2. Authentication
  3. Response Formats
  4. Error Responses
  5. Pagination
  6. Rate Limiting
  7. Endpoints
  8. Health
  9. Contact Form
  10. Users
  11. Projects
  12. Files
  13. AI
  14. Billing
  15. Usage
  16. WebSocket
  17. Admin
  18. Webhooks

Overview

Base URL

Development: http://localhost:8000/api/v1  (or /api/v2)
Production:  https://your-domain.com/api/v1  (or /api/v2)

API Versions

Version Status Description
v1 Stable Original API with standard responses
v2 Stable Enhanced responses with metadata wrapper

Both versions are available simultaneously. v2 responses include: - Request ID for tracing - ISO 8601 timestamps with timezone - API version in response metadata

Route Structure

/api/v1/
├── public/          # No authentication required
│   ├── health       # Health checks
│   ├── contact      # Contact form submissions
│   ├── webhooks/    # External service webhooks
│   └── metrics      # Prometheus metrics
├── app/             # Authentication required
│   ├── users/       # User profile management
│   ├── projects/    # Project CRUD
│   ├── files/       # File upload/download
│   ├── ai/          # AI completions
│   ├── billing/     # Subscription management
│   └── ws           # WebSocket connections
└── admin/           # Authentication + Admin role required
    ├── users/       # User management
    ├── jobs/        # Background job monitoring
    ├── dashboard/   # System metrics & stats
    ├── feature-flags/ # Feature flag management
    └── impersonate/ # User impersonation

HTTP Methods Convention

Method Usage Example
GET Retrieve resource(s) GET /projects
POST Create new resource POST /projects
PATCH Partial update PATCH /projects/{id}
DELETE Remove resource DELETE /projects/{id}

Note: We use PATCH (not PUT) for updates because all update fields are optional.


Authentication

Bearer Token

All /app/* and /admin/* endpoints require a JWT token in the Authorization header:

Authorization: Bearer <jwt_token>

Supported Auth Providers

Provider JWT Algorithm Token Source
Supabase RS256 (or HS256 legacy) supabase.auth.getSession()
Clerk RS256 useAuth().getToken()
Custom OAuth RS256 Your OAuth provider

Token Structure (JWT Claims)

{
  "sub": "user_123abc",           // User ID (required)
  "email": "user@example.com",    // User email
  "role": "user",                 // user | admin | superadmin
  "exp": 1704067200,              // Expiration timestamp
  "iat": 1704063600               // Issued at timestamp
}

Authentication Errors

Status Code Description
401 AUTHENTICATION_ERROR Missing or invalid token
403 AUTHORIZATION_ERROR Insufficient permissions

Response Formats

Success Response (Single Resource)

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "My Project",
  "description": "Project description",
  "owner_id": "user_123abc",
  "created_at": "2026-01-10T12:00:00Z",
  "updated_at": "2026-01-10T12:00:00Z"
}

Success Response (List with Pagination)

{
  "items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Project 1",
      "created_at": "2026-01-10T12:00:00Z"
    },
    {
      "id": "660e8400-e29b-41d4-a716-446655440001",
      "name": "Project 2",
      "created_at": "2026-01-09T12:00:00Z"
    }
  ],
  "total": 42,
  "skip": 0,
  "limit": 20
}

Success Response (Simple Message)

{
  "message": "Operation completed successfully"
}

No Content Response

For DELETE operations, returns 204 No Content with empty body.

v2 Response Format (Enhanced)

API v2 wraps all responses in a standardized format with metadata:

{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "user@example.com",
    "full_name": "John Doe",
    "is_premium": true,
    "days_since_joined": 42
  },
  "meta": {
    "request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "timestamp": "2026-01-11T12:00:00Z",
    "version": "v2"
  }
}

v2 endpoints also include additional computed fields (e.g., is_premium, days_since_joined).


API Version Headers

All API responses include version headers:

Header Description Example
X-API-Version API version used for this request v1 or v2
X-API-Latest-Version Latest available API version v2

Deprecated Version Headers (when applicable)

When a version is deprecated, responses include:

Header Description Example
Deprecation RFC 8594 deprecation flag true
Sunset RFC 8594 removal date Wed, 31 Dec 2025 23:59:59 GMT
X-Deprecation-Notice Human-readable message API v1 is deprecated...
Link Link to successor version </api/v2/>; rel="successor-version"

Version Selection

Versions can be specified via:

  1. URL Path (recommended): /api/v1/... or /api/v2/...
  2. Accept-Version Header: Accept-Version: v2
  3. X-API-Version Header: X-API-Version: v2

URL path takes precedence over headers.


Error Responses

Error Response Format

All errors follow this consistent structure:

{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error message",
    "details": {
      "field": "additional_info"
    }
  }
}

Error Codes Reference

HTTP Status Code Description Common Causes
400 BAD_REQUEST Invalid request Malformed JSON, invalid parameters
401 AUTHENTICATION_ERROR Auth failed Missing/expired token
403 AUTHORIZATION_ERROR Access denied Wrong role, not owner
404 NOT_FOUND Resource not found Invalid ID, deleted resource
409 CONFLICT Resource conflict Duplicate entry
422 VALIDATION_ERROR Validation failed Invalid field values
429 RATE_LIMIT_EXCEEDED Too many requests Rate limit hit
502 EXTERNAL_SERVICE_ERROR External service failed AI/Email/Payment error
503 SERVICE_UNAVAILABLE Service not configured Missing API keys

Example Error Responses

Not Found (404)

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Project not found",
    "details": {
      "resource": "Project",
      "id": "invalid-uuid"
    }
  }
}

Validation Error (422)

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Name must be at least 1 character",
    "details": {
      "field": "name"
    }
  }
}

Rate Limit (429)

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded",
    "details": {
      "retry_after": 60
    }
  }
}


Pagination

Query Parameters

Parameter Type Default Range Description
skip integer 0 0+ Number of items to skip
limit integer 20 1-100 Maximum items to return

Request Example

GET /api/v1/app/projects?skip=20&limit=10

Response Structure

{
  "items": [...],
  "total": 100,    // Total items in database
  "skip": 20,      // Items skipped
  "limit": 10      // Max items returned
}

Calculating Pagination

// Frontend pagination helper
const totalPages = Math.ceil(response.total / response.limit);
const currentPage = Math.floor(response.skip / response.limit) + 1;
const hasNextPage = response.skip + response.items.length < response.total;
const hasPrevPage = response.skip > 0;

Rate Limiting

Rate Limit Headers

Every response includes these headers:

Header Description Example
X-RateLimit-Limit Max requests per window 60
X-RateLimit-Remaining Remaining requests 45
X-RateLimit-Reset Unix timestamp when limit resets 1704067200

Default Limits

Route Pattern Limit Window
Default 60 requests per minute
/app/ai/* 10 requests per minute
/public/auth/* 5 requests per minute

Rate Limit Response (429)

HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1704067200
Retry-After: 45

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded",
    "details": {
      "retry_after": 45
    }
  }
}

Endpoints

Health Endpoints

Check Health

GET /api/v1/public/health

Response (200)

{
  "status": "healthy",
  "timestamp": "2026-01-10T12:00:00Z"
}

Check Readiness

GET /api/v1/public/health/ready

Response (200)

{
  "status": "healthy",
  "timestamp": "2026-01-10T12:00:00Z",
  "components": {
    "database": { "status": "healthy" },
    "cache": { "status": "healthy" }
  }
}


Contact Form Endpoints

Public endpoints for contact form submissions. No authentication required.

Submit Contact Form

POST /api/v1/public/contact
Content-Type: application/json

{
  "name": "John Doe",
  "email": "john@example.com",
  "message": "I'd like to learn more about your services.",
  "subject": "Product Inquiry",
  "phone": "+1-555-0123",
  "company": "Acme Inc",
  "extra_fields": {
    "budget": "$5000-$10000",
    "project_type": "web-app",
    "referral_source": "google"
  },
  "source": "homepage"
}

Request Body

Field Type Required Description
name string Yes Sender's name (2-100 chars)
email string Yes Sender's email address
message string Yes Message content (10-5000 chars)
subject string Configurable Message subject (max 200 chars)
phone string Configurable Phone number (max 50 chars)
company string No Company name (max 200 chars)
extra_fields object No Custom fields (any key-value pairs)
source string No Form source for analytics (max 100 chars)

Note: subject and phone can be made required via CONTACT_REQUIRE_SUBJECT and CONTACT_REQUIRE_PHONE settings.

Response (200)

{
  "success": true,
  "message": "Thank you for your message. We'll get back to you soon!",
  "reference_id": "CNT-A1B2C3D4"
}

Error Response (429 - Rate Limited)

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many contact form submissions. Please try again later.",
    "details": { "retry_after": 3600 }
  }
}

Get Contact Form Status

GET /api/v1/public/contact/status

Response (200)

{
  "available": true,
  "rate_limit": {
    "limit": 5,
    "remaining": 4,
    "reset": 1704110400,
    "window": "5/hour"
  },
  "config": {
    "require_subject": false,
    "require_phone": false,
    "sends_confirmation": true
  }
}

Configuration

Environment Variable Default Description
CONTACT_REQUIRE_SUBJECT false Make subject field required
CONTACT_REQUIRE_PHONE false Make phone field required
CONTACT_SEND_CONFIRMATION true Send confirmation email to sender
CONTACT_WEBHOOK_URL - Webhook URL for CRM integrations
CONTACT_RATE_LIMIT 5/hour Rate limit per IP address
ADMIN_EMAIL - Admin notification email

Webhook Integration

When CONTACT_WEBHOOK_URL is set, submissions are sent to your webhook:

{
  "event": "contact.submitted",
  "timestamp": "2026-01-11T12:00:00Z",
  "data": {
    "reference_id": "CNT-A1B2C3D4",
    "name": "John Doe",
    "email": "john@example.com",
    "phone": "+1-555-0123",
    "company": "Acme Inc",
    "subject": "Product Inquiry",
    "message": "I'd like to learn more...",
    "extra_fields": { "budget": "$5000-$10000" },
    "source": "homepage",
    "submitted_at": "2026-01-11T12:00:00Z"
  }
}

Webhook Headers

Header Description
X-Webhook-Signature SHA256 signature for verification
X-Reference-Id Submission reference ID

User Endpoints

Get Current User

GET /api/v1/app/users/me
Authorization: Bearer <token>

Response (200)

{
  "id": "user_123abc",
  "email": "user@example.com",
  "full_name": "John Doe",
  "avatar_url": "https://example.com/avatar.jpg",
  "role": "user",
  "is_active": true,
  "subscription_plan": "pro",
  "subscription_status": "active",
  "created_at": "2026-01-01T00:00:00Z"
}

Update Current User

PATCH /api/v1/app/users/me
Authorization: Bearer <token>
Content-Type: application/json

{
  "full_name": "John Smith",
  "avatar_url": "https://example.com/new-avatar.jpg"
}

Request Body

Field Type Required Description
full_name string No Display name (max 255 chars)
avatar_url string No Avatar URL (max 2048 chars)

Response (200): Updated user object


Project Endpoints

List Projects

GET /api/v1/app/projects
Authorization: Bearer <token>

Query Parameters

Parameter Type Default Description
skip integer 0 Items to skip
limit integer 20 Max items (1-100)
search string - Search by name

Response (200)

{
  "items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "My Project",
      "description": "Project description",
      "owner_id": "user_123abc",
      "created_at": "2026-01-10T12:00:00Z",
      "updated_at": "2026-01-10T12:00:00Z"
    }
  ],
  "total": 1,
  "skip": 0,
  "limit": 20
}

Create Project

POST /api/v1/app/projects
Authorization: Bearer <token>
Content-Type: application/json

{
  "name": "New Project",
  "description": "Optional description"
}

Request Body

Field Type Required Constraints Description
name string Yes 1-255 chars Project name
description string No max 2000 chars Description

Response (201)

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "New Project",
  "description": "Optional description",
  "owner_id": "user_123abc",
  "created_at": "2026-01-10T12:00:00Z",
  "updated_at": "2026-01-10T12:00:00Z"
}

Get Project

GET /api/v1/app/projects/{project_id}
Authorization: Bearer <token>

Path Parameters

Parameter Type Description
project_id string (UUID) Project ID

Response (200): Project object

Errors - 404 NOT_FOUND: Project doesn't exist or user doesn't own it

Update Project

PATCH /api/v1/app/projects/{project_id}
Authorization: Bearer <token>
Content-Type: application/json

{
  "name": "Updated Name",
  "description": "Updated description"
}

Request Body

Field Type Required Description
name string No New name (1-255 chars)
description string No New description

Response (200): Updated project object

Delete Project

DELETE /api/v1/app/projects/{project_id}
Authorization: Bearer <token>

Response (204): No content

Note: Projects are soft-deleted (marked with deleted_at timestamp).


File Endpoints

Get Presigned Upload URL

POST /api/v1/app/files/upload-url
Authorization: Bearer <token>
Content-Type: application/json

{
  "filename": "document.pdf",
  "content_type": "application/pdf",
  "size": 1048576
}

Request Body

Field Type Required Description
filename string Yes Original filename
content_type string Yes MIME type
size integer Yes File size in bytes

Response (200)

{
  "upload_url": "https://storage.example.com/presigned-upload-url",
  "file_id": "file_abc123",
  "key": "uploads/user_123/abc123/document.pdf",
  "expires_in": 3600
}

Confirm Upload

POST /api/v1/app/files/confirm
Authorization: Bearer <token>
Content-Type: application/json

{
  "file_id": "file_abc123"
}

Response (200)

{
  "id": "file_abc123",
  "filename": "document.pdf",
  "content_type": "application/pdf",
  "size": 1048576,
  "status": "uploaded",
  "created_at": "2026-01-10T12:00:00Z"
}

List Files

GET /api/v1/app/files
Authorization: Bearer <token>

Response (200): Paginated list of files

Get Download URL

GET /api/v1/app/files/{file_id}/download-url
Authorization: Bearer <token>

Response (200)

{
  "download_url": "https://storage.example.com/presigned-download-url",
  "expires_in": 3600
}

Delete File

DELETE /api/v1/app/files/{file_id}
Authorization: Bearer <token>

Response (204): No content


AI Endpoints

Get AI Status

GET /api/v1/app/ai/status
Authorization: Bearer <token>

Response (200)

{
  "available": true,
  "providers": ["openai", "anthropic"],
  "default_provider": "openai",
  "default_model": "gpt-4o"
}

Chat Completion

POST /api/v1/app/ai/completions
Authorization: Bearer <token>
Content-Type: application/json

{
  "messages": [
    { "role": "system", "content": "You are a helpful assistant." },
    { "role": "user", "content": "Hello, how are you?" }
  ],
  "model": "gpt-4o",
  "temperature": 0.7,
  "max_tokens": 1000,
  "stream": false
}

Request Body

Field Type Required Default Description
messages array Yes - Chat messages
messages[].role string Yes - system, user, or assistant
messages[].content string Yes - Message content
model string No gpt-4o Model to use
temperature number No 0.7 Creativity (0-2)
max_tokens integer No 1000 Max response tokens
stream boolean No false Enable streaming

Response (200)

{
  "content": "Hello! I'm doing well, thank you for asking.",
  "model": "gpt-4o",
  "provider": "openai",
  "usage": {
    "prompt_tokens": 25,
    "completion_tokens": 12,
    "total_tokens": 37
  },
  "finish_reason": "stop",
  "latency_ms": 450.5
}

Simple Chat

POST /api/v1/app/ai/chat
Authorization: Bearer <token>
Content-Type: application/json

{
  "prompt": "Explain quantum computing in one sentence.",
  "system": "You are a physics teacher.",
  "temperature": 0.5
}

Request Body

Field Type Required Description
prompt string Yes User prompt
system string No System instruction
model string No Model to use
temperature number No Creativity (0-2)
max_tokens integer No Max response tokens
stream boolean No Enable streaming

Routed Chat (Auto Model Selection)

POST /api/v1/app/ai/chat/routed
Authorization: Bearer <token>
Content-Type: application/json

{
  "prompt": "Solve this complex coding problem...",
  "complexity": "complex"
}

Complexity Levels

Level Model Used Best For
simple gpt-4o-mini Classification, extraction
moderate gpt-4o Summarization, analysis
complex claude-sonnet Reasoning, coding
search Perplexity Current information

Streaming Response

When stream: true, response is Server-Sent Events:

data: Hello
data:  world
data: !
data: [DONE]

Billing Endpoints

Get Billing Status

GET /api/v1/app/billing/status
Authorization: Bearer <token>

Response (200)

{
  "plan": "pro",
  "status": "active",
  "current_period_end": "2026-02-10T12:00:00Z",
  "cancel_at_period_end": false,
  "has_active_subscription": true
}

Create Checkout Session

POST /api/v1/app/billing/checkout
Authorization: Bearer <token>
Content-Type: application/json

{
  "plan": "monthly",
  "success_url": "https://app.example.com/billing/success",
  "cancel_url": "https://app.example.com/billing/cancel"
}

Request Body

Field Type Required Description
plan string Yes monthly or yearly
success_url string Yes Redirect on success
cancel_url string Yes Redirect on cancel

Response (200)

{
  "session_id": "cs_xxx",
  "url": "https://checkout.stripe.com/pay/cs_xxx"
}

Get Billing Portal

GET /api/v1/app/billing/portal?return_url=https://app.example.com/settings
Authorization: Bearer <token>

Response (200)

{
  "url": "https://billing.stripe.com/session/xxx"
}

Get Invoices

GET /api/v1/app/billing/invoices?limit=10
Authorization: Bearer <token>

Response (200)

[
  {
    "id": "in_xxx",
    "number": "INV-0001",
    "status": "paid",
    "amount_due": 1999,
    "amount_paid": 1999,
    "currency": "usd",
    "created": 1704067200,
    "hosted_invoice_url": "https://invoice.stripe.com/xxx",
    "invoice_pdf": "https://pay.stripe.com/invoice/xxx/pdf"
  }
]

Cancel Subscription

POST /api/v1/app/billing/cancel?immediate=false
Authorization: Bearer <token>

Query Parameters

Parameter Type Default Description
immediate boolean false Cancel immediately (no refund)

Response (200)

{
  "message": "Subscription will cancel at the end of the billing period",
  "cancel_at_period_end": true,
  "current_period_end": "2026-02-10T12:00:00Z"
}

Resume Subscription

POST /api/v1/app/billing/resume
Authorization: Bearer <token>

Response (200)

{
  "message": "Subscription resumed",
  "status": "active",
  "plan": "pro"
}


Usage Endpoints

Track and monitor API usage, AI tokens, storage, and other metrics for usage-based billing.

Get Usage Summary

GET /api/v1/app/usage/summary
Authorization: Bearer <token>

Query Parameters

Parameter Type Required Description
metric string No Filter by specific metric (default: all)

Response (200)

{
  "metrics": {
    "api_requests": {
      "current_period": 1250,
      "previous_period": 980,
      "growth_rate": 27.55,
      "daily_average": 41.67
    },
    "ai_tokens": {
      "current_period": 45000,
      "previous_period": 32000,
      "growth_rate": 40.63,
      "daily_average": 1500
    },
    "storage_bytes": {
      "current_period": 104857600,
      "previous_period": 52428800,
      "growth_rate": 100.0,
      "daily_average": 3495253
    }
  },
  "period": {
    "start": "2026-01-01T00:00:00Z",
    "end": "2026-01-31T23:59:59Z"
  }
}

Get Current Period Usage

GET /api/v1/app/usage/current-period
Authorization: Bearer <token>

Response (200)

{
  "api_requests": 1250,
  "ai_tokens": 45000,
  "ai_requests": 150,
  "storage_bytes": 104857600,
  "file_uploads": 25,
  "file_downloads": 89,
  "websocket_messages": 340,
  "background_jobs": 12,
  "email_sent": 8,
  "period": {
    "start": "2026-01-01T00:00:00Z",
    "end": "2026-01-31T23:59:59Z"
  }
}

GET /api/v1/app/usage/trends?metric=ai_tokens
Authorization: Bearer <token>

Query Parameters

Parameter Type Required Description
metric string Yes Metric to analyze
days integer No Number of days (default: 30)

Response (200)

{
  "metric": "ai_tokens",
  "current_period": 45000,
  "previous_period": 32000,
  "growth_rate": 40.63,
  "daily_average": 1500,
  "peak_day": "2026-01-15",
  "peak_value": 3200,
  "trend": "increasing"
}

Get Daily Usage Breakdown

GET /api/v1/app/usage/daily?metric=api_requests&days=7
Authorization: Bearer <token>

Query Parameters

Parameter Type Required Description
metric string Yes Metric to retrieve
days integer No Number of days (default: 30, max: 90)

Response (200)

{
  "metric": "api_requests",
  "data": [
    { "date": "2026-01-05", "value": 42 },
    { "date": "2026-01-06", "value": 38 },
    { "date": "2026-01-07", "value": 55 },
    { "date": "2026-01-08", "value": 61 },
    { "date": "2026-01-09", "value": 47 },
    { "date": "2026-01-10", "value": 52 },
    { "date": "2026-01-11", "value": 49 }
  ],
  "total": 344,
  "average": 49.14
}

Get Usage Breakdown by Category

GET /api/v1/app/usage/breakdown?metric=ai_tokens
Authorization: Bearer <token>

Query Parameters

Parameter Type Required Description
metric string Yes Metric to break down

Response (200)

{
  "metric": "ai_tokens",
  "breakdown": {
    "gpt-4o": 25000,
    "gpt-4o-mini": 15000,
    "claude-sonnet-4-5": 5000
  },
  "total": 45000
}

List Available Metrics

GET /api/v1/app/usage/metrics
Authorization: Bearer <token>

Response (200)

{
  "metrics": [
    {
      "key": "api_requests",
      "name": "API Requests",
      "description": "Total API requests made",
      "unit": "requests"
    },
    {
      "key": "ai_tokens",
      "name": "AI Tokens",
      "description": "AI/LLM tokens consumed",
      "unit": "tokens"
    },
    {
      "key": "ai_requests",
      "name": "AI Requests",
      "description": "Number of AI completion requests",
      "unit": "requests"
    },
    {
      "key": "storage_bytes",
      "name": "Storage",
      "description": "Storage space used",
      "unit": "bytes"
    },
    {
      "key": "file_uploads",
      "name": "File Uploads",
      "description": "Number of files uploaded",
      "unit": "files"
    },
    {
      "key": "file_downloads",
      "name": "File Downloads",
      "description": "Number of files downloaded",
      "unit": "files"
    },
    {
      "key": "websocket_messages",
      "name": "WebSocket Messages",
      "description": "WebSocket messages sent/received",
      "unit": "messages"
    },
    {
      "key": "background_jobs",
      "name": "Background Jobs",
      "description": "Background jobs executed",
      "unit": "jobs"
    },
    {
      "key": "email_sent",
      "name": "Emails Sent",
      "description": "Emails sent",
      "unit": "emails"
    }
  ]
}


WebSocket Endpoints

Real-time communication via WebSocket connections.

Connect to WebSocket

WebSocket: ws://localhost:8000/api/v1/app/ws?token=<jwt_token>

Connection Query Parameters

Parameter Required Description
token Yes JWT Bearer token for authentication

Connection Events

On successful connection:

{
  "type": "connected",
  "data": {
    "user_id": "user_123abc",
    "connected_at": "2026-01-11T12:00:00Z"
  }
}

Sending Messages

Subscribe to Channel

{
  "type": "subscribe",
  "channel": "project:proj_123"
}

Unsubscribe from Channel

{
  "type": "unsubscribe",
  "channel": "project:proj_123"
}

Send Message to Channel

{
  "type": "message",
  "channel": "project:proj_123",
  "data": {
    "action": "update",
    "content": "Hello team!"
  }
}

Receiving Events

Channel Message

{
  "type": "channel_message",
  "channel": "project:proj_123",
  "data": { ... },
  "sender_id": "user_456def",
  "timestamp": "2026-01-11T12:00:00Z"
}

System Notification

{
  "type": "notification",
  "data": {
    "title": "New comment",
    "message": "Someone commented on your project"
  }
}

Error Event

{
  "type": "error",
  "message": "Invalid channel format",
  "code": "INVALID_CHANNEL"
}

Broadcast Message (Server-side)

From your code, broadcast to connected users:

from app.services.websocket import get_ws_manager

manager = get_ws_manager()

# Broadcast to specific user
await manager.send_to_user(user_id, {"type": "notification", "data": {...}})

# Broadcast to channel
await manager.broadcast_to_channel("project:proj_123", {"type": "update", "data": {...}})

Admin Endpoints

Note: All admin endpoints require Authorization header AND user must have admin or superadmin role.

List All Users

GET /api/v1/admin/users?skip=0&limit=20
Authorization: Bearer <admin_token>

Response (200): Paginated list of users with admin details

Get User by ID

GET /api/v1/admin/users/{user_id}
Authorization: Bearer <admin_token>

Update User (Admin)

PATCH /api/v1/admin/users/{user_id}
Authorization: Bearer <admin_token>
Content-Type: application/json

{
  "role": "admin",
  "is_active": true
}

Deactivate User

POST /api/v1/admin/users/{user_id}/deactivate
Authorization: Bearer <admin_token>

Activate User

POST /api/v1/admin/users/{user_id}/activate
Authorization: Bearer <admin_token>

List Background Jobs

GET /api/v1/admin/jobs
Authorization: Bearer <admin_token>

Retry Failed Job

POST /api/v1/admin/jobs/{job_id}/retry
Authorization: Bearer <admin_token>

Dashboard Statistics

GET /api/v1/admin/dashboard/stats
Authorization: Bearer <admin_token>

Response (200)

{
  "users": {
    "total": 1250,
    "active": 1100,
    "new_last_7_days": 45,
    "new_last_30_days": 180
  },
  "subscriptions": {
    "active": 450,
    "by_plan": {
      "free": 800,
      "pro": 350,
      "enterprise": 100
    }
  },
  "webhooks": {
    "total": 5000,
    "failed": 12,
    "pending": 3
  },
  "jobs": {
    "queued": 25,
    "completed_last_24h": 1500,
    "failed_last_24h": 5
  }
}

List Feature Flags

GET /api/v1/admin/feature-flags
Authorization: Bearer <admin_token>

Response (200)

{
  "items": [
    {
      "id": "flag_123",
      "key": "new_dashboard",
      "name": "New Dashboard UI",
      "description": "Enable the redesigned dashboard",
      "flag_type": "percentage",
      "is_enabled": true,
      "percentage": 25,
      "user_ids": [],
      "plans": [],
      "created_at": "2026-01-01T00:00:00Z"
    }
  ],
  "total": 1
}

Create Feature Flag

POST /api/v1/admin/feature-flags
Authorization: Bearer <admin_token>
Content-Type: application/json

{
  "key": "beta_feature",
  "name": "Beta Feature",
  "description": "New experimental feature",
  "flag_type": "percentage",
  "percentage": 10,
  "is_enabled": true
}

Flag Types

Type Description
boolean Simple on/off toggle
percentage Roll out to % of users
user_list Enable for specific user IDs
plan_based Enable for specific subscription plans

Update Feature Flag

PATCH /api/v1/admin/feature-flags/{flag_id}
Authorization: Bearer <admin_token>
Content-Type: application/json

{
  "percentage": 50,
  "is_enabled": true
}

Delete Feature Flag

DELETE /api/v1/admin/feature-flags/{flag_id}
Authorization: Bearer <admin_token>

Check Feature Flag

GET /api/v1/admin/feature-flags/{flag_key}/check?user_id=user_123
Authorization: Bearer <admin_token>

Response (200)

{
  "flag_key": "new_dashboard",
  "is_enabled": true,
  "reason": "percentage_rollout"
}

Impersonate User

POST /api/v1/admin/impersonate/start
Authorization: Bearer <admin_token>
Content-Type: application/json

{
  "user_id": "user_123abc"
}

Response (200)

{
  "message": "Impersonation started",
  "impersonated_user": {
    "id": "user_123abc",
    "email": "user@example.com",
    "full_name": "John Doe"
  },
  "token": "<impersonation_jwt_token>",
  "expires_at": "2026-01-11T13:00:00Z"
}

Note: Impersonation is logged in the audit log. Admins cannot impersonate other admins or superadmins.

Stop Impersonation

POST /api/v1/admin/impersonate/stop
Authorization: Bearer <impersonation_token>

Admin Usage Analytics

GET /api/v1/admin/usage/summary/{user_id}
Authorization: Bearer <admin_token>

Response (200): Usage summary for specified user (same format as user endpoint)

GET /api/v1/admin/usage/top-users?metric=ai_tokens&limit=10
Authorization: Bearer <admin_token>

Query Parameters

Parameter Type Default Description
metric string api_requests Metric to rank by
limit integer 10 Number of top users (max: 100)

Response (200)

{
  "metric": "ai_tokens",
  "users": [
    { "user_id": "user_123", "email": "heavy@example.com", "value": 125000 },
    { "user_id": "user_456", "email": "moderate@example.com", "value": 45000 },
    { "user_id": "user_789", "email": "light@example.com", "value": 12000 }
  ],
  "period": {
    "start": "2026-01-01T00:00:00Z",
    "end": "2026-01-31T23:59:59Z"
  }
}

Get Audit Logs

GET /api/v1/admin/dashboard/audit-logs?limit=50
Authorization: Bearer <admin_token>

Query Parameters

Parameter Type Description
actor_id string Filter by actor user ID
action string Filter by action type
resource_type string Filter by resource type
limit integer Max results (default: 50)

Response (200)

{
  "items": [
    {
      "id": "log_123",
      "actor_id": "admin_456",
      "action": "impersonate.start",
      "resource_type": "user",
      "resource_id": "user_789",
      "details": { "reason": "Support ticket #123" },
      "ip_address": "192.168.1.1",
      "created_at": "2026-01-11T12:00:00Z"
    }
  ],
  "total": 1
}


Webhook Endpoints

Note: Webhook endpoints don't require Bearer authentication. They verify requests using provider-specific signatures.

Stripe Webhook

POST /api/v1/public/webhooks/stripe
Stripe-Signature: t=xxx,v1=xxx

Handled Events - checkout.session.completed - New subscription - customer.subscription.updated - Plan change - customer.subscription.deleted - Cancellation - invoice.paid - Successful payment - invoice.payment_failed - Failed payment

Clerk Webhook

POST /api/v1/public/webhooks/clerk
svix-id: xxx
svix-timestamp: xxx
svix-signature: xxx

Handled Events - user.created - New user signup - user.updated - Profile update - user.deleted - User deletion

Supabase Webhook

POST /api/v1/public/webhooks/supabase
Authorization: Bearer <webhook_secret>

Handled Events - INSERT on auth.users - New user - UPDATE on auth.users - User update - DELETE on auth.users - User deletion

Apple App Store Webhook

POST /api/v1/public/webhooks/apple
Content-Type: application/json

{
  "signedPayload": "<JWS_signed_notification>"
}

Handled Events - SUBSCRIBED - New subscription - DID_RENEW - Renewal - EXPIRED - Expiration - REFUND - Refund issued

Google Play Webhook

POST /api/v1/public/webhooks/google
Content-Type: application/json

{
  "message": {
    "data": "<base64_encoded_notification>",
    "messageId": "xxx"
  }
}

Handled Events - SUBSCRIPTION_PURCHASED - New subscription - SUBSCRIPTION_RENEWED - Renewal - SUBSCRIPTION_CANCELED - Cancellation - SUBSCRIPTION_EXPIRED - Expiration


Response Headers

Standard Headers

Every response includes:

Header Description
X-Request-ID Unique request identifier for debugging
X-RateLimit-Limit Rate limit ceiling
X-RateLimit-Remaining Remaining requests
X-RateLimit-Reset Reset timestamp

Security Headers (Production)

Header Value
X-Content-Type-Options nosniff
X-Frame-Options DENY
Strict-Transport-Security max-age=31536000; includeSubDomains
Content-Security-Policy default-src 'self'

Distributed Tracing (OpenTelemetry)

When OpenTelemetry is enabled (OTEL_ENABLED=true), all requests are automatically traced.

Trace Context Propagation

The API supports W3C Trace Context propagation. Include these headers to continue a trace from your frontend:

Header Description Example
traceparent W3C Trace Context 00-abc123...-def456...-01
tracestate Vendor-specific trace info vendor=value

Trace Correlation in Logs

All log entries include trace context when available:

{
  "timestamp": "2026-01-11T12:00:00Z",
  "level": "INFO",
  "message": "Request completed",
  "trace_id": "abc123def456789012345678901234",
  "span_id": "1234567890abcdef",
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}

Supported Exporters

Exporter Configuration Use Case
OTLP OTEL_EXPORTER_OTLP_ENDPOINT Jaeger, Grafana Tempo, etc.
Zipkin OTEL_EXPORTER_ZIPKIN_ENDPOINT Zipkin-compatible backends
Console OTEL_EXPORTER=console Local development

Auto-Instrumented Components

  • HTTP requests (FastAPI endpoints)
  • Database queries (SQLAlchemy)
  • Redis operations
  • External HTTP calls (httpx)

OpenAPI / Swagger

Interactive API documentation is available at:

  • Swagger UI: http://localhost:8000/docs
  • ReDoc: http://localhost:8000/redoc
  • OpenAPI JSON: http://localhost:8000/openapi.json