- Introduced RefreshTokenView to allow users to refresh their access tokens using a valid refresh token. - Enhanced LoginView to ensure correct user/account loading and improved error handling during user serialization. - Updated API response structure to include access and refresh token expiration times. - Adjusted frontend API handling to support both new and legacy token response formats.
37 KiB
IGNY8 API Complete Reference v1.0
Base URL: https://api.igny8.com/api/v1/
Version: 1.0.0
Last Updated: 2025-01-XX
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
- Quick Start
- Overview & Architecture
- Authentication & Authorization
- Response Format Standard
- Error Handling
- Rate Limiting
- Pagination
- Roles & Permissions
- Tenant / Site / Sector Scoping
- Complete Endpoint Reference
- Integration Examples
- Testing & Debugging
- 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
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
- Unified Response Format: All endpoints return consistent JSON structure
- Layered Authorization: Authentication → Tenant Access → Role → Site/Sector
- Centralized Error Handling: All errors wrapped in unified format
- Scoped Rate Limiting: Different limits for different operation types
- Tenant Isolation: All resources scoped by account/site/sector
- 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
├── 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_idandaccount_id - Type:
access(15-minute expiry) - Automatically sets
request.accountvia middleware - Resolves account → tenant context automatically
Token Payload:
{
"user_id": 1,
"account_id": 1,
"type": "access",
"exp": 1234567890
}
Fallback Methods
-
Session Authentication (admin panel)
- Class:
CSRFExemptSessionAuthentication - Use case: Django admin panel (
/admin/)
- Class:
-
Basic Authentication (debug/testing)
- Class:
rest_framework.authentication.BasicAuthentication - Use case: API testing tools (Postman, curl)
- Class:
Authentication Order
- JWT Token Authentication (tried first)
- Session Authentication (fallback)
- Basic Authentication (last fallback)
- If all fail: 401 Unauthorized
Getting an Access Token
Login Endpoint:
POST /api/v1/auth/login/
Content-Type: application/json
{
"email": "user@example.com",
"password": "your_password"
}
Response:
{
"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:
POST /api/v1/auth/refresh/
Content-Type: application/json
{
"refresh": "your_refresh_token"
}
Public Endpoints (No Authentication Required)
POST /api/v1/auth/register/- User registrationPOST /api/v1/auth/login/- User loginGET /api/v1/auth/plans/- List plansGET /api/v1/auth/industries/- List industriesGET /api/v1/system/status/- System health checkGET /api/v1/system/ping/- Health check endpoint
All other endpoints require JWT authentication.
Authorization Layers
Every endpoint enforces layered authorization:
- User Authentication: User must be authenticated
- Tenant Access: User must belong to the tenant/account
- Role Authorization: User must have appropriate role
- 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
{
"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
{
"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
{
"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
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_idfor error tracking - Logs full exception details
- In DEBUG mode: includes traceback + request context
Error Response Examples
Validation Error (400):
{
"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):
{
"success": false,
"error": "Authentication required",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
Permission Error (403):
{
"success": false,
"error": "Permission denied",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
Rate Limit (429):
{
"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 allowedX-Throttle-Remaining: Remaining requests in current windowX-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-Resetbefore retrying
Example:
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
{
"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 itemsnext: 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:
- Account/Tenant - User's account
- Site - Specific site within account
- Sector - Specific sector within site
Enforcement
Base Classes:
AccountModelViewSet- Handles account isolationSiteSectorModelViewSet- 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
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:
{
"email": "user@example.com",
"password": "password123",
"password_confirm": "password123"
}
Response:
{
"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:
{
"email": "user@example.com",
"password": "password123"
}
Response:
{
"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:
{
"refresh": "your_refresh_token"
}
POST /api/v1/auth/change-password/
Purpose: Change user password
Authentication: Required (IsAuthenticated)
Request:
{
"old_password": "oldpass123",
"new_password": "newpass123",
"new_password_confirm": "newpass123"
}
GET /api/v1/auth/me/
Purpose: Get current user information
Authentication: Required (IsAuthenticated)
Response:
{
"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 usersPOST /api/v1/auth/users/- Create userGET /api/v1/auth/users/{id}/- Get userPUT /api/v1/auth/users/{id}/- Update userDELETE /api/v1/auth/users/{id}/- Delete user
Custom Actions:
POST /api/v1/auth/users/invite/- Invite userPOST /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 accountsPOST /api/v1/auth/accounts/- Create accountGET /api/v1/auth/accounts/{id}/- Get accountPUT /api/v1/auth/accounts/{id}/- Update accountDELETE /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 sitesPOST /api/v1/auth/sites/- Create siteGET /api/v1/auth/sites/{id}/- Get sitePUT /api/v1/auth/sites/{id}/- Update siteDELETE /api/v1/auth/sites/{id}/- Delete site
Custom Actions:
GET /api/v1/auth/sites/{id}/sectors/- Get site sectorsPOST /api/v1/auth/sites/{id}/set_active/- Set active sitePOST /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 sectorsPOST /api/v1/auth/sectors/- Create sectorGET /api/v1/auth/sectors/{id}/- Get sectorPUT /api/v1/auth/sectors/{id}/- Update sectorDELETE /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 keywordGET /api/v1/planner/keywords/{id}/- Get keywordPUT /api/v1/planner/keywords/{id}/- Update keywordDELETE /api/v1/planner/keywords/{id}/- Delete keyword
Filtering:
status- Filter by statuscluster_id- Filter by clusterseed_keyword__intent- Filter by intentseed_keyword_id- Filter by seed keyword IDdifficulty_min,difficulty_max- Difficulty rangevolume_min,volume_max- Volume rangesite_id- Filter by site (query param)sector_id- Filter by sector (query param)
Search:
search- Search by keyword text
Ordering:
ordering- Order bycreated_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] }
- Request:
POST /api/v1/planner/keywords/bulk_update_status/- Bulk update status- Request:
{ "ids": [1, 2, 3], "status": "active" }
- Request:
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 }
- Request:
GET /api/v1/planner/keywords/export/- Export keywords to CSVPOST /api/v1/planner/keywords/import_keywords/- Import keywords from CSVPOST /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
- Request:
Cluster Management
Base Path: /api/v1/planner/clusters/
Permission: IsAuthenticatedAndActive + HasTenantAccess
Inherits: SiteSectorModelViewSet
Standard CRUD:
GET /api/v1/planner/clusters/- List clustersPOST /api/v1/planner/clusters/- Create clusterGET /api/v1/planner/clusters/{id}/- Get clusterPUT /api/v1/planner/clusters/{id}/- Update clusterDELETE /api/v1/planner/clusters/{id}/- Delete cluster
Filtering:
status- Filter by statussite_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 clustersPOST /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
- Request:
Content Ideas Management
Base Path: /api/v1/planner/ideas/
Permission: IsAuthenticatedAndActive + HasTenantAccess
Inherits: SiteSectorModelViewSet
Standard CRUD:
GET /api/v1/planner/ideas/- List content ideasPOST /api/v1/planner/ideas/- Create content ideaGET /api/v1/planner/ideas/{id}/- Get content ideaPUT /api/v1/planner/ideas/{id}/- Update content ideaDELETE /api/v1/planner/ideas/{id}/- Delete content idea
Filtering:
status- Filter by statuscluster_id- Filter by clustercontent_type- Filter by content typesite_id- Filter by site (query param)sector_id- Filter by sector (query param)
Custom Actions:
POST /api/v1/planner/ideas/bulk_delete/- Bulk delete ideasPOST /api/v1/planner/ideas/bulk_queue_to_writer/- Queue ideas to writer (create tasks)- Request:
{ "ids": [1, 2, 3] }
- Request:
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 tasksPOST /api/v1/writer/tasks/- Create taskGET /api/v1/writer/tasks/{id}/- Get taskPUT /api/v1/writer/tasks/{id}/- Update taskDELETE /api/v1/writer/tasks/{id}/- Delete task
Filtering:
status- Filter by status (draft, in_progress, review, completed, archived)cluster_id- Filter by clustercontent_type- Filter by content typecontent_structure- Filter by content structuresite_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 tasksPOST /api/v1/writer/tasks/bulk_update/- Bulk update task statusPOST /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
- Request:
Content Management
Base Path: /api/v1/writer/content/
Permission: IsAuthenticatedAndActive + HasTenantAccess
Inherits: SiteSectorModelViewSet
Standard CRUD:
GET /api/v1/writer/content/- List contentPOST /api/v1/writer/content/- Create contentGET /api/v1/writer/content/{id}/- Get contentPUT /api/v1/writer/content/{id}/- Update contentDELETE /api/v1/writer/content/{id}/- Delete content
Filtering:
status- Filter by statuscontent_type- Filter by content typesite_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
- Request:
Image Management
Base Path: /api/v1/writer/images/
Permission: IsAuthenticatedAndActive + HasTenantAccess
Inherits: SiteSectorModelViewSet
Standard CRUD:
GET /api/v1/writer/images/- List imagesPOST /api/v1/writer/images/- Create imageGET /api/v1/writer/images/{id}/- Get imagePUT /api/v1/writer/images/{id}/- Update imageDELETE /api/v1/writer/images/{id}/- Delete image
Filtering:
image_type- Filter by type (featured, in_article, desktop, mobile)status- Filter by statuscontent_id- Filter by contenttask_id- Filter by tasksite_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 URLGET /api/v1/writer/images/content_images/- Get images for content- Query Params:
content_id(required)
- Query Params:
POST /api/v1/writer/images/generate_images/- Generate images using AI- Request:
{ "ids": [1, 2, 3, ...] } - Returns: Celery task ID for progress tracking
- Request:
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 promptsPOST /api/v1/system/prompts/- Create promptGET /api/v1/system/prompts/{id}/- Get promptPUT /api/v1/system/prompts/{id}/- Update promptDELETE /api/v1/system/prompts/{id}/- Delete prompt
Custom Actions:
GET /api/v1/system/prompts/by_type/{prompt_type}/- Get prompt by typePOST /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 settingsPOST /api/v1/system/settings/integrations/{pk}/save/- Save integration settingsPUT /api/v1/system/settings/integrations/{pk}/- Update integration settingsPOST /api/v1/system/settings/integrations/{pk}/test/- Test connection- Request:
{ "provider": "openai" }or{ "provider": "runware" }
- Request:
POST /api/v1/system/settings/integrations/{pk}/generate/- Test image generationGET /api/v1/system/settings/task_progress/{task_id}/- Get Celery task progressGET /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
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:
{
"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 typestart_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 summaryGET /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 typestart_date- Filter by start dateend_date- Filter by end date
Integration Examples
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
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
# 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)
// 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)
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:
POST /api/v1/planner/keywords/auto_cluster/
{
"ids": [1, 2, 3, 4, 5],
"sector_id": 1
}
Response:
{
"success": true,
"data": {
"task_id": "abc123-def456-ghi789"
}
}
Poll Progress:
GET /api/v1/system/settings/task_progress/abc123-def456-ghi789/
Progress Response:
{
"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
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:
- Document breaking change
- Provide migration guide
- Deprecate in v1 with timeline
- Implement in v2
- 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
API Version: 1.0.0
Status: ✅ 100% IMPLEMENTED