# Floyi API — Full LLM Reference > Floyi is a topic-first content strategy platform to build topical authority for SEO and AI search. > It replaces disconnected tools with a closed loop: Map → Brief → Draft → Authority Tracking. ## Authentication Every request must include an `X-API-Key` header. POST/PUT/PATCH requests also need `Content-Type: application/json`. ``` X-API-Key: fyi_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Content-Type: application/json ``` Base URL: `https://api.floyi.com/api/v1/` Keys are created in Settings > API Keys. Key format: `fyi_live_` + 32 hex chars (44 total). Keys are hashed server-side — lost keys cannot be recovered. ## Machine-Readable Schema - OpenAPI 3.0 YAML: GET /api/v1/schema/ - Swagger UI: /api/v1/docs/ - ReDoc: /api/v1/redoc/ --- ## 1. User Profile & Credits ### GET /api/v1/me/profile/ **Scope:** user:read Returns the authenticated user's profile. Response: ```json { "uuid": "abc-123", "email": "user@example.com", "first_name": "Jane", "last_name": "Doe", "subscription_plan": "pro", "subscription_interval": "monthly", "account_status": "active", "date_joined": "2025-01-15T...", "last_active": "2026-02-24T..." } ``` ### GET /api/v1/me/credits/ **Scope:** user:read Returns the user's credit balance breakdown. Response: ```json { "free_credits": 0, "monthly_credits": 500, "payg_credits": 100, "total_credits": 600, "monthly_credits_last_reset": "2026-02-01T...", "subscription_renewal_date": "2026-03-01T..." } ``` --- ## 2. Brands ### GET /api/v1/brands/ **Scope:** brands:read List all brands in your workspace. Query params: - `search` (string) — Filter by brand name (case-insensitive) Response: Array of brand objects. ### GET /api/v1/brands/{id}/ **Scope:** brands:read Get full brand details. Response: ```json { "id": "uuid", "brand_name": "Floyi", "website_url": "https://floyi.com", "mission": "...", "vision": "...", "tagline": "...", "target_audience": "...", "brand_voice": "...", "values": "...", "marketplace": "...", "market_position": "...", "key_competitors": "...", "unique_selling_proposition": "...", "brand_personality": "...", "brand_story": "...", "language": "en", "country_code": "US", "country_name": "United States", "stage": "...", "content_scope": "...", "created_at": "2025-...", "updated_at": "2026-..." } ``` ### POST /api/v1/brands/ **Scope:** brands:write Create a new brand. Request body: ```json { "brand_name": "My Brand", "website_url": "https://example.com", "description": "A brief description", "language": "en" } ``` Optional fields: mission, vision, tagline, target_audience, brand_voice, values, marketplace, key_competitors, unique_selling_proposition. --- ## 3. Topical Maps ### GET /api/v1/maps/ **Scope:** maps:read List all topical maps. Query params: - `brand_id` (uuid) — Filter by brand Response: Array of map summary objects with brand_id, brand_name, is_uploaded, timestamps. ### GET /api/v1/maps/{brand_id}/ **Scope:** maps:read Get the full raw topical map with keyword clusters. Response: ```json { "brand_id": "uuid", "brand_name": "Floyi", "is_uploaded": false, "cluster_count": 150, "clusters": [ { "id": "cluster-uuid", "centroid": "best seo tools", "keyword_count": 12, "keywords": [ { "keyword": "best seo tools 2026", "main_topic": "SEO Tools", "subtopic_2": "Reviews", "subtopic_3": "", "subtopic_4": "", "search_volume": 2400, "cpc": 3.50, "competition": 0.8, "url_slug": "/best-seo-tools", "search_intent": "commercial", "content_type": "listicle", "has_serp_data": true } ] } ] } ``` --- ## 4. Content Briefs ### GET /api/v1/briefs/ **Scope:** briefs:read List content briefs. Query params: - `brand_id` (uuid) — Filter by brand - `status` (string) — Filter by status: PENDING, IN_PROGRESS, COMPLETE, PARTIAL_COMPLETE, ERROR - `search` (string) — Search by query_text or generated_title ### GET /api/v1/briefs/{id}/ **Scope:** briefs:read Get full brief with result_json and curated_brief_json. ### GET /api/v1/briefs/{id}/status/ **Scope:** briefs:read Poll brief generation status. Response: ```json { "id": "uuid", "status": "COMPLETE", "query_text": "best seo tools for agencies", "generated_title": "Best SEO Tools for Agencies in 2026" } ``` ### POST /api/v1/briefs/generate/ **Scope:** briefs:write Trigger content brief generation. Costs credits. Request body: ```json { "query_text": "best seo tools for agencies", "brand_id": "uuid", "selected_serp_data": [ {"url": "https://...", "title": "...", "snippet": "..."} ], "user_provided_keywords": ["keyword1", "keyword2"], "ai_model_id": "claude-sonnet-4" } ``` - `selected_serp_data` is optional — auto-fetched from stored SERP data if omitted - `ai_model_id` is optional — uses default if not specified - Returns 202 with brief ID. Poll `/api/v1/briefs/{id}/status/` for progress. --- ## 5. Content Articles ### GET /api/v1/content/articles/ **Scope:** content:read List articles. Query params: - `brand_id` (uuid) - `search` (string) ### GET /api/v1/content/articles/{id}/ **Scope:** content:read Get article details. ### GET /api/v1/content/articles/{id}/status/ **Scope:** content:read Get article generation progress. Response: ```json { "id": "uuid", "machine_state": "draft_done", "sections_total": 8, "sections_approved": 6, "sections_drafting": 2, "sections_not_started": 0, "sections_needs_attention": 0, "completion_percentage": 75.0, "specialists_running": false, "specialists_complete": true } ``` ### POST /api/v1/content/articles/create-from-brief/ **Scope:** content:write Create a new article from a completed brief. Request body: ```json { "brief_id": "uuid" } ``` ### POST /api/v1/content/articles/{id}/generate/ **Scope:** content:write Trigger draft generation. Costs credits. Request body: ```json { "ai_model_id": "claude-sonnet-4", "intent": "human", "specialists": { "web_research": false, "fact_check": false, "conversion_coach": false, "intro_key_takeaways": false, "web_research_mode": "basic" } } ``` Returns 202. Poll `/api/v1/content/articles/{id}/status/` for progress. --- ## 6. Topical Authority ### GET /api/v1/authority/ **Scope:** authority:read List authority maps (one per brand). Query params: - `brand_id` (uuid) ### GET /api/v1/authority/{brand_id}/ **Scope:** authority:read Get the enriched authority hierarchy with coverage, SERP rankings, and AI presence. Response includes for each node: ```json { "node_id": "uuid", "name": "best seo tools", "type": "PAGE", "mt": "SEO Tools", "st2": "Reviews", "keywords": ["best seo tools 2026", "top seo software"], "published": true, "importance": 78.5, "priority_category": "High", "serp_position": 3, "serp_all_positions": [3, 7, 12], "aio_status": "mentioned_cited", "aimode_status": "N/A", "chatgpt_status": "cited" } ``` AI presence statuses: `mentioned_cited`, `cited`, `mentioned`, `not_present`, `N/A` ### GET /api/v1/authority/{brand_id}/serp-data/{node_id}/ **Scope:** authority:read Get stored SERP results for a specific node. ### PATCH /api/v1/authority/{brand_id}/nodes/{node_id}/published/ **Scope:** authority:write Toggle published status. Request body: ```json {"published": true} ``` --- ## 7. Topical Research ### GET /api/v1/research/ **Scope:** research:read List research records. ### GET /api/v1/research/{brand_id}/ **Scope:** research:read Get the full 4-level topic tree (Main Topic > Subtopic 2 > Subtopic 3 > Subtopic 4 > Keywords). ### GET /api/v1/research/{brand_id}/stats/ **Scope:** research:read Get tree statistics only (node counts by level, keyword totals). ### GET /api/v1/research/{brand_id}/task-status/ **Scope:** research:read Poll AI generation task status. ### PATCH /api/v1/research/{brand_id}/nodes/rename/ **Scope:** research:write Rename a node. Request: ```json { "path": ["Main Topic", "Subtopic 2", "Node Name"], "new_name": "New Node Name" } ``` ### POST /api/v1/research/{brand_id}/nodes/add/ **Scope:** research:write Add a new node. Request: ```json { "parent_path": ["Main Topic", "Subtopic 2"], "name": "New Node", "position": 0 } ``` ### POST /api/v1/research/{brand_id}/nodes/delete/ **Scope:** research:write Delete a node. Request: ```json { "path": ["Main Topic", "Subtopic 2", "Node to Delete"] } ``` ### PATCH /api/v1/research/{brand_id}/nodes/keywords/ **Scope:** research:write Add or remove keywords from a node. Request: ```json { "path": ["Main Topic", "Subtopic 2", "Node"], "add": ["new keyword 1", "new keyword 2"], "remove": ["old keyword"] } ``` ### POST /api/v1/research/{brand_id}/nodes/move/ **Scope:** research:write Move a node to a new parent. Request: ```json { "source_path": ["Main Topic", "Old Parent", "Node"], "target_parent_path": ["Main Topic", "New Parent"], "position": 0 } ``` ### POST /api/v1/research/{brand_id}/nodes/merge/ **Scope:** research:write Merge one node into another. Request: ```json { "keep_path": ["Main Topic", "Node to Keep"], "merge_path": ["Main Topic", "Node to Merge Into Keep"] } ``` ### POST /api/v1/research/{brand_id}/nodes/bulk/ **Scope:** research:write Execute multiple operations atomically. Request: ```json { "operations": [ {"op": "rename", "path": ["MT", "ST2", "Old"], "new_name": "New"}, {"op": "add", "parent_path": ["MT", "ST2"], "name": "Added Node"}, {"op": "delete", "path": ["MT", "Unwanted"]} ] } ``` ### POST /api/v1/research/{brand_id}/analyze/dedup/ **Scope:** research:write Run semantic deduplication analysis. Request: ```json {"threshold": 0.92} ``` ### POST /api/v1/research/{brand_id}/diff/ **Scope:** research:read Compare two tree states. Request: ```json { "before": [{"name": "MT", "children": [...]}], "after": [{"name": "MT", "children": [...]}] } ``` --- ## 8. Analytics (Admin Only) ### GET /api/v1/analytics/signups/ **Scope:** admin:read Daily signup counts. Query params: - `days` (int, default 30, max 365) - `period` ("today", "week", "month" — overrides days) ### GET /api/v1/analytics/active-users/ **Scope:** admin:read Active user counts (DAU/WAU/MAU). ### GET /api/v1/analytics/subscriptions/ **Scope:** admin:read Subscription plan breakdown. ### GET /api/v1/analytics/credits/ **Scope:** admin:read Aggregate credit usage stats. --- ## Permission Scopes | Scope | Access | |-------|--------| | user:read | Profile and credit balance | | brands:read | List and read brands | | brands:write | Create brands | | briefs:read | List and read content briefs | | briefs:write | Generate content briefs (costs credits) | | content:read | List and read articles | | content:write | Create articles, generate drafts (costs credits) | | maps:read | List and read raw topical maps | | authority:read | Read authority hierarchy, SERP data, AI presence | | authority:write | Toggle published status on nodes | | research:read | Read research trees, stats, task status, diffs | | research:write | Node CRUD, keyword management, merge, bulk ops, dedup | | admin:read | Admin analytics (requires staff user and Admin key type) | ## Rate Limits | Key Type | Requests/Min | |----------|-------------| | Developer | 60 | | Integration | 120 | | Admin | 300 | Exceeding returns 429 with `Retry-After` header. ## Error Codes | Code | Meaning | |------|---------| | 400 | Bad request — invalid input or missing required fields | | 401 | Unauthorized — invalid, expired, or revoked API key | | 402 | Payment required — insufficient credits | | 403 | Forbidden — valid key but missing required scope | | 404 | Not found — resource doesn't exist or not accessible | | 409 | Conflict — generation already in progress or duplicate name | | 413 | Payload too large (research diff: 2MB limit) | | 429 | Rate limit exceeded | | 500 | Server error | ## Common Workflows ### Generate a content brief 1. GET /api/v1/brands/ → pick a brand_id 2. POST /api/v1/briefs/generate/ with query_text and brand_id 3. Poll GET /api/v1/briefs/{id}/status/ until status is COMPLETE 4. GET /api/v1/briefs/{id}/ to read the full brief ### Generate an article from a brief 1. POST /api/v1/content/articles/create-from-brief/ with brief_id 2. POST /api/v1/content/articles/{id}/generate/ with ai_model_id 3. Poll GET /api/v1/content/articles/{id}/status/ until machine_state is draft_done ### Review topical authority 1. GET /api/v1/authority/{brand_id}/ for the full hierarchy with rankings 2. GET /api/v1/authority/{brand_id}/serp-data/{node_id}/ for SERP details 3. PATCH /api/v1/authority/{brand_id}/nodes/{node_id}/published/ to mark content as published ### Refine research tree 1. GET /api/v1/research/{brand_id}/ to see current tree 2. Use nodes/rename, nodes/add, nodes/delete, nodes/move, nodes/merge, nodes/keywords to refine 3. POST /api/v1/research/{brand_id}/analyze/dedup/ to find semantic duplicates 4. POST /api/v1/research/{brand_id}/nodes/bulk/ for batch operations