# IGNY8 API Complete Reference v1.0

**Base URL**: `https://api.igny8.com/api/v1/`  
**Version**: 1.0.0  
**Last Updated**: 2025-01-XX (Added 6 missing modules: Linker, Optimizer, Publisher, Site Builder, Automation, Integration)  
**Status**: ✅ **100% IMPLEMENTED** - All endpoints use unified format

**Purpose**: Complete, unified reference for IGNY8 API covering authentication, endpoints, response formats, error handling, rate limiting, permissions, and integration examples.

---

## Table of Contents

1. [Quick Start](#quick-start)
2. [Overview & Architecture](#overview--architecture)
3. [Authentication & Authorization](#authentication--authorization)
4. [Response Format Standard](#response-format-standard)
5. [Error Handling](#error-handling)
6. [Rate Limiting](#rate-limiting)
7. [Pagination](#pagination)
8. [Roles & Permissions](#roles--permissions)
9. [Tenant / Site / Sector Scoping](#tenant--site--sector-scoping)
10. [Complete Endpoint Reference](#complete-endpoint-reference)
11. [Integration Examples](#integration-examples)
12. [Testing & Debugging](#testing--debugging)
13. [Change Management](#change-management)

---

## Quick Start

### Interactive Documentation

- **Swagger UI**: `https://api.igny8.com/api/docs/`
- **ReDoc**: `https://api.igny8.com/api/redoc/`
- **OpenAPI Schema**: `https://api.igny8.com/api/schema/`

### Basic Example

```python
import requests

BASE_URL = "https://api.igny8.com/api/v1"

# 1. Login
response = requests.post(
    f"{BASE_URL}/auth/login/",
    json={"email": "user@example.com", "password": "password"}
)
data = response.json()

if data['success']:
    token = data['data']['access']
    
    # 2. Use token for authenticated requests
    headers = {
        'Authorization': f'Bearer {token}',
        'Content-Type': 'application/json'
    }
    
    # 3. Get keywords
    response = requests.get(
        f"{BASE_URL}/planner/keywords/",
        headers=headers
    )
    result = response.json()
    
    if result['success']:
        keywords = result['results']  # Paginated results
        print(f"Found {result['count']} keywords")
```

---

## Overview & Architecture

### API Standard v1.0 - Key Principles

1. **Unified Response Format**: All endpoints return consistent JSON structure
2. **Layered Authorization**: Authentication → Tenant Access → Role → Site/Sector
3. **Centralized Error Handling**: All errors wrapped in unified format
4. **Scoped Rate Limiting**: Different limits for different operation types
5. **Tenant Isolation**: All resources scoped by account/site/sector
6. **Request Tracking**: Every request has a unique ID for debugging

### Base URL Structure

```
Production: https://api.igny8.com/api/v1/
Development: http://localhost:8000/api/v1/
```

### Module Namespaces

```
/api/v1/
├── auth/          # Authentication and user management
├── planner/       # Keywords, clusters, content ideas
├── writer/        # Tasks, content, images
├── linker/        # Internal linking operations
├── optimizer/     # Content optimization and scoring
├── publisher/     # Publishing records and site deployment
├── site-builder/  # Site blueprint management
├── automation/    # Automation rules and scheduled tasks
├── integration/   # External platform integrations
├── system/        # Settings, prompts, integrations
└── billing/       # Credits, transactions, usage
```

### Technology Stack

- **Framework**: Django REST Framework (DRF)
- **Authentication**: JWT Bearer tokens (primary), Session (fallback), Basic (fallback)
- **Pagination**: CustomPageNumberPagination (default: 10, max: 100)
- **Rate Limiting**: Scoped throttles per module/operation type
- **OpenAPI**: drf-spectacular for schema generation

### Implementation Status

✅ **100% Complete** - All endpoints implemented with:
- Unified response format
- Proper authentication and authorization
- Rate limiting configured
- Error handling standardized
- Request ID tracking
- Complete Swagger/OpenAPI documentation

---

## Authentication & Authorization

### Authentication Methods

#### Primary: JWT Bearer Token

```
Authorization: Bearer <access_token>
```

**Token Characteristics:**
- Contains `user_id` and `account_id`
- Type: `access` (15-minute expiry)
- Automatically sets `request.account` via middleware
- Resolves account → tenant context automatically

**Token Payload:**
```json
{
  "user_id": 1,
  "account_id": 1,
  "type": "access",
  "exp": 1234567890
}
```

#### Fallback Methods

1. **Session Authentication** (admin panel)
   - Class: `CSRFExemptSessionAuthentication`
   - Use case: Django admin panel (`/admin/`)

2. **Basic Authentication** (debug/testing)
   - Class: `rest_framework.authentication.BasicAuthentication`
   - Use case: API testing tools (Postman, curl)

### Authentication Order

1. JWT Token Authentication (tried first)
2. Session Authentication (fallback)
3. Basic Authentication (last fallback)
4. If all fail: 401 Unauthorized

### Getting an Access Token

**Login Endpoint:**
```http
POST /api/v1/auth/login/
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "your_password"
}
```

**Response:**
```json
{
  "success": true,
  "data": {
    "user": {
      "id": 1,
      "email": "user@example.com",
      "username": "user",
      "role": "owner",
      "account": { ... }
    },
    "access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  },
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

### Token Expiration

- **Access Token**: 15 minutes
- **Refresh Token**: 7 days

**Refresh Token:**
```http
POST /api/v1/auth/refresh/
Content-Type: application/json

{
  "refresh": "your_refresh_token"
}
```

### Public Endpoints (No Authentication Required)

- `POST /api/v1/auth/register/` - User registration
- `POST /api/v1/auth/login/` - User login
- `GET /api/v1/auth/plans/` - List plans
- `GET /api/v1/auth/industries/` - List industries
- `GET /api/v1/system/status/` - System health check
- `GET /api/v1/system/ping/` - Health check endpoint
- `GET /api/v1/publisher/sites/{site_id}/definition/` - Get site definition for Sites Renderer

**All other endpoints require JWT authentication.**

### Authorization Layers

Every endpoint enforces layered authorization:

1. **User Authentication**: User must be authenticated
2. **Tenant Access**: User must belong to the tenant/account
3. **Role Authorization**: User must have appropriate role
4. **Site/Sector Access**: User must have access to requested site/sector

---

## Response Format Standard

### Mandatory Format

**This is the global standard for all endpoints - no exceptions.**

### Success Response

```json
{
  "success": true,
  "data": {
    "id": 1,
    "name": "Example Keyword",
    "status": "active"
  },
  "message": "Optional human-readable success message",
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

### Paginated Response

```json
{
  "success": true,
  "count": 120,
  "next": "http://api.igny8.com/api/v1/planner/keywords/?page=3",
  "previous": "http://api.igny8.com/api/v1/planner/keywords/?page=1",
  "results": [
    {"id": 1, "name": "Keyword 1"},
    {"id": 2, "name": "Keyword 2"},
    ...
  ],
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

### Error Response

```json
{
  "success": false,
  "error": "Readable top-level error message",
  "errors": {
    "field_name": ["Field-specific error messages"]
  },
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

### Response Helper Functions

**File:** `backend/igny8_core/api/response.py`

```python
from igny8_core.api.response import success_response, error_response, paginated_response

# Success response
return success_response(
    data={"id": 1, "name": "Example"},
    message="Resource created successfully",
    status_code=status.HTTP_201_CREATED
)

# Error response
return error_response(
    error="Validation failed",
    errors={"email": ["Invalid email format"]},
    status_code=status.HTTP_400_BAD_REQUEST
)

# Paginated response
paginator = CustomPageNumberPagination()
page = paginator.paginate_queryset(queryset, request)
serializer = MySerializer(page, many=True)
paginated_data = paginator.get_paginated_response(serializer.data).data
return paginated_response(paginated_data, message="Resources retrieved successfully")
```

---

## Error Handling

### HTTP Status Codes

| Code | Meaning | Description |
|------|---------|-------------|
| 200 | OK | Request successful |
| 201 | Created | Resource created successfully |
| 204 | No Content | Resource deleted successfully |
| 400 | Bad Request | Validation error or invalid request |
| 401 | Unauthorized | Authentication required |
| 403 | Forbidden | Permission denied |
| 404 | Not Found | Resource not found |
| 409 | Conflict | Resource conflict (e.g., duplicate) |
| 422 | Unprocessable Entity | Validation failed |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Server error |

### Centralized Exception Handler

**File:** `backend/igny8_core/api/exception_handlers.py`

All exceptions are handled by a centralized exception handler that:
- Wraps all errors in unified format
- Uses proper HTTP status codes
- Includes sanitized validation errors under `errors`
- Always attaches `request_id` for error tracking
- Logs full exception details
- In DEBUG mode: includes traceback + request context

### Error Response Examples

**Validation Error (400):**
```json
{
  "success": false,
  "error": "Validation failed",
  "errors": {
    "email": ["Invalid email format"],
    "password": ["Password must be at least 8 characters"]
  },
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

**Authentication Error (401):**
```json
{
  "success": false,
  "error": "Authentication required",
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

**Permission Error (403):**
```json
{
  "success": false,
  "error": "Permission denied",
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

**Rate Limit (429):**
```json
{
  "success": false,
  "error": "Rate limit exceeded",
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

### Server-side Logging

- All 4xx errors logged as **warning**
- All 5xx errors logged as **error**
- Structured format with timestamp, request_id, endpoint, user_id, account_id, status_code, error_message
- Rotating log files
- Sentry integration hooks for production

---

## Rate Limiting

### Rate Limiting Configuration

Rate limits are scoped by operation type. Check response headers for limit information:

- `X-Throttle-Limit`: Maximum requests allowed
- `X-Throttle-Remaining`: Remaining requests in current window
- `X-Throttle-Reset`: Time when limit resets (Unix timestamp)

### Rate Limit Scopes

| Scope | Limit | Description |
|-------|-------|-------------|
| `ai_function` | 10/min | AI content generation, clustering |
| `image_gen` | 15/min | Image generation |
| `content_write` | 30/min | Content creation, updates |
| `content_read` | 100/min | Content listing, retrieval |
| `auth` | 20/min | Login, register, password reset |
| `auth_strict` | 5/min | Sensitive auth operations |
| `planner` | 60/min | Keyword, cluster, idea operations |
| `planner_ai` | 10/min | AI-powered planner operations |
| `writer` | 60/min | Task, content management |
| `writer_ai` | 10/min | AI-powered writer operations |
| `system` | 100/min | Settings, prompts, profiles |
| `system_admin` | 30/min | Admin-only system operations |
| `billing` | 30/min | Credit queries, usage logs |
| `billing_admin` | 10/min | Credit management (admin) |
| `default` | 100/min | Default for endpoints without scope |

### Handling Rate Limits

When rate limited (429), the response includes:
- Error message: "Rate limit exceeded"
- Headers with reset time
- Wait until `X-Throttle-Reset` before retrying

**Example:**
```http
HTTP/1.1 429 Too Many Requests
X-Throttle-Limit: 60
X-Throttle-Remaining: 0
X-Throttle-Reset: 1700123456
Retry-After: 60

{
  "success": false,
  "error": "Rate limit exceeded",
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

### Debug Mode Bypass

Set `IGNY8_DEBUG_THROTTLE=True` or `DEBUG=True` to bypass throttling in development.

---

## Pagination

### Pagination Configuration

**Default Settings:**
- Default page size: **10**
- Maximum page size: **100**
- Query parameter: `page_size` (optional)
- Page parameter: `page` (default: 1)

### Query Parameters

**Pagination:**
```
?page=2&page_size=25
```

**Filtering:**
```
?status=active
?site_id=1
?sector_id=2
?cluster_id=5
```

**Search:**
```
?search=keyword
```

**Ordering:**
```
?ordering=-created_at
?ordering=name,status
```

### Pagination Response Format

```json
{
  "success": true,
  "count": 150,
  "next": "http://api.igny8.com/api/v1/planner/keywords/?page=3&page_size=25",
  "previous": "http://api.igny8.com/api/v1/planner/keywords/?page=1&page_size=25",
  "results": [
    // Array of results
  ],
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

### Pagination Fields

- `count`: Total number of items
- `next`: URL to next page (null if last page)
- `previous`: URL to previous page (null if first page)
- `results`: Array of items for current page

---

## Roles & Permissions

### Role Hierarchy

```
owner > admin > editor > viewer > system_bot
```

### Standard Permission Classes

**File:** `backend/igny8_core/api/permissions.py`

| Permission Class | Description | Use Case |
|-----------------|------------|----------|
| `IsAuthenticatedAndActive` | User authenticated and active | Base permission for most endpoints |
| `HasTenantAccess` | User belongs to tenant/account | Tenant isolation |
| `IsViewerOrAbove` | Viewer, editor, admin, or owner | Read-only operations |
| `IsEditorOrAbove` | Editor, admin, or owner | Content operations |
| `IsAdminOrOwner` | Admin or owner only | Settings, keys, billing |

### Permission Matrix by Endpoint Type

| Endpoint Type | Required Permissions | Roles Allowed |
|--------------|---------------------|---------------|
| Public (register, login) | `AllowAny` | Anyone |
| Read-only (list, retrieve) | `IsAuthenticatedAndActive` + `HasTenantAccess` | All authenticated users |
| Content operations | `IsAuthenticatedAndActive` + `HasTenantAccess` + `IsEditorOrAbove` | Editor, Admin, Owner |
| User management | `IsAuthenticatedAndActive` + `HasTenantAccess` + `IsAdminOrOwner` | Admin, Owner |
| Billing/Transactions | `IsAuthenticatedAndActive` + `HasTenantAccess` + `IsAdminOrOwner` | Admin, Owner |
| Integration settings | `IsAuthenticatedAndActive` + `HasTenantAccess` + `IsAdminOrOwner` | Admin, Owner |

---

## Tenant / Site / Sector Scoping

### Scoping Rules

Every resource created or fetched must be scoped by:

1. **Account/Tenant** - User's account
2. **Site** - Specific site within account
3. **Sector** - Specific sector within site

### Enforcement

**Base Classes:**
- `AccountModelViewSet` - Handles account isolation
- `SiteSectorModelViewSet` - Filters queries by site/sector

**Requirements:**
- All custom actions must use `.get_queryset()` to avoid bypassing filters
- Any ID list must be verified to belong to the authenticated tenant
- Site/sector access validated based on user role

### Scoping Example

```python
class KeywordViewSet(SiteSectorModelViewSet):
    # Automatically filters by:
    # 1. account (from request.account)
    # 2. site_id (from query params or request)
    # 3. sector_id (from query params or request)
    
    queryset = Keyword.objects.all()
    serializer_class = KeywordSerializer
    
    def get_queryset(self):
        # Base class handles account/site/sector filtering
        queryset = super().get_queryset()
        # Additional filtering can be added here
        return queryset
```

---

## Complete Endpoint Reference

### Authentication Endpoints

**Base Path**: `/api/v1/auth/`

#### POST `/api/v1/auth/register/`
**Purpose**: User registration  
**Authentication**: None (AllowAny)

**Request:**
```json
{
  "email": "user@example.com",
  "password": "password123",
  "password_confirm": "password123"
}
```

**Response:**
```json
{
  "success": true,
  "data": {
    "user": {
      "id": 1,
      "email": "user@example.com",
      "role": "owner",
      "account": { ... }
    }
  },
  "message": "Registration successful"
}
```

#### POST `/api/v1/auth/login/`
**Purpose**: User login  
**Authentication**: None (AllowAny)

**Request:**
```json
{
  "email": "user@example.com",
  "password": "password123"
}
```

**Response:**
```json
{
  "success": true,
  "data": {
    "user": { ... },
    "access": "eyJ0eXAiOiJKV1QiLCJhbGc...",
    "refresh": "eyJ0eXAiOiJKV1QiLCJhbGc...",
    "access_expires_at": "2025-01-XXT...",
    "refresh_expires_at": "2025-01-XXT..."
  },
  "message": "Login successful",
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

#### POST `/api/v1/auth/refresh/`
**Purpose**: Refresh access token  
**Authentication**: None (requires refresh token)

**Request:**
```json
{
  "refresh": "your_refresh_token"
}
```

#### POST `/api/v1/auth/change-password/`
**Purpose**: Change user password  
**Authentication**: Required (IsAuthenticated)

**Request:**
```json
{
  "old_password": "oldpass123",
  "new_password": "newpass123",
  "new_password_confirm": "newpass123"
}
```

#### GET `/api/v1/auth/me/`
**Purpose**: Get current user information  
**Authentication**: Required (IsAuthenticated)

**Response:**
```json
{
  "success": true,
  "data": {
    "user": {
      "id": 1,
      "email": "user@example.com",
      "role": "owner",
      "account": { ... },
      "accessible_sites": [ ... ]
    }
  }
}
```

### User Management Endpoints

**Base Path**: `/api/v1/auth/users/`  
**Permission**: IsOwnerOrAdmin

**Standard CRUD:**
- `GET /api/v1/auth/users/` - List users
- `POST /api/v1/auth/users/` - Create user
- `GET /api/v1/auth/users/{id}/` - Get user
- `PUT /api/v1/auth/users/{id}/` - Update user
- `DELETE /api/v1/auth/users/{id}/` - Delete user

**Custom Actions:**
- `POST /api/v1/auth/users/invite/` - Invite user
- `POST /api/v1/auth/users/{id}/activate/` - Activate user

### Account Management Endpoints

**Base Path**: `/api/v1/auth/accounts/`  
**Permission**: IsOwnerOrAdmin

**Standard CRUD:**
- `GET /api/v1/auth/accounts/` - List accounts
- `POST /api/v1/auth/accounts/` - Create account
- `GET /api/v1/auth/accounts/{id}/` - Get account
- `PUT /api/v1/auth/accounts/{id}/` - Update account
- `DELETE /api/v1/auth/accounts/{id}/` - Delete account

### Site Management Endpoints

**Base Path**: `/api/v1/auth/sites/`  
**Permission**: IsEditorOrAbove

**Standard CRUD:**
- `GET /api/v1/auth/sites/` - List sites
- `POST /api/v1/auth/sites/` - Create site
- `GET /api/v1/auth/sites/{id}/` - Get site
- `PUT /api/v1/auth/sites/{id}/` - Update site
- `DELETE /api/v1/auth/sites/{id}/` - Delete site

**Custom Actions:**
- `GET /api/v1/auth/sites/{id}/sectors/` - Get site sectors
- `POST /api/v1/auth/sites/{id}/set_active/` - Set active site
- `POST /api/v1/auth/sites/{id}/select_sectors/` - Select sectors

### Sector Management Endpoints

**Base Path**: `/api/v1/auth/sectors/`  
**Permission**: IsEditorOrAbove

**Standard CRUD:**
- `GET /api/v1/auth/sectors/` - List sectors
- `POST /api/v1/auth/sectors/` - Create sector
- `GET /api/v1/auth/sectors/{id}/` - Get sector
- `PUT /api/v1/auth/sectors/{id}/` - Update sector
- `DELETE /api/v1/auth/sectors/{id}/` - Delete sector

### Planner Module Endpoints

**Base Path**: `/api/v1/planner/`

#### Keyword Management

**Base Path**: `/api/v1/planner/keywords/`  
**Permission**: IsAuthenticatedAndActive + HasTenantAccess  
**Inherits**: SiteSectorModelViewSet

**Standard CRUD:**
- `GET /api/v1/planner/keywords/` - List keywords (paginated)
- `POST /api/v1/planner/keywords/` - Create keyword
- `GET /api/v1/planner/keywords/{id}/` - Get keyword
- `PUT /api/v1/planner/keywords/{id}/` - Update keyword
- `DELETE /api/v1/planner/keywords/{id}/` - Delete keyword

**Filtering:**
- `status` - Filter by status
- `cluster_id` - Filter by cluster
- `seed_keyword__intent` - Filter by intent
- `seed_keyword_id` - Filter by seed keyword ID
- `difficulty_min`, `difficulty_max` - Difficulty range
- `volume_min`, `volume_max` - Volume range
- `site_id` - Filter by site (query param)
- `sector_id` - Filter by sector (query param)

**Search:**
- `search` - Search by keyword text

**Ordering:**
- `ordering` - Order by `created_at`, `seed_keyword__volume`, `seed_keyword__difficulty`
- Default: `-created_at` (newest first)

**Custom Actions:**
- `POST /api/v1/planner/keywords/bulk_delete/` - Bulk delete keywords
  - Request: `{ "ids": [1, 2, 3] }`
- `POST /api/v1/planner/keywords/bulk_update_status/` - Bulk update status
  - Request: `{ "ids": [1, 2, 3], "status": "active" }`
- `POST /api/v1/planner/keywords/bulk_add_from_seed/` - Add keywords from seed library
  - Request: `{ "seed_keyword_ids": [1, 2, 3], "site_id": 1, "sector_id": 1 }`
- `GET /api/v1/planner/keywords/export/` - Export keywords to CSV
- `POST /api/v1/planner/keywords/import_keywords/` - Import keywords from CSV
- `POST /api/v1/planner/keywords/auto_cluster/` - Auto-cluster keywords using AI
  - Request: `{ "ids": [1, 2, 3, ...], "sector_id": 1 }`
  - Max Keywords: 20 per batch
  - Returns: Celery task ID for progress tracking

#### Cluster Management

**Base Path**: `/api/v1/planner/clusters/`  
**Permission**: IsAuthenticatedAndActive + HasTenantAccess  
**Inherits**: SiteSectorModelViewSet

**Standard CRUD:**
- `GET /api/v1/planner/clusters/` - List clusters
- `POST /api/v1/planner/clusters/` - Create cluster
- `GET /api/v1/planner/clusters/{id}/` - Get cluster
- `PUT /api/v1/planner/clusters/{id}/` - Update cluster
- `DELETE /api/v1/planner/clusters/{id}/` - Delete cluster

**Filtering:**
- `status` - Filter by status
- `site_id` - Filter by site (query param)
- `sector_id` - Filter by sector (query param)

**Search:**
- `search` - Search by cluster name

**Custom Actions:**
- `POST /api/v1/planner/clusters/bulk_delete/` - Bulk delete clusters
- `POST /api/v1/planner/clusters/auto_generate_ideas/` - Auto-generate content ideas
  - Request: `{ "ids": [1] }` (max 1 cluster per batch)
  - Returns: Celery task ID for progress tracking

#### Content Ideas Management

**Base Path**: `/api/v1/planner/ideas/`  
**Permission**: IsAuthenticatedAndActive + HasTenantAccess  
**Inherits**: SiteSectorModelViewSet

**Standard CRUD:**
- `GET /api/v1/planner/ideas/` - List content ideas
- `POST /api/v1/planner/ideas/` - Create content idea
- `GET /api/v1/planner/ideas/{id}/` - Get content idea
- `PUT /api/v1/planner/ideas/{id}/` - Update content idea
- `DELETE /api/v1/planner/ideas/{id}/` - Delete content idea

**Filtering:**
- `status` - Filter by status
- `cluster_id` - Filter by cluster
- `content_type` - Filter by content type
- `site_id` - Filter by site (query param)
- `sector_id` - Filter by sector (query param)

**Custom Actions:**
- `POST /api/v1/planner/ideas/bulk_delete/` - Bulk delete ideas
- `POST /api/v1/planner/ideas/bulk_queue_to_writer/` - Queue ideas to writer (create tasks)
  - Request: `{ "ids": [1, 2, 3] }`

### Writer Module Endpoints

**Base Path**: `/api/v1/writer/`

#### Task Management

**Base Path**: `/api/v1/writer/tasks/`  
**Permission**: IsAuthenticatedAndActive + HasTenantAccess  
**Inherits**: SiteSectorModelViewSet

**Standard CRUD:**
- `GET /api/v1/writer/tasks/` - List tasks
- `POST /api/v1/writer/tasks/` - Create task
- `GET /api/v1/writer/tasks/{id}/` - Get task
- `PUT /api/v1/writer/tasks/{id}/` - Update task
- `DELETE /api/v1/writer/tasks/{id}/` - Delete task

**Filtering:**
- `status` - Filter by status (draft, in_progress, review, completed, archived)
- `cluster_id` - Filter by cluster
- `content_type` - Filter by content type
- `content_structure` - Filter by content structure
- `site_id` - Filter by site (query param)
- `sector_id` - Filter by sector (query param)

**Search:**
- `search` - Search by title or keywords

**Custom Actions:**
- `POST /api/v1/writer/tasks/bulk_delete/` - Bulk delete tasks
- `POST /api/v1/writer/tasks/bulk_update/` - Bulk update task status
- `POST /api/v1/writer/tasks/auto_generate_content/` - Auto-generate content using AI
  - Request: `{ "ids": [1, 2, 3, ...] }` (max 50 tasks per batch)
  - Returns: Celery task ID for progress tracking

#### Content Management

**Base Path**: `/api/v1/writer/content/`  
**Permission**: IsAuthenticatedAndActive + HasTenantAccess  
**Inherits**: SiteSectorModelViewSet

**Standard CRUD:**
- `GET /api/v1/writer/content/` - List content
- `POST /api/v1/writer/content/` - Create content
- `GET /api/v1/writer/content/{id}/` - Get content
- `PUT /api/v1/writer/content/{id}/` - Update content
- `DELETE /api/v1/writer/content/{id}/` - Delete content

**Filtering:**
- `status` - Filter by status
- `content_type` - Filter by content type
- `site_id` - Filter by site (query param)
- `sector_id` - Filter by sector (query param)

**Custom Actions:**
- `POST /api/v1/writer/content/generate_image_prompts/` - Generate image prompts from content
  - Request: `{ "ids": [1, 2, 3] }`
  - Returns: Celery task ID for progress tracking

#### Image Management

**Base Path**: `/api/v1/writer/images/`  
**Permission**: IsAuthenticatedAndActive + HasTenantAccess  
**Inherits**: SiteSectorModelViewSet

**Standard CRUD:**
- `GET /api/v1/writer/images/` - List images
- `POST /api/v1/writer/images/` - Create image
- `GET /api/v1/writer/images/{id}/` - Get image
- `PUT /api/v1/writer/images/{id}/` - Update image
- `DELETE /api/v1/writer/images/{id}/` - Delete image

**Filtering:**
- `image_type` - Filter by type (featured, in_article, desktop, mobile)
- `status` - Filter by status
- `content_id` - Filter by content
- `task_id` - Filter by task
- `site_id` - Filter by site (query param)
- `sector_id` - Filter by sector (query param)

**Custom Actions:**
- `GET /api/v1/writer/images/{id}/file/` - Get image file URL
- `GET /api/v1/writer/images/content_images/` - Get images for content
  - Query Params: `content_id` (required)
- `POST /api/v1/writer/images/generate_images/` - Generate images using AI
  - Request: `{ "ids": [1, 2, 3, ...] }`
  - Returns: Celery task ID for progress tracking
- `POST /api/v1/writer/images/bulk_update/` - Bulk update image status

### System Module Endpoints

**Base Path**: `/api/v1/system/`

#### AI Prompt Management

**Base Path**: `/api/v1/system/prompts/`  
**Permission**: IsAuthenticatedAndActive + HasTenantAccess  
**Inherits**: AccountModelViewSet

**Standard CRUD:**
- `GET /api/v1/system/prompts/` - List prompts
- `POST /api/v1/system/prompts/` - Create prompt
- `GET /api/v1/system/prompts/{id}/` - Get prompt
- `PUT /api/v1/system/prompts/{id}/` - Update prompt
- `DELETE /api/v1/system/prompts/{id}/` - Delete prompt

**Custom Actions:**
- `GET /api/v1/system/prompts/by_type/{prompt_type}/` - Get prompt by type
- `POST /api/v1/system/prompts/save/` - Save prompt (requires editor/admin)
- `POST /api/v1/system/prompts/reset/` - Reset prompt to default

#### Integration Settings

**Base Path**: `/api/v1/system/settings/integrations/`  
**Permission**: IsAdminOrOwner

**Custom URL Patterns:**
- `GET /api/v1/system/settings/integrations/{pk}/` - Get integration settings
- `POST /api/v1/system/settings/integrations/{pk}/save/` - Save integration settings
- `PUT /api/v1/system/settings/integrations/{pk}/` - Update integration settings
- `POST /api/v1/system/settings/integrations/{pk}/test/` - Test connection
  - Request: `{ "provider": "openai" }` or `{ "provider": "runware" }`
- `POST /api/v1/system/settings/integrations/{pk}/generate/` - Test image generation
- `GET /api/v1/system/settings/task_progress/{task_id}/` - Get Celery task progress
- `GET /api/v1/system/integrations/image_generation/` - Get image generation settings

#### System Status

**Base Path**: `/api/v1/system/`

- `GET /api/v1/system/status/` - System health check (AllowAny)
- `GET /api/v1/system/ping/` - Health check endpoint (AllowAny)
- `GET /api/v1/system/request-metrics/{request_id}/` - Get request metrics for debugging

### Linker Module Endpoints

**Base Path**: `/api/v1/linker/`  
**Permission**: IsAuthenticatedAndActive + HasTenantAccess

#### Process Content for Internal Linking

- `POST /api/v1/linker/process/` - Process single content item for internal linking

**Request:**
```json
{
  "content_id": 123
}
```

**Response:**
```json
{
  "success": true,
  "data": {
    "content_id": 123,
    "suggested_links": [
      {
        "target_content_id": 456,
        "target_title": "Related Article",
        "anchor_text": "relevant keyword",
        "confidence": 0.85
      }
    ]
  }
}
```

#### Batch Process Content

- `POST /api/v1/linker/batch_process/` - Process multiple content items for linking

**Request:**
```json
{
  "content_ids": [123, 456, 789]
}
```

### Optimizer Module Endpoints

**Base Path**: `/api/v1/optimizer/`  
**Permission**: IsAuthenticatedAndActive + HasTenantAccess

#### Optimize Content

- `POST /api/v1/optimizer/optimize/` - Optimize content (auto-detects entry point)

**Request:**
```json
{
  "ids": [123, 456],
  "entry_point": "seo"  // Optional: "seo", "readability", "engagement"
}
```

**Response:**
```json
{
  "success": true,
  "data": {
    "optimized_content": "...",
    "seo_score": 85,
    "readability_score": 78,
    "engagement_score": 82
  }
}
```

#### Batch Optimize Content

- `POST /api/v1/optimizer/batch_optimize/` - Batch optimize multiple content items

**Request:**
```json
{
  "ids": [123, 456, 789],
  "entry_point": "seo"  // Optional
}
```

#### Analyze Content

- `POST /api/v1/optimizer/analyze/` - Analyze content without optimization

**Request:**
```json
{
  "id": 123
}
```

**Response:**
```json
{
  "success": true,
  "data": {
    "seo_score": 75,
    "readability_score": 70,
    "engagement_score": 68,
    "recommendations": [
      "Add more internal links",
      "Improve heading structure"
    ]
  }
}
```

### Publisher Module Endpoints

**Base Path**: `/api/v1/publisher/`  
**Permission**: IsAuthenticatedAndActive + HasTenantAccess

#### Publishing Records

**Base Path**: `/api/v1/publisher/publishing-records/`  
**Inherits**: SiteSectorModelViewSet

**Standard CRUD:**
- `GET /api/v1/publisher/publishing-records/` - List publishing records (paginated)
- `POST /api/v1/publisher/publishing-records/` - Create publishing record
- `GET /api/v1/publisher/publishing-records/{id}/` - Get publishing record
- `PUT /api/v1/publisher/publishing-records/{id}/` - Update publishing record
- `DELETE /api/v1/publisher/publishing-records/{id}/` - Delete publishing record

**Filtering:**
- `status` - Filter by publishing status
- `destination_type` - Filter by destination (wordpress, sites_renderer, etc.)
- `site_id` - Filter by site
- `sector_id` - Filter by sector

#### Deployment Records

**Base Path**: `/api/v1/publisher/deployments/`  
**Inherits**: SiteSectorModelViewSet

**Standard CRUD:**
- `GET /api/v1/publisher/deployments/` - List deployment records (paginated)
- `POST /api/v1/publisher/deployments/` - Create deployment record
- `GET /api/v1/publisher/deployments/{id}/` - Get deployment record
- `PUT /api/v1/publisher/deployments/{id}/` - Update deployment record
- `DELETE /api/v1/publisher/deployments/{id}/` - Delete deployment record

#### Publishing Actions

- `POST /api/v1/publisher/publish/` - Publish content to destination

**Request:**
```json
{
  "content_id": 123,
  "destination_type": "wordpress",
  "destination_id": 1
}
```

- `POST /api/v1/publisher/deploy/` - Deploy site blueprint

**Request:**
```json
{
  "blueprint_id": 456,
  "environment": "production"
}
```

- `POST /api/v1/publisher/check_readiness/` - Check deployment readiness

**Request:**
```json
{
  "blueprint_id": 456
}
```

#### Public Endpoint (No Authentication)

- `GET /api/v1/publisher/sites/{site_id}/definition/` - Get site definition for Sites Renderer

**Response:**
```json
{
  "success": true,
  "data": {
    "site_id": 1,
    "slug": "example-site",
    "blueprints": [...],
    "pages": [...]
  }
}
```

### Site Builder Module Endpoints

**Base Path**: `/api/v1/site-builder/`  
**Permission**: IsAuthenticatedAndActive + HasTenantAccess

#### Site Blueprints

**Base Path**: `/api/v1/site-builder/blueprints/`  
**Inherits**: SiteSectorModelViewSet

**Standard CRUD:**
- `GET /api/v1/site-builder/blueprints/` - List site blueprints (paginated)
- `POST /api/v1/site-builder/blueprints/` - Create site blueprint
- `GET /api/v1/site-builder/blueprints/{id}/` - Get blueprint details
- `PUT /api/v1/site-builder/blueprints/{id}/` - Update blueprint
- `DELETE /api/v1/site-builder/blueprints/{id}/` - Delete blueprint

**Custom Actions:**
- `POST /api/v1/site-builder/blueprints/{id}/generate_structure/` - Generate site structure using AI
- `POST /api/v1/site-builder/blueprints/{id}/generate_all_pages/` - Generate all pages for blueprint
- `POST /api/v1/site-builder/blueprints/{id}/create_tasks/` - Create Writer tasks for pages
- `GET /api/v1/site-builder/blueprints/{id}/progress/` - Get cluster-level completion status
- `POST /api/v1/site-builder/blueprints/{id}/clusters/attach/` - Attach planner clusters
- `POST /api/v1/site-builder/blueprints/{id}/clusters/detach/` - Detach clusters
- `GET /api/v1/site-builder/blueprints/{id}/taxonomies/` - List taxonomies
- `POST /api/v1/site-builder/blueprints/{id}/taxonomies/` - Create taxonomy
- `POST /api/v1/site-builder/blueprints/{id}/taxonomies/import/` - Import taxonomies
- `POST /api/v1/site-builder/blueprints/bulk_delete/` - Bulk delete blueprints

**Filtering:**
- `status` - Filter by blueprint status
- `site_id` - Filter by site
- `sector_id` - Filter by sector

#### Page Blueprints

**Base Path**: `/api/v1/site-builder/pages/`  
**Inherits**: SiteSectorModelViewSet

**Standard CRUD:**
- `GET /api/v1/site-builder/pages/` - List page blueprints (paginated)
- `POST /api/v1/site-builder/pages/` - Create page blueprint
- `GET /api/v1/site-builder/pages/{id}/` - Get page details
- `PUT /api/v1/site-builder/pages/{id}/` - Update page
- `DELETE /api/v1/site-builder/pages/{id}/` - Delete page

**Custom Actions:**
- `POST /api/v1/site-builder/pages/{id}/generate_content/` - Generate content for page
- `POST /api/v1/site-builder/pages/{id}/regenerate/` - Regenerate page content

**Filtering:**
- `site_blueprint_id` - Filter by site blueprint
- `status` - Filter by page status

#### Site Assets

- `GET /api/v1/site-builder/assets/` - List files for site

**Query Parameters:**
- `site_id` - Filter by site
- `file_type` - Filter by file type

- `POST /api/v1/site-builder/assets/` - Upload file

**Request:** Multipart form data
```json
{
  "file": "<file>",
  "site_id": 1,
  "file_type": "image"
}
```

- `DELETE /api/v1/site-builder/assets/` - Delete file

**Request:**
```json
{
  "file_path": "path/to/file.jpg",
  "site_id": 1
}
```

#### Site Builder Metadata

- `GET /api/v1/site-builder/metadata/` - Get metadata (business types, audience profiles, etc.)

**Response:**
```json
{
  "success": true,
  "data": {
    "business_types": [...],
    "audience_profiles": [...],
    "brand_personalities": [...],
    "hero_imagery_directions": [...]
  }
}
```

### Automation Module Endpoints

**Base Path**: `/api/v1/automation/`  
**Permission**: IsAuthenticatedAndActive + HasTenantAccess

#### Automation Rules

**Base Path**: `/api/v1/automation/rules/`  
**Inherits**: SiteSectorModelViewSet

**Standard CRUD:**
- `GET /api/v1/automation/rules/` - List automation rules (paginated)
- `POST /api/v1/automation/rules/` - Create automation rule
- `GET /api/v1/automation/rules/{id}/` - Get rule details
- `PUT /api/v1/automation/rules/{id}/` - Update rule
- `DELETE /api/v1/automation/rules/{id}/` - Delete rule

**Custom Actions:**
- `POST /api/v1/automation/rules/{id}/execute/` - Manually execute automation rule

**Filtering:**
- `status` - Filter by rule status (active, inactive)
- `trigger_type` - Filter by trigger type
- `site_id` - Filter by site
- `sector_id` - Filter by sector

#### Scheduled Tasks

**Base Path**: `/api/v1/automation/scheduled-tasks/`  
**Inherits**: AccountModelViewSet

**Standard CRUD:**
- `GET /api/v1/automation/scheduled-tasks/` - List scheduled tasks (paginated)
- `POST /api/v1/automation/scheduled-tasks/` - Create scheduled task
- `GET /api/v1/automation/scheduled-tasks/{id}/` - Get task details
- `PUT /api/v1/automation/scheduled-tasks/{id}/` - Update task
- `DELETE /api/v1/automation/scheduled-tasks/{id}/` - Delete task

**Filtering:**
- `status` - Filter by task status
- `task_type` - Filter by task type
- `next_run_date` - Filter by next run date

### Integration Module Endpoints

**Base Path**: `/api/v1/integration/`  
**Permission**: IsAuthenticatedAndActive + HasTenantAccess

#### Site Integrations

**Base Path**: `/api/v1/integration/integrations/`  
**Inherits**: SiteSectorModelViewSet

**Standard CRUD:**
- `GET /api/v1/integration/integrations/` - List site integrations (paginated)
- `POST /api/v1/integration/integrations/` - Create integration
- `GET /api/v1/integration/integrations/{id}/` - Get integration details
- `PUT /api/v1/integration/integrations/{id}/` - Update integration
- `DELETE /api/v1/integration/integrations/{id}/` - Delete integration

**Custom Actions:**
- `POST /api/v1/integration/integrations/{id}/test_connection/` - Test connection to integrated platform

**Request:**
```json
{}
```

**Response:**
```json
{
  "success": true,
  "data": {
    "connected": true,
    "message": "Connection successful"
  }
}
```

- `POST /api/v1/integration/integrations/{id}/sync/` - Sync content with integrated platform

**Request:**
```json
{
  "content_ids": [123, 456],
  "sync_type": "full"  // or "incremental"
}
```

- `GET /api/v1/integration/integrations/{id}/sync_health/` - Get sync health status

**Response:**
```json
{
  "success": true,
  "data": {
    "last_sync": "2025-01-XXT...",
    "sync_status": "healthy",
    "pending_items": 0,
    "failed_items": 0
  }
}
```

**Filtering:**
- `platform_type` - Filter by platform (wordpress, shopify, etc.)
- `status` - Filter by integration status
- `site_id` - Filter by site
- `sector_id` - Filter by sector

### Billing Module Endpoints

**Base Path**: `/api/v1/billing/`

#### Credit Balance

**Base Path**: `/api/v1/billing/credits/balance/`  
**Permission**: IsAuthenticatedAndActive + HasTenantAccess

- `GET /api/v1/billing/credits/balance/balance/` - Get credit balance

**Response:**
```json
{
  "success": true,
  "data": {
    "credits": 1000,
    "plan_credits_per_month": 500,
    "credits_used_this_month": 250,
    "credits_remaining": 750
  }
}
```

#### Credit Usage

**Base Path**: `/api/v1/billing/credits/usage/`  
**Permission**: IsAuthenticatedAndActive + HasTenantAccess

**Standard CRUD:**
- `GET /api/v1/billing/credits/usage/` - List usage logs (paginated)
- `GET /api/v1/billing/credits/usage/{id}/` - Get usage log

**Filtering:**
- `operation_type` - Filter by operation type
- `start_date` - Filter by start date (YYYY-MM-DD)
- `end_date` - Filter by end date (YYYY-MM-DD)

**Custom Actions:**
- `GET /api/v1/billing/credits/usage/summary/` - Get usage summary
- `GET /api/v1/billing/credits/usage/limits/` - Get usage limits

#### Credit Transactions

**Base Path**: `/api/v1/billing/credits/transactions/`  
**Permission**: IsAdminOrOwner

**Standard CRUD:**
- `GET /api/v1/billing/credits/transactions/` - List transactions (paginated)
- `GET /api/v1/billing/credits/transactions/{id}/` - Get transaction

**Filtering:**
- `transaction_type` - Filter by type
- `start_date` - Filter by start date
- `end_date` - Filter by end date

---

## Integration Examples

### Python

```python
import requests

BASE_URL = "https://api.igny8.com/api/v1"

# Login
response = requests.post(
    f"{BASE_URL}/auth/login/",
    json={"email": "user@example.com", "password": "password"}
)
data = response.json()

if data['success']:
    token = data['data']['access']
    
    # Use token for authenticated requests
    headers = {
        'Authorization': f'Bearer {token}',
        'Content-Type': 'application/json'
    }
    
    # Get keywords
    response = requests.get(
        f"{BASE_URL}/planner/keywords/?page=1&page_size=25",
        headers=headers
    )
    result = response.json()
    
    if result['success']:
        keywords = result['results']
        print(f"Found {result['count']} keywords")
    else:
        print(f"Error: {result['error']}")
```

### JavaScript

```javascript
const BASE_URL = 'https://api.igny8.com/api/v1';

// Login
const loginResponse = await fetch(`${BASE_URL}/auth/login/`, {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
        email: 'user@example.com',
        password: 'password'
    })
});

const loginData = await loginResponse.json();

if (loginData.success) {
    const token = loginData.data.access;
    
    // Use token for authenticated requests
    const headers = {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
    };
    
    // Get keywords
    const keywordsResponse = await fetch(
        `${BASE_URL}/planner/keywords/?page=1&page_size=25`,
        { headers }
    );
    
    const keywordsData = await keywordsResponse.json();
    
    if (keywordsData.success) {
        const keywords = keywordsData.results;
        console.log(`Found ${keywordsData.count} keywords`);
    } else {
        console.error('Error:', keywordsData.error);
    }
}
```

### cURL

```bash
# Login
curl -X POST https://api.igny8.com/api/v1/auth/login/ \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com","password":"password"}'

# Get keywords (with token)
curl -X GET https://api.igny8.com/api/v1/planner/keywords/ \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json"
```

### Frontend Integration (TypeScript)

```typescript
// Using fetchAPI wrapper (automatically extracts data from unified format)
import { fetchAPI } from './services/api';

// List keywords
const response = await fetchAPI('/v1/planner/keywords/?page=1&page_size=25');
// response is already extracted: { count, next, previous, results }

// Create keyword
const newKeyword = await fetchAPI('/v1/planner/keywords/', {
  method: 'POST',
  body: JSON.stringify({
    keyword: 'example keyword',
    site_id: 1,
    sector_id: 2,
    status: 'active'
  })
});

// Error handling
try {
  const data = await fetchAPI('/v1/planner/keywords/');
} catch (error) {
  // Error is already parsed from unified format
  console.error(error.message);
  if (error.errors) {
    // Handle field-specific errors
    Object.keys(error.errors).forEach(field => {
      console.error(`${field}: ${error.errors[field].join(', ')}`);
    });
  }
}
```

### WordPress Plugin Integration (PHP)

```php
class Igny8API {
    private $base_url = 'https://api.igny8.com/api/v1';
    private $token;
    
    public function login($email, $password) {
        $response = wp_remote_post($this->base_url . '/auth/login/', [
            'headers' => ['Content-Type' => 'application/json'],
            'body' => json_encode(['email' => $email, 'password' => $password])
        ]);
        
        $data = json_decode(wp_remote_retrieve_body($response), true);
        
        if ($data['success']) {
            $this->token = $data['data']['access'];
            return true;
        }
        
        return false;
    }
    
    public function getKeywords($page = 1, $page_size = 25) {
        $response = wp_remote_get(
            $this->base_url . '/planner/keywords/?page=' . $page . '&page_size=' . $page_size,
            [
                'headers' => [
                    'Authorization' => 'Bearer ' . $this->token,
                    'Content-Type' => 'application/json'
                ]
            ]
        );
        
        $data = json_decode(wp_remote_retrieve_body($response), true);
        
        if ($data['success']) {
            return $data['results'];
        }
        
        return [];
    }
}
```

---

## Testing & Debugging

### Request ID Tracking

Every API request includes a unique `request_id` in the response. Use this ID for:
- Debugging issues
- Log correlation
- Support requests

The `request_id` is included in:
- All success responses
- All error responses
- Response headers (`X-Request-ID`)

### Progress Tracking (AI Functions)

All AI functions return a Celery task ID for progress tracking:

**Request:**
```json
POST /api/v1/planner/keywords/auto_cluster/
{
  "ids": [1, 2, 3, 4, 5],
  "sector_id": 1
}
```

**Response:**
```json
{
  "success": true,
  "data": {
    "task_id": "abc123-def456-ghi789"
  }
}
```

**Poll Progress:**
```json
GET /api/v1/system/settings/task_progress/abc123-def456-ghi789/
```

**Progress Response:**
```json
{
  "state": "PROGRESS",
  "meta": {
    "phase": "AI_CALL",
    "percentage": 50,
    "message": "Processing keywords...",
    "request_steps": [...],
    "response_steps": [...],
    "cost": 0.05,
    "tokens": 1500
  }
}
```

### Error Handling Best Practices

**401 Unauthorized**: Trigger logout → redirect to login  
**403 Forbidden**: Show permission alert  
**429 Too Many Requests**: Show rate limit warning with retry time  
**4xx/5xx**: Display error message from `error` field

### Rate Limit Monitoring

```typescript
const throttleLimit = response.headers.get('X-Throttle-Limit');
const throttleRemaining = response.headers.get('X-Throttle-Remaining');

if (parseInt(throttleRemaining) < 5) {
  showNotification('Approaching rate limit', 'warning');
}
```

---

## Change Management

### Versioning Strategy

- **v1** remains stable long-term
- Breaking changes require **v2**
- Deprecations allowed only with explicit timeline
- Non-breaking changes can be added to v1

### Breaking Changes

**Definition:** Changes that require client code updates

**Examples:**
- Removing an endpoint
- Changing response structure
- Changing authentication method
- Removing a field from response

**Process:**
1. Document breaking change
2. Provide migration guide
3. Deprecate in v1 with timeline
4. Implement in v2
5. Maintain v1 for deprecation period

### Non-Breaking Changes

**Definition:** Changes that don't require client code updates

**Examples:**
- Adding new endpoints
- Adding optional fields to response
- Adding new query parameters
- Performance improvements

### Changelog

All API changes are documented in `CHANGELOG.md` with:
- Version number
- Date
- Type (Added, Changed, Fixed, Deprecated, Removed, Security)
- Description
- Affected areas
- Migration notes (if applicable)

---

## Summary

### Implementation Status

✅ **100% Complete** - All endpoints implemented with:
- Unified response format (`{success, data, message, errors, request_id}`)
- Proper authentication and authorization (JWT Bearer tokens)
- Rate limiting configured (scoped by operation type)
- Error handling standardized (centralized exception handler)
- Request ID tracking (every request has unique ID)
- Complete Swagger/OpenAPI documentation
- Tenant/site/sector scoping (automatic filtering)
- Pagination standardized (default: 10, max: 100)

### Key Features

- **100+ endpoints** across 5 modules
- **Unified response format** for all endpoints
- **Scoped rate limiting** (10-100 requests/minute depending on operation)
- **Layered authorization** (Authentication → Tenant → Role → Site/Sector)
- **Complete OpenAPI documentation** (Swagger UI, ReDoc)
- **Request ID tracking** for debugging
- **Progress tracking** for AI functions
- **Comprehensive error handling** with clear messages

### Access Points

- **Interactive Documentation**: `https://api.igny8.com/api/docs/`
- **ReDoc**: `https://api.igny8.com/api/redoc/`
- **OpenAPI Schema**: `https://api.igny8.com/api/schema/`

---

**Last Updated**: 2025-01-XX (Added 6 missing modules: Linker, Optimizer, Publisher, Site Builder, Automation, Integration)  
**API Version**: 1.0.0  
**Status**: ✅ **100% IMPLEMENTED** - All 10 modules documented with complete endpoint reference

