# Floyi LLM Full Reference
Site: https://floyi.com
Generated: 2026-08-13T19:22:39.352Z
## Documentation
Source: https://floyi.com/docs/
Floyi documentation overview:
- Getting started: account creation, sign in/out and core navigation.
- Tools: Brand Foundation, Audience Insights, Topical Research, SERP Clustering, Topical Map, Topical Authority Scorecard, Topical Authority Planner, Briefs & Drafts, and Content Creation.
- Billing: subscriptions, credits, purchases and billing history.
---
## API Reference
Source: https://floyi.com/docs/api/reference/
:::caution[Beta]
The Floyi Public API is currently in **beta** and available on the **Scale plan**. Endpoints, scopes, and rate limits may change before general availability.
:::
Floyi's External API lets you access your data programmatically through a versioned REST API. Use it to connect AI agents, automate workflows with Zapier or Make, or build custom dashboards on top of your Floyi workspace. If you want an AI assistant to drive Floyi conversationally rather than through code, use the [Floyi MCP server](/docs/mcp/overview/) instead.
_Last updated: 2026-08-11_
## What You'll Learn
- How to create and manage API keys
- How to authenticate API requests
- All available V1 endpoints with examples
- Permission scopes, rate limits, and error handling
---
## Terminology & Hierarchy Levels
Floyi uses a 4-level topical hierarchy. The **API field names** (used in JSON responses) differ from the **display labels** shown in the Floyi dashboard. Every API response includes a `_meta` object with the mapping, but here is the complete reference:
| Level | API Field Name | Display Label | Description |
| --- | --- | --- | --- |
| 0 | `main_topic` | **Pillar** | Top-level topic category (e.g., "Email Marketing") |
| 1 | `subtopic_2` | **Hub** | Major subtopic grouping (e.g., "Email Automation") |
| 2 | `subtopic_3` | **Branch** | Specific topic area (e.g., "Drip Campaigns") |
| 3 | `subtopic_4` | **Resource** | Individual content asset -- can be an article, video, tool, calculator, or any content format (e.g., "Welcome Sequence Templates") |
**Node types** in the authority hierarchy also use internal labels that map to the same display names:
| Internal Type | Display Label |
| --- | --- |
| `PILLAR` | Pillar |
| `HUB` | Hub |
| `BRANCH` | Branch |
| `RESOURCE` | Resource |
:::note
Always use the display labels (Pillar, Hub, Branch, Resource) when presenting hierarchy data to users. The API field names (`main_topic`, `subtopic_2`, etc.) are internal identifiers that should not be shown in user-facing interfaces.
:::
### Understanding `_meta` in Responses
Every V1 API response includes a `_meta` object with:
- **`description`** - What this endpoint returns and how to interpret the data
- **`level_labels`** - Mapping from API field names to display labels (included on hierarchy endpoints)
- **`node_type_labels`** - Mapping from internal node types to display labels (included on authority endpoints)
Example:
```json
{
"_meta": {
"description": "Returns the full 4-level topical hierarchy...",
"level_labels": {
"main_topic": "Pillar",
"subtopic_2": "Hub",
"subtopic_3": "Branch",
"subtopic_4": "Resource"
}
},
"brand_id": "...",
"research_data": [...]
}
```
### Topical Research vs. Topical Maps vs. Authority
| Module | API Endpoint | Contains | Search Metrics? |
| --- | --- | --- | --- |
| **Topical Research** | `/api/v1/research/` | Topic hierarchy (taxonomy) with keyword annotations | No -- purely structural |
| **Topical Maps** | `/api/v1/maps/` | Raw keyword clusters with search volume, CPC, competition, SERP data | Yes |
| **Topical Authority** | `/api/v1/authority/` | Enriched hierarchy with coverage, SERP rankings, AI search presence | Yes |
### Standalone vs. Authority Content Workflows
Floyi's API supports two content generation workflows:
| Workflow | Brief Endpoint | Article Endpoint | Use Case |
| --- | --- | --- | --- |
| **Standalone** | `/api/v1/briefs/` | `/api/v1/content/articles/` | One-off briefs for any topic (`query_text`). Not linked to the authority hierarchy. |
| **Authority** | `/api/v1/authority/{brand_id}/briefs/` | `/api/v1/authority/{brand_id}/articles/` | Hierarchy-linked briefs by `node_id`. Tied to your topical map for the Planner tab. |
:::tip
**Which should I use?** If you have a topical map and want briefs/articles tracked in the Planner tab, use the **Authority** endpoints. If you want to generate a quick brief for any topic without hierarchy linkage, use the **Standalone** endpoints.
:::
---
## Machine-Readable Documentation
Floyi provides machine-readable API documentation for developer tools, AI coding assistants, and automation platforms.
| Resource | URL | Description |
| --- | --- | --- |
| **Interactive Docs (Swagger UI)** | [api.floyi.com/api/v1/docs/](https://api.floyi.com/api/v1/docs/) | Browse and test endpoints in your browser |
| **Alternative Viewer (ReDoc)** | [api.floyi.com/api/v1/redoc/](https://api.floyi.com/api/v1/redoc/) | Clean, readable API reference |
| **OpenAPI 3.0 Schema (YAML)** | [api.floyi.com/api/v1/schema/](https://api.floyi.com/api/v1/schema/) | Import into Postman, Insomnia, or any API client |
| **LLM Reference** | [api.floyi.com/llms-full.txt](https://api.floyi.com/llms-full.txt) | Full API reference optimized for AI coding assistants |
| **LLM Summary** | [api.floyi.com/llms.txt](https://api.floyi.com/llms.txt) | Compact endpoint listing for AI agents |
The OpenAPI schema can be imported directly into tools like Postman or Insomnia to auto-generate request templates. AI coding assistants (Claude, ChatGPT, Cursor, etc.) can read the `llms-full.txt` file to understand the full API without needing authentication.
---
## Part 1: Getting Started
### Requirements
| Requirement | Details |
| --- | --- |
| **Floyi Plan** | Scale |
| **API Key** | Created in Settings > API Keys |
| **Authentication** | `X-API-Key` header on every request |
| **Workspace** | `X-Team-ID` header (optional - omit for personal workspace) |
| **Base URL** | `https://api.floyi.com/api/v1/` |
:::note
The External API is currently in **beta**. API key creation requires a **Scale plan** - if you are on the Free, Creator, or Pro plan, the API Keys tab in Settings will prompt you to upgrade.
:::
### Creating Your First API Key
1. Go to **Settings > API Keys**.
2. Click **Create API Key**.
3. Enter a **name** for the key (e.g., "My AI Agent" or "Zapier Integration").
4. Choose a **key type** (see Key Types below).
5. Review and customize **permissions** if needed.
6. Click **Create**.
7. **Copy the API key immediately.** It is shown only once and cannot be retrieved later.
The same key also authenticates the [MCP server](/docs/mcp/overview/) - you never need separate keys for the REST API and an MCP connection.
:::caution
Store your API key securely. Treat it like a password. Never commit it to version control, share it in chat, or expose it in client-side code.
:::
### Key Types
| Type | Description | Rate Limit | Default Permissions |
| --- | --- | --- | --- |
| **Integration** | For Zapier, Make, n8n, and workflow automation. Read and write access to core features. | 120 requests/min | Brands, briefs, content, maps (read + write) |
| **Developer** | For custom apps, dashboards, and external tools. Read-only access to your own data. | 60 requests/min | Brands, briefs, content, maps (read only) |
### Key Format
All Floyi API keys follow the format:
```
fyi_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```
The `fyi_live_` prefix identifies Floyi keys in logs and secret scanners. The full key is 41 characters.
---
## Part 2: Authentication
Every API request must include your key in the `X-API-Key` header.
For `POST`, `PUT`, and `PATCH` requests, you must also set the `Content-Type: application/json` header and send a JSON request body.
### Example Request
```bash
# GET request (read)
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/brands/
# POST request (write)
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"brand_name": "My Brand"}' \
https://api.floyi.com/api/v1/brands/
```
```python
API_KEY = "fyi_live_your_key_here"
BASE_URL = "https://api.floyi.com/api/v1"
headers = {"X-API-Key": API_KEY}
# GET request (read)
response = requests.get(f"{BASE_URL}/brands/", headers=headers)
brands = response.json()
# POST request (write)
response = requests.post(
f"{BASE_URL}/brands/",
headers=headers,
json={"brand_name": "My Brand"},
)
new_brand = response.json()
```
```javascript
const API_KEY = "fyi_live_your_key_here";
const BASE_URL = "https://api.floyi.com/api/v1";
const headers = { "X-API-Key": API_KEY };
// GET request (read)
const brandsRes = await fetch(`${BASE_URL}/brands/`, { headers });
const brands = await brandsRes.json();
// POST request (write)
const createRes = await fetch(`${BASE_URL}/brands/`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ brand_name: "My Brand" }),
});
const newBrand = await createRes.json();
```
:::tip
**Using a team workspace?** API keys are account-level - they default to your personal workspace. To access a team's data, add the `X-Team-ID` header with the team's UUID (e.g., `-H "X-Team-ID: a1b2c3d4-..."` in curl). Without it, you'll only see personal workspace data. See [Workspace Selection](#workspace-selection-x-team-id) below.
:::
### Authentication Errors
| Status | Meaning |
| --- | --- |
| `401 Unauthorized` | Missing, invalid, expired, or revoked API key |
| `403 Forbidden` | Valid key but missing the required permission scope |
| `429 Too Many Requests` | Rate limit exceeded. Wait and retry. |
A `401` response includes a description in the response body:
```json
{
"detail": "Invalid API key."
}
```
Possible messages: `"Invalid API key."`, `"API key has expired."`, `"API key has been revoked."`, `"User account is no longer active."`, `"Request from unauthorized IP address."`, `"The External API is currently in beta. Contact support to request access."`
A `403` response means the key is valid but lacks the required scope:
```json
{
"detail": "You do not have permission to perform this action."
}
```
Check your key's assigned scopes in **Settings > API Keys** and ensure they include the scope listed for the endpoint you are calling (e.g., `briefs:write` for brief generation).
### Workspace Selection (X-Team-ID)
API keys are **account-level** - they are not tied to a specific workspace. To control which workspace your request operates on, use the optional `X-Team-ID` header.
| X-Team-ID Header | Result |
| --- | --- |
| **Omitted** | Personal workspace (your own brands, briefs, etc.) |
| **Valid team UUID** | Team workspace (brands, briefs, etc. belonging to that team) |
| **Invalid UUID** | `403 Forbidden` |
| **UUID of a team you don't belong to** | `403 Forbidden` |
**Discovering your team UUIDs:**
Call the `/api/v1/me/teams/` endpoint to list all teams you are an active member of. Each team object includes the `id` (UUID) you need for the `X-Team-ID` header.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/me/teams/
```
```json
{
"_meta": { "description": "Lists all teams the authenticated user is an active member of..." },
"results": [
{
"team": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Acme Marketing",
"slug": "acme-marketing",
"plan_name": "Scale Plan",
"created_at": "2025-09-15T10:00:00Z"
},
"role": "owner",
"status": "active"
}
]
}
```
**Using the team UUID in requests:**
```bash
# Personal workspace (no header)
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/brands/
# Team workspace
curl -H "X-API-Key: fyi_live_your_key_here" \
-H "X-Team-ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
https://api.floyi.com/api/v1/brands/
```
```python
# Personal workspace (no header)
response = requests.get(f"{BASE_URL}/brands/", headers=headers)
# Team workspace
team_headers = {**headers, "X-Team-ID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}
response = requests.get(f"{BASE_URL}/brands/", headers=team_headers)
```
```javascript
// Personal workspace (no header)
const res = await fetch(`${BASE_URL}/brands/`, { headers });
// Team workspace
const teamHeaders = { ...headers, "X-Team-ID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" };
const teamRes = await fetch(`${BASE_URL}/brands/`, { headers: teamHeaders });
```
:::tip
You can use the same API key for both personal and team workspaces. The `X-Team-ID` header is the only thing that determines which workspace a request operates on. You can access any team where you are an active member.
:::
---
## Part 3: Permission Scopes
Each API key has a set of permission scopes that control which endpoints it can access. You can customize scopes when creating a key.
| Scope | Description |
| --- | --- |
| `authority:read` | Read topical authority hierarchy, SERP data, and AI search presence |
| `authority:write` | Toggle published status, manage authority keywords, organize the hierarchy (move, rename, combine, create, archive, restore, clear, update URL slug), and generate authority briefs & article drafts |
| `brands:read` | List and read brand details |
| `brands:write` | Create and update brands |
| `briefs:read` | List and read content briefs |
| `briefs:write` | Create and trigger brief generation |
| `clustering:read` | List and read clustering reports and SERP data |
| `clustering:write` | Start clustering, recluster, and delete reports |
| `content:read` | List and read articles and content |
| `content:write` | Create articles, trigger draft generation |
| `maps:read` | List and read raw topical map data |
| `research:read` | Read topical research data, stats, task status, diff comparison |
| `research:write` | Add, rename, delete, move, merge nodes, update keywords |
| `user:read` | Read your own profile, credit balance, teams, and audit logs |
---
## Part 4: Rate Limits
Rate limits are applied per key based on the key type.
| Key Type | Limit |
| --- | --- |
| Developer | 60 requests per minute |
| Integration | 120 requests per minute |
When you exceed the rate limit, the API returns a `429 Too Many Requests` response with a `Retry-After` header indicating how many seconds to wait.
```json
{
"detail": "Request was throttled. Expected available in 12 seconds."
}
```
---
## Part 5: API Endpoints
All endpoints are under `/api/v1/`. Responses are JSON. List endpoints return arrays of objects. Detail endpoints return a single object.
### Brands
**Scope required:** `brands:read` (GET), `brands:write` (POST)
#### List Brands
```
GET /api/v1/brands/
```
Returns all brands in your workspace, ordered by most recently created.
**Query parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `search` | string | Search brands by name (case-insensitive) |
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/brands/
# Search by name
curl -H "X-API-Key: fyi_live_your_key_here" \
"https://api.floyi.com/api/v1/brands/?search=floyi"
```
```python
response = requests.get(f"{BASE_URL}/brands/", headers=headers)
brands = response.json()
# Search by name
response = requests.get(
f"{BASE_URL}/brands/",
headers=headers,
params={"search": "floyi"},
)
```
```javascript
const res = await fetch(`${BASE_URL}/brands/`, { headers });
const brands = await res.json();
// Search by name
const searchRes = await fetch(`${BASE_URL}/brands/?search=floyi`, { headers });
```
**Response:**
```json
[
{
"id": "a1b2c3d4-...",
"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": "completed",
"content_scope": "...",
"created_at": "2026-02-01T10:00:00Z",
"updated_at": "2026-02-15T14:30:00Z"
}
]
```
#### Get Brand Details
```
GET /api/v1/brands/{id}/
```
Returns full details for a single brand. The response shape is the same as each object in the list endpoint. Returns `404` if the brand is not found or you do not have access.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/brands/a1b2c3d4-.../
```
```python
brand_id = "a1b2c3d4-..."
response = requests.get(f"{BASE_URL}/brands/{brand_id}/", headers=headers)
brand = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(`${BASE_URL}/brands/${brandId}/`, { headers });
const brand = await res.json();
```
**Response:**
```json
{
"id": "a1b2c3d4-...",
"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": "completed",
"content_scope": "...",
"created_at": "2026-02-01T10:00:00Z",
"updated_at": "2026-02-15T14:30:00Z"
}
```
#### Create a Brand
```
POST /api/v1/brands/
```
**Request body:**
```json
{
"brand_name": "My New Brand",
"website_url": "https://example.com",
"mission": "Help teams create better content",
"target_audience": "Content marketers and SEO professionals",
"language": "en"
}
```
**Required fields:** `brand_name`
**Optional fields:** `website_url`, `mission`, `vision`, `tagline`, `target_audience`, `brand_voice`, `values`, `marketplace`, `key_competitors`, `unique_selling_proposition`, `description`, `language`
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_integration_key" \
-H "Content-Type: application/json" \
-d '{
"brand_name": "My New Brand",
"website_url": "https://example.com",
"mission": "Help teams create better content",
"target_audience": "Content marketers and SEO professionals",
"language": "en"
}' \
https://api.floyi.com/api/v1/brands/
```
```python
response = requests.post(
f"{BASE_URL}/brands/",
headers=headers,
json={
"brand_name": "My New Brand",
"website_url": "https://example.com",
"mission": "Help teams create better content",
"target_audience": "Content marketers and SEO professionals",
"language": "en",
},
)
brand = response.json()
```
```javascript
const res = await fetch(`${BASE_URL}/brands/`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
brand_name: "My New Brand",
website_url: "https://example.com",
mission: "Help teams create better content",
target_audience: "Content marketers and SEO professionals",
language: "en",
}),
});
const brand = await res.json();
```
**Response (201 Created):**
```json
{
"id": "a1b2c3d4-...",
"brand_name": "My New Brand",
"website_url": "https://example.com",
"mission": "Help teams create better content",
"vision": null,
"tagline": null,
"target_audience": "Content marketers and SEO professionals",
"brand_voice": null,
"values": null,
"marketplace": null,
"market_position": null,
"key_competitors": null,
"unique_selling_proposition": null,
"brand_personality": null,
"brand_story": null,
"language": "en",
"country_code": null,
"country_name": null,
"stage": "new",
"content_scope": null,
"created_at": "2026-02-22T10:00:00Z",
"updated_at": "2026-02-22T10:00:00Z"
}
```
The response returns the full brand object, including the `id` you need for subsequent API calls (briefs, maps, articles).
**Error responses:**
| Status | Cause |
| --- | --- |
| `400 Bad Request` | Missing `brand_name` or validation error. Response body contains field-level errors. |
```json
{
"brand_name": ["This field is required."]
}
```
---
### Content Briefs
**Scope required:** `briefs:read` (GET), `briefs:write` (POST)
#### List Briefs
```
GET /api/v1/briefs/
```
Returns all content briefs in your workspace.
**Query parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `brand_id` | UUID | Filter briefs by brand |
| `status` | string | Filter by brief status (e.g., `COMPLETE`, `PENDING`, `PROCESSING`) |
| `search` | string | Search by topic/query text or generated title (case-insensitive) |
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
"https://api.floyi.com/api/v1/briefs/?brand_id=a1b2c3d4-..."
# Search by topic name
curl -H "X-API-Key: fyi_live_your_key_here" \
"https://api.floyi.com/api/v1/briefs/?search=what+is+topical+authority"
```
```python
response = requests.get(
f"{BASE_URL}/briefs/",
headers=headers,
params={"brand_id": "a1b2c3d4-..."},
)
briefs = response.json()
# Search by topic name
response = requests.get(
f"{BASE_URL}/briefs/",
headers=headers,
params={"search": "what is topical authority"},
)
```
```javascript
const res = await fetch(
`${BASE_URL}/briefs/?brand_id=a1b2c3d4-...`,
{ headers },
);
const briefs = await res.json();
// Search by topic name
const searchRes = await fetch(
`${BASE_URL}/briefs/?search=what+is+topical+authority`,
{ headers },
);
```
**Response:**
```json
[
{
"id": "b5c6d7e8-...",
"query_text": "best seo tools for agencies",
"brand_name": "Floyi",
"status": "COMPLETE",
"generated_title": "Best SEO Tools for Agencies in 2026",
"generated_meta_description": "Discover the top SEO tools...",
"created_at": "2026-02-10T08:00:00Z",
"updated_at": "2026-02-10T08:15:00Z"
}
]
```
#### Get Brief Details
```
GET /api/v1/briefs/{id}/
```
Returns the full brief including the complete `result_json` and `curated_brief_json` with all SERP analysis, competitor data, headings, and recommendations. Returns `404` if the brief is not found or you do not have access.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/briefs/b5c6d7e8-.../
```
```python
brief_id = "b5c6d7e8-..."
response = requests.get(f"{BASE_URL}/briefs/{brief_id}/", headers=headers)
brief = response.json()
```
```javascript
const briefId = "b5c6d7e8-...";
const res = await fetch(`${BASE_URL}/briefs/${briefId}/`, { headers });
const brief = await res.json();
```
**Response:**
```json
{
"id": "b5c6d7e8-...",
"query_text": "best seo tools for agencies",
"brand_name": "Floyi",
"status": "COMPLETE",
"generated_title": "Best SEO Tools for Agencies in 2026",
"generated_meta_description": "Discover the top SEO tools...",
"result_json": {
"header_sections": [ ... ],
"serp_analysis": { ... },
"competitor_data": [ ... ],
"keyword_recommendations": [ ... ]
},
"curated_brief_json": {
"header_sections": [ ... ],
"meta_title": "...",
"meta_description": "..."
},
"input_params": {
"query_text": "best seo tools for agencies",
"brand_id": "a1b2c3d4-...",
"selected_serp_data": [ ... ]
},
"created_at": "2026-02-10T08:00:00Z",
"updated_at": "2026-02-10T08:15:00Z"
}
```
**Detail-only fields (not included in the list endpoint):**
| Field | Type | Description |
| --- | --- | --- |
| `result_json` | object | The raw brief output from the AI agent. Contains `header_sections` (outline with headings, subheadings, and talking points), `serp_analysis`, `competitor_data`, and `keyword_recommendations`. Structure varies based on the brief agent version. |
| `curated_brief_json` | object | The user-edited version of the brief (if the user customized it in the Floyi editor). Same structure as `result_json`. `null` if no edits have been made. |
| `input_params` | object | The original request parameters used to generate this brief, including `query_text`, `brand_id`, `selected_serp_data`, and any optional fields. |
:::note
The `result_json` and `curated_brief_json` fields contain complex nested structures produced by the brief generation agent. The exact shape may vary, but both always include a `header_sections` array representing the content outline.
:::
#### Check Brief Status
```
GET /api/v1/briefs/{id}/status/
```
Returns just the status of a brief. Useful for polling during brief generation.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/briefs/b5c6d7e8-.../status/
```
```python
brief_id = "b5c6d7e8-..."
response = requests.get(f"{BASE_URL}/briefs/{brief_id}/status/", headers=headers)
status = response.json()
```
```javascript
const briefId = "b5c6d7e8-...";
const res = await fetch(`${BASE_URL}/briefs/${briefId}/status/`, { headers });
const status = await res.json();
```
**Response:**
```json
{
"id": "b5c6d7e8-...",
"status": "COMPLETE",
"query_text": "best seo tools for agencies",
"generated_title": "Best SEO Tools for Agencies in 2026"
}
```
**Status values:**
| Status | Description |
| --- | --- |
| `DRAFT` | Brief created but generation has not started |
| `PENDING` | Brief is queued for generation |
| `PROCESSING` | Brief generation is actively running |
| `AWAITING_OUTLINE_REVIEW` | Generation paused for user outline review (interactive mode) |
| `RESUMING_PROCESSING` | Generation resuming after outline review |
| `RETRY_PAUSED` | Generation paused due to a transient error; will retry automatically |
| `COMPLETE` | Brief generation finished successfully |
| `PARTIAL_COMPLETE` | Brief generated but some sections may be incomplete |
| `FAILED` | Brief generation failed |
:::tip
When polling, treat `COMPLETE` and `PARTIAL_COMPLETE` as terminal success states, and `FAILED` as a terminal error state. All other statuses indicate the brief is still in progress.
:::
#### Generate a Brief
```
POST /api/v1/briefs/generate/
```
Triggers standalone content brief generation for any topic. This is a freeform endpoint - you provide the topic text directly. For hierarchy-linked briefs (tied to your topical authority map), use the [Authority Briefs](#authority-briefs) endpoints instead.
Returns immediately with a `202 Accepted` response. Poll the status endpoint for progress.
**Request body:**
```json
{
"query_text": "best seo tools for agencies",
"brand_id": "a1b2c3d4-...",
"ai_model_id": "gpt-5-mini"
}
```
**Required fields:** `query_text`, `brand_id`
**Optional fields:**
| Field | Type | Description |
| --- | --- | --- |
| `selected_serp_data` | object[] | SERP competitor pages to analyze (max 15, each must include `url`). If omitted, auto-fetched from cached SERP data for this keyword in the topical map. Returns `400` if no cached data exists. |
| `user_provided_keywords` | string[] | Additional keywords to include in the brief |
| `internal_link_suggestions` | object[] | Internal links to suggest (each: `url`, `anchor_text`) |
| `content_info_context` | object | Additional context (SERP features, AI overview data, etc.) |
| `ai_model_id` | string | AI model to use (e.g. `"gpt-5-mini"`). Uses default if not specified. |
```bash
# Minimal
curl -X POST \
-H "X-API-Key: fyi_live_your_integration_key" \
-H "Content-Type: application/json" \
-d '{
"query_text": "best seo tools for agencies",
"brand_id": "a1b2c3d4-..."
}' \
https://api.floyi.com/api/v1/briefs/generate/
# With SERP data and keywords
curl -X POST \
-H "X-API-Key: fyi_live_your_integration_key" \
-H "Content-Type: application/json" \
-d '{
"query_text": "best seo tools for agencies",
"brand_id": "a1b2c3d4-...",
"selected_serp_data": [
{"url": "https://example.com", "title": "Example", "snippet": "..."}
],
"user_provided_keywords": ["seo software", "agency tools"]
}' \
https://api.floyi.com/api/v1/briefs/generate/
```
```python
# Minimal
response = requests.post(
f"{BASE_URL}/briefs/generate/",
headers=headers,
json={
"query_text": "best seo tools for agencies",
"brand_id": "a1b2c3d4-...",
},
)
brief = response.json()
# With SERP data and keywords
response = requests.post(
f"{BASE_URL}/briefs/generate/",
headers=headers,
json={
"query_text": "best seo tools for agencies",
"brand_id": "a1b2c3d4-...",
"selected_serp_data": [
{"url": "https://example.com", "title": "Example", "snippet": "..."}
],
"user_provided_keywords": ["seo software", "agency tools"],
},
)
```
```javascript
// Minimal
const res = await fetch(`${BASE_URL}/briefs/generate/`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
query_text: "best seo tools for agencies",
brand_id: "a1b2c3d4-...",
}),
});
const brief = await res.json();
// With SERP data and keywords
const res2 = await fetch(`${BASE_URL}/briefs/generate/`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
query_text: "best seo tools for agencies",
brand_id: "a1b2c3d4-...",
selected_serp_data: [
{ url: "https://example.com", title: "Example", snippet: "..." },
],
user_provided_keywords: ["seo software", "agency tools"],
}),
});
```
**Response (202 Accepted):**
```json
{
"id": "b5c6d7e8-...",
"status": "PENDING",
"query_text": "best seo tools for agencies",
"brand_name": "Floyi",
"message": "Brief generation started. Poll /api/v1/briefs/{id}/status/ for progress."
}
```
:::tip
After generating a brief, poll `GET /api/v1/briefs/{id}/status/` every 10-15 seconds until the status changes to `COMPLETE`. Brief generation typically takes 1-3 minutes depending on the number of SERP pages to analyze.
:::
**Error responses:**
| Status | Cause |
| --- | --- |
| `400 Bad Request` | Validation error (missing required fields, SERP entry missing `url`, or no SERP data available) |
| `402 Payment Required` | Insufficient credits to generate a brief |
| `404 Not Found` | Brand not found or you do not have access |
**400 - No SERP data available (auto-fetch):**
When `selected_serp_data` is omitted, the API attempts to auto-fetch cached SERP data for the topic from the brand's topical map. If no cached SERP data exists for that keyword, the request fails with a `400`:
```json
{
"detail": "No SERP data available for this topic. Please provide selected_serp_data or ensure SERP data has been collected for this topic in the topical map."
}
```
To resolve this, either:
1. Provide `selected_serp_data` manually with competitor pages you want analyzed, or
2. Ensure SERP data has been collected for this topic in the topical map first (via the Floyi dashboard)
**400 - SERP entry missing url:**
```json
{
"detail": "selected_serp_data[0] must include a 'url' field."
}
```
**402 - Insufficient credits:**
```json
{
"detail": "Insufficient credits."
}
```
**404 - Brand not found:**
```json
{
"detail": "Brand not found or you do not have access."
}
```
:::note
Standalone briefs are not linked to the authority hierarchy. If you need briefs tied to specific topics in your topical map (for the Planner tab), use `POST /api/v1/authority/{brand_id}/briefs/generate/` instead.
:::
---
### Content Articles
**Scope required:** `content:read` (GET), `content:write` (POST)
#### List Articles
```
GET /api/v1/content/articles/
```
Returns all content articles in your workspace.
**Query parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `brand_id` | UUID | Filter articles by brand |
| `search` | string | Search by article title (case-insensitive) |
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
"https://api.floyi.com/api/v1/content/articles/?brand_id=a1b2c3d4-..."
# Search by title
curl -H "X-API-Key: fyi_live_your_key_here" \
"https://api.floyi.com/api/v1/content/articles/?search=seo+tools"
```
```python
response = requests.get(
f"{BASE_URL}/content/articles/",
headers=headers,
params={"brand_id": "a1b2c3d4-..."},
)
articles = response.json()
# Search by title
response = requests.get(
f"{BASE_URL}/content/articles/",
headers=headers,
params={"search": "seo tools"},
)
```
```javascript
const res = await fetch(
`${BASE_URL}/content/articles/?brand_id=a1b2c3d4-...`,
{ headers },
);
const articles = await res.json();
// Search by title
const searchRes = await fetch(
`${BASE_URL}/content/articles/?search=seo+tools`,
{ headers },
);
```
**Response:**
```json
[
{
"id": "c7d8e9f0-...",
"title": "Best SEO Tools for Agencies in 2026",
"brand_id": "a1b2c3d4-...",
"brand_name": "Floyi",
"machine_state": "completed",
"editorial_state": "draft",
"created_at": "2026-02-12T09:00:00Z",
"updated_at": "2026-02-14T11:00:00Z"
}
]
```
#### Get Article Details
```
GET /api/v1/content/articles/{id}/
```
Returns the full article including `brief_id`, `additional_directions`, the `sections` array, and all metadata. Returns `404` if the article is not found or you do not have access.
**Response:**
```json
{
"id": "c7d8e9f0-...",
"title": "Best SEO Tools for Agencies in 2026",
"brand_id": "a1b2c3d4-...",
"brand_name": "Floyi",
"brief_id": "b5c6d7e8-...",
"machine_state": "completed",
"editorial_state": "draft",
"additional_directions": "Focus on enterprise pricing tiers and team collaboration features.",
"sections": [
{
"id": "d1e2f3a4-...",
"position": 0,
"heading": "Introduction",
"status": "approved",
"content": "Choosing the right SEO stack starts with how your team actually works...",
"ai_draft": "Choosing the right SEO stack starts with how your team actually works...",
"word_count_target": 200
},
{
"id": "e2f3a4b5-...",
"position": 1,
"heading": "Comparing the Top Agency Platforms",
"status": "approved",
"content": "Here is how the leading platforms stack up for agency workflows...",
"ai_draft": "Here is how the leading platforms stack up for agency workflows...",
"word_count_target": 800
}
],
"created_at": "2026-02-12T09:00:00Z",
"updated_at": "2026-02-14T11:00:00Z"
}
```
**Detail-only fields (not included in the list endpoint):**
| Field | Type | Description |
| --- | --- | --- |
| `brief_id` | UUID or null | The content brief this article was created from. `null` if the article was created without a brief. |
| `additional_directions` | string or null | Custom instructions provided for draft generation. `null` if none were set. |
| `sections` | array | The article's sections, ordered by `position`. Empty until sections are synced from the brief. See the field table below. |
**Section fields:**
| Field | Type | Description |
| --- | --- | --- |
| `id` | UUID | Section identifier |
| `position` | integer | Order position (0-based) |
| `heading` | string | Section heading |
| `status` | string | Draft status: `not_started`, `drafting`, `approved`, `needs_attention` |
| `content` | string | The section's current text as the app renders it - the polished revision when one exists, then any human revision, then the AI draft - with internal links resolved to full URLs. Read this field. |
| `ai_draft` | string or null | The raw AI-generated first draft for this section, kept for backward compatibility. May lag behind `content`. |
| `word_count_target` | integer or null | Target word count for this section |
#### Generate Draft from Brief
```
POST /api/v1/content/articles/generate/
```
Creates a new article from a completed content brief and immediately starts AI draft generation - one step instead of two. The brief must be in `COMPLETE` or `PARTIAL_COMPLETE` status and have generated sections.
**Request body:**
```json
{
"brief_id": "b5c6d7e8-...",
"ai_model_id": "claude-sonnet-4",
"intent": "human",
"specialists": {
"research_agent": true,
"intro_key_takeaways": true,
"research_mode": "basic"
}
}
```
**Required fields:** `brief_id`, `ai_model_id`
**Optional fields:**
| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `intent` | string | `"human"` | Writing style, matching the app's Strategic Intents: `"human"` (Teach - conversational, natural tone), `"llm"` (Define - definitive, citation-ready for search and AI engines), `"exec"` (Convince - persuasive, evidence-driven for commercial pages) |
| `specialists` | object | all `false` | Specialist agents to enable during generation (see below) |
**Specialist agents:**
| Specialist | Description | Availability |
| --- | --- | --- |
| `research_agent` | Researches the web for up-to-date information and verifies claims and data accuracy - one agent pair working together | Resource pages only |
| `intro_key_takeaways` | Generates a polished intro and key takeaways section | Resource pages only |
| `research_mode` | `"basic"` or `"advanced"` depth for research | When `research_agent` is `true` |
:::note
Specialist availability depends on the article type. Resource pages (blog posts, guides) can use `research_agent` and `intro_key_takeaways`. Local/landing pages automatically get the Conversion Coach agent (conversion-optimized CTAs and messaging) - it is enabled by page type, not by request. The API filters specialists to match the article type.
:::
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_integration_key" \
-H "Content-Type: application/json" \
-d '{"brief_id": "b5c6d7e8-...", "ai_model_id": "claude-sonnet-4"}' \
https://api.floyi.com/api/v1/content/articles/generate/
```
```python
response = requests.post(
f"{BASE_URL}/content/articles/generate/",
headers=headers,
json={
"brief_id": "b5c6d7e8-...",
"ai_model_id": "claude-sonnet-4",
},
)
article = response.json()
# article["id"] -> use for status polling
```
```javascript
const res = await fetch(`${BASE_URL}/content/articles/generate/`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
brief_id: "b5c6d7e8-...",
ai_model_id: "claude-sonnet-4",
}),
});
const article = await res.json();
// article.id -> use for status polling
```
**Response (202 Accepted):**
```json
{
"id": "c7d8e9f0-...",
"brief_id": "b5c6d7e8-...",
"title": "Best SEO Tools for Agencies in 2026",
"task_id": "e1f2a3b4-...",
"status": "generating",
"message": "Article created and draft generation started. Poll /api/v1/content/articles/{id}/status/ for progress."
}
```
:::tip
After triggering generation, poll `GET /api/v1/content/articles/{id}/status/` every 15-30 seconds. Draft generation typically takes 3-10 minutes depending on the number of sections and specialists enabled.
:::
**Error responses:**
| Status | Cause |
| --- | --- |
| `400 Bad Request` | `brief_id` or `ai_model_id` missing, brief not in `COMPLETE`/`PARTIAL_COMPLETE` status, brief has no associated brand, or brief has no content sections |
| `402 Payment Required` | Insufficient credits for draft or specialist agents |
| `404 Not Found` | Brief or brand not found, or you do not have access |
#### Regenerate Draft
```
POST /api/v1/content/articles/{id}/generate/
```
Regenerates draft for an existing article. Creates a new version, re-syncs sections from the brief, resets all sections, and generates fresh content. Optionally accepts a different `brief_id` to switch briefs.
**Request body:**
```json
{
"ai_model_id": "claude-sonnet-4",
"brief_id": "b5c6d7e8-...",
"intent": "human",
"specialists": {
"research_agent": true,
"intro_key_takeaways": true,
"research_mode": "basic"
}
}
```
**Required fields:** `ai_model_id`
**Optional fields:** `brief_id` (switch to a different brief), `intent`, `specialists` (same options as [Generate Draft from Brief](#generate-draft-from-brief))
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_integration_key" \
-H "Content-Type: application/json" \
-d '{"ai_model_id": "claude-sonnet-4"}' \
https://api.floyi.com/api/v1/content/articles/c7d8e9f0-.../generate/
```
```python
article_id = "c7d8e9f0-..."
response = requests.post(
f"{BASE_URL}/content/articles/{article_id}/generate/",
headers=headers,
json={"ai_model_id": "claude-sonnet-4"},
)
result = response.json()
```
```javascript
const articleId = "c7d8e9f0-...";
const res = await fetch(
`${BASE_URL}/content/articles/${articleId}/generate/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ ai_model_id: "claude-sonnet-4" }),
},
);
const result = await res.json();
```
**Response (202 Accepted):**
```json
{
"id": "c7d8e9f0-...",
"brief_id": "b5c6d7e8-...",
"title": "Best SEO Tools for Agencies in 2026",
"task_id": "e1f2a3b4-...",
"status": "regenerating",
"message": "Draft regeneration started. Poll /api/v1/content/articles/{id}/status/ for progress."
}
```
**Error responses:**
| Status | Cause |
| --- | --- |
| `400 Bad Request` | Missing `ai_model_id` |
| `402 Payment Required` | Insufficient credits for draft or specialist agents |
| `409 Conflict` | Article generation already in progress |
**409 - Already in progress:**
```json
{
"detail": "Article generation already in progress."
}
```
**402 - Insufficient credits:**
```json
{
"detail": "Insufficient credits."
}
```
#### Check Draft Status
```
GET /api/v1/content/articles/{id}/status/
```
Returns the current generation progress of an article. Useful for polling during draft generation.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/content/articles/c7d8e9f0-.../status/
```
```python
article_id = "c7d8e9f0-..."
response = requests.get(
f"{BASE_URL}/content/articles/{article_id}/status/",
headers=headers,
)
status = response.json()
```
```javascript
const articleId = "c7d8e9f0-...";
const res = await fetch(
`${BASE_URL}/content/articles/${articleId}/status/`,
{ headers },
);
const status = await res.json();
```
**Response:**
```json
{
"id": "c7d8e9f0-...",
"machine_state": "in_progress",
"sections_total": 8,
"sections_approved": 3,
"sections_drafting": 2,
"sections_not_started": 3,
"sections_needs_attention": 0,
"completion_percentage": 37.5,
"specialists_running": true,
"specialists_complete": false
}
```
**Machine state values:**
| State | Description |
| --- | --- |
| `ready` | Article created, waiting for draft generation |
| `in_progress` | Draft generation is actively running |
| `draft_done` | All sections drafted successfully |
| `incomplete` | Generation finished but some sections may need attention |
:::tip
When polling, treat `draft_done` as the terminal success state. Once complete, fetch the full article with `GET /api/v1/content/articles/{id}/` to see the final content.
:::
---
### Topical Maps
**Scope required:** `maps:read`
Returns the raw topical map data as created during keyword research and clustering, before any Topical Authority overrides are applied. For the enriched authority view (with organizer edits, SERP rankings, importance scores, and AI search presence), use the [Topical Authority](#topical-authority) endpoints instead.
#### List Topical Maps
```
GET /api/v1/maps/
```
Returns all topical maps in your workspace.
**Query parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `brand_id` | UUID | Filter maps by brand |
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/maps/
# Filter by brand
curl -H "X-API-Key: fyi_live_your_key_here" \
"https://api.floyi.com/api/v1/maps/?brand_id=a1b2c3d4-..."
```
```python
response = requests.get(f"{BASE_URL}/maps/", headers=headers)
maps = response.json()
# Filter by brand
response = requests.get(
f"{BASE_URL}/maps/",
headers=headers,
params={"brand_id": "a1b2c3d4-..."},
)
```
```javascript
const res = await fetch(`${BASE_URL}/maps/`, { headers });
const maps = await res.json();
// Filter by brand
const filteredRes = await fetch(
`${BASE_URL}/maps/?brand_id=a1b2c3d4-...`,
{ headers },
);
```
**Response:**
```json
[
{
"brand_id": "a1b2c3d4-...",
"brand_name": "Floyi",
"is_uploaded": false,
"created_at": "2026-01-20T12:00:00Z",
"updated_at": "2026-02-18T16:00:00Z"
}
]
```
#### Get Raw Map Clusters
```
GET /api/v1/maps/{brand_id}/
```
Returns the full raw keyword clusters from the topical map, including all search metrics, SERP analysis, and content metadata. Each cluster contains its centroid keyword and all associated keywords with their complete data. Returns `404` if no map exists for this brand or you do not have access.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/maps/a1b2c3d4-.../
```
```python
brand_id = "a1b2c3d4-..."
response = requests.get(
f"{BASE_URL}/maps/{brand_id}/", headers=headers
)
map_data = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(`${BASE_URL}/maps/${brandId}/`, { headers });
const mapData = await res.json();
```
**Response:**
```json
{
"brand_id": "a1b2c3d4-...",
"brand_name": "Floyi",
"is_uploaded": false,
"cluster_count": 85,
"clusters": [
{
"id": "c1d2e3f4-...",
"centroid": "best keyword research tools",
"keyword_count": 3,
"keywords": [
{
"keyword": "best keyword research tools",
"main_topic": "SEO Strategy",
"subtopic_2": "Keyword Research",
"subtopic_3": "Keyword Tools",
"subtopic_4": "best keyword research tools",
"sort_order": 0,
"search_volume": 2400,
"cpc": 3.50,
"competition": 0.72,
"url_slug": "best-keyword-research-tools",
"has_serp_data": true,
"serp_analysis": "Informational listicle format dominates...",
"serp_competitors": "ahrefs.com, semrush.com, moz.com",
"serp_freshness": "2025-12",
"content_title": "Best Keyword Research Tools",
"search_intent": "informational",
"buyers_journey": "consideration",
"content_type": "listicle",
"snippet": "Discover the top keyword research tools...",
"similarity": 0.95
}
]
}
],
"created_at": "2026-01-20T12:00:00Z",
"updated_at": "2026-02-18T16:00:00Z"
}
```
**Cluster fields:**
| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Cluster identifier |
| `centroid` | string | The primary keyword representing this cluster |
| `keyword_count` | integer | Number of keywords in this cluster |
| `keywords` | object[] | All keywords in this cluster |
**Keyword fields - Hierarchy:**
| Field | Type | Description |
| --- | --- | --- |
| `keyword` | string | The keyword text |
| `main_topic` | string | Main Topic (level 1 of the hierarchy) |
| `subtopic_2` | string | Subtopic 2 (level 2) |
| `subtopic_3` | string | Subtopic 3 (level 3) |
| `subtopic_4` | string | Subtopic 4 (level 4) |
| `sort_order` | integer | Sort position within the cluster |
**Keyword fields - Search Metrics:**
| Field | Type | Description |
| --- | --- | --- |
| `search_volume` | number | Monthly search volume |
| `cpc` | number | Cost per click (USD) |
| `competition` | number | Competition score (0-1) |
**Keyword fields - SERP Data:**
| Field | Type | Description |
| --- | --- | --- |
| `has_serp_data` | boolean | Whether SERP analysis data is available |
| `serp_analysis` | string | SERP analysis summary |
| `serp_competitors` | string | Top competing domains in SERP |
| `serp_freshness` | string | SERP freshness / recency indicator |
**Keyword fields - Content & URL:**
| Field | Type | Description |
| --- | --- | --- |
| `url_slug` | string | Suggested URL slug |
| `content_title` | string | Suggested content title |
| `search_intent` | string | Search intent classification |
| `buyers_journey` | string | Buyer's journey stage |
| `content_type` | string | Recommended content format |
| `snippet` | string | Content snippet / description |
| `similarity` | number/string | Similarity score to cluster centroid |
:::tip
This returns the original keyword research data. If the user has made edits in Floyi's Organizer (renames, moves, combines), those changes are **not** reflected here. Use the [Topical Authority](#topical-authority) endpoints to see the current effective hierarchy with all edits applied.
:::
---
### Topical Research
**Scope required:** `research:read` (GET), `research:write` (PATCH/POST)
Access the pre-clustering topical research tree - the 4-level topic hierarchy (Main Topics > Subtopic 2 > Subtopic 3 > Subtopic 4 > Keywords) that users build during the research phase before clustering into a topical map. These endpoints support both reading the tree and making atomic modifications (rename, add, delete, move, merge, keyword updates).
#### List Research Records
```
GET /api/v1/research/
```
Returns all topical research records in your workspace.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/research/
```
```python
response = requests.get(f"{BASE_URL}/research/", headers=headers)
records = response.json()
```
```javascript
const res = await fetch(`${BASE_URL}/research/`, { headers });
const records = await res.json();
```
**Response:**
```json
[
{
"brand_id": "a1b2c3d4-...",
"brand_name": "Floyi",
"core_topic": "content strategy",
"created_at": "2026-02-01T10:00:00Z",
"updated_at": "2026-02-20T14:30:00Z"
}
]
```
#### Get Research Tree
```
GET /api/v1/research/{brand_id}/
```
Returns the full 4-level topic hierarchy with computed stats and generation status. Returns `404` if no research data exists for this brand.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/research/{BRAND_ID}/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.get(
f"{BASE_URL}/research/{brand_id}/", headers=headers
)
tree = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(`${BASE_URL}/research/${brandId}/`, { headers });
const tree = await res.json();
```
**Response:**
```json
{
"brand_id": "a1b2c3d4-...",
"brand_name": "Floyi",
"core_topic": "content strategy",
"research_data": [
{
"main_topic": "email marketing",
"subtopic_2": [
{
"name": "email automation",
"subtopic_3": [...],
"subtopic_4": [],
"keywords": []
}
],
"subtopic_3": [],
"subtopic_4": [],
"keywords": []
}
],
"stats": {
"main_topic_count": 5,
"st2_count": 23,
"st3_count": 67,
"st4_count": 142,
"keyword_count": 890,
"leaf_nodes_without_keywords": 12,
"total_nodes": 237
},
"generation_status": {
"has_running_task": false
},
"created_at": "2026-02-01T10:00:00Z",
"updated_at": "2026-02-20T14:30:00Z"
}
```
#### Get Tree Stats
```
GET /api/v1/research/{brand_id}/stats/
```
Returns only the stats without the full tree. Includes per-main-topic breakdown.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/research/{BRAND_ID}/stats/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.get(
f"{BASE_URL}/research/{brand_id}/stats/", headers=headers
)
stats = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/research/${brandId}/stats/`, { headers }
);
const stats = await res.json();
```
**Response:**
```json
{
"brand_id": "a1b2c3d4-...",
"main_topic_count": 5,
"st2_count": 23,
"st3_count": 67,
"st4_count": 142,
"keyword_count": 890,
"leaf_nodes_without_keywords": 12,
"total_nodes": 237,
"main_topics": [
{"name": "email marketing", "st2_count": 6, "st3_count": 18, "st4_count": 42, "keyword_count": 234}
],
"generation_status": {"has_running_task": false}
}
```
#### Get Task Status
```
GET /api/v1/research/{brand_id}/task-status/
```
Poll the status of any running AI generation task. Performs Celery reconciliation - if the model says a task is running but Celery reports it as finished, the status is synced.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/research/{BRAND_ID}/task-status/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.get(
f"{BASE_URL}/research/{brand_id}/task-status/", headers=headers
)
task = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/research/${brandId}/task-status/`, { headers }
);
const task = await res.json();
```
**Response (task running):**
```json
{
"has_running_task": true,
"task_id": "3a8c1d2e-...",
"task_type": "generate_st2_st3_v2",
"task_status": "running",
"progress": {"current": 3, "total": 5, "message": "Generating ST2+ST3 for main topic 3 of 5..."},
"started_at": "2026-02-23T14:10:00+00:00",
"error": null
}
```
**Response (no task):**
```json
{
"has_running_task": false
}
```
:::caution
All write operations below require the brand to be in the **Topical Research** stage - after the brand advances to clustering or beyond, they reject with `400 Bad Request` ("Brand is not in the TOPICAL_RESEARCH stage"). They also reject with `409 Conflict` if a generation task is currently running. Wait for the task to complete or cancel it from the Floyi dashboard before making changes.
:::
#### Rename Node
```
PATCH /api/v1/research/{brand_id}/nodes/rename/
```
**Scope required:** `research:write`
**Request body:**
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `path` | string[] | Yes | Path to the node (e.g., `["email marketing", "email automation"]`) |
| `new_name` | string | Yes | New name for the node (lowercased automatically) |
```bash
curl -X PATCH \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"path": ["email marketing", "email automation"], "new_name": "marketing automation"}' \
https://api.floyi.com/api/v1/research/{BRAND_ID}/nodes/rename/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.patch(
f"{BASE_URL}/research/{brand_id}/nodes/rename/",
headers=headers,
json={
"path": ["email marketing", "email automation"],
"new_name": "marketing automation",
},
)
result = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/research/${brandId}/nodes/rename/`,
{
method: "PATCH",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
path: ["email marketing", "email automation"],
new_name: "marketing automation",
}),
},
);
const result = await res.json();
```
**Response:**
```json
{
"success": true,
"operation": "rename",
"path": ["email marketing", "email automation"],
"old_name": "email automation",
"new_name": "marketing automation",
"updated_path": ["email marketing", "marketing automation"]
}
```
#### Add Node (Single)
```
POST /api/v1/research/{brand_id}/nodes/add/
```
**Scope required:** `research:write`
Adds **one node** per request. To add multiple nodes at once, use **Bulk Operations** below instead.
**Request body:**
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `parent_path` | string[] | Yes | Path to parent node. The depth determines the level of the new node (see examples below). |
| `name` | string | Yes | Name of the new topic (lowercased automatically) |
| `position` | integer or null | No | Insertion index. `null` appends to end. |
**`parent_path` determines the node level:**
| `parent_path` | New node level |
| --- | --- |
| `[]` (empty array) | **Pillar** (root level) |
| `["email marketing"]` | **Hub** under that Pillar |
| `["email marketing", "automation"]` | **Branch** |
| `["email marketing", "automation", "drip campaigns"]` | **Resource** (leaf level) |
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"parent_path": ["email marketing"], "name": "email deliverability"}' \
https://api.floyi.com/api/v1/research/{BRAND_ID}/nodes/add/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/research/{brand_id}/nodes/add/",
headers=headers,
json={
"parent_path": ["email marketing"],
"name": "email deliverability",
},
)
result = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/research/${brandId}/nodes/add/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
parent_path: ["email marketing"],
name: "email deliverability",
}),
},
);
const result = await res.json();
```
**Response:**
```json
{
"success": true,
"operation": "add",
"parent_path": ["email marketing"],
"name": "email deliverability",
"level": "ST2",
"path": ["email marketing", "email deliverability"]
}
```
#### Delete Node
```
POST /api/v1/research/{brand_id}/nodes/delete/
```
**Scope required:** `research:write`
Deletes a node and all its descendants (subtopics and keywords).
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"path": ["email marketing", "email automation", "trigger-based emails"]}' \
https://api.floyi.com/api/v1/research/{BRAND_ID}/nodes/delete/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/research/{brand_id}/nodes/delete/",
headers=headers,
json={
"path": ["email marketing", "email automation", "trigger-based emails"],
},
)
result = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/research/${brandId}/nodes/delete/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
path: ["email marketing", "email automation", "trigger-based emails"],
}),
},
);
const result = await res.json();
```
**Response:**
```json
{
"success": true,
"operation": "delete",
"path": ["email marketing", "email automation", "trigger-based emails"],
"deleted_node": "trigger-based emails",
"deleted_descendants": 4,
"deleted_keywords": 12
}
```
#### Update Keywords (Single Node)
```
PATCH /api/v1/research/{brand_id}/nodes/keywords/
```
**Scope required:** `research:write`
Updates keywords on **one node** per request (but you can add/remove multiple keywords in that call). To update keywords on many nodes at once, use **Bulk Operations** below with the `update_keywords` action.
Keywords can be added to **any level** of the tree - Pillars, Hubs, Branches, and Resources all hold keywords.
**Request body:**
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `path` | string[] | Yes | Path to the target node. Works at any level (Pillar, Hub, Branch, or Resource). |
| `add` | string[] | No | Keywords to add (lowercased, duplicates skipped). Max 200 per request. |
| `remove` | string[] | No | Keywords to remove (missing ones skipped). Max 200 per request. |
At least one of `add` or `remove` must be a non-empty array. Each array accepts up to **200 keywords** per request - if you need more, split across multiple calls.
**Which nodes can have keywords?**
All levels. The `path` depth determines which node receives the keywords:
| `path` | Target node |
| --- | --- |
| `["email marketing"]` | Pillar node |
| `["email marketing", "email automation"]` | Hub node |
| `["email marketing", "email automation", "drip campaigns"]` | Branch node |
| `["email marketing", "email automation", "drip campaigns", "welcome sequences"]` | Resource node |
```bash
curl -X PATCH \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"path": ["email marketing", "email automation"], "add": ["drip campaign"], "remove": ["old keyword"]}' \
https://api.floyi.com/api/v1/research/{BRAND_ID}/nodes/keywords/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.patch(
f"{BASE_URL}/research/{brand_id}/nodes/keywords/",
headers=headers,
json={
"path": ["email marketing", "email automation"],
"add": ["drip campaign"],
"remove": ["old keyword"],
},
)
result = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/research/${brandId}/nodes/keywords/`,
{
method: "PATCH",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
path: ["email marketing", "email automation"],
add: ["drip campaign"],
remove: ["old keyword"],
}),
},
);
const result = await res.json();
```
**Response:**
```json
{
"success": true,
"operation": "update_keywords",
"path": ["email marketing", "email automation"],
"added": ["drip campaign"],
"removed": ["old keyword"],
"current_keywords": ["email tools", "drip campaign"]
}
```
#### Move Node
```
POST /api/v1/research/{brand_id}/nodes/move/
```
**Scope required:** `research:write`
Move a node (and its entire subtree) to a different parent. Use an empty `target_parent_path` (`[]`) to promote a node to a Main Topic.
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"source_path": ["content marketing", "outreach"], "target_parent_path": ["seo", "link building"]}' \
https://api.floyi.com/api/v1/research/{BRAND_ID}/nodes/move/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/research/{brand_id}/nodes/move/",
headers=headers,
json={
"source_path": ["content marketing", "outreach"],
"target_parent_path": ["seo", "link building"],
},
)
result = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/research/${brandId}/nodes/move/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
source_path: ["content marketing", "outreach"],
target_parent_path: ["seo", "link building"],
}),
},
);
const result = await res.json();
```
**Response:**
```json
{
"success": true,
"operation": "move",
"source_path": ["content marketing", "outreach"],
"target_parent_path": ["seo", "link building"],
"new_path": ["seo", "link building", "outreach"]
}
```
#### Merge Nodes
```
POST /api/v1/research/{brand_id}/nodes/merge/
```
**Scope required:** `research:write`
Merge two same-level nodes under the same parent. Children and keywords from `merge_path` are moved to `keep_path`, then `merge_path` is deleted.
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"keep_path": ["email marketing", "email automation"], "merge_path": ["email marketing", "marketing automation"]}' \
https://api.floyi.com/api/v1/research/{BRAND_ID}/nodes/merge/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/research/{brand_id}/nodes/merge/",
headers=headers,
json={
"keep_path": ["email marketing", "email automation"],
"merge_path": ["email marketing", "marketing automation"],
},
)
result = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/research/${brandId}/nodes/merge/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
keep_path: ["email marketing", "email automation"],
merge_path: ["email marketing", "marketing automation"],
}),
},
);
const result = await res.json();
```
**Response:**
```json
{
"success": true,
"operation": "merge",
"keep_path": ["email marketing", "email automation"],
"merged_from": "marketing automation",
"children_moved": 3,
"keywords_merged": 8
}
```
#### Bulk Operations (Recommended for Multiple Changes)
```
POST /api/v1/research/{brand_id}/nodes/bulk/
```
**Scope required:** `research:write`
**This is the recommended endpoint for building or modifying hierarchies.** Execute up to **200 operations** in a single atomic request (all-or-nothing). Operations are applied sequentially - later operations see changes from earlier ones, so you can create a parent node and immediately add children to it in the same request.
**Supported actions:** `add`, `rename`, `delete`, `move`, `merge`, `update_keywords`
Each action uses the same parameters as its individual endpoint (see above).
**Individual vs Bulk - when to use which:**
| Endpoint | Use case |
| --- | --- |
| `nodes/add` | Add a single node |
| `nodes/keywords` | Update keywords on a single node |
| `nodes/bulk` | **Build hierarchies, batch edits, or any multi-step change** (up to 200 ops, atomic) |
**Example: Build a full Pillar → Hub → Branch → Resource hierarchy with keywords in one request:**
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"operations": [
{"action": "add", "parent_path": [], "name": "email marketing"},
{"action": "add", "parent_path": ["email marketing"], "name": "email automation"},
{"action": "add", "parent_path": ["email marketing"], "name": "email deliverability"},
{"action": "add", "parent_path": ["email marketing", "email automation"], "name": "drip campaigns"},
{"action": "add", "parent_path": ["email marketing", "email automation"], "name": "triggered emails"},
{"action": "add", "parent_path": ["email marketing", "email automation", "drip campaigns"], "name": "welcome sequences"},
{"action": "add", "parent_path": ["email marketing", "email automation", "drip campaigns"], "name": "onboarding flows"},
{"action": "update_keywords", "path": ["email marketing"], "add": ["email marketing strategy", "email campaigns"]},
{"action": "update_keywords", "path": ["email marketing", "email automation"], "add": ["marketing automation tools", "email workflow"]},
{"action": "update_keywords", "path": ["email marketing", "email automation", "drip campaigns", "welcome sequences"], "add": ["welcome email series", "new subscriber emails", "welcome email template"]}
]
}' \
https://api.floyi.com/api/v1/research/{BRAND_ID}/nodes/bulk/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/research/{brand_id}/nodes/bulk/",
headers=headers,
json={
"operations": [
{"action": "add", "parent_path": [], "name": "email marketing"},
{"action": "add", "parent_path": ["email marketing"], "name": "email automation"},
{"action": "add", "parent_path": ["email marketing"], "name": "email deliverability"},
{"action": "add", "parent_path": ["email marketing", "email automation"], "name": "drip campaigns"},
{"action": "add", "parent_path": ["email marketing", "email automation"], "name": "triggered emails"},
{"action": "add", "parent_path": ["email marketing", "email automation", "drip campaigns"], "name": "welcome sequences"},
{"action": "add", "parent_path": ["email marketing", "email automation", "drip campaigns"], "name": "onboarding flows"},
{"action": "update_keywords", "path": ["email marketing"], "add": ["email marketing strategy", "email campaigns"]},
{"action": "update_keywords", "path": ["email marketing", "email automation"], "add": ["marketing automation tools", "email workflow"]},
{"action": "update_keywords", "path": ["email marketing", "email automation", "drip campaigns", "welcome sequences"], "add": ["welcome email series", "new subscriber emails", "welcome email template"]},
],
},
)
result = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/research/${brandId}/nodes/bulk/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
operations: [
{ action: "add", parent_path: [], name: "email marketing" },
{ action: "add", parent_path: ["email marketing"], name: "email automation" },
{ action: "add", parent_path: ["email marketing"], name: "email deliverability" },
{ action: "add", parent_path: ["email marketing", "email automation"], name: "drip campaigns" },
{ action: "add", parent_path: ["email marketing", "email automation"], name: "triggered emails" },
{ action: "add", parent_path: ["email marketing", "email automation", "drip campaigns"], name: "welcome sequences" },
{ action: "add", parent_path: ["email marketing", "email automation", "drip campaigns"], name: "onboarding flows" },
{ action: "update_keywords", path: ["email marketing"], add: ["email marketing strategy", "email campaigns"] },
{ action: "update_keywords", path: ["email marketing", "email automation"], add: ["marketing automation tools", "email workflow"] },
{ action: "update_keywords", path: ["email marketing", "email automation", "drip campaigns", "welcome sequences"], add: ["welcome email series", "new subscriber emails", "welcome email template"] },
],
}),
},
);
const result = await res.json();
```
This creates the following structure in a single atomic request:
```
email marketing (Pillar) ← keywords: email marketing strategy, email campaigns
├── email automation (Hub) ← keywords: marketing automation tools, email workflow
│ ├── drip campaigns (Branch)
│ │ ├── welcome sequences (Resource) ← keywords: welcome email series, new subscriber emails, welcome email template
│ │ └── onboarding flows (Resource)
│ └── triggered emails (Branch)
└── email deliverability (Hub)
```
**Simple batch example:**
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"operations": [
{"action": "rename", "path": ["seo tools", "keyword research"], "new_name": "keyword research tools"},
{"action": "add", "parent_path": ["seo tools"], "name": "link building tools"},
{"action": "delete", "path": ["seo tools", "deprecated category"]}
]
}' \
https://api.floyi.com/api/v1/research/{BRAND_ID}/nodes/bulk/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/research/{brand_id}/nodes/bulk/",
headers=headers,
json={
"operations": [
{"action": "rename", "path": ["seo tools", "keyword research"], "new_name": "keyword research tools"},
{"action": "add", "parent_path": ["seo tools"], "name": "link building tools"},
{"action": "delete", "path": ["seo tools", "deprecated category"]},
],
},
)
result = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/research/${brandId}/nodes/bulk/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
operations: [
{ action: "rename", path: ["seo tools", "keyword research"], new_name: "keyword research tools" },
{ action: "add", parent_path: ["seo tools"], name: "link building tools" },
{ action: "delete", path: ["seo tools", "deprecated category"] },
],
}),
},
);
const result = await res.json();
```
**Atomicity:** If any operation fails, **all** previous operations in the batch are rolled back. No partial changes are applied.
**Response (success):**
```json
{
"success": true,
"operations_applied": 3,
"results": [
{"operation": "rename", "success": true, "old_name": "keyword research", "new_name": "keyword research tools"},
{"operation": "add", "success": true, "name": "link building tools", "level": "ST2"},
{"operation": "delete", "success": true, "deleted_node": "deprecated category", "deleted_descendants": 2, "deleted_keywords": 5}
]
}
```
**Response (failure - all rolled back):**
```json
{
"success": false,
"error": "Operation 2 (add) failed: Name already exists at this level.",
"failed_at_index": 1,
"operations_rolled_back": 1,
"message": "All operations rolled back. No changes were applied."
}
```
#### Compute Diff
```
POST /api/v1/research/{brand_id}/diff/
```
**Scope required:** `research:read`
Compare two tree states and return a structured diff. Useful for agents to summarize changes before confirming with the user.
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"before": [...], "after": [...]}' \
https://api.floyi.com/api/v1/research/{BRAND_ID}/diff/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/research/{brand_id}/diff/",
headers=headers,
json={"before": [...], "after": [...]},
)
diff = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/research/${brandId}/diff/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ before: [...], after: [...] }),
},
);
const diff = await res.json();
```
**Response:**
```json
{
"changes": [
{"type": "added", "level": "ST2", "path": ["seo", "link building tools"], "name": "link building tools"},
{"type": "deleted", "level": "ST3", "path": ["seo", "old category"], "name": "old category", "descendants_deleted": 3}
],
"summary": {
"nodes_added": 1,
"nodes_deleted": 1,
"nodes_renamed": 0,
"nodes_moved": 0,
"keywords_added": 0,
"keywords_removed": 0
}
}
```
**Limits:** Combined `before` + `after` payload must not exceed 2MB. Combined node count must not exceed 5,000.
**Error responses for all write endpoints:**
| Status | When |
| --- | --- |
| `400 Bad Request` | Invalid request body, missing required fields, validation failure |
| `404 Not Found` | Brand or research record not found |
| `409 Conflict` | Name already exists, or generation task is running |
| `413 Payload Too Large` | Diff payload exceeds 2MB |
---
### Topical Authority
**Scope required:** `authority:read` (GET), `authority:write` (PATCH)
Returns the authority-enriched hierarchy with all organizer overrides applied, plus coverage data (importance scores, published status), SERP rankings, and AI search presence. This is the same view shown in the Floyi dashboard's Topical Authority section.
#### List Authority Maps
```
GET /api/v1/authority/
```
Returns all authority maps in your workspace.
**Query parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `brand_id` | UUID | Filter by brand |
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/authority/
# Filter by brand
curl -H "X-API-Key: fyi_live_your_key_here" \
"https://api.floyi.com/api/v1/authority/?brand_id=a1b2c3d4-..."
```
```python
response = requests.get(f"{BASE_URL}/authority/", headers=headers)
maps = response.json()
# Filter by brand
response = requests.get(
f"{BASE_URL}/authority/",
headers=headers,
params={"brand_id": "a1b2c3d4-..."},
)
```
```javascript
const res = await fetch(`${BASE_URL}/authority/`, { headers });
const maps = await res.json();
// Filter by brand
const filteredRes = await fetch(
`${BASE_URL}/authority/?brand_id=a1b2c3d4-...`,
{ headers },
);
```
**Response:**
```json
[
{
"brand_id": "a1b2c3d4-...",
"brand_name": "Floyi",
"is_uploaded": false,
"created_at": "2026-01-20T12:00:00Z",
"updated_at": "2026-02-18T16:00:00Z"
}
]
```
#### Get Current Hierarchy
```
GET /api/v1/authority/{brand_id}/
```
Returns the **current effective hierarchy** for an authority map. This includes all user edits from the Organizer (renames, moves, combines, new topics) applied on top of the base map data. It returns the same view of the map that the Floyi dashboard shows. Returns `404` if no map exists for this brand or you do not have access.
Each node in the `hierarchy` array represents a topic cluster with its position in the 4-level hierarchy (Main Topic > Subtopic 2 > Subtopic 3 > Subtopic 4), keywords, published status, importance score, SERP ranking, and AI search presence.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../
```
```python
brand_id = "a1b2c3d4-..."
response = requests.get(
f"{BASE_URL}/authority/{brand_id}/", headers=headers
)
hierarchy = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/`, { headers }
);
const hierarchy = await res.json();
```
**Response:**
```json
{
"brand_id": "a1b2c3d4-...",
"brand_name": "Floyi",
"is_uploaded": false,
"node_count": 142,
"hierarchy": [
{
"node_id": "f1a2b3c4-...",
"name": "best keyword research tools",
"type": "RESOURCE",
"source": "resources",
"parent_id": "d4e5f6a7-...",
"mt": "SEO Strategy",
"st2": "Keyword Research",
"st3": "Keyword Tools",
"st4": "best keyword research tools",
"keywords": ["best keyword research tools", "keyword research software", "top keyword tools"],
"keyword_count": 3,
"url_slug": "best-keyword-research-tools",
"published": true,
"importance": 82.3,
"priority_category": "Medium",
"serp_position": 4,
"serp_all_positions": [4, 12],
"aio_status": "cited",
"aimode_status": "mentioned",
"chatgpt_status": "N/A"
},
{
"node_id": "a5b6c7d8-...",
"name": "SEO Strategy",
"type": "PILLAR",
"mt": "SEO Strategy",
"st2": "SEO Strategy",
"st3": "SEO Strategy",
"st4": "SEO Strategy",
"keywords": ["seo strategy", "seo planning", "search engine optimization strategy"],
"keyword_count": 3,
"url_slug": "seo-strategy",
"published": false,
"importance": 95.1,
"priority_category": "High",
"serp_position": null,
"serp_all_positions": [],
"aio_status": "not_present",
"aimode_status": "N/A",
"chatgpt_status": "N/A"
}
],
"created_at": "2026-01-20T12:00:00Z",
"updated_at": "2026-02-18T16:00:00Z"
}
```
**Hierarchy node fields:**
| Field | Type | Description |
| --- | --- | --- |
| `node_id` | UUID | Unique identifier for this topic node |
| `name` | string | Topic name (reflects any renames from the Organizer) |
| `type` | string | Hierarchy level: `PILLAR`, `HUB`, `BRANCH`, or `RESOURCE`. Architecture nodes use uppercase; resource nodes use lowercase. |
| `source` | string | Node origin: `"architecture"` (site architecture pages) or `"resources"` (topical map content) |
| `parent_id` | UUID or null | Parent node ID for building tree structures. `null` for root-level pillars. |
| `mt` | string | Main Topic (level 1) |
| `st2` | string | Subtopic 2 (level 2) |
| `st3` | string | Subtopic 3 (level 3) |
| `st4` | string | Subtopic 4 (level 4) |
| `keywords` | string[] | All keywords in this topic cluster |
| `keyword_count` | integer | Number of keywords in this cluster |
| `url_slug` | string | Suggested URL slug for the centroid keyword |
| `published` | boolean | Whether content has been published for this topic |
| `importance` | float | Importance score (0 to 100) based on topical authority analysis. Matches the score shown in the Floyi dashboard. |
| `priority_category` | string | Priority bucket: `High`, `Medium`, or `Low` |
| `serp_position` | integer or null | Your brand's best SERP ranking position (1-based) for this topic. `null` if not ranking. |
| `serp_all_positions` | integer[] | All SERP positions where your brand ranks for this topic |
| `aio_status` | string | Your brand's presence in Google AI Overviews: `cited`, `mentioned`, `not_present`, or `N/A` (not tracked) |
| `aimode_status` | string | Your brand's presence in Google AI Mode: `mentioned_cited`, `cited`, `mentioned`, `not_present`, or `N/A` |
| `chatgpt_status` | string | Your brand's presence in ChatGPT Search: `mentioned_cited`, `cited`, `mentioned`, `not_present`, or `N/A` |
:::tip
**Building a tree:** Use `parent_id` to build parent-child relationships. Alternatively, group nodes by `mt` (pillars), then `st2` (hubs), then `st3` (branches), then `st4` (resources).
**Filtering by source:** Add `?source=architecture` or `?source=resources` to return only nodes of that type. Without this parameter, both sources are returned.
**AI presence statuses:** `cited` means your URL appears in source links, `mentioned` means your brand name appears in the AI-generated text, `mentioned_cited` means both, `not_present` means the AI response exists but your brand is absent, and `N/A` means tracking has not been enabled or no AI response has been captured for this topic.
:::
#### Get SERP Data for a Node
```
GET /api/v1/authority/{brand_id}/serp-data/{node_id}/
```
Returns all stored SERP (Search Engine Results Page) results for a specific topic node. Use this to see which competitor pages rank for a topic before generating a brief. The `node_id` comes from the hierarchy response above.
:::note
This endpoint returns **all** stored SERP data without filtering. Your AI agent or workflow should select which competitors are most relevant for the brief.
:::
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../serp-data/f1a2b3c4-.../
```
```python
brand_id = "a1b2c3d4-..."
node_id = "f1a2b3c4-..."
response = requests.get(
f"{BASE_URL}/authority/{brand_id}/serp-data/{node_id}/",
headers=headers,
)
serp_data = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const nodeId = "f1a2b3c4-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/serp-data/${nodeId}/`,
{ headers },
);
const serpData = await res.json();
```
**Response:**
```json
{
"node_id": "f1a2b3c4-...",
"keyword": "best keyword research tools",
"serp_results": [
{
"position": 1,
"url": "https://ahrefs.com/blog/keyword-research-tools/",
"title": "12 Best Keyword Research Tools (Free & Paid)",
"snippet": "We tested and reviewed the best keyword research tools..."
},
{
"position": 2,
"url": "https://backlinko.com/best-keyword-research-tools",
"title": "Best Keyword Research Tools in 2026",
"snippet": "A hands-on comparison of the top keyword tools..."
}
],
"total_results": 10,
"serp_updated_at": "2026-02-15T12:00:00Z",
"snapshot_date": "2026-02-15"
}
```
**SERP result fields:**
| Field | Type | Description |
| --- | --- | --- |
| `position` | integer | Rank position in Google search results |
| `url` | string | URL of the ranking page |
| `title` | string | Page title from the SERP |
| `snippet` | string | Description snippet from the SERP |
**Error responses:**
| Status | Cause |
| --- | --- |
| `404 Not Found` | Node not found in the hierarchy, or no SERP data available for this node |
#### Toggle Published Status
```
PATCH /api/v1/authority/{brand_id}/nodes/{node_id}/published/
```
**Scope required:** `authority:write`
Marks a topic node as published or unpublished. This updates the topical authority coverage tracking. Use this after you publish content for a topic to keep your authority metrics accurate.
**Request body:**
```json
{
"published": true
}
```
**Required fields:** `published` (boolean)
```bash
curl -X PATCH \
-H "X-API-Key: fyi_live_your_integration_key" \
-H "Content-Type: application/json" \
-d '{"published": true}' \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../nodes/f1a2b3c4-.../published/
```
```python
brand_id = "a1b2c3d4-..."
node_id = "f1a2b3c4-..."
response = requests.patch(
f"{BASE_URL}/authority/{brand_id}/nodes/{node_id}/published/",
headers=headers,
json={"published": True},
)
result = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const nodeId = "f1a2b3c4-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/nodes/${nodeId}/published/`,
{
method: "PATCH",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ published: true }),
},
);
const result = await res.json();
```
**Response:**
```json
{
"node_id": "f1a2b3c4-...",
"published": true,
"message": "Published status updated."
}
```
After updating, Floyi automatically recalculates coverage rollups for the topical authority view.
**Error responses:**
| Status | Cause |
| --- | --- |
| `400 Bad Request` | Invalid `node_id` format (must be a valid UUID), missing `published` field, or brand not in the `TOPICAL_AUTHORITY` stage |
| `404 Not Found` | Map not found or you do not have access |
---
### Authority Keywords
**Scope required:** `authority:read` (GET), `authority:write` (POST, DELETE)
Manage keywords (anchor texts) on individual nodes in the authority hierarchy. Keywords are used for internal linking anchor text suggestions. They come from three sources:
- **`map`** - Synced automatically from the topical map clustering data. Cannot be deleted via API.
- **`ai`** - Generated by AI (via the Floyi dashboard). Can be deleted.
- **`user`** - Manually added via API, dashboard, or created by combine operations. Can be deleted.
#### List Keywords
```
GET /api/v1/authority/{brand_id}/nodes/{node_id}/keywords/
```
Returns all keywords for a specific node. Optionally filter by source.
| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `brand_id` | path | UUID | Yes | The brand (authority map) ID |
| `node_id` | path | UUID | Yes | The node ID |
| `source` | query | string | No | Filter by source: `map`, `ai`, or `user` |
```bash
# List all keywords for a node
curl -s "https://api.floyi.com/api/v1/authority/{brand_id}/nodes/{node_id}/keywords/" \
-H "X-API-Key: fyi_live_your_key"
# Filter by source
curl -s "https://api.floyi.com/api/v1/authority/{brand_id}/nodes/{node_id}/keywords/?source=user" \
-H "X-API-Key: fyi_live_your_key"
```
```python
res = requests.get(
f"{BASE}/api/v1/authority/{brand_id}/nodes/{node_id}/keywords/",
headers=headers,
params={"source": "user"}, # optional
)
keywords = res.json()["keywords"]
```
```javascript
const res = await fetch(
`${BASE}/api/v1/authority/${brandId}/nodes/${nodeId}/keywords/`,
{ headers: { "X-API-Key": apiKey } }
);
const { keywords } = await res.json();
```
**Response:**
```json
{
"_meta": { "description": "Lists all keywords (anchor texts) for a specific node..." },
"node_id": "a1b2c3d4-...",
"count": 5,
"keywords": [
{
"id": 142,
"keyword": "topical authority seo",
"source": "map",
"search_volume": 1200,
"cpc_value": "3.50",
"created_at": "2025-10-15T14:30:00Z"
},
{
"id": 143,
"keyword": "topic cluster strategy",
"source": "ai",
"search_volume": 880,
"cpc_value": "2.10",
"created_at": "2025-10-16T09:00:00Z"
},
{
"id": 150,
"keyword": "content hub planning",
"source": "user",
"search_volume": null,
"cpc_value": null,
"created_at": "2025-11-01T12:00:00Z"
}
]
}
```
#### Add Keywords
```
POST /api/v1/authority/{brand_id}/nodes/{node_id}/keywords/
```
Add one or more keywords to a node. Supports comma-separated input for bulk adds. Keywords are normalized to lowercase. Duplicates (case-insensitive) are skipped and reported.
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `keywords` | string | Yes | One or more keywords, comma-separated (e.g. `"seo tools, keyword research"`) |
```bash
curl -s -X POST "https://api.floyi.com/api/v1/authority/{brand_id}/nodes/{node_id}/keywords/" \
-H "X-API-Key: fyi_live_your_key" \
-H "Content-Type: application/json" \
-d '{"keywords": "seo tools, keyword research, serp analysis"}'
```
```python
res = requests.post(
f"{BASE}/api/v1/authority/{brand_id}/nodes/{node_id}/keywords/",
headers=headers,
json={"keywords": "seo tools, keyword research, serp analysis"},
)
created = res.json()["keywords"]
```
```javascript
const res = await fetch(
`${BASE}/api/v1/authority/${brandId}/nodes/${nodeId}/keywords/`,
{
method: "POST",
headers: { "X-API-Key": apiKey, "Content-Type": "application/json" },
body: JSON.stringify({ keywords: "seo tools, keyword research, serp analysis" }),
}
);
const { keywords } = await res.json();
```
**Response (201 Created):**
```json
{
"_meta": { "description": "Add one or more keywords to a node..." },
"node_id": "a1b2c3d4-...",
"created_count": 2,
"keywords": [
{
"id": 160,
"keyword": "seo tools",
"source": "user",
"search_volume": null,
"cpc_value": null,
"created_at": "2025-11-02T10:00:00Z"
},
{
"id": 161,
"keyword": "serp analysis",
"source": "user",
"search_volume": null,
"cpc_value": null,
"created_at": "2025-11-02T10:00:00Z"
}
],
"duplicates_skipped": [
{ "keyword": "keyword research", "existing_source": "map" }
]
}
```
:::note
If **all** keywords already exist, the response is `409 Conflict` with `duplicates_skipped` details.
:::
**Error responses:**
| Status | Cause |
| --- | --- |
| `400 Bad Request` | Missing or empty `keywords` field |
| `404 Not Found` | Map not found or you do not have access |
| `409 Conflict` | All submitted keywords already exist on this node |
#### Delete a Keyword
```
DELETE /api/v1/authority/{brand_id}/nodes/{node_id}/keywords/{keyword_id}/
```
Delete a keyword by its ID. User-added, AI-generated, and combine-created keywords can all be deleted. Only original map-sourced keywords (synced from clustering data) are protected.
| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `brand_id` | path | UUID | Yes | The brand (authority map) ID |
| `node_id` | path | UUID | Yes | The node ID |
| `keyword_id` | path | integer | Yes | The keyword ID (from the `id` field in list response) |
```bash
curl -s -X DELETE "https://api.floyi.com/api/v1/authority/{brand_id}/nodes/{node_id}/keywords/160/" \
-H "X-API-Key: fyi_live_your_key"
```
```python
res = requests.delete(
f"{BASE}/api/v1/authority/{brand_id}/nodes/{node_id}/keywords/160/",
headers=headers,
)
```
```javascript
const res = await fetch(
`${BASE}/api/v1/authority/${brandId}/nodes/${nodeId}/keywords/160/`,
{ method: "DELETE", headers: { "X-API-Key": apiKey } }
);
```
**Response:**
```json
{
"_meta": { "description": "Delete a keyword from a node by its ID..." },
"deleted": true,
"keyword_id": 160,
"keyword": "seo tools"
}
```
**Error responses:**
| Status | Cause |
| --- | --- |
| `403 Forbidden` | Attempted to delete a `map`-sourced keyword |
| `404 Not Found` | Keyword not found, or map/node not accessible |
---
### Authority Briefs
**Scope required:** `authority:read` (GET), `authority:write` (POST)
Authority briefs are linked to topics in your authority hierarchy. Unlike [standalone briefs](#content-briefs) (which accept freeform `query_text`), authority briefs require a `node_id` from the hierarchy. The topic name, search intent, and content context are derived from the node automatically.
#### List Authority Briefs
```
GET /api/v1/authority/{brand_id}/briefs/
```
Returns all authority-linked content briefs for a brand.
**Query parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `status` | string | Filter by brief status (e.g., `COMPLETE`, `PENDING`) |
| `search` | string | Search by topic/query text or generated title (case-insensitive) |
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../briefs/
# Filter by status
curl -H "X-API-Key: fyi_live_your_key_here" \
"https://api.floyi.com/api/v1/authority/a1b2c3d4-.../briefs/?status=COMPLETE"
```
```python
brand_id = "a1b2c3d4-..."
response = requests.get(
f"{BASE_URL}/authority/{brand_id}/briefs/", headers=headers
)
briefs = response.json()
# Filter by status
response = requests.get(
f"{BASE_URL}/authority/{brand_id}/briefs/",
headers=headers,
params={"status": "COMPLETE"},
)
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/briefs/`, { headers }
);
const briefs = await res.json();
// Filter by status
const filteredRes = await fetch(
`${BASE_URL}/authority/${brandId}/briefs/?status=COMPLETE`,
{ headers },
);
```
**Response:**
```json
{
"brand_id": "a1b2c3d4-...",
"brand_name": "Floyi",
"results": [
{
"id": "b5c6d7e8-...",
"query_text": "best keyword research tools",
"brand_name": "Floyi",
"status": "COMPLETE",
"generated_title": "Best Keyword Research Tools in 2026",
"generated_meta_description": "Discover the top keyword research tools...",
"created_at": "2026-02-10T08:00:00Z",
"updated_at": "2026-02-10T08:15:00Z"
}
]
}
```
#### Get Authority Brief Details
```
GET /api/v1/authority/{brand_id}/briefs/{id}/
```
Returns the full brief including `result_json`, `curated_brief_json`, `input_params`, and `topic_node` linkage to the authority hierarchy.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../briefs/b5c6d7e8-.../
```
```python
brand_id = "a1b2c3d4-..."
brief_id = "b5c6d7e8-..."
response = requests.get(
f"{BASE_URL}/authority/{brand_id}/briefs/{brief_id}/",
headers=headers,
)
brief = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const briefId = "b5c6d7e8-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/briefs/${briefId}/`,
{ headers },
);
const brief = await res.json();
```
**Response:**
```json
{
"id": "b5c6d7e8-...",
"query_text": "best keyword research tools",
"brand_name": "Floyi",
"status": "COMPLETE",
"generated_title": "Best Keyword Research Tools in 2026",
"generated_meta_description": "Discover the top keyword research tools...",
"result_json": { ... },
"curated_brief_json": { ... },
"input_params": { ... },
"topic_node": "f1a2b3c4-...",
"created_at": "2026-02-10T08:00:00Z",
"updated_at": "2026-02-10T08:15:00Z"
}
```
**Detail-only fields:**
| Field | Type | Description |
| --- | --- | --- |
| `result_json` | object | The raw brief output from the AI agent |
| `curated_brief_json` | object | The user-edited version (if customized). `null` if no edits. |
| `input_params` | object | Original request parameters including `node_id`, `brand_id`, `selected_serp_data` |
| `topic_node` | UUID | The authority hierarchy node this brief is linked to |
#### Check Authority Brief Status
```
GET /api/v1/authority/{brand_id}/briefs/{id}/status/
```
Returns just the status of an authority brief. Useful for polling during generation.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../briefs/b5c6d7e8-.../status/
```
```python
brand_id = "a1b2c3d4-..."
brief_id = "b5c6d7e8-..."
response = requests.get(
f"{BASE_URL}/authority/{brand_id}/briefs/{brief_id}/status/",
headers=headers,
)
status = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const briefId = "b5c6d7e8-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/briefs/${briefId}/status/`,
{ headers },
);
const status = await res.json();
```
**Response:**
```json
{
"id": "b5c6d7e8-...",
"status": "COMPLETE",
"query_text": "best keyword research tools",
"generated_title": "Best Keyword Research Tools in 2026",
"topic_node": "f1a2b3c4-..."
}
```
#### Generate Authority Brief
```
POST /api/v1/authority/{brand_id}/briefs/generate/
```
Triggers content brief generation for a topic from the authority hierarchy. The topic must exist in the brand's hierarchy - use `GET /api/v1/authority/{brand_id}/` to browse available topics and get `node_id` values.
Returns immediately with a `202 Accepted` response. Poll the status endpoint for progress.
**Request body:**
```json
{
"node_id": "f1a2b3c4-...",
"ai_model_id": "gpt-5-mini"
}
```
**Required fields:** `node_id`
**Optional fields:**
| Field | Type | Description |
| --- | --- | --- |
| `selected_serp_data` | object[] | SERP competitor pages to analyze (max 15, each must include `url`). Auto-fetched from node's stored SERP data if omitted. |
| `user_provided_keywords` | string[] | Additional keywords to include in the brief |
| `internal_link_suggestions` | object[] | Internal links to suggest (each: `url`, `anchor_text`) |
| `ai_model_id` | string | AI model to use (e.g. `"gpt-5-mini"`). Uses default if not specified. |
:::tip
**How it works:** First call `GET /api/v1/authority/{brand_id}/` to get the topic hierarchy. Pick a topic and use its `node_id` in the generate request. The API automatically derives the topic name, search intent, and content context from the hierarchy node. If `selected_serp_data` is omitted, SERP data is auto-fetched from the node's stored data.
:::
:::tip
Use `GET /api/v1/authority/{brand_id}/serp-data/{node_id}/` to preview available SERP data before generating a brief, so you or your AI agent can choose which competitors to include.
:::
```bash
# Minimal (topic name, SERP data, and context all derived from the node)
curl -X POST \
-H "X-API-Key: fyi_live_your_integration_key" \
-H "Content-Type: application/json" \
-d '{"node_id": "f1a2b3c4-..."}' \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../briefs/generate/
# With custom SERP data (you choose which competitors to analyze)
curl -X POST \
-H "X-API-Key: fyi_live_your_integration_key" \
-H "Content-Type: application/json" \
-d '{
"node_id": "f1a2b3c4-...",
"selected_serp_data": [
{"url": "https://example.com", "title": "Example", "snippet": "..."}
]
}' \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../briefs/generate/
```
```python
brand_id = "a1b2c3d4-..."
# Minimal
response = requests.post(
f"{BASE_URL}/authority/{brand_id}/briefs/generate/",
headers=headers,
json={"node_id": "f1a2b3c4-..."},
)
brief = response.json()
# With custom SERP data
response = requests.post(
f"{BASE_URL}/authority/{brand_id}/briefs/generate/",
headers=headers,
json={
"node_id": "f1a2b3c4-...",
"selected_serp_data": [
{"url": "https://example.com", "title": "Example", "snippet": "..."}
],
},
)
```
```javascript
const brandId = "a1b2c3d4-...";
// Minimal
const res = await fetch(
`${BASE_URL}/authority/${brandId}/briefs/generate/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ node_id: "f1a2b3c4-..." }),
},
);
const brief = await res.json();
// With custom SERP data
const res2 = await fetch(
`${BASE_URL}/authority/${brandId}/briefs/generate/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
node_id: "f1a2b3c4-...",
selected_serp_data: [
{ url: "https://example.com", title: "Example", snippet: "..." },
],
}),
},
);
```
**Response (202 Accepted):**
```json
{
"id": "b5c6d7e8-...",
"status": "PENDING",
"query_text": "best keyword research tools",
"brand_name": "Floyi",
"node_id": "f1a2b3c4-...",
"message": "Brief generation started. Poll /api/v1/authority/{brand_id}/briefs/{id}/status/ for progress."
}
```
:::tip
After generating, poll `GET /api/v1/authority/{brand_id}/briefs/{id}/status/` every 10-15 seconds until the status changes to `COMPLETE`. Brief generation typically takes 1-3 minutes.
:::
**Error responses:**
| Status | Cause |
| --- | --- |
| `400 Bad Request` | Validation error (SERP entry missing `url`, or no SERP data available), or brand not in the `TOPICAL_AUTHORITY` stage |
| `402 Payment Required` | Insufficient credits |
| `404 Not Found` | Brand not found, node not found in hierarchy, or no hierarchy exists |
**404 - Node not in hierarchy:**
```json
{
"detail": "Topic node not found in the current authority hierarchy. Use GET /api/v1/authority/{brand_id}/ to browse valid topics."
}
```
**400 - No SERP data available:**
```json
{
"detail": "No SERP data available for this topic. Please provide selected_serp_data or ensure SERP data has been collected for this topic in the topical map."
}
```
---
### Authority Articles
**Scope required:** `authority:read` (GET), `authority:write` (POST)
Authority articles are linked to topics in your authority hierarchy via `topic_node`. Unlike [standalone articles](#content-articles), authority articles are created from authority briefs and maintain the hierarchy linkage throughout the workflow.
#### List Authority Articles
```
GET /api/v1/authority/{brand_id}/articles/
```
Returns all authority-linked articles for a brand.
**Query parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `search` | string | Search by article title (case-insensitive) |
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../articles/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.get(
f"{BASE_URL}/authority/{brand_id}/articles/",
headers=headers,
)
articles = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/articles/`,
{ headers },
);
const articles = await res.json();
```
**Response:**
```json
{
"brand_id": "a1b2c3d4-...",
"brand_name": "Floyi",
"results": [
{
"id": "c7d8e9f0-...",
"title": "Best Keyword Research Tools in 2026",
"brand_id": "a1b2c3d4-...",
"brand_name": "Floyi",
"topic_node": "f1a2b3c4-...",
"machine_state": "draft_done",
"editorial_state": "draft",
"created_at": "2026-02-12T09:00:00Z",
"updated_at": "2026-02-14T11:00:00Z"
}
]
}
```
#### Get Authority Article Details
```
GET /api/v1/authority/{brand_id}/articles/{id}/
```
Returns the full article including brief reference, topic_node linkage, and all draft sections with their content.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../articles/c7d8e9f0-.../
```
```python
brand_id = "a1b2c3d4-..."
article_id = "c7d8e9f0-..."
response = requests.get(
f"{BASE_URL}/authority/{brand_id}/articles/{article_id}/",
headers=headers,
)
article = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const articleId = "c7d8e9f0-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/articles/${articleId}/`,
{ headers },
);
const article = await res.json();
```
**Response:**
```json
{
"id": "c7d8e9f0-...",
"title": "Best Keyword Research Tools in 2026",
"brand_id": "a1b2c3d4-...",
"brand_name": "Floyi",
"brief_id": "b5c6d7e8-...",
"topic_node": "f1a2b3c4-...",
"machine_state": "draft_done",
"editorial_state": "draft",
"additional_directions": null,
"sections": [
{
"id": "d1e2f3a4-...",
"position": 0,
"heading": "Introduction",
"status": "approved",
"content": "Keyword research is the foundation of any successful SEO strategy...",
"ai_draft": "Keyword research is the foundation of any successful SEO strategy...",
"word_count_target": 200
},
{
"id": "e2f3a4b5-...",
"position": 1,
"heading": "Top Keyword Research Tools Compared",
"status": "approved",
"content": "Here are the best keyword research tools for 2026...",
"ai_draft": "Here are the best keyword research tools for 2026...",
"word_count_target": 800
}
],
"created_at": "2026-02-12T09:00:00Z",
"updated_at": "2026-02-14T11:00:00Z"
}
```
**Section fields:**
| Field | Type | Description |
| --- | --- | --- |
| `id` | UUID | Section identifier |
| `position` | integer | Order position (0-based) |
| `heading` | string | Section heading |
| `status` | string | Draft status: `not_started`, `drafting`, `approved`, `needs_attention` |
| `content` | string | The section's current text as the app renders it - the polished revision when one exists, then any human revision, then the AI draft - with internal links resolved to full URLs. Read this field. |
| `ai_draft` | string or null | The raw AI-generated first draft for this section, kept for backward compatibility. May lag behind `content`. |
| `word_count_target` | integer or null | Target word count for this section |
#### Check Authority Article Status
```
GET /api/v1/authority/{brand_id}/articles/{id}/status/
```
Returns generation progress including section-level status.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../articles/c7d8e9f0-.../status/
```
```python
brand_id = "a1b2c3d4-..."
article_id = "c7d8e9f0-..."
response = requests.get(
f"{BASE_URL}/authority/{brand_id}/articles/{article_id}/status/",
headers=headers,
)
status = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const articleId = "c7d8e9f0-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/articles/${articleId}/status/`,
{ headers },
);
const status = await res.json();
```
**Response:**
```json
{
"id": "c7d8e9f0-...",
"machine_state": "in_progress",
"topic_node": "f1a2b3c4-...",
"sections_total": 8,
"sections_approved": 3,
"sections_drafting": 2,
"sections_not_started": 3,
"sections_needs_attention": 0,
"completion_percentage": 37.5,
"specialists_running": true,
"specialists_complete": false
}
```
#### Generate Authority Article Draft from Brief
```
POST /api/v1/authority/{brand_id}/articles/generate/
```
Creates a new article from a completed authority brief and immediately starts AI draft generation - one step instead of two. The brief must be in `COMPLETE` or `PARTIAL_COMPLETE` status, must be an authority brief (not standalone), and must have generated sections. The article inherits the `topic_node` linkage from the brief.
**Request body:**
```json
{
"brief_id": "b5c6d7e8-...",
"ai_model_id": "claude-sonnet-4",
"intent": "human",
"specialists": {
"research_agent": true,
"intro_key_takeaways": true,
"research_mode": "basic"
}
}
```
**Required fields:** `brief_id`, `ai_model_id`
**Optional fields:** `intent`, `specialists` (same options as [standalone article generation](#generate-draft-from-brief))
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_integration_key" \
-H "Content-Type: application/json" \
-d '{"brief_id": "b5c6d7e8-...", "ai_model_id": "claude-sonnet-4"}' \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../articles/generate/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/authority/{brand_id}/articles/generate/",
headers=headers,
json={
"brief_id": "b5c6d7e8-...",
"ai_model_id": "claude-sonnet-4",
},
)
article = response.json()
# article["id"] -> use for status polling
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/articles/generate/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
brief_id: "b5c6d7e8-...",
ai_model_id: "claude-sonnet-4",
}),
},
);
const article = await res.json();
// article.id -> use for status polling
```
**Response (202 Accepted):**
```json
{
"id": "c7d8e9f0-...",
"brief_id": "b5c6d7e8-...",
"title": "Best Keyword Research Tools in 2026",
"topic_node": "f1a2b3c4-...",
"task_id": "e1f2a3b4-...",
"status": "generating",
"message": "Article created and draft generation started. Poll /api/v1/authority/{brand_id}/articles/{id}/status/ for progress."
}
```
:::tip
After triggering generation, poll `GET /api/v1/authority/{brand_id}/articles/{id}/status/` every 15-30 seconds. Draft generation typically takes 3-10 minutes depending on sections and specialists enabled.
:::
**Error responses:**
| Status | Cause |
| --- | --- |
| `400 Bad Request` | `brief_id` or `ai_model_id` missing, brief not complete, brief is not an authority brief, brief has no sections, or brand not in the `TOPICAL_AUTHORITY` stage |
| `402 Payment Required` | Insufficient credits for draft or specialist agents |
| `404 Not Found` | Brief or brand not found, or you do not have access |
#### Regenerate Authority Article Draft
```
POST /api/v1/authority/{brand_id}/articles/{id}/generate/
```
Regenerates draft for an existing authority article. Creates a new version, re-syncs sections from the brief, resets all sections, and generates fresh content. Optionally accepts a different `brief_id` to switch briefs (must also be an authority brief). The `topic_node` linkage is updated if the new brief has a different node.
**Request body:**
```json
{
"ai_model_id": "claude-sonnet-4",
"brief_id": "b5c6d7e8-...",
"intent": "human",
"specialists": {
"research_agent": true,
"intro_key_takeaways": true,
"research_mode": "basic"
}
}
```
**Required fields:** `ai_model_id`
**Optional fields:** `brief_id` (switch to a different authority brief), `intent`, `specialists` (same options as [standalone article generation](#generate-draft-from-brief))
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_integration_key" \
-H "Content-Type: application/json" \
-d '{"ai_model_id": "claude-sonnet-4"}' \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../articles/c7d8e9f0-.../generate/
```
```python
brand_id = "a1b2c3d4-..."
article_id = "c7d8e9f0-..."
response = requests.post(
f"{BASE_URL}/authority/{brand_id}/articles/{article_id}/generate/",
headers=headers,
json={"ai_model_id": "claude-sonnet-4"},
)
result = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const articleId = "c7d8e9f0-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/articles/${articleId}/generate/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ ai_model_id: "claude-sonnet-4" }),
},
);
const result = await res.json();
```
**Response (202 Accepted):**
```json
{
"id": "c7d8e9f0-...",
"brief_id": "b5c6d7e8-...",
"title": "Best Keyword Research Tools in 2026",
"topic_node": "f1a2b3c4-...",
"task_id": "e1f2a3b4-...",
"status": "regenerating",
"message": "Draft regeneration started. Poll /api/v1/authority/{brand_id}/articles/{id}/status/ for progress."
}
```
**Error responses:**
| Status | Cause |
| --- | --- |
| `400 Bad Request` | Missing `ai_model_id`, or brand not in the `TOPICAL_AUTHORITY` stage |
| `402 Payment Required` | Insufficient credits for draft or specialist agents |
| `409 Conflict` | Article generation already in progress |
---
### User Profile, Credits, Teams & Audit Logs
**Scope required:** `user:read`
#### Get Your Profile
```
GET /api/v1/me/profile/
```
Returns the authenticated user's profile.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/me/profile/
```
```python
response = requests.get(f"{BASE_URL}/me/profile/", headers=headers)
profile = response.json()
```
```javascript
const res = await fetch(`${BASE_URL}/me/profile/`, { headers });
const profile = await res.json();
```
**Response:**
```json
{
"uuid": "e1f2a3b4-...",
"email": "user@example.com",
"first_name": "Jane",
"last_name": "Doe",
"subscription_plan": "Scale Plan",
"subscription_interval": "monthly",
"account_status": "active",
"date_joined": "2025-06-01T00:00:00Z",
"last_active": "2026-02-21T09:30:00Z"
}
```
#### Get Your Credit Balance
```
GET /api/v1/me/credits/
```
Returns your current credit balance across all credit types.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/me/credits/
```
```python
response = requests.get(f"{BASE_URL}/me/credits/", headers=headers)
credits = response.json()
```
```javascript
const res = await fetch(`${BASE_URL}/me/credits/`, { headers });
const credits = await res.json();
```
**Response:**
```json
{
"free_credits": 0,
"monthly_credits": 450,
"payg_credits": 100,
"total_credits": 550,
"monthly_credits_last_reset": "2026-02-01T00:00:00Z",
"subscription_renewal_date": "2026-03-01T00:00:00Z"
}
```
#### List Your Teams
```
GET /api/v1/me/teams/
```
Returns all teams you are an active member of. Use the team `id` as the `X-Team-ID` header value to access that team's workspace data (see [Workspace Selection](#workspace-selection-x-team-id)).
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/me/teams/
```
```python
response = requests.get(f"{BASE_URL}/me/teams/", headers=headers)
teams = response.json()
```
```javascript
const res = await fetch(`${BASE_URL}/me/teams/`, { headers });
const teams = await res.json();
```
**Response:**
```json
{
"_meta": { "description": "Lists all teams the authenticated user is an active member of..." },
"results": [
{
"team": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Acme Marketing",
"slug": "acme-marketing",
"plan_name": "Scale Plan",
"created_at": "2025-09-15T10:00:00Z"
},
"role": "owner",
"status": "active"
}
]
}
```
**Response fields:**
| Field | Description |
| --- | --- |
| `team.id` | The team UUID - use this as the `X-Team-ID` header value |
| `team.name` | Display name of the team |
| `team.slug` | URL-friendly team identifier |
| `role` | Your role in this team: `owner`, `admin`, or `member` |
| `status` | Membership status (always `active` in this response) |
---
### Standalone Clustering
The Clustering Tool lets you cluster any set of keywords by SERP URL overlap - no brand required. It fetches SERP data for each keyword, then groups keywords that share similar search results.
**Scope:** `clustering:read` (read), `clustering:write` (write)
#### List Clustering Reports
```
GET /api/v1/clustering/
```
Returns all standalone clustering reports.
```bash
curl -H "X-API-Key: fyi_live_your_key" \
https://api.floyi.com/api/v1/clustering/
```
```python
response = requests.get(f"{BASE_URL}/clustering/", headers=headers)
reports = response.json()
```
```javascript
const res = await fetch(`${BASE_URL}/clustering/`, { headers });
const reports = await res.json();
```
#### Get Clustering Report Details
```
GET /api/v1/clustering/{id}/
```
Returns full report with cluster results, keyword metrics, and SERP data timestamps.
```bash
curl -H "X-API-Key: fyi_live_your_key" \
https://api.floyi.com/api/v1/clustering/{id}/
```
```python
report_id = "abc-123"
response = requests.get(f"{BASE_URL}/clustering/{report_id}/", headers=headers)
report = response.json()
```
```javascript
const reportId = "abc-123";
const res = await fetch(`${BASE_URL}/clustering/${reportId}/`, { headers });
const report = await res.json();
```
#### Check Clustering Task Progress
```
GET /api/v1/clustering/{id}/status/
```
Polls the progress of a clustering task. Returns task state, progress percentage, and message.
```bash
curl -H "X-API-Key: fyi_live_your_key" \
https://api.floyi.com/api/v1/clustering/{id}/status/
```
```python
report_id = "abc-123"
response = requests.get(f"{BASE_URL}/clustering/{report_id}/status/", headers=headers)
status = response.json()
```
```javascript
const reportId = "abc-123";
const res = await fetch(`${BASE_URL}/clustering/${reportId}/status/`, { headers });
const status = await res.json();
```
**Response:**
```json
{
"_meta": { "description": "..." },
"id": "abc-123",
"status": "in_progress",
"state": "PENDING",
"progress": 45,
"message": "Fetching SERPs and clustering in progress..."
}
```
#### Get SERP Data for a Keyword
```
GET /api/v1/clustering/{id}/serp-data/?keyword=seo+tools
```
Returns stored SERP results for a specific keyword within a clustering report. Does not trigger live scraping.
```bash
curl -H "X-API-Key: fyi_live_your_key" \
"https://api.floyi.com/api/v1/clustering/{id}/serp-data/?keyword=seo+tools"
```
```python
report_id = "abc-123"
response = requests.get(
f"{BASE_URL}/clustering/{report_id}/serp-data/",
headers=headers,
params={"keyword": "seo tools"},
)
serp = response.json()
```
```javascript
const reportId = "abc-123";
const res = await fetch(
`${BASE_URL}/clustering/${reportId}/serp-data/?keyword=seo+tools`,
{ headers },
);
const serp = await res.json();
```
#### Create Report + Start Clustering
```
POST /api/v1/clustering/
```
Creates a new clustering report and starts SERP-based keyword clustering. Costs credits based on keyword count. Poll `GET /clustering/{id}/status/` for progress.
**Request body:**
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `report_name` | string | Yes | Name for this clustering report |
| `keywords` | string[] | Yes | List of keywords to cluster (max 10,000) |
| `country` | string | No | Country code for SERP data (default: `"us"`) |
| `location` | string | No | Location for SERP data (e.g. `"New York, NY"`) |
| `language` | string | No | Language code (default: `"en"`) |
| `overlap_percentage` | float | No | URL overlap threshold 0.2-0.9 (default: `0.4`) |
| `ai_model_id` | string | No | AI model to use (uses default if omitted) |
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"report_name": "SEO Tools Cluster",
"keywords": ["seo tools", "keyword research", "backlink checker", "rank tracker"],
"country": "us",
"overlap_percentage": 0.4
}' \
https://api.floyi.com/api/v1/clustering/
```
```python
response = requests.post(
f"{BASE_URL}/clustering/",
headers=headers,
json={
"report_name": "SEO Tools Cluster",
"keywords": ["seo tools", "keyword research", "backlink checker", "rank tracker"],
"country": "us",
"overlap_percentage": 0.4,
},
)
report = response.json()
# Poll report["id"] via /clustering/{id}/status/ for progress
```
```javascript
const res = await fetch(`${BASE_URL}/clustering/`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
report_name: "SEO Tools Cluster",
keywords: ["seo tools", "keyword research", "backlink checker", "rank tracker"],
country: "us",
overlap_percentage: 0.4,
}),
});
const report = await res.json();
// Poll report.id via /clustering/{id}/status/ for progress
```
**Response (202):**
```json
{
"_meta": { "description": "..." },
"id": "abc-123",
"report_name": "SEO Tools Cluster",
"status": "in_progress",
"task_id": "celery-task-id",
"group_id": "group-uuid",
"total_batches": 1,
"total_keywords": 4,
"message": "Clustering started. Poll /api/v1/clustering/{id}/status/ for progress."
}
```
**Errors:**
| Status | Meaning |
| --- | --- |
| 400 | No valid keywords provided |
| 402 | Insufficient credits |
#### Re-cluster with New Overlap
```
POST /api/v1/clustering/{id}/recluster/
```
Re-clusters keywords using existing SERP data with a new overlap percentage. No new SERP fetching, so no additional credit cost for SERPs.
**Request body:**
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `overlap_percentage` | float | Yes | New overlap threshold 0.2-0.9 |
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key" \
-H "Content-Type: application/json" \
-d '{"overlap_percentage": 0.6}' \
https://api.floyi.com/api/v1/clustering/{id}/recluster/
```
```python
report_id = "abc-123"
response = requests.post(
f"{BASE_URL}/clustering/{report_id}/recluster/",
headers=headers,
json={"overlap_percentage": 0.6},
)
result = response.json()
```
```javascript
const reportId = "abc-123";
const res = await fetch(
`${BASE_URL}/clustering/${reportId}/recluster/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ overlap_percentage: 0.6 }),
},
);
const result = await res.json();
```
**Errors:**
| Status | Meaning |
| --- | --- |
| 404 | Report not found |
| 409 | Clustering already in progress |
#### Delete a Clustering Report
```
DELETE /api/v1/clustering/{id}/
```
Permanently deletes a clustering report and all associated SERP data.
```bash
curl -X DELETE \
-H "X-API-Key: fyi_live_your_key" \
https://api.floyi.com/api/v1/clustering/{id}/
```
```python
report_id = "abc-123"
response = requests.delete(f"{BASE_URL}/clustering/{report_id}/", headers=headers)
# Returns 204 No Content on success
```
```javascript
const reportId = "abc-123";
const res = await fetch(
`${BASE_URL}/clustering/${reportId}/`,
{ method: "DELETE", headers },
);
// Returns 204 No Content on success
```
Returns `204 No Content` on success.
---
### Authority Clustering
Authority Clustering is the brand-tied version. Keywords are automatically extracted from the brand's topical research hierarchy - you don't provide them manually. Results feed into the topical map generation pipeline.
**Scope:** `clustering:read` (read), `clustering:write` (write)
#### Get Brand Clustering Results
```
GET /api/v1/authority/{brand_id}/clustering/
```
Returns the most recent clustering results for a brand, including cluster centroids, keyword associations, and metrics.
```bash
curl -H "X-API-Key: fyi_live_your_key" \
https://api.floyi.com/api/v1/authority/{brand_id}/clustering/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.get(
f"{BASE_URL}/authority/{brand_id}/clustering/",
headers=headers,
)
results = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/clustering/`,
{ headers },
);
const results = await res.json();
```
#### Check Brand Clustering Progress
```
GET /api/v1/authority/{brand_id}/clustering/status/
```
Polls the progress of a brand clustering task.
```bash
curl -H "X-API-Key: fyi_live_your_key" \
https://api.floyi.com/api/v1/authority/{brand_id}/clustering/status/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.get(
f"{BASE_URL}/authority/{brand_id}/clustering/status/",
headers=headers,
)
status = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/clustering/status/`,
{ headers },
);
const status = await res.json();
```
#### Get Brand SERP Data for a Keyword
```
GET /api/v1/authority/{brand_id}/clustering/serp-data/?keyword=seo+tools
```
Returns stored SERP results for a keyword from the brand's clustering data.
```bash
curl -H "X-API-Key: fyi_live_your_key" \
"https://api.floyi.com/api/v1/authority/{brand_id}/clustering/serp-data/?keyword=seo+tools"
```
```python
brand_id = "a1b2c3d4-..."
response = requests.get(
f"{BASE_URL}/authority/{brand_id}/clustering/serp-data/",
headers=headers,
params={"keyword": "seo tools"},
)
serp = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/clustering/serp-data/?keyword=seo+tools`,
{ headers },
);
const serp = await res.json();
```
#### Start Brand Clustering
```
POST /api/v1/authority/{brand_id}/clustering/start/
```
Starts SERP-based keyword clustering for a brand. Keywords are automatically extracted from the brand's topical research. Costs credits based on keyword count. Poll `GET /authority/{brand_id}/clustering/status/` for progress.
**Request body:**
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `country` | string | No | Country code for SERP data (default: `"us"`) |
| `location` | string | No | Location for SERP data |
| `language` | string | No | Language code (default: `"en"`) |
| `overlap_percentage` | float | No | URL overlap threshold 0.2-0.9 (default: `0.4`) |
| `ai_model_id` | string | No | AI model to use |
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key" \
-H "Content-Type: application/json" \
-d '{"country": "us", "overlap_percentage": 0.4}' \
https://api.floyi.com/api/v1/authority/{brand_id}/clustering/start/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/authority/{brand_id}/clustering/start/",
headers=headers,
json={"country": "us", "overlap_percentage": 0.4},
)
result = response.json()
# Poll via /authority/{brand_id}/clustering/status/ for progress
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/clustering/start/`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ country: "us", overlap_percentage: 0.4 }),
}
);
const result = await res.json();
// Poll via /authority/{brandId}/clustering/status/ for progress
```
**Response (202):**
```json
{
"_meta": { "description": "..." },
"brand_id": "abc-123",
"status": "in_progress",
"task_id": "celery-task-id",
"group_id": "group-uuid",
"total_batches": 3,
"total_keywords": 250,
"message": "Clustering started. Poll /api/v1/authority/{brand_id}/clustering/status/ for progress."
}
```
**Errors:**
| Status | Meaning |
| --- | --- |
| 400 | No keywords found in topical research, or brand not in the `CLUSTERING` stage |
| 402 | Insufficient credits |
| 404 | Brand not found |
| 409 | Clustering already in progress |
#### Re-cluster Brand with New Overlap
```
POST /api/v1/authority/{brand_id}/clustering/recluster/
```
Re-clusters a brand's keywords using existing SERP data with a new overlap percentage.
**Request body:**
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `overlap_percentage` | float | Yes | New overlap threshold 0.2-0.9 |
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key" \
-H "Content-Type: application/json" \
-d '{"overlap_percentage": 0.6}' \
https://api.floyi.com/api/v1/authority/{brand_id}/clustering/recluster/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/authority/{brand_id}/clustering/recluster/",
headers=headers,
json={"overlap_percentage": 0.6},
)
result = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/clustering/recluster/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ overlap_percentage: 0.6 }),
},
);
const result = await res.json();
```
**Errors:**
| Status | Meaning |
| --- | --- |
| 400 | Brand not in the `CLUSTERING` stage |
| 404 | Brand or clustering results not found |
| 409 | Clustering already in progress |
---
### Images
The Images API lets you analyze article content for optimal image placements, generate images using AI models, and retrieve the results. Images are scoped to individual articles.
**Scope:** `content:read` (read), `content:write` (write)
#### List Article Images
```
GET /api/v1/content/articles/{article_id}/images/
```
Returns all generated images for an article, including URLs, prompts, and placement metadata.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/content/articles/a1b2c3d4-.../images/
```
```python
article_id = "a1b2c3d4-..."
response = requests.get(
f"{BASE_URL}/content/articles/{article_id}/images/",
headers=headers,
)
images = response.json()
```
```javascript
const articleId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/content/articles/${articleId}/images/`,
{ headers },
);
const images = await res.json();
```
**Response:**
```json
{
"article_id": "a1b2c3d4-...",
"images": [
{
"id": "e5f6a7b8-...",
"image_url": "https://cdn.example.com/images/generated-image.png",
"alt_text": "Keyword research dashboard comparison",
"anchor_heading": "Top Keyword Research Tools Compared",
"prompt": "A clean, modern dashboard showing keyword research metrics...",
"model_used": "dall-e-3",
"inserted": true,
"created_at": "2026-03-15T10:30:00Z"
}
],
"free_images_remaining": 0
}
```
**Image fields:**
| Field | Type | Description |
| --- | --- | --- |
| `id` | UUID | Image identifier |
| `image_url` | string | URL of the generated image |
| `alt_text` | string | Alt text for the image |
| `anchor_heading` | string | The article heading where the image is placed |
| `prompt` | string | The prompt used to generate the image |
| `model_used` | string | The AI model that generated the image |
| `inserted` | boolean | Whether the image has been inserted into the article |
| `created_at` | datetime | When the image was generated |
#### List Image Models
```
GET /api/v1/content/articles/{article_id}/images/models/
```
Returns available image generation models with capabilities, supported sizes, and credit costs.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/content/articles/a1b2c3d4-.../images/models/
```
```python
article_id = "a1b2c3d4-..."
response = requests.get(
f"{BASE_URL}/content/articles/{article_id}/images/models/",
headers=headers,
)
models = response.json()
```
```javascript
const articleId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/content/articles/${articleId}/images/models/`,
{ headers },
);
const models = await res.json();
```
**Response:**
```json
{
"models": [
{
"model_id": "dall-e-3",
"display_name": "DALL-E 3",
"api_format": "openai",
"family": "dall-e",
"supported_sizes": ["1024x1024", "1792x1024", "1024x1792"],
"default_size": "1024x1024",
"supported_aspect_ratios": ["1:1", "16:9", "9:16"],
"credit_cost": 2
}
]
}
```
#### Analyze Image Placements
```
POST /api/v1/content/articles/{article_id}/images/analyze/
```
Analyzes the article's draft content and returns suggested image placements with AI-generated prompts. No credits are charged for analysis. The article must have generated draft content.
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/content/articles/a1b2c3d4-.../images/analyze/
```
```python
article_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/content/articles/{article_id}/images/analyze/",
headers=headers,
)
placements = response.json()
```
```javascript
const articleId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/content/articles/${articleId}/images/analyze/`,
{ method: "POST", headers },
);
const placements = await res.json();
```
**Response:**
```json
{
"placements": [
{
"anchor_heading": "Top Keyword Research Tools Compared",
"prompt": "A clean, modern dashboard showing keyword research metrics and competitor analysis...",
"alt_text": "Keyword research dashboard comparison",
"reasoning": "This section compares multiple tools - a visual comparison would help readers."
}
],
"free_images_remaining": 1
}
```
#### Generate Images
```
POST /api/v1/content/articles/{article_id}/images/generate/
```
Generates images for selected placements via a background task. The first image per article is free; additional images cost credits based on the model. Use the analyze endpoint first to get placement suggestions with prompts.
**Request body:**
```json
{
"placements": [
{
"anchor_heading": "Top Keyword Research Tools Compared",
"prompt": "A clean, modern dashboard showing keyword research metrics...",
"model_id": "dall-e-3",
"size_params": { "width": 1024, "height": 1024 },
"alt_text": "Keyword research dashboard comparison"
}
]
}
```
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"placements": [{"anchor_heading": "Top Tools", "prompt": "...", "model_id": "dall-e-3", "size_params": {"width": 1024, "height": 1024}, "alt_text": "..."}]}' \
https://api.floyi.com/api/v1/content/articles/a1b2c3d4-.../images/generate/
```
```python
article_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/content/articles/{article_id}/images/generate/",
headers=headers,
json={
"placements": [
{
"anchor_heading": "Top Keyword Research Tools Compared",
"prompt": "A clean dashboard showing keyword metrics...",
"model_id": "dall-e-3",
"size_params": {"width": 1024, "height": 1024},
"alt_text": "Keyword research dashboard comparison",
}
]
},
)
result = response.json()
task_id = result["task_id"]
```
```javascript
const articleId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/content/articles/${articleId}/images/generate/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
placements: [
{
anchor_heading: "Top Keyword Research Tools Compared",
prompt: "A clean dashboard showing keyword metrics...",
model_id: "dall-e-3",
size_params: { width: 1024, height: 1024 },
alt_text: "Keyword research dashboard comparison",
},
],
}),
},
);
const result = await res.json();
const taskId = result.task_id;
```
**Response (202 Accepted):**
```json
{
"task_id": "abc123-...",
"article_id": "a1b2c3d4-...",
"placement_count": 1,
"free_images_used": 1,
"paid_images": 0,
"credit_cost": 0,
"message": "Image generation started. Poll .../images/status/?task_id=abc123-... for progress."
}
```
**Errors:**
| Status | Meaning |
| --- | --- |
| 400 | No placements provided or unknown image model |
| 402 | Insufficient credits for paid images |
| 404 | Article not found |
#### Check Image Generation Status
```
GET /api/v1/content/articles/{article_id}/images/status/?task_id={task_id}
```
Polls the background image generation task. Returns status and progress information.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
"https://api.floyi.com/api/v1/content/articles/a1b2c3d4-.../images/status/?task_id=abc123-..."
```
```python
article_id = "a1b2c3d4-..."
task_id = "abc123-..."
response = requests.get(
f"{BASE_URL}/content/articles/{article_id}/images/status/",
headers=headers,
params={"task_id": task_id},
)
status = response.json()
```
```javascript
const articleId = "a1b2c3d4-...";
const taskId = "abc123-...";
const res = await fetch(
`${BASE_URL}/content/articles/${articleId}/images/status/?task_id=${taskId}`,
{ headers },
);
const status = await res.json();
```
**Response:**
```json
{
"task_id": "abc123-...",
"state": "SUCCESS",
"status": "completed",
"message": "Image generation completed.",
"result": { "images_generated": 1, "images_failed": 0 }
}
```
---
### WordPress
The WordPress API lets you publish articles directly to WordPress sites, manage site connections, and track publishing history. Publishing runs as a background task.
**Scope:** `content:read` (read), `content:write` (write)
#### List WordPress Connections
```
GET /api/v1/cms/wordpress/connections/
```
Returns all WordPress site connections for the current workspace, including status, capabilities, and detected SEO plugin.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/cms/wordpress/connections/
```
```python
response = requests.get(
f"{BASE_URL}/cms/wordpress/connections/",
headers=headers,
)
connections = response.json()
```
```javascript
const res = await fetch(
`${BASE_URL}/cms/wordpress/connections/`,
{ headers },
);
const connections = await res.json();
```
**Response:**
```json
{
"results": [
{
"id": "c1d2e3f4-...",
"site_name": "My Blog",
"site_url": "https://myblog.com",
"status": "active",
"capabilities": { "posts": true, "pages": true, "media": true },
"seo_plugin_slug": "yoast-seo",
"seo_plugin_version": "22.1",
"created_at": "2026-02-01T12:00:00Z"
}
]
}
```
#### List Publish Records
```
GET /api/v1/cms/wordpress/publish-records/
```
Returns WordPress publish records showing what has been published, where, and when. Filter by article or connection.
**Query parameters:** `?article_id=` `?connection_id=`
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
"https://api.floyi.com/api/v1/cms/wordpress/publish-records/?article_id=a1b2c3d4-..."
```
```python
response = requests.get(
f"{BASE_URL}/cms/wordpress/publish-records/",
headers=headers,
params={"article_id": "a1b2c3d4-..."},
)
records = response.json()
```
```javascript
const res = await fetch(
`${BASE_URL}/cms/wordpress/publish-records/?article_id=a1b2c3d4-...`,
{ headers },
);
const records = await res.json();
```
**Response:**
```json
{
"results": [
{
"id": 42,
"article_id": "a1b2c3d4-...",
"article_title": "Best Keyword Research Tools in 2026",
"site_name": "My Blog",
"site_url": "https://myblog.com",
"wp_post_id": 1234,
"wp_post_type": "post",
"wp_permalink": "https://myblog.com/best-keyword-research-tools/",
"wp_status": "publish",
"last_published_at": "2026-03-20T14:00:00Z",
"last_sync_at": "2026-03-20T14:00:00Z",
"needs_update": false,
"published_title": "Best Keyword Research Tools in 2026",
"published_slug": "best-keyword-research-tools",
"created_at": "2026-03-20T14:00:00Z",
"updated_at": "2026-03-20T14:00:00Z"
}
]
}
```
#### Publish Article to WordPress
```
POST /api/v1/cms/wordpress/publish/
```
Publishes a single article to a WordPress site. The publish runs as a background task - use the returned `task_id` to poll for completion.
**Request body:**
```json
{
"article_id": "a1b2c3d4-...",
"site_connection_id": "c1d2e3f4-...",
"status": "draft",
"post_type": "post",
"categories": [1, 2],
"tags": [5],
"seo_title": "Best Keyword Research Tools | Floyi",
"seo_description": "Compare the top keyword research tools for 2026...",
"include_schema": true
}
```
**Required fields:** `article_id`, `site_connection_id`
**Optional fields:** `status` (default `"draft"`), `post_type` (default `"post"`), `categories`, `tags`, `author_id`, `slug`, `seo_title`, `seo_description`, `seo_focus_keyword`, `include_schema`, `scheduled_date`
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"article_id": "a1b2c3d4-...", "site_connection_id": "c1d2e3f4-...", "status": "draft"}' \
https://api.floyi.com/api/v1/cms/wordpress/publish/
```
```python
response = requests.post(
f"{BASE_URL}/cms/wordpress/publish/",
headers=headers,
json={
"article_id": "a1b2c3d4-...",
"site_connection_id": "c1d2e3f4-...",
"status": "draft",
"seo_title": "Best Keyword Research Tools | Floyi",
},
)
result = response.json()
task_id = result["task_id"]
```
```javascript
const res = await fetch(
`${BASE_URL}/cms/wordpress/publish/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
article_id: "a1b2c3d4-...",
site_connection_id: "c1d2e3f4-...",
status: "draft",
}),
},
);
const result = await res.json();
const taskId = result.task_id;
```
**Response (202 Accepted):**
```json
{
"task_id": "wp-task-123-...",
"article_id": "a1b2c3d4-...",
"site_connection_id": "c1d2e3f4-...",
"message": "Publishing task queued. Poll .../task-status/?task_id=wp-task-123-... for progress."
}
```
**Errors:**
| Status | Meaning |
| --- | --- |
| 400 | Invalid request data or WordPress connection not active |
| 404 | Article or WordPress connection not found |
#### Bulk Publish Articles
```
POST /api/v1/cms/wordpress/bulk-publish/
```
Publishes up to 50 articles in a single request. Each article can target a different WordPress connection with its own publish settings. Runs as a single background task.
**Request body:**
```json
{
"articles": [
{
"article_id": "a1b2c3d4-...",
"site_connection_id": "c1d2e3f4-...",
"status": "draft"
},
{
"article_id": "b2c3d4e5-...",
"site_connection_id": "c1d2e3f4-...",
"status": "publish"
}
]
}
```
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"articles": [{"article_id": "a1b2c3d4-...", "site_connection_id": "c1d2e3f4-...", "status": "draft"}]}' \
https://api.floyi.com/api/v1/cms/wordpress/bulk-publish/
```
```python
response = requests.post(
f"{BASE_URL}/cms/wordpress/bulk-publish/",
headers=headers,
json={
"articles": [
{"article_id": "a1b2c3d4-...", "site_connection_id": "c1d2e3f4-...", "status": "draft"},
{"article_id": "b2c3d4e5-...", "site_connection_id": "c1d2e3f4-...", "status": "publish"},
]
},
)
result = response.json()
task_id = result["task_id"]
```
```javascript
const res = await fetch(
`${BASE_URL}/cms/wordpress/bulk-publish/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
articles: [
{ article_id: "a1b2c3d4-...", site_connection_id: "c1d2e3f4-...", status: "draft" },
{ article_id: "b2c3d4e5-...", site_connection_id: "c1d2e3f4-...", status: "publish" },
],
}),
},
);
const result = await res.json();
```
**Response (202 Accepted):**
```json
{
"task_id": "wp-bulk-456-...",
"article_count": 2,
"message": "Bulk publishing 2 articles. Poll .../task-status/?task_id=wp-bulk-456-... for progress."
}
```
#### Check Publish Task Status
```
GET /api/v1/cms/wordpress/task-status/?task_id={task_id}
```
Polls the status of a publish or bulk-publish background task.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
"https://api.floyi.com/api/v1/cms/wordpress/task-status/?task_id=wp-task-123-..."
```
```python
task_id = "wp-task-123-..."
response = requests.get(
f"{BASE_URL}/cms/wordpress/task-status/",
headers=headers,
params={"task_id": task_id},
)
status = response.json()
```
```javascript
const taskId = "wp-task-123-...";
const res = await fetch(
`${BASE_URL}/cms/wordpress/task-status/?task_id=${taskId}`,
{ headers },
);
const status = await res.json();
```
**Response:**
```json
{
"task_id": "wp-task-123-...",
"state": "SUCCESS",
"status": "completed",
"message": "Publishing completed.",
"result": { "wp_post_id": 1234, "wp_permalink": "https://myblog.com/best-keyword-research-tools/" }
}
```
---
### Content Guide
The Content Guide API lets you manage brand content guidelines - terminology rules, compliance policies, competitor mention policies, brand messaging rules, and boilerplate snippets. You can also trigger AI-powered generation of an entire content guide from brand profile data.
**Scope:** `content:read` (read), `content:write` (write)
#### Get Full Content Guide
```
GET /api/v1/content-guide/{brand_id}/
```
Returns all active content guide entries across all five categories for a brand.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/content-guide/a1b2c3d4-.../
```
```python
brand_id = "a1b2c3d4-..."
response = requests.get(
f"{BASE_URL}/content-guide/{brand_id}/",
headers=headers,
)
guide = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/content-guide/${brandId}/`,
{ headers },
);
const guide = await res.json();
```
**Response:**
```json
{
"brand_id": "a1b2c3d4-...",
"brand_name": "Floyi",
"terminology": [
{
"id": 1,
"term": "SEO tool",
"preferred_term": "content strategy platform",
"severity": "discouraged",
"note": "We position as a strategy platform, not a tool.",
"is_active": true,
"priority": 1,
"created_at": "2026-03-01T10:00:00Z",
"updated_at": "2026-03-01T10:00:00Z"
}
],
"compliance": [
{
"id": 1,
"name": "Health Claims Policy",
"rules_json": {
"banned_claims": ["guaranteed results"],
"required_disclosures": ["Results may vary"]
},
"is_active": true,
"priority": 1,
"created_at": "2026-03-01T10:00:00Z",
"updated_at": "2026-03-01T10:00:00Z"
}
],
"competitor_policies": [
{
"id": 1,
"competitor_name": "Clearscope",
"mention_policy": "neutral",
"comparison_notes": "Acknowledge strengths but highlight our closed-loop workflow.",
"is_active": true,
"priority": 1,
"created_at": "2026-03-01T10:00:00Z",
"updated_at": "2026-03-01T10:00:00Z"
}
],
"brand_messaging": [
{
"id": 1,
"rule_type": "messaging_pillar",
"content": "Topic-first strategy replaces the disconnected tool stack.",
"is_active": true,
"priority": 1,
"created_at": "2026-03-01T10:00:00Z",
"updated_at": "2026-03-01T10:00:00Z"
}
],
"boilerplate": [
{
"id": 1,
"snippet_type": "about",
"name": "Company About",
"content": "Floyi is a topic-first content strategy platform...",
"is_active": true,
"created_at": "2026-03-01T10:00:00Z",
"updated_at": "2026-03-01T10:00:00Z"
}
]
}
```
#### Get Content Guide Summary
```
GET /api/v1/content-guide/{brand_id}/summary/
```
Returns entry counts per category without the full data. Useful for dashboards and status checks.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/content-guide/a1b2c3d4-.../summary/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.get(
f"{BASE_URL}/content-guide/{brand_id}/summary/",
headers=headers,
)
summary = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/content-guide/${brandId}/summary/`,
{ headers },
);
const summary = await res.json();
```
**Response:**
```json
{
"brand_id": "a1b2c3d4-...",
"counts": {
"terminology": 12,
"compliance": 3,
"competitor_policies": 5,
"brand_messaging": 8,
"boilerplate": 4
},
"total": 32,
"is_empty": false
}
```
#### Create Terminology Entry
```
POST /api/v1/content-guide/{brand_id}/terminology/
```
Adds a terminology/lexicon entry to the content guide. Terminology entries define preferred terms and discouraged alternatives.
**Request body:**
```json
{
"term": "SEO tool",
"preferred_term": "content strategy platform",
"severity": "discouraged",
"note": "We position as a strategy platform, not a tool."
}
```
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `term` | string | yes | The term to control |
| `preferred_term` | string | yes | The preferred alternative |
| `severity` | string | no | `"discouraged"`, `"banned"`, or `"preferred"` |
| `note` | string | no | Explanation for writers |
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"term": "SEO tool", "preferred_term": "content strategy platform", "severity": "discouraged"}' \
https://api.floyi.com/api/v1/content-guide/a1b2c3d4-.../terminology/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/content-guide/{brand_id}/terminology/",
headers=headers,
json={
"term": "SEO tool",
"preferred_term": "content strategy platform",
"severity": "discouraged",
},
)
entry = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/content-guide/${brandId}/terminology/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
term: "SEO tool",
preferred_term: "content strategy platform",
severity: "discouraged",
}),
},
);
const entry = await res.json();
```
Returns `201 Created` with the new entry.
#### Create Compliance Rule
```
POST /api/v1/content-guide/{brand_id}/compliance/
```
Adds a compliance rule set. Each rule set has a name and a `rules_json` object containing `banned_claims` and `required_disclosures` arrays.
**Request body:**
```json
{
"name": "Health Claims Policy",
"rules_json": {
"banned_claims": ["guaranteed results", "instant rankings"],
"required_disclosures": ["Results may vary based on industry"]
}
}
```
#### Create Competitor Policy
```
POST /api/v1/content-guide/{brand_id}/competitor-policy/
```
Defines how a competitor should be referenced in content.
**Request body:**
```json
{
"competitor_name": "Clearscope",
"mention_policy": "neutral",
"comparison_notes": "Acknowledge strengths but highlight our closed-loop workflow."
}
```
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `competitor_name` | string | yes | Name of the competitor |
| `mention_policy` | string | no | `"neutral"`, `"positive"`, `"avoid"`, or `"compare"` |
| `comparison_notes` | string | no | Guidance for writers when comparing |
#### Create Brand Messaging Rule
```
POST /api/v1/content-guide/{brand_id}/brand-messaging/
```
Adds a brand messaging rule (messaging pillar, tone directive, or key phrase).
**Request body:**
```json
{
"rule_type": "messaging_pillar",
"content": "Topic-first strategy replaces the disconnected tool stack."
}
```
#### Create Boilerplate Snippet
```
POST /api/v1/content-guide/{brand_id}/boilerplate/
```
Adds a pre-approved boilerplate snippet (about section, disclaimer, CTA, etc.).
**Request body:**
```json
{
"snippet_type": "about",
"name": "Company About",
"content": "Floyi is a topic-first content strategy platform that takes you from brand strategy to published drafts in one system."
}
```
#### Start AI Content Guide Generation
```
POST /api/v1/content-guide/{brand_id}/ai-generate/
```
Triggers AI-powered generation of a complete content guide based on the brand's profile data (name, mission, voice, audience). The brand must have `brand_name`, `mission`, and `brand_voice` set. Costs credits. Returns a `task_id` for polling.
**Request body (optional):**
```json
{
"ai_model_id": "gpt-5-mini"
}
```
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{}' \
https://api.floyi.com/api/v1/content-guide/a1b2c3d4-.../ai-generate/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/content-guide/{brand_id}/ai-generate/",
headers=headers,
json={},
)
result = response.json()
task_id = result["task_id"]
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/content-guide/${brandId}/ai-generate/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({}),
},
);
const result = await res.json();
const taskId = result.task_id;
```
**Response (202 Accepted):**
```json
{
"task_id": "cg-gen-789-...",
"brand_id": "a1b2c3d4-...",
"message": "Content guide generation started. Poll .../ai-generate/status/?task_id=cg-gen-789-... for progress."
}
```
**Errors:**
| Status | Meaning |
| --- | --- |
| 400 | Brand missing required fields (brand_name, mission, brand_voice) |
| 404 | Brand not found |
#### Check AI Generation Status
```
GET /api/v1/content-guide/{brand_id}/ai-generate/status/?task_id={task_id}
```
Polls the AI content guide generation task. When complete, the response includes the full generated `content_guide` object.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
"https://api.floyi.com/api/v1/content-guide/a1b2c3d4-.../ai-generate/status/?task_id=cg-gen-789-..."
```
```python
brand_id = "a1b2c3d4-..."
task_id = "cg-gen-789-..."
response = requests.get(
f"{BASE_URL}/content-guide/{brand_id}/ai-generate/status/",
headers=headers,
params={"task_id": task_id},
)
status = response.json()
if status["status"] == "completed":
content_guide = status["content_guide"]
```
```javascript
const brandId = "a1b2c3d4-...";
const taskId = "cg-gen-789-...";
const res = await fetch(
`${BASE_URL}/content-guide/${brandId}/ai-generate/status/?task_id=${taskId}`,
{ headers },
);
const status = await res.json();
if (status.status === "completed") {
const contentGuide = status.content_guide;
}
```
**Response (completed):**
```json
{
"task_id": "cg-gen-789-...",
"state": "SUCCESS",
"status": "completed",
"message": "Content guide generation completed.",
"content_guide": {
"terminology": [...],
"compliance": [...],
"competitor_policies": [...],
"brand_messaging": [...],
"boilerplate": [...]
}
}
```
#### Save AI-Generated Content Guide
```
POST /api/v1/content-guide/{brand_id}/ai-generate/save/
```
Saves the AI-generated content guide entries to the brand. Pass the `content_guide` object received from the completed generation status response.
**Request body:**
```json
{
"content_guide": {
"terminology": [
{ "term": "SEO tool", "preferred_term": "content strategy platform", "severity": "discouraged" }
],
"compliance": [
{ "name": "Claims Policy", "banned_claims": ["guaranteed results"], "required_disclosures": [] }
],
"competitor_policies": [
{ "competitor_name": "Clearscope", "mention_policy": "neutral", "comparison_notes": "..." }
],
"brand_messaging": [
{ "rule_type": "messaging_pillar", "content": "Topic-first strategy..." }
],
"boilerplate": [
{ "snippet_type": "about", "name": "Company About", "content": "..." }
]
}
}
```
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"content_guide": {"terminology": [...], "compliance": [...]}}' \
https://api.floyi.com/api/v1/content-guide/a1b2c3d4-.../ai-generate/save/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/content-guide/{brand_id}/ai-generate/save/",
headers=headers,
json={"content_guide": content_guide},
)
result = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/content-guide/${brandId}/ai-generate/save/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ content_guide: contentGuide }),
},
);
const result = await res.json();
```
**Response:**
```json
{
"success": true,
"counts": {
"terminology": 12,
"compliance": 3,
"competitor_policies": 5,
"brand_messaging": 8,
"boilerplate": 4
}
}
```
---
### Authority Organizer
The Authority Organizer API lets you restructure the topical authority hierarchy - move, rename, combine, create, archive, and restore nodes. All operations are stored as overrides on top of the base topical map, so they can be cleared to reset back to the original structure.
The hierarchy follows a 4-level structure: **Pillar > Hub > Branch > Resource**. Node types are automatically recalculated when nodes are moved.
**Scope:** `authority:read` (read), `authority:write` (write)
#### List Active Overrides
```
GET /api/v1/authority/{brand_id}/organizer/overrides/
```
Returns all active hierarchy overrides for a brand's authority map, including moves, renames, combines, creates, and archives.
```bash
curl -H "X-API-Key: fyi_live_your_key_here" \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../organizer/overrides/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.get(
f"{BASE_URL}/authority/{brand_id}/organizer/overrides/",
headers=headers,
)
overrides = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/organizer/overrides/`,
{ headers },
);
const overrides = await res.json();
```
**Response:**
```json
{
"brand_id": "a1b2c3d4-...",
"count": 3,
"overrides": [
{
"id": 1,
"node_id": "f1a2b3c4-...",
"override_type": "rename",
"original_name": "SEO Tools",
"new_name": "Keyword Research Tools",
"created_at": "2026-03-15T10:00:00Z"
},
{
"id": 2,
"node_id": "g2h3i4j5-...",
"override_type": "move",
"original_parent_id": "p1q2r3s4-...",
"new_parent_id": "t5u6v7w8-...",
"created_at": "2026-03-15T10:05:00Z"
},
{
"id": 3,
"node_id": "x9y0z1a2-...",
"override_type": "create",
"name": "AI Search Optimization",
"parent_id": "f1a2b3c4-...",
"created_at": "2026-03-16T08:00:00Z"
}
]
}
```
#### Move a Node
```
POST /api/v1/authority/{brand_id}/organizer/move/
```
Moves a node (and all its descendants) to a new parent. The node's type (Pillar/Hub/Branch/Resource) is automatically recalculated based on its new depth. Set `new_parent_id` to `null` to make it a top-level Pillar.
**Request body:**
```json
{
"node_id": "f1a2b3c4-...",
"new_parent_id": "t5u6v7w8-...",
"previous_parent_id": "p1q2r3s4-..."
}
```
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `node_id` | string | yes | UUID of the node to move |
| `new_parent_id` | string | no | UUID of the new parent (`null` for top-level) |
| `previous_parent_id` | string | no | Current parent UUID (for audit trail) |
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"node_id": "f1a2b3c4-...", "new_parent_id": "t5u6v7w8-..."}' \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../organizer/move/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/authority/{brand_id}/organizer/move/",
headers=headers,
json={
"node_id": "f1a2b3c4-...",
"new_parent_id": "t5u6v7w8-...",
},
)
result = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/organizer/move/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
node_id: "f1a2b3c4-...",
new_parent_id: "t5u6v7w8-...",
}),
},
);
const result = await res.json();
```
**Response:**
```json
{
"success": true,
"node_id": "f1a2b3c4-...",
"new_parent_id": "t5u6v7w8-...",
"message": "Node moved successfully."
}
```
#### Rename a Node
```
POST /api/v1/authority/{brand_id}/organizer/rename/
```
Renames a node. The new name must be unique within the map (case-insensitive). Renaming also updates the node's SERP tracking query.
**Request body:**
```json
{
"node_id": "f1a2b3c4-...",
"new_name": "Keyword Research Tools",
"original_name": "SEO Tools"
}
```
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `node_id` | string | yes | UUID of the node to rename |
| `new_name` | string | yes | New name (must be unique in the map) |
| `original_name` | string | no | Current name (for audit trail) |
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"node_id": "f1a2b3c4-...", "new_name": "Keyword Research Tools"}' \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../organizer/rename/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/authority/{brand_id}/organizer/rename/",
headers=headers,
json={
"node_id": "f1a2b3c4-...",
"new_name": "Keyword Research Tools",
},
)
result = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/organizer/rename/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
node_id: "f1a2b3c4-...",
new_name: "Keyword Research Tools",
}),
},
);
const result = await res.json();
```
**Response:**
```json
{
"success": true,
"node_id": "f1a2b3c4-...",
"new_name": "Keyword Research Tools",
"message": "Node renamed successfully."
}
```
**Errors:**
| Status | Meaning |
| --- | --- |
| 404 | Authority map not found |
| 409 | A node with that name already exists |
#### Combine Nodes
```
POST /api/v1/authority/{brand_id}/organizer/combine/
```
Combines two or more nodes into one. The primary node survives; merged nodes are removed. Children of merged nodes are reparented to the primary. Names of merged nodes are added as keywords on the primary node. Cross-level combines are allowed, but the resulting hierarchy cannot exceed 4 levels.
**Request body:**
```json
{
"primary_id": "f1a2b3c4-...",
"merged_ids": ["g2h3i4j5-...", "k6l7m8n9-..."],
"combined_name": "SEO & Keyword Tools",
"merged_names": ["Keyword Planners", "Search Tools"]
}
```
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `primary_id` | string | yes | UUID of the surviving node |
| `merged_ids` | string[] | yes | UUIDs of nodes to merge into primary |
| `combined_name` | string | no | New name for the combined node (defaults to primary's name) |
| `merged_names` | string[] | no | Names of merged nodes (auto-resolved if omitted) |
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"primary_id": "f1a2b3c4-...", "merged_ids": ["g2h3i4j5-..."]}' \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../organizer/combine/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/authority/{brand_id}/organizer/combine/",
headers=headers,
json={
"primary_id": "f1a2b3c4-...",
"merged_ids": ["g2h3i4j5-...", "k6l7m8n9-..."],
"combined_name": "SEO & Keyword Tools",
},
)
result = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/organizer/combine/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
primary_id: "f1a2b3c4-...",
merged_ids: ["g2h3i4j5-...", "k6l7m8n9-..."],
combined_name: "SEO & Keyword Tools",
}),
},
);
const result = await res.json();
```
**Response:**
```json
{
"success": true,
"primary_id": "f1a2b3c4-...",
"merged_ids": ["g2h3i4j5-...", "k6l7m8n9-..."],
"combined_name": "SEO & Keyword Tools",
"merged_names_as_keywords": ["Keyword Planners", "Search Tools"],
"message": "Nodes combined successfully. Merged nodes removed; their children reparented to the primary node; their names added as keywords."
}
```
**Errors:**
| Status | Meaning |
| --- | --- |
| 400 | primary_id in merged_ids, or combine would exceed 4 hierarchy levels |
| 404 | Authority map not found |
#### Create a Node
```
POST /api/v1/authority/{brand_id}/organizer/create/
```
Creates a new node in the hierarchy. The node type (Pillar/Hub/Branch/Resource) is automatically determined by its depth. Omit `parent_id` to create a top-level Pillar.
**Request body:**
```json
{
"name": "AI Search Optimization",
"parent_id": "f1a2b3c4-..."
}
```
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes | Name for the new node (must be unique) |
| `parent_id` | string | no | Parent node UUID (`null` for top-level Pillar) |
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"name": "AI Search Optimization", "parent_id": "f1a2b3c4-..."}' \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../organizer/create/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/authority/{brand_id}/organizer/create/",
headers=headers,
json={
"name": "AI Search Optimization",
"parent_id": "f1a2b3c4-...",
},
)
result = response.json()
new_node_id = result["node_id"]
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/organizer/create/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
name: "AI Search Optimization",
parent_id: "f1a2b3c4-...",
}),
},
);
const result = await res.json();
const newNodeId = result.node_id;
```
**Response (201 Created):**
```json
{
"success": true,
"node_id": "new-uuid-generated-...",
"name": "AI Search Optimization",
"parent_id": "f1a2b3c4-...",
"message": "Node created successfully."
}
```
#### Archive Nodes
```
POST /api/v1/authority/{brand_id}/organizer/archive/
```
Archives one or more nodes. Archived nodes are hidden from the effective hierarchy but can be restored later. No data is deleted.
**Request body:**
```json
{
"node_ids": ["f1a2b3c4-...", "g2h3i4j5-..."]
}
```
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"node_ids": ["f1a2b3c4-..."]}' \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../organizer/archive/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/authority/{brand_id}/organizer/archive/",
headers=headers,
json={"node_ids": ["f1a2b3c4-...", "g2h3i4j5-..."]},
)
result = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/organizer/archive/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ node_ids: ["f1a2b3c4-...", "g2h3i4j5-..."] }),
},
);
const result = await res.json();
```
**Response:**
```json
{
"success": true,
"archived_node_ids": ["f1a2b3c4-...", "g2h3i4j5-..."],
"count": 2,
"message": "Archived 2 node(s)."
}
```
#### Restore Nodes
```
POST /api/v1/authority/{brand_id}/organizer/restore/
```
Restores previously archived nodes, making them visible in the hierarchy again.
**Request body:**
```json
{
"node_ids": ["f1a2b3c4-..."]
}
```
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"node_ids": ["f1a2b3c4-..."]}' \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../organizer/restore/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.post(
f"{BASE_URL}/authority/{brand_id}/organizer/restore/",
headers=headers,
json={"node_ids": ["f1a2b3c4-..."]},
)
result = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/organizer/restore/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ node_ids: ["f1a2b3c4-..."] }),
},
);
const result = await res.json();
```
**Response:**
```json
{
"success": true,
"restored_node_ids": ["f1a2b3c4-..."],
"count": 1,
"message": "Restored 1 node(s)."
}
```
#### Clear Overrides
```
POST /api/v1/authority/{brand_id}/organizer/clear/
```
Resets hierarchy overrides back to the baseline topical map state. Pass specific `node_ids` to clear only those nodes, or omit to clear ALL overrides for the entire map. This action is irreversible.
**Request body:**
```json
{
"node_ids": ["f1a2b3c4-..."]
}
```
Omit `node_ids` (or pass `null`) to clear all overrides:
```json
{}
```
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{}' \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../organizer/clear/
```
```python
brand_id = "a1b2c3d4-..."
# Clear all overrides
response = requests.post(
f"{BASE_URL}/authority/{brand_id}/organizer/clear/",
headers=headers,
json={},
)
result = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
// Clear all overrides
const res = await fetch(
`${BASE_URL}/authority/${brandId}/organizer/clear/`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({}),
},
);
const result = await res.json();
```
**Response:**
```json
{
"success": true,
"cleared_count": 5,
"message": "Cleared 5 override(s)."
}
```
**Errors:**
| Status | Meaning |
| --- | --- |
| 404 | Authority map not found |
#### Update Node URL Slug
```
PATCH /api/v1/authority/{brand_id}/organizer/update-url-slug/
```
Sets the URL slug for a single authority node - useful when you want the published resource to live at a specific path. The slug is normalized server-side. Requires the `authority:write` scope.
**Request body:**
```json
{
"node_id": "f1a2b3c4-...",
"url_slug": "/roomba-j7-review"
}
```
| Field | Type | Notes |
| --- | --- | --- |
| `node_id` | string (UUID) | The node to update. |
| `url_slug` | string | Target slug, max 500 characters. Normalized on save. |
```bash
curl -X PATCH \
-H "X-API-Key: fyi_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"node_id": "f1a2b3c4-...", "url_slug": "/roomba-j7-review"}' \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../organizer/update-url-slug/
```
```python
brand_id = "a1b2c3d4-..."
response = requests.patch(
f"{BASE_URL}/authority/{brand_id}/organizer/update-url-slug/",
headers=headers,
json={"node_id": "f1a2b3c4-...", "url_slug": "/roomba-j7-review"},
)
result = response.json()
```
```javascript
const brandId = "a1b2c3d4-...";
const res = await fetch(
`${BASE_URL}/authority/${brandId}/organizer/update-url-slug/`,
{
method: "PATCH",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ node_id: "f1a2b3c4-...", url_slug: "/roomba-j7-review" }),
},
);
const result = await res.json();
```
**Response:**
```json
{
"success": true,
"node_id": "f1a2b3c4-...",
"url_slug": "/roomba-j7-review",
"message": "URL slug updated."
}
```
**Errors:**
| Status | Meaning |
| --- | --- |
| 400 | Invalid slug (e.g. disallowed characters) |
| 404 | Node or authority map not found |
---
## Part 6: Managing API Keys
You can manage your API keys from the **Settings > API Keys** tab in Floyi or programmatically through the key management endpoints.
### Viewing Your Keys
The API Keys tab shows all your keys with:
- **Name** - The label you gave the key
- **Prefix** - The first 12 characters (e.g., `fyi_live_a3b...`) for identification
- **Type** - Integration or Developer
- **Status** - Active or Revoked
- **Last Used** - When the key was last used to make a request
- **Created** - When the key was created
### Revoking a Key
Revoking permanently deactivates a key. Any request using a revoked key will receive a `401` error.
1. Find the key in the API Keys tab.
2. Click the **Revoke** button (trash icon).
3. Confirm the revocation.
Revocation is immediate and irreversible.
### Rotating a Key
Rotating creates a new key with the same name, type, scopes, and settings as the old key, then revokes the old key. Use this to periodically refresh your keys without changing your configuration.
1. Find the key in the API Keys tab.
2. Click the **Rotate** button.
3. Copy the new key immediately.
The old key stops working as soon as the new key is created.
---
## Part 7: Audit Logging
Every request made to the `/api/v1/` endpoints using an API key is logged automatically. Audit logs capture:
- Endpoint path and HTTP method
- Response status code
- Client IP address
- Response time in milliseconds
- Timestamp
Use the audit log endpoint to view your request history, debug issues, and monitor for unauthorized access.
### View Audit Logs
```
GET /api/v1/me/audit-logs/
```
**Scope required:** `user:read`
Returns a paginated list of API request logs for all of your API keys. Results are ordered by most recent first. Audit logs are retained for **90 days**.
**Query parameters:**
| Parameter | Type | Description |
| --- | --- | --- |
| `api_key_id` | UUID | Filter by a specific API key |
| `method` | string | Filter by HTTP method (`GET`, `POST`, `PUT`, `DELETE`) |
| `status_code` | integer | Filter by response status code (e.g., `200`, `400`, `429`) |
| `endpoint` | string | Filter by endpoint path (partial match) |
| `page` | integer | Page number (default: 1) |
| `page_size` | integer | Results per page (default: 50, max: 200) |
```bash
# View recent audit logs
curl -H "X-API-Key: fyi_live_your_key" \
https://api.floyi.com/api/v1/me/audit-logs/
# Filter by specific key and method
curl -H "X-API-Key: fyi_live_your_key" \
"https://api.floyi.com/api/v1/me/audit-logs/?api_key_id=a1b2c3d4-...&method=POST"
# Filter by status code (e.g., find failed requests)
curl -H "X-API-Key: fyi_live_your_key" \
"https://api.floyi.com/api/v1/me/audit-logs/?status_code=429&page_size=20"
```
```python
# View recent audit logs
response = requests.get(f"{BASE_URL}/me/audit-logs/", headers=headers)
logs = response.json()
# Filter by specific key and method
response = requests.get(
f"{BASE_URL}/me/audit-logs/",
headers=headers,
params={"api_key_id": "a1b2c3d4-...", "method": "POST"},
)
# Filter by status code
response = requests.get(
f"{BASE_URL}/me/audit-logs/",
headers=headers,
params={"status_code": 429, "page_size": 20},
)
```
```javascript
// View recent audit logs
const res = await fetch(`${BASE_URL}/me/audit-logs/`, { headers });
const logs = await res.json();
// Filter by specific key and method
const params = new URLSearchParams({
api_key_id: "a1b2c3d4-...",
method: "POST",
});
const res2 = await fetch(
`${BASE_URL}/me/audit-logs/?${params}`,
{ headers },
);
// Filter by status code
const res3 = await fetch(
`${BASE_URL}/me/audit-logs/?status_code=429&page_size=20`,
{ headers },
);
```
**Response:**
```json
{
"_meta": {
"description": "Paginated list of API request audit logs..."
},
"count": 342,
"next": "https://api.floyi.com/api/v1/me/audit-logs/?page=2",
"previous": null,
"results": [
{
"id": "e1f2a3b4-...",
"api_key_name": "My Integration Key",
"api_key_prefix": "fyi_live_a3b...",
"endpoint": "/api/v1/brands/",
"method": "GET",
"status_code": 200,
"ip_address": "203.0.113.42",
"response_time_ms": 45,
"timestamp": "2026-02-27T14:30:00Z"
},
{
"id": "d5c6b7a8-...",
"api_key_name": "My Integration Key",
"api_key_prefix": "fyi_live_a3b...",
"endpoint": "/api/v1/research/tr_abc123/tree/",
"method": "GET",
"status_code": 200,
"ip_address": "203.0.113.42",
"response_time_ms": 120,
"timestamp": "2026-02-27T14:29:55Z"
}
]
}
```
**Response fields:**
| Field | Description |
| --- | --- |
| `count` | Total number of matching audit log entries |
| `next` | URL for the next page (null if on the last page) |
| `previous` | URL for the previous page (null if on the first page) |
| `id` | Unique audit log entry ID |
| `api_key_name` | Name of the API key that made the request |
| `api_key_prefix` | Prefix of the API key (e.g., `fyi_live_a3b...`) |
| `endpoint` | The API endpoint that was called |
| `method` | HTTP method (GET, POST, PUT, DELETE) |
| `status_code` | HTTP response status code |
| `ip_address` | Client IP address |
| `response_time_ms` | Server response time in milliseconds |
| `timestamp` | When the request was made (ISO 8601) |
---
## Part 8: Security Best Practices
### Key Storage
- Store API keys in environment variables or a secrets manager. Never hardcode them.
- Floyi stores only the SHA-256 hash of your key. The plaintext is shown once at creation and cannot be recovered.
### Rotation Schedule
Rotate your API keys periodically, especially if they are used in shared environments. Floyi's rotate feature makes this seamless - same settings, new key, old key revoked instantly.
---
## Part 9: Common Use Cases
### AI Agent: Full Content Pipeline (Authority Flow)
An AI agent can automate your entire content workflow - from analyzing topic gaps to generating published drafts. This uses the **authority endpoints** so all briefs and articles are linked to your topical hierarchy.
```bash
# 1. Fetch the authority hierarchy to analyze coverage
curl -H "X-API-Key: fyi_live_your_key" \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../
# 2. Get SERP data for the chosen topic
curl -H "X-API-Key: fyi_live_your_key" \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../serp-data/f1a2b3c4-.../
# 3. Generate an authority brief (node_id from step 1)
curl -X POST \
-H "X-API-Key: fyi_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"node_id": "f1a2b3c4-...",
"selected_serp_data": [
{"url": "https://competitor1.com/...", "title": "...", "snippet": "..."},
{"url": "https://competitor2.com/...", "title": "...", "snippet": "..."}
]
}' \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../briefs/generate/
# 4. Poll until brief is complete (every 10-15 seconds)
curl -H "X-API-Key: fyi_live_your_key" \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../briefs/b5c6d7e8-.../status/
# 5. Generate an authority article draft from the completed brief
curl -X POST \
-H "X-API-Key: fyi_live_your_key" \
-H "Content-Type: application/json" \
-d '{"brief_id": "b5c6d7e8-...", "ai_model_id": "claude-sonnet-4", "specialists": {"research_agent": true}}' \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../articles/generate/
# 6. Poll until draft is complete (every 15-30 seconds)
curl -H "X-API-Key: fyi_live_your_key" \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../articles/c7d8e9f0-.../status/
# 7. Mark the topic as published
curl -X PATCH \
-H "X-API-Key: fyi_live_your_key" \
-H "Content-Type: application/json" \
-d '{"published": true}' \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../nodes/f1a2b3c4-.../published/
```
```python
API_KEY = "fyi_live_your_key"
BASE_URL = "https://api.floyi.com/api/v1"
headers = {"X-API-Key": API_KEY}
brand_id = "a1b2c3d4-..."
# 1. Fetch the authority hierarchy
hierarchy = requests.get(
f"{BASE_URL}/authority/{brand_id}/", headers=headers
).json()
# 2. Pick a topic and get its SERP data
node_id = "f1a2b3c4-..."
serp = requests.get(
f"{BASE_URL}/authority/{brand_id}/serp-data/{node_id}/",
headers=headers,
).json()
# 3. Generate an authority brief
brief = requests.post(
f"{BASE_URL}/authority/{brand_id}/briefs/generate/",
headers=headers,
json={
"node_id": node_id,
"selected_serp_data": serp["serp_results"][:5],
},
).json()
# 4. Poll until brief is complete
while True:
status = requests.get(
f"{BASE_URL}/authority/{brand_id}/briefs/{brief['id']}/status/",
headers=headers,
).json()
if status["status"] in ("COMPLETE", "PARTIAL_COMPLETE", "FAILED"):
break
time.sleep(12)
# 5. Generate an authority article draft
article = requests.post(
f"{BASE_URL}/authority/{brand_id}/articles/generate/",
headers=headers,
json={
"brief_id": brief["id"],
"ai_model_id": "claude-sonnet-4",
"specialists": {"research_agent": True},
},
).json()
# 6. Poll until draft is complete
while True:
progress = requests.get(
f"{BASE_URL}/authority/{brand_id}/articles/{article['id']}/status/",
headers=headers,
).json()
if progress["completion_percentage"] == 100.0:
break
time.sleep(20)
# 7. Mark the topic as published
requests.patch(
f"{BASE_URL}/authority/{brand_id}/nodes/{node_id}/published/",
headers=headers,
json={"published": True},
)
```
```javascript
const API_KEY = "fyi_live_your_key";
const BASE_URL = "https://api.floyi.com/api/v1";
const headers = { "X-API-Key": API_KEY };
const brandId = "a1b2c3d4-...";
// 1. Fetch the authority hierarchy
const hierarchy = await fetch(
`${BASE_URL}/authority/${brandId}/`, { headers }
).then(r => r.json());
// 2. Pick a topic and get its SERP data
const nodeId = "f1a2b3c4-...";
const serp = await fetch(
`${BASE_URL}/authority/${brandId}/serp-data/${nodeId}/`, { headers }
).then(r => r.json());
// 3. Generate an authority brief
const brief = await fetch(
`${BASE_URL}/authority/${brandId}/briefs/generate/`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
node_id: nodeId,
selected_serp_data: serp.serp_results.slice(0, 5),
}),
}
).then(r => r.json());
// 4. Poll until brief is complete
const poll = async (url, check, interval) => {
while (true) {
const data = await fetch(url, { headers }).then(r => r.json());
if (check(data)) return data;
await new Promise(r => setTimeout(r, interval));
}
};
await poll(
`${BASE_URL}/authority/${brandId}/briefs/${brief.id}/status/`,
d => ["COMPLETE", "PARTIAL_COMPLETE", "FAILED"].includes(d.status),
12000,
);
// 5. Generate an authority article draft
const article = await fetch(
`${BASE_URL}/authority/${brandId}/articles/generate/`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
brief_id: brief.id,
ai_model_id: "claude-sonnet-4",
specialists: { research_agent: true },
}),
}
).then(r => r.json());
// 6. Poll until draft is complete
await poll(
`${BASE_URL}/authority/${brandId}/articles/${article.id}/status/`,
d => d.completion_percentage === 100.0,
20000,
);
// 7. Mark the topic as published
await fetch(
`${BASE_URL}/authority/${brandId}/nodes/${nodeId}/published/`, {
method: "PATCH",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ published: true }),
}
);
```
The AI agent can loop through this flow for each topic in the map, prioritizing by importance score and unpublished status.
### Zapier: Create a Brand When a Client is Added
Use a Zapier Webhook step to call the brands endpoint when a new client appears in your CRM:
```bash
curl -X POST \
-H "X-API-Key: fyi_live_your_integration_key" \
-H "Content-Type: application/json" \
-d '{"brand_name": "New Client Inc", "website_url": "https://newclient.com"}' \
https://api.floyi.com/api/v1/brands/
```
```python
response = requests.post(
f"{BASE_URL}/brands/",
headers=headers,
json={"brand_name": "New Client Inc", "website_url": "https://newclient.com"},
)
```
```javascript
await fetch(`${BASE_URL}/brands/`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
brand_name: "New Client Inc",
website_url: "https://newclient.com",
}),
});
```
### Quick Content Pipeline (Authority Flow)
Generate an authority brief, create an article, and trigger a draft - the minimum steps to go from a hierarchy topic to content:
```bash
# 1. Generate an authority brief (node_id from GET /api/v1/authority/{brand_id}/)
curl -X POST \
-H "X-API-Key: fyi_live_your_integration_key" \
-H "Content-Type: application/json" \
-d '{"node_id": "f1a2b3c4-..."}' \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../briefs/generate/
# Returns: {"id": "b5c6d7e8-...", "status": "PENDING"}
# 2. Poll until brief is complete (every 10-15 seconds)
curl -H "X-API-Key: fyi_live_your_integration_key" \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../briefs/b5c6d7e8-.../status/
# 3. Generate an authority article draft
curl -X POST \
-H "X-API-Key: fyi_live_your_integration_key" \
-H "Content-Type: application/json" \
-d '{"brief_id": "b5c6d7e8-...", "ai_model_id": "claude-sonnet-4"}' \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../articles/generate/
# 4. Poll until draft is complete (every 15-30 seconds)
curl -H "X-API-Key: fyi_live_your_integration_key" \
https://api.floyi.com/api/v1/authority/a1b2c3d4-.../articles/c7d8e9f0-.../status/
```
```python
brand_id = "a1b2c3d4-..."
# 1. Generate an authority brief
brief = requests.post(
f"{BASE_URL}/authority/{brand_id}/briefs/generate/",
headers=headers,
json={"node_id": "f1a2b3c4-..."},
).json()
# 2. Poll until brief is complete
while True:
s = requests.get(
f"{BASE_URL}/authority/{brand_id}/briefs/{brief['id']}/status/",
headers=headers,
).json()
if s["status"] in ("COMPLETE", "PARTIAL_COMPLETE", "FAILED"):
break
time.sleep(12)
# 3. Generate an authority article draft
article = requests.post(
f"{BASE_URL}/authority/{brand_id}/articles/generate/",
headers=headers,
json={"brief_id": brief["id"], "ai_model_id": "claude-sonnet-4"},
).json()
# 4. Poll until draft is complete
while True:
p = requests.get(
f"{BASE_URL}/authority/{brand_id}/articles/{article['id']}/status/",
headers=headers,
).json()
if p["completion_percentage"] == 100.0:
break
time.sleep(20)
```
```javascript
const brandId = "a1b2c3d4-...";
// 1. Generate an authority brief
const brief = await fetch(
`${BASE_URL}/authority/${brandId}/briefs/generate/`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ node_id: "f1a2b3c4-..." }),
}
).then(r => r.json());
// 2. Poll until brief is complete
let status;
do {
await new Promise(r => setTimeout(r, 12000));
status = await fetch(
`${BASE_URL}/authority/${brandId}/briefs/${brief.id}/status/`,
{ headers },
).then(r => r.json());
} while (!["COMPLETE", "PARTIAL_COMPLETE", "FAILED"].includes(status.status));
// 3. Generate an authority article draft
const article = await fetch(
`${BASE_URL}/authority/${brandId}/articles/generate/`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({ brief_id: brief.id, ai_model_id: "claude-sonnet-4" }),
}
).then(r => r.json());
// 4. Poll until draft is complete
let progress;
do {
await new Promise(r => setTimeout(r, 20000));
progress = await fetch(
`${BASE_URL}/authority/${brandId}/articles/${article.id}/status/`,
{ headers },
).then(r => r.json());
} while (progress.completion_percentage < 100.0);
```
### Quick Content Pipeline (Standalone)
For one-off briefs not tied to the authority hierarchy:
```bash
# 1. Generate a standalone brief with any topic
curl -X POST \
-H "X-API-Key: fyi_live_your_integration_key" \
-H "Content-Type: application/json" \
-d '{"query_text": "best seo tools for agencies", "brand_id": "a1b2c3d4-..."}' \
https://api.floyi.com/api/v1/briefs/generate/
# 2. Poll until brief is complete
curl -H "X-API-Key: fyi_live_your_integration_key" \
https://api.floyi.com/api/v1/briefs/b5c6d7e8-.../status/
# 3. Generate an article draft from the brief
curl -X POST \
-H "X-API-Key: fyi_live_your_integration_key" \
-H "Content-Type: application/json" \
-d '{"brief_id": "b5c6d7e8-...", "ai_model_id": "claude-sonnet-4"}' \
https://api.floyi.com/api/v1/content/articles/generate/
# 4. Poll until complete
curl -H "X-API-Key: fyi_live_your_integration_key" \
https://api.floyi.com/api/v1/content/articles/c7d8e9f0-.../status/
```
```python
# 1. Generate a standalone brief
brief = requests.post(
f"{BASE_URL}/briefs/generate/",
headers=headers,
json={
"query_text": "best seo tools for agencies",
"brand_id": "a1b2c3d4-...",
},
).json()
# 2. Poll until brief is complete
while True:
s = requests.get(
f"{BASE_URL}/briefs/{brief['id']}/status/", headers=headers
).json()
if s["status"] in ("COMPLETE", "PARTIAL_COMPLETE", "FAILED"):
break
time.sleep(12)
# 3. Generate an article draft
article = requests.post(
f"{BASE_URL}/content/articles/generate/",
headers=headers,
json={"brief_id": brief["id"], "ai_model_id": "claude-sonnet-4"},
).json()
# 4. Poll until complete
while True:
p = requests.get(
f"{BASE_URL}/content/articles/{article['id']}/status/",
headers=headers,
).json()
if p["completion_percentage"] == 100.0:
break
time.sleep(20)
```
```javascript
// 1. Generate a standalone brief
const brief = await fetch(`${BASE_URL}/briefs/generate/`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
query_text: "best seo tools for agencies",
brand_id: "a1b2c3d4-...",
}),
}).then(r => r.json());
// 2. Poll until brief is complete
let status;
do {
await new Promise(r => setTimeout(r, 12000));
status = await fetch(
`${BASE_URL}/briefs/${brief.id}/status/`, { headers }
).then(r => r.json());
} while (!["COMPLETE", "PARTIAL_COMPLETE", "FAILED"].includes(status.status));
// 3. Generate an article draft
const article = await fetch(`${BASE_URL}/content/articles/generate/`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
brief_id: brief.id,
ai_model_id: "claude-sonnet-4",
}),
}).then(r => r.json());
// 4. Poll until complete
let progress;
do {
await new Promise(r => setTimeout(r, 20000));
progress = await fetch(
`${BASE_URL}/content/articles/${article.id}/status/`, { headers }
).then(r => r.json());
} while (progress.completion_percentage < 100.0);
```
---
## Endpoint Reference
| Endpoint | Method | Scope | Description |
| --- | --- | --- | --- |
| **Brands** | | | |
| `/api/v1/brands/` | GET | `brands:read` | List all brands (`?search=`) |
| `/api/v1/brands/{id}/` | GET | `brands:read` | Get brand details |
| `/api/v1/brands/` | POST | `brands:write` | Create a brand |
| **Content Briefs (Standalone)** | | | |
| `/api/v1/briefs/` | GET | `briefs:read` | List standalone briefs (`?brand_id=` `?status=` `?search=`) |
| `/api/v1/briefs/{id}/` | GET | `briefs:read` | Get brief with full data |
| `/api/v1/briefs/{id}/status/` | GET | `briefs:read` | Check brief generation status |
| `/api/v1/briefs/generate/` | POST | `briefs:write` | Generate brief (freeform `query_text`) |
| **Content Articles (Standalone)** | | | |
| `/api/v1/content/articles/` | GET | `content:read` | List standalone articles (`?brand_id=` `?search=`) |
| `/api/v1/content/articles/{id}/` | GET | `content:read` | Get article details with sections |
| `/api/v1/content/articles/{id}/status/` | GET | `content:read` | Check draft generation progress |
| `/api/v1/content/articles/generate/` | POST | `content:write` | Generate article draft from a brief |
| `/api/v1/content/articles/{id}/generate/` | POST | `content:write` | Regenerate draft for existing article |
| **Topical Maps** | | | |
| `/api/v1/maps/` | GET | `maps:read` | List topical maps (`?brand_id=`) |
| `/api/v1/maps/{brand_id}/` | GET | `maps:read` | Get raw map clusters |
| **Topical Research** | | | |
| `/api/v1/research/` | GET | `research:read` | List research records |
| `/api/v1/research/{brand_id}/` | GET | `research:read` | Get full research tree with stats |
| `/api/v1/research/{brand_id}/stats/` | GET | `research:read` | Get tree stats only |
| `/api/v1/research/{brand_id}/task-status/` | GET | `research:read` | Poll AI generation task status |
| `/api/v1/research/{brand_id}/nodes/rename/` | PATCH | `research:write` | Rename a node |
| `/api/v1/research/{brand_id}/nodes/add/` | POST | `research:write` | Add a new node |
| `/api/v1/research/{brand_id}/nodes/delete/` | POST | `research:write` | Delete a node and descendants |
| `/api/v1/research/{brand_id}/nodes/keywords/` | PATCH | `research:write` | Add/remove keywords on a node |
| `/api/v1/research/{brand_id}/nodes/move/` | POST | `research:write` | Move node to new parent |
| `/api/v1/research/{brand_id}/nodes/merge/` | POST | `research:write` | Merge two same-level nodes |
| `/api/v1/research/{brand_id}/nodes/bulk/` | POST | `research:write` | Execute multiple operations atomically |
| `/api/v1/research/{brand_id}/diff/` | POST | `research:read` | Compare two tree states |
| **Topical Authority** | | | |
| `/api/v1/authority/` | GET | `authority:read` | List authority maps (`?brand_id=`) |
| `/api/v1/authority/{brand_id}/` | GET | `authority:read` | Get enriched hierarchy with overrides |
| `/api/v1/authority/{brand_id}/serp-data/{node_id}/` | GET | `authority:read` | Get stored SERP results for a node |
| `/api/v1/authority/{brand_id}/nodes/{node_id}/published/` | PATCH | `authority:write` | Toggle published status |
| **Authority Keywords** | | | |
| `/api/v1/authority/{brand_id}/nodes/{node_id}/keywords/` | GET | `authority:read` | List keywords for a node (`?source=`) |
| `/api/v1/authority/{brand_id}/nodes/{node_id}/keywords/` | POST | `authority:write` | Add keyword(s) to a node |
| `/api/v1/authority/{brand_id}/nodes/{node_id}/keywords/{keyword_id}/` | DELETE | `authority:write` | Delete a keyword |
| **Authority Briefs** | | | |
| `/api/v1/authority/{brand_id}/briefs/` | GET | `authority:read` | List authority briefs (`?status=` `?search=`) |
| `/api/v1/authority/{brand_id}/briefs/{id}/` | GET | `authority:read` | Get authority brief with full data |
| `/api/v1/authority/{brand_id}/briefs/{id}/status/` | GET | `authority:read` | Check authority brief status |
| `/api/v1/authority/{brand_id}/briefs/generate/` | POST | `authority:write` | Generate brief for a hierarchy node |
| **Authority Articles** | | | |
| `/api/v1/authority/{brand_id}/articles/` | GET | `authority:read` | List authority articles (`?search=`) |
| `/api/v1/authority/{brand_id}/articles/{id}/` | GET | `authority:read` | Get authority article with sections |
| `/api/v1/authority/{brand_id}/articles/{id}/status/` | GET | `authority:read` | Check draft generation progress |
| `/api/v1/authority/{brand_id}/articles/generate/` | POST | `authority:write` | Generate article draft from authority brief |
| `/api/v1/authority/{brand_id}/articles/{id}/generate/` | POST | `authority:write` | Regenerate draft for existing authority article |
| **Standalone Clustering** | | | |
| `/api/v1/clustering/` | GET | `clustering:read` | List clustering reports |
| `/api/v1/clustering/{id}/` | GET | `clustering:read` | Get report with full cluster results |
| `/api/v1/clustering/{id}/status/` | GET | `clustering:read` | Check clustering task progress |
| `/api/v1/clustering/{id}/serp-data/?keyword=` | GET | `clustering:read` | Get SERP data for a keyword |
| `/api/v1/clustering/` | POST | `clustering:write` | Create report + start clustering |
| `/api/v1/clustering/{id}/recluster/` | POST | `clustering:write` | Re-cluster with new overlap |
| `/api/v1/clustering/{id}/` | DELETE | `clustering:write` | Delete clustering report |
| **Authority Clustering** | | | |
| `/api/v1/authority/{brand_id}/clustering/` | GET | `clustering:read` | Get brand clustering results |
| `/api/v1/authority/{brand_id}/clustering/status/` | GET | `clustering:read` | Check brand clustering progress |
| `/api/v1/authority/{brand_id}/clustering/serp-data/?keyword=` | GET | `clustering:read` | Get brand SERP data for keyword |
| `/api/v1/authority/{brand_id}/clustering/start/` | POST | `clustering:write` | Start brand clustering |
| `/api/v1/authority/{brand_id}/clustering/recluster/` | POST | `clustering:write` | Re-cluster brand with new overlap |
| **Images** | | | |
| `/api/v1/content/articles/{article_id}/images/` | GET | `content:read` | List generated images for an article |
| `/api/v1/content/articles/{article_id}/images/models/` | GET | `content:read` | List available image generation models |
| `/api/v1/content/articles/{article_id}/images/analyze/` | POST | `content:write` | Analyze content and suggest image placements |
| `/api/v1/content/articles/{article_id}/images/generate/` | POST | `content:write` | Generate images for selected placements |
| `/api/v1/content/articles/{article_id}/images/status/?task_id=` | GET | `content:read` | Check image generation task progress |
| **WordPress** | | | |
| `/api/v1/cms/wordpress/connections/` | GET | `content:read` | List WordPress site connections |
| `/api/v1/cms/wordpress/publish-records/` | GET | `content:read` | List publish records (`?article_id=` `?connection_id=`) |
| `/api/v1/cms/wordpress/publish/` | POST | `content:write` | Publish a single article to WordPress |
| `/api/v1/cms/wordpress/bulk-publish/` | POST | `content:write` | Bulk publish up to 50 articles |
| `/api/v1/cms/wordpress/task-status/?task_id=` | GET | `content:read` | Check publish task progress |
| **Content Guide** | | | |
| `/api/v1/content-guide/{brand_id}/` | GET | `content:read` | Get full content guide (all categories) |
| `/api/v1/content-guide/{brand_id}/summary/` | GET | `content:read` | Get entry counts per category |
| `/api/v1/content-guide/{brand_id}/terminology/` | POST | `content:write` | Create a terminology entry |
| `/api/v1/content-guide/{brand_id}/compliance/` | POST | `content:write` | Create a compliance rule |
| `/api/v1/content-guide/{brand_id}/competitor-policy/` | POST | `content:write` | Create a competitor policy |
| `/api/v1/content-guide/{brand_id}/brand-messaging/` | POST | `content:write` | Create a brand messaging rule |
| `/api/v1/content-guide/{brand_id}/boilerplate/` | POST | `content:write` | Create a boilerplate snippet |
| `/api/v1/content-guide/{brand_id}/ai-generate/` | POST | `content:write` | Start AI content guide generation |
| `/api/v1/content-guide/{brand_id}/ai-generate/status/?task_id=` | GET | `content:read` | Check AI generation progress |
| `/api/v1/content-guide/{brand_id}/ai-generate/save/` | POST | `content:write` | Save AI-generated entries to the brand |
| **Authority Organizer** | | | |
| `/api/v1/authority/{brand_id}/organizer/overrides/` | GET | `authority:read` | List active hierarchy overrides |
| `/api/v1/authority/{brand_id}/organizer/move/` | POST | `authority:write` | Move a node to a new parent |
| `/api/v1/authority/{brand_id}/organizer/rename/` | POST | `authority:write` | Rename a node |
| `/api/v1/authority/{brand_id}/organizer/combine/` | POST | `authority:write` | Combine two or more nodes into one |
| `/api/v1/authority/{brand_id}/organizer/create/` | POST | `authority:write` | Create a new node in the hierarchy |
| `/api/v1/authority/{brand_id}/organizer/archive/` | POST | `authority:write` | Archive node(s) |
| `/api/v1/authority/{brand_id}/organizer/restore/` | POST | `authority:write` | Restore archived node(s) |
| `/api/v1/authority/{brand_id}/organizer/clear/` | POST | `authority:write` | Clear overrides (reset to baseline) |
| **User** | | | |
| `/api/v1/me/profile/` | GET | `user:read` | Get your profile |
| `/api/v1/me/credits/` | GET | `user:read` | Get your credit balance |
| `/api/v1/me/teams/` | GET | `user:read` | List your teams (for X-Team-ID header) |
| `/api/v1/me/audit-logs/` | GET | `user:read` | Paginated API request logs (`?api_key_id=` `?method=` `?status_code=` `?endpoint=`) |
---
## Frequently Asked Questions
### Who can create API keys?
Only users on the **Scale Plan** can create API keys.
### Can I recover a lost API key?
No. Floyi stores only the SHA-256 hash of the key, not the plaintext. If you lose a key, revoke it and create a new one.
### How do I know which scopes my key has?
The scopes are set when you create the key based on the key type (Integration or Developer) and any customizations you made. You can also call `GET /api/v1/me/` scopes endpoint to see all available scopes and the defaults for each key type.
### What happens if I downgrade my plan?
Existing API keys will **stop working** immediately. All API requests will return a `401 Unauthorized` error until you upgrade back to the Scale plan. Your keys are not deleted - they will resume working once you re-subscribe. You also cannot create new keys while on a non-Scale plan.
### Can I use the API from a browser?
The API is designed for server-to-server communication. While technically possible, we recommend against calling the API from client-side JavaScript since it would expose your API key. Use a backend proxy instead.
### Is there a sandbox or test environment?
Not currently. All API requests operate on your live Floyi data. Use a dedicated test brand or workspace to experiment without affecting production content.
### How do I find a resource without knowing its ID?
Use the `?search=` query parameter on list endpoints. Search is case-insensitive and supports partial matches:
- **Brands:** `?search=floyi` searches by brand name
- **Briefs:** `?search=topical+authority` searches by topic/query text and generated title
- **Articles:** `?search=seo+tools` searches by article title
You can combine search with other filters: `?search=topical&brand_id=...&status=COMPLETE`
### What format are IDs in?
All resource IDs are UUIDs (e.g., `a1b2c3d4-e5f6-7890-abcd-ef1234567890`).
### Are responses paginated?
Most list endpoints return all matching results without pagination. Use query filters (e.g., `brand_id`, `status`, `search`) to narrow results. The audit logs endpoint (`/api/v1/me/audit-logs/`) is paginated with `?page=` and `?page_size=` parameters.
### Can I use the API with team workspaces?
Yes. API keys are **account-level** and work with any workspace you have access to. Include the `X-Team-ID` header with a team UUID to access that team's data, or omit the header to access your personal workspace. Use `GET /api/v1/me/teams/` to discover your team UUIDs. You can only access teams where you are an active member (owner, admin, or member role).
### Can team members share an API key?
No. Each API key is tied to the user who created it. Only users on the **Scale Plan** can create keys. If a team member needs API access, they must be on a Scale plan themselves and create their own key. The key inherits the creator's team memberships - it can only access teams that the key owner belongs to.
---
## Billing and Payments
Source: https://floyi.com/docs/billing/
Everything billing-related in Floyi comes down to two things: your subscription plan and your credit balance. This section covers both, plus invoices and payment methods.
- [How Floyi credits work](/docs/billing/credits/) - what's free, what costs credits, and the order credits are used in
- [Purchasing PAYG credits](/docs/billing/purchase-credits/) - top up with pay-as-you-go credits that never expire
- [Managing your subscription](/docs/billing/subscription-management/) - upgrade, downgrade, or cancel your plan
## Subscription Information
To view your subscription details:
1. Click on 'Settings' in the bottom-left corner of the Floyi interface.
2. Open the **Billing & Credits** tab. In the 'Current Subscription' section, you can see:
- Your current subscription plan and its status
- Amount, discounts, and next billing date
- Billing History and Credits History (accessible via dedicated buttons)
3. The 'Credits Overview' section below shows your credits broken down by type (Monthly, PAYG, and Free), plus your Included Topical Research usage for the month.
For a full tour of the Settings page, see [Managing Your Account Settings](https://floyi.com/docs/getting-started/account-settings/).
## Billing and Credit History
### Viewing Your Billing History
1. Go to 'Settings' in the bottom-left corner.
2. In the **Billing & Credits** tab, click 'Billing History.'
The Billing History displays:
- Purchase date
- Description
- Amount
- Status
- Invoice link
To view an invoice, click 'View' under the Invoice column.
### Viewing Your Credit History
1. Go to 'Settings' in the bottom-left corner.
2. In the **Billing & Credits** tab, click 'Credits History.'
The Credits History shows transactions for your Personal Workspace. Team transactions are available under **Settings → Team**.
The Credits History displays your credit usage transactions:
- Purchase date
- Description
- Credits added or used
- Remaining balance
To export your credit transactions history, click 'Export CSV' in the top-right corner of the Credits History window.
## Subscription Plans
Floyi offers both Monthly and Yearly subscription plans to suit your needs.
- **Monthly Plans:** Credits are replenished at the start of each billing cycle, but unused credits expire at the end of the month
- **Yearly Plans:** Save with two months free when subscribing annually
- **Strategy Essentials:** Brand foundation, personas, topic hierarchy, URL slugs, scorecard, and anchor texts are free with every plan
- **Included Research:** Each plan includes free topical research runs per month (Pro: 5, Scale: 15). After your included research, additional runs use credits.
- **Unlimited Brands:** All paid plans include unlimited brands and projects
## Billing Cycles
Credits reset at the start of your monthly billing period at the time you signed up.
**Example:** If your plan begins on August 28, your credits will reset on September 28 at 00:00 GMT.
## Pay-As-You-Go (PAYG) Credits
For added flexibility, PAYG credits are available for purchase independently of your subscription.
- **No Expiration:** PAYG credits remain in your account until used
- **Usage Priority:** Monthly Credits are deducted first; PAYG Credits are used only after Monthly Credits are exhausted
- **Pricing:**
- Scale Plan: $6 per 1,000 credits
- Pro Plan: $7 per 1,000 credits
- Creator Plan: $9 per 1,000 credits ($7 per 1,000 on purchases of 50,000+)
- Non-subscribers: $10 per 1,000 credits ($7 per 1,000 on purchases of 50,000+)
- Promo codes can be applied for discounted purchases
- **Team workspaces:** PAYG purchases can only be made by the team Owner
## Payment Methods
Floyi supports the following payment methods:
- **Card Payments:** Visa, Mastercard, American Express, and more
- **Link:** Quick and secure checkout
## Invoices
Every purchase comes with a detailed invoice for your records, emailed directly to you and stored in your Billing History.
---
## How Do Floyi Credits Work?
Source: https://floyi.com/docs/billing/credits/
## Strategy Essentials (No Credits Needed)
These actions are included with your plan at no credit cost:
- **Brand Foundation** - Create and regenerate your brand, including URL scraping and voice analysis
- **Buyer Personas** - Generate audience personas for your brand
- **Topic Hierarchy** - Build your topical map structure (both standard and AI-powered)
- **URL Slugs** - Generate SEO-friendly URLs for your topics
- **Scorecard & Planner** - Calculate and track your topical authority. Scoring is free; refreshing costs 1 credit per topic for SERP rankings, plus 1 credit per topic for AI Mode and 1 credit per topic for ChatGPT if those are enabled in your settings.
- **Anchor Texts** - Generate internal linking suggestions
Audits are not part of the free essentials: organic audits (GSC import) and topical audits (site crawl) consume credits per page (see below).
## Included Topical Research
Each plan includes free topical research runs per month:
| Plan | Included Research |
| ------- | --------------------------------- |
| Free | 1 (lifetime, limited to 3 levels) |
| Creator | 3 per month |
| Pro | 5 per month |
| Scale | 15 per month |
Research is tracked per brand - the first time you research a new brand uses one allocation slot. Regenerating research on the same brand is always free within the same billing cycle.
After your included research is used, additional research runs use credits from your balance at the normal rate.
## What Costs Credits
Credits are used for production outputs and data operations:
- **Content Briefs** - ~150 credits per brief
- **Content Drafts** - 150 credits per draft
- **Specialist Agents** - 20-30 credits per specialist (research, fact-check, intro, conversion)
- **Content Info Snapshots** - 1 credit per topic (scales with map size)
- **Keyword Generation** - 1 credit per topic (scales with map size)
- **SERP Clustering** - 1 credit per keyword
- **SERP Insights** - 50 credits per analysis
- **AIRS Analyzer** - 10-100 credits depending on scope
- **Authority SERP Refresh** - 1 credit per topic for SERP rankings, plus 1 credit per topic for AI Mode tracking and 1 credit per topic for ChatGPT tracking (if enabled)
- **Content & Topical Audits** - 1 credit per page (crawling + AI costs)
- **Inline AI Edits** - 1 credit per edit
Credit costs scale with the AI model you select. Each model has a multiplier (shown in the model selector). The default model (GPT-5 Mini) has a 1x multiplier. Advanced models cost more credits per action.
## Ways to Get Credits
### 1. Welcome Bonus Credits
- When you sign up for Floyi, you receive 500 free credits as a welcome bonus
- Free credits are used first before Monthly or PAYG credits
### 2. Monthly Subscription Credits
- Subscription plans provide a monthly credit allowance that replenishes each billing cycle
- Unused Monthly Credits expire at the end of the billing cycle
- Subscribing yearly provides two months free
| Plan | Monthly Credits |
| ------- | --------------- |
| Creator | 5,000 |
| Pro | 15,000 |
| Scale | 50,000 |
### 3. Pay-As-You-Go (PAYG) Credits
- PAYG Credits are purchased separately and never expire
- Monthly Credits are always deducted first; PAYG Credits are used only when Monthly Credits are exhausted
- Subscribers get discounted PAYG rates. For more details, check the [guide on purchasing credits](/docs/billing/purchase-credits/)
## Credit Priority
When credits are deducted, they are used in this order:
1. **Free Credits** (welcome bonus) - used first
2. **Monthly Credits** (subscription) - used second
3. **PAYG Credits** (purchased) - used last, never expire
## Notes
1. **Credit Expiration:**
- Free Credits and Monthly Credits expire at the end of their billing cycle
- PAYG Credits have no expiration
2. **AI Model Multipliers:**
- Each AI model has a cost multiplier that affects credit consumption
- Basic models (1-2x) are the most cost-effective
- Advanced models (6-8x) provide higher quality but use more credits
3. **Pricing Details:**
- For the latest information on plans and pricing, visit [Floyi's Pricing Page](https://floyi.com/pricing/)
---
## How to Purchase Credits
Source: https://floyi.com/docs/billing/purchase-credits/
PAYG credits supplement the monthly allowance included with your plan. If you're new to the credit system, read up on [credit types and usage priority](/docs/billing/credits/) first; for plan-level questions, see the [billing overview](/docs/billing/).
## Benefits of PAYG Credits
- **No Expiration:** Credits remain in your account until used
- **Supplement Monthly Credits:** Seamlessly integrate with your subscription
- **Bulk Discounts:** On the Creator and Free rates, purchases of 50,000 credits or more get a reduced per-1,000 price
- **Additional Savings:** Subscribers enjoy reduced rates for PAYG credits
## How to Purchase PAYG Credits
### 1. Access the PAYG Section
1. Click on 'Settings' in the bottom-left corner of the screen.
2. Open the **Billing & Credits** tab and scroll down to the 'Pay As You Go Credits' section.
### 2. Select Credit Amount
1. Use the slider to choose your desired credit amount, from 1,000 to 100,000 credits (1,000-credit steps up to 10,000, then 5,000-credit steps).
- The slider reflects your plan's discounted rate, and the price shown is the price you pay at checkout
- On the Creator and Free rates, purchases of 50,000 credits or more get a reduced per-1,000 price
2. **Optional:** Enter a Promo Code if you have one for additional discounts.
### 3. Complete Your Purchase
#### Paying with a Card
1. Click 'Purchase Credits.'
2. Enter your card details, including:
- Card number
- Cardholder name
- Billing country
3. **Optional:** Save your payment information for faster checkout next time.
4. Click 'Pay' to finalize your purchase.
#### Paying with Link
1. Click 'Pay with Link.'
2. Log in to your Link account in the new window that opens.
3. Enter the verification code sent to your mobile number (or email, if prompted).
4. Enter your card's CVC code when requested.
5. Click 'Pay' to complete your transaction.
## PAYG Credits Notes
- Your purchased PAYG credits will be immediately available in your account after successful payment
- **Trial accounts:** PAYG purchases are unavailable during a trial-upgrade to your full plan to unlock credit top-ups
- **Team workspaces:** Only the team Owner can purchase PAYG credits. Non-owner members will see a notice directing them to the Owner
---
## Floyi Subscription Management
Source: https://floyi.com/docs/billing/subscription-management/
## Managing Your Subscription Plan
Floyi offers flexible subscription options to meet your needs. You can manage your subscription, update payment methods, or change your plan directly within your account settings. Changing plans changes your [monthly credit allowance](/docs/billing/credits/); for the full billing picture, start at the [billing section overview](/docs/billing/).
### How to Upgrade Your Subscription
To upgrade your subscription:
1. Go to **Settings** in the bottom-left corner of the Floyi interface.
2. Open the **Billing & Credits** tab.
3. Click 'Manage Subscription' to open the Stripe customer portal.
4. Select 'Update Subscription.'
5. Choose your desired subscription plan upgrade.
6. Click 'Continue.'
7. If required, select your payment method and click 'Confirm.'
8. (Optional) Enter a Promo Code and click 'Apply.'
9. Click 'Confirm' to complete the upgrade process.
### How to Downgrade Your Subscription
To downgrade your subscription:
1. Go to **Settings** in the bottom-left corner of the Floyi interface.
2. Open the **Billing & Credits** tab.
3. Click 'Manage Subscription' to open the Stripe customer portal.
4. Select 'Update Subscription.'
5. Choose your desired subscription downgrade plan.
6. Click 'Continue.'
7. If required, select your payment method and click 'Confirm.'
8. (Optional) Enter a Promo Code and click 'Apply.'
9. Click 'Confirm' to finalize your downgrade.
### How to Cancel Your Subscription
To cancel your subscription:
1. Go to **Settings** in the bottom-left corner of the Floyi interface.
2. Open the **Billing & Credits** tab.
3. Click 'Manage Subscription' to open the Stripe customer portal.
4. Select 'Cancel Subscription.'
5. You'll be redirected to your current subscription page, where you'll see confirmation that your subscription will remain active until the end of your billing period.
6. Click 'Cancel Subscription' again to confirm.
### Important Notes
- **Upgrades:** Switching to a higher plan takes effect immediately, and you're charged the prorated difference. Any active discount on your account carries over.
- **Downgrades:** Changes take effect at the start of your next billing period.
- **Cancellation Timing:** Canceling your subscription ensures no further charges after the current billing cycle. You keep access until the end of the period, and Settings shows the scheduled cancellation date.
- **Promo Codes:** Promo codes must be applied before confirming the transaction for upgrades or downgrades.
- **Trials:** During a trial, a banner in the **Billing & Credits** tab shows your remaining days and a 'Cancel Trial' button.
- **Team workspaces:** Subscription management is only available to the team Owner. Non-owner members see a notice directing them to the Owner.
---
## Getting Started with Floyi
Source: https://floyi.com/docs/getting-started/
This guide walks you through your first session in Floyi, from creating a project to generating your first brief and draft. It is designed for new users who want a clear path, not a full feature tour.
It follows the exact in-app flow: project → Brand Foundation → personas → Topical Research → SERP Clustering → Topical Map → Topical Authority → Planner → briefs and drafts.
If you want a detailed breakdown of every module, see the [Floyi Tools Overview](https://floyi.com/docs/tools/).
---
## What you will do
In this guide you will:
1. Create your first project.
2. Set up Brand Foundation and personas.
3. Run Topical Research for a core theme.
4. Start SERP Clustering directly from the research outline (no exports).
5. Build a Topical Map from clustering results.
6. Run a Topical Authority compute.
7. Prioritize topics in the Planner.
8. Generate your first brief and draft.
You can do all of this with a single site or brand.
---
## Step 1: Create your first project
1. [Sign in](/docs/getting-started/sign-in-and-out/) to Floyi - or [create your account](/docs/getting-started/sign-up/) if you don't have one yet.
2. Create a new project and name it after your brand or main domain.
3. Choose the primary country and language for your audience.
A project keeps Brand Foundation, personas, research, clustering, maps, briefs, and drafts together. One project per brand/domain keeps everything clean.
> If you work with multiple brands or domains, create one project per brand.
---
## Step 2: Set up Brand Foundation
Next, give Floyi the context it needs so every workflow uses the same strategy.
1. Open **Brand Foundation** in your project.
2. Add brand name, domain, and a short description.
3. Fill in: what you sell, who you help, value pillars/differentiators, and key competitors.
4. Save it; you can refine tone and positioning later.
You can keep this light for your first run, then come back later to refine voice, positioning and detailed notes.
See: [Brand Foundation](https://floyi.com/docs/tools/brand-foundation/)
---
## Step 3: Create 1 to 3 key personas
Now define who you are writing for.
1. Open **Audience Insights**.
2. Use your Brand Foundation as context when prompted.
3. Start with one primary persona such as:
- Your main buyer
- Your main user
- A key influencer or champion
4. Generate the persona, then skim and edit:
- Role and responsibilities
- Pains and triggers
- Goals and success criteria
5. Repeat for one or two more personas if needed.
You can always return to add, refine or delete personas, but having at least one solid persona will help all later steps.
See: [Audience Insights](https://floyi.com/docs/tools/audience-insights/)
---
## Step 4: Run Topical Research for a core theme
With brand and audience in place, you can start building your topic strategy.
1. Open **Topical Research**.
2. Choose a core theme that is central to your product, for example:
- "Email deliverability for SaaS"
- "B2B payment processing"
3. Select:
- Brand Foundation profile
- One primary persona
4. Run the research to generate main topics and subtopics.
5. Review the outline:
- Rename any topics that feel off
- Remove items that are clearly out of scope
- Add any obvious missing topics at the right level
You now have a structured outline tailored to your brand and audience, not a generic keyword dump.
See: [Topical Research](https://floyi.com/docs/tools/topical-research/)
---
## Step 5: Start SERP Clustering
Next, connect your topics to real search behavior.
1. From Topical Research, head directly to **SERP Clustering**.
2. Confirm your country, language, and SERP similarity percentage.
3. Run clustering to fetch SERPs and group related queries.
4. Review the clusters:
- Check if the centroid keyword matches the main intent
- Merge or split clusters only where it is clearly needed
- Note any clusters that look like "supporting content" rather than main pages
You can re-cluster for free using the same SERPs, so do not overthink it on the first pass.
See: [SERP Clustering](https://floyi.com/docs/tools/serp-clustering/)
---
## Step 6: Build your first Topical Map
Now you can turn clusters into a navigable map.
1. In **Clustering**, click **Start Topical Hierarchy** when clusters look right.
2. The map is generated from your clustering data; you land in **Topical Map & Content Plan**.
3. Clean the hierarchy: pillars at the top, clusters under the right pillar, remove noise.
4. Add or adjust URL slugs for page-level topics you plan to publish.
Your Topical Map is now a source of truth for how your site should be structured around this theme.
See: [Topical Map](https://floyi.com/docs/tools/topical-map/)
---
## Step 7: Run your first Topical Authority pass
If your site already has content, you can see where you stand today.
1. In **Topical Map**, click **Next: Topical Authority**.
2. Fix any validation issues (structure, required slugs) if prompted.
3. Start the Topical Authority compute to fetch rankings and AI Overviews for the map.
4. Once it completes, review:
- Coverage across the map
- Visibility and Share of Voice
- Which pillars and topics are currently weak or empty
If your site is new and has little or no content, you can skip this step now and return after you have published a few pieces.
See: [Topical Authority Scorecard](https://floyi.com/docs/tools/topical-authority-scorecard/)
---
## Step 8: Prioritize topics in the Planner
Now turn insight into a simple publishing queue.
1. Open **Topical Authority Planner**.
2. Use filters such as **Not published**, **Not in SERP**, or weak pillars.
3. Pick 3-5 topics for your first batch.
4. Confirm URL slugs, check suggested internal links/anchors, and add team notes.
5. Use the **Published** toggle to reflect current status where applicable.
You now have a small, focused list of topics that matter to authority, not just isolated keywords.
See: [Topical Authority Planner](https://floyi.com/docs/tools/topical-authority-planner/)
---
## Step 9: Generate your first brief and draft
Finish the loop by creating content from the plan.
1. In the Planner, pick one of your selected topics.
2. Open the topic drawer and generate a **Content Brief**:
- Include your Brand Foundation and main persona
- Pull in relevant internal links and anchors
- Review SERP insights and competitors
3. Once the brief looks right, open it in the **Content Creation** workspace.
4. Use the AI Writer to generate a first draft.
5. Edit the draft:
- Correct details and add real examples
- Tighten headings and structure
- Align tone with your brand
When you are happy, mark the content as ready to publish in your own CMS, then update its status in Floyi.
See:
- [Content Briefs](https://floyi.com/docs/tools/content-briefs/)
- [Content Creation](https://floyi.com/docs/tools/content-creation/)
---
## Next steps
After you have completed this first loop:
- Repeat the workflow for additional pillars or themes
- Refine Brand Foundation and personas with real feedback
- Connect [Google Workspace and other integrations](/docs/getting-started/account-settings/) as your workflow grows
- Continue building briefs and drafts for your Topical Map to cover more of your product and customer journey
- Use Scorecard and Planner on a schedule to keep authority on track
From here, the individual module docs go deeper into advanced options, settings and edge cases. When you feel comfortable with this basic loop, the [complete tools reference](https://floyi.com/docs/tools/) is the best place to explore everything else that is available.
Ready to scale up? [Explore Floyi's plans and pricing](/pricing/) to find the right fit for your team.
---
## Managing Your Account Settings
Source: https://floyi.com/docs/getting-started/account-settings/
Settings is where you manage your profile, subscription, credits, external connections, and login security. New to Floyi? Follow the [step-by-step setup guide](/docs/getting-started/) first.
## Accessing Account Settings
1. Click **Settings** in the bottom-left corner of Floyi.
2. The page opens with five tabs:
- **Account**
- **Billing & Credits**
- **Plans & Upgrades**
- **Integrations**
- **Security**
## Account Tab
- Update your **First Name** and **Last Name**, then click **Save Changes**.
- View your email (read-only). Email updates require support-contact `support@floyi.com`.
- Review **Account Overview** (credits and usage snapshot).
## Billing & Credits Tab
- See your **current plan**, status, amount, discounts, and next billing date.
- Click **Manage Subscription** to open Stripe - see [upgrading and downgrading plans](/docs/billing/subscription-management/) for the full walkthrough.
- Open **Billing History** or **Credits History** modals for detailed records.
- Check **Credits Overview** to see remaining credits broken down by type: **Monthly** (subscription credits that reset each billing cycle), **PAYG** (pay-as-you-go credits that never expire), and **Free** (promotional credits). See [how credit types are prioritized](/docs/billing/credits/) when credits are deducted.
- Read any **announcements** tied to billing or credits.
### Pay As You Go Credits
Use the PAYG slider to [purchase additional credits](/docs/billing/purchase-credits/) from 1,000 to 100,000. PAYG credits never expire and are used after your monthly subscription credits are depleted.
- **Plan-based pricing:** The slider automatically reflects your plan's discounted rate-Scale, Pro, and Free plans each have their own per-1,000 pricing. The price you see on the slider is the price you pay at checkout.
- **Bulk discount:** Free plans receive a lower rate when purchasing 50,000+ credits.
- **Promo codes:** Enter an optional promo code before purchasing.
- **Checkout:** Click **Purchase Credits** to complete payment via Stripe Checkout. Credits are added to your account immediately after payment.
**Team members:** PAYG purchases can only be made by the team Owner. Non-owner members will see a notice directing them to the team Owner.
## Plans & Upgrades Tab
- Compare **Pro** and **Scale** plans.
- Toggle **Monthly / Yearly** pricing (yearly shows the monthly equivalent and savings).
- If you're already on a paid plan, click **Manage Subscription**; otherwise, choose a plan and click **Subscribe Now** (promo code optional).
**Team members:** Subscription management is only available to the team Owner.
## Integrations Tab
Connect external services to enhance your Floyi workflow. Currently supported integrations:
### Google Workspace
Connect your Google account to enable exports directly to Google Docs and Google Sheets.
**To connect:**
1. Click **Connect Google Account** in the Google Workspace section.
2. Sign in with your Google account in the popup window.
3. Review the permissions Floyi requests:
- **Google Drive**: Create files in your Drive for exports
- **Google Docs**: Create and edit documents for brief/draft exports
- **Google Sheets**: Create spreadsheets for data exports
4. Click **Allow** to grant access.
5. Once connected, you'll see a green "Connected" status with your Google email.
**What you can do once connected:**
- Export content briefs and drafts directly to Google Docs
- Export Planner data, clustering results, and reports to Google Sheets
- Export Brand Foundation and Audience Insights to Google Docs
**To disconnect:**
1. Click the **Disconnect** button next to your connected account.
2. Confirm the disconnection in the dialog.
3. Your existing exported files remain in your Drive; only future exports are affected.
### Google Business Profile
Connect your verified Google Business Profile to sync business data for local SEO features.
**To connect:**
1. Click **Connect Google Business Profile** in the GBP section.
2. Sign in with the Google account that manages your business profile.
3. Grant permission for Floyi to read your business profile data (read-only access).
4. If you manage multiple locations, select the business profile you want to connect.
5. Once connected, you'll see your business name and connection status.
**What syncs from GBP:**
- Business legal name
- Full address (street, city, state, postal code)
- Primary phone number
- Website URL
- Business category
- Operating hours for each day
- Service areas (for service-area businesses)
**How to use GBP data:**
1. Navigate to [your brand's Brand Foundation](/docs/tools/brand-foundation/).
2. In the **Business Info** card (sidebar), click **Sync from GBP**.
3. Your business data populates automatically.
4. Review and edit any fields as needed.
5. Floyi generates **LocalBusiness Schema (JSON-LD)** from this data for your local SEO pages.
**To disconnect:**
1. Click **Disconnect** next to your connected GBP.
2. Confirm the disconnection.
3. Previously synced data in Brand Foundation remains; only the live connection is removed.
**Notes:**
- GBP connection is read-only-Floyi never modifies your Google Business Profile
- You can reconnect at any time to sync updated data
- If you manage multiple business profiles, you can switch between them here
## Security Tab
- **Change Password:** Enter current password, then new password and confirmation, and click **Update Password**.
- **Log Out:** Use the red **Log Out** button (with confirmation) to end your session.
- Follow the built-in security tips: unique passwords, don't share credentials, log out on shared devices, and contact support for suspicious activity.
---
## Signing In and Signing Out of Floyi
Source: https://floyi.com/docs/getting-started/sign-in-and-out/
## Signing In
Once your Floyi account is activated, you're ready to sign in. If you don't have an account yet, [create one first](/docs/getting-started/sign-up/). Follow these steps:
1. Navigate to the Sign In page.
2. Choose one of the two options:
- **Continue with Google:** Click the Google button and select your Google account (no separate password required).
- **Email and password:** Enter your email and password in the required fields, then click **Sign In**.
After signing in, you'll be redirected to the Floyi dashboard, where you can start using the app's powerful tools.
## Signing Out
Logging out of Floyi is simple. Here's how:
1. Go to the 'Settings' menu in the bottom-left corner of the Floyi app.
2. Scroll down to the very bottom of the page.
3. You'll see the 'Log Out' button highlighted in red.
4. Click on 'Log Out' to safely exit your account.
## Tips for a Smooth Experience
- **Save Time:** Use the Google option or enable your browser's password manager to streamline sign-ins.
- **Stay Secure:** Always log out, especially when using Floyi on shared or public devices.
- **Explore:** After signing in, follow the [guided first session](/docs/getting-started/) to build your first topical map, or review [your account settings](/docs/getting-started/account-settings/) to configure your profile.
---
## How to Create Your Floyi Account
Source: https://floyi.com/docs/getting-started/sign-up/
Creating your account is step one of the [Floyi getting started guide](/docs/getting-started/). It takes about two minutes with Google or email.
## 1. Start the Sign-Up Process
- From the [Login page](https://app.floyi.com/login), click **Continue with Google** or **Don't have an account? Sign up.**
- Both options route you to the sign-up flow at [app.floyi.com/signup](https://app.floyi.com/signup).
## 2. Choose How You Want to Sign Up
- **Sign up with Google:** Click **Continue with Google** and select the Google account you want to use. No separate password or email verification is needed.
- **Sign up with email:** Enter your email and password in the fields provided, then continue.
> **Tip:** For email sign-up, use a strong, unique password that isn't reused elsewhere.
## 3. Submit Your Information
- Click **Sign Up** to create your account.
- If you used Google, you'll be taken straight to Floyi. If you used email, you'll see a confirmation screen with activation instructions.
## 4. Verify Your Email (Email Sign-Up Only)
- Check your inbox for a verification link from Floyi.
> **Note:** If you don't see it in your main inbox, check spam or junk.
## 5. Confirm Your Email
- Click **Confirm** in the email to verify your account.
- You'll be redirected to sign in and start using Floyi.
## Next Steps
- Learn how to [sign in and out of Floyi](/docs/getting-started/sign-in-and-out/) securely.
- Configure your [account settings and integrations](/docs/getting-started/account-settings/) - profile, billing, and Google connections.
---
## Floyi MCP Server
Source: https://floyi.com/docs/mcp/overview/
:::caution[Beta]
The Floyi MCP server is currently in **beta** and available on the **Scale plan**. Tools, limits, and connection steps may change before general availability.
:::
The Floyi MCP server connects compatible AI assistants directly to your Floyi workspace. Instead of switching between your AI assistant and the Floyi app, you work in one conversation: ask for your content gaps, generate a brief for the biggest one, turn it into a draft, and publish it to WordPress or GitHub - all through natural language.
MCP (Model Context Protocol) is an open standard that lets AI assistants securely use external tools. Floyi's server exposes 99 tools covering the full pipeline: brand setup, audience personas, site architecture, topical research, AI Search Gaps, clustering, map building, briefs, drafts, quality review, publishing, and authority monitoring.
_Last updated: 2026-07-21_
## What You'll Learn
- What the Floyi MCP server can do
- How to connect Claude, ChatGPT web, or Codex with a secure sign-in - no API key to manage
- How to connect developer clients with an API key
- How credits work when an AI assistant drives Floyi
- Security, workspaces, and built-in guardrails
- Troubleshooting common connection issues
---
## Part 1: What You Can Do
An AI assistant connected to Floyi can:
- **Explore your strategy** - brands, topical maps, research trees, personas, and authority scores
- **Find opportunities** - content gaps, competitor gaps, AI search citation gaps
- **Run the pipeline** - take a brand from foundation through research, clustering, and map building
- **Produce content** - generate strategy-aware briefs and first drafts using Floyi's own generation pipeline
- **Read work back** - pull finished briefs and MCP-readable draft content out of Floyi for review or reuse; the server flags web-editor-only content it cannot safely project
- **Publish** - send finished articles to connected WordPress sites or commit Markdown/MDX to connected GitHub repositories
- **Monitor** - refresh authority data, compare competitors, track AI search visibility
:::note[How writes work]
Brief and draft generation run through Floyi's own pipeline - the exact same generation tasks the web app uses. When you ask your assistant to "start a draft," Floyi generates it natively (correct sections, internal links, map position, formatting) and saves it to your workspace. You are not asking the assistant to imitate Floyi; you are triggering Floyi to do the work, then reading the result back.
:::
For the full tool list, see the [MCP Tool Catalog](/docs/mcp/tools/). For example prompts and workflows, see [MCP Use Cases & Workflows](/docs/mcp/use-cases/).
---
## Part 2: Requirements
| Requirement | Details |
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| **Floyi Plan** | Scale (legacy Agency accounts remain eligible) |
| **Endpoint** | `https://mcp.floyi.com/mcp` |
| **Transport** | Streamable HTTP |
| **Auth** | **OAuth sign-in** (Claude connector, ChatGPT developer-mode app, or Codex - no key to manage) or an **API key** for developer clients |
| **Client** | Claude (web + Desktop), ChatGPT web in developer mode, Codex in the ChatGPT desktop app, Claude Code, or any Streamable HTTP MCP client |
---
## Part 3: Connect with OAuth (recommended)
The fastest way to connect: add the Floyi endpoint in your assistant's app or MCP settings, then approve the connection in your browser. You do not create, copy, or manage an API key - you sign into Floyi, choose the workspace, and approve.
Connectors are account-level in Claude - add it once and it is available on both claude.ai and Claude Desktop. Requires a Claude Pro, Max, Team, or Enterprise plan.
1. Open Claude → **Settings → Connectors → Add custom connector**.
2. Name it (e.g. "Floyi") and paste the URL: `https://mcp.floyi.com/mcp`. Click **Add**.
3. Click **Connect**. Your browser opens Floyi's authorization page - sign in if you aren't already.
4. **Choose the workspace** (Personal or a team) the connection should use, review the permissions, and click **Allow access**. Your browser returns to Claude and the connector shows as connected.
5. In a new conversation, enable the Floyi connector from the tools menu. Each tool shows its own permission prompt on first use - choose "Always allow" for the tools you're comfortable automating.
Verify it works - ask:
```
Show which Floyi workspace this connection is bound to, then list its brands.
```
ChatGPT web connects to Floyi as a developer-mode app. Developer mode is available on ChatGPT Plus, Pro, Business, Enterprise, and Education plans (not Free or Go); Business, Enterprise, and Education workspaces may require an administrator to allow it.
1. In ChatGPT web, open **Settings → Security and login** and turn on **Developer mode**. If the toggle is unavailable in a managed workspace, ask your workspace administrator to enable it.
2. Close Settings, then open **Plugins** from the ChatGPT sidebar (or go directly to [chatgpt.com/plugins](https://chatgpt.com/plugins)). This is the Plugin directory page - not the "Plugins" tab inside Settings, which only manages plugins you've already installed and has no create button.
3. Select the **+** button in the top-right corner (next to the search box). A **New Plugin** dialog opens - fill it in:
- **Name:** Floyi
- **Description** (optional): Connect Floyi to explore content strategy, run workflows, and create or publish content.
- **Connection:** keep **Server URL** selected and enter `https://mcp.floyi.com/mcp`
- **Authentication:** **OAuth**
- Review the custom-MCP-server notice and tick **I understand and want to continue**.
4. Select **Create**. ChatGPT discovers Floyi's OAuth configuration automatically. When prompted to connect, sign into Floyi, choose the workspace, review the permissions, and select **Allow access**.
5. Start a new ChatGPT conversation, select **+ → More**, and choose **Floyi** from the available apps.
The ChatGPT app and Codex MCP connection are separate. Adding Floyi here does not also connect it to Codex in the ChatGPT desktop app.
Note: Floyi works as a regular ChatGPT app. It is not a Company Knowledge or deep-research source because those modes require standardized `search` and `fetch` tools that Floyi intentionally does not expose.
Codex in the ChatGPT desktop app connects directly to remote MCP servers. Its MCP configuration is shared with Codex CLI and the Codex IDE extension on the same host, but it is separate from ChatGPT web apps and permissions.
1. Open the ChatGPT desktop app, then go to **Settings → MCP servers**.
2. Select **Add server**.
3. Name it "Floyi," choose **Streamable HTTP**, and enter `https://mcp.floyi.com/mcp` as the server URL.
4. Save the server and select **Restart**.
5. Return to **Settings → MCP servers** and select **Authenticate** for Floyi. Your browser opens Floyi's authorization page - sign in, choose the workspace, review the permissions, and select **Allow access**.
6. Start a Codex conversation and enter `/mcp` to confirm that Floyi is connected.
Connecting Floyi to Codex does not also install the Floyi app in ChatGPT web. Complete the ChatGPT web steps separately if you want to use Floyi in both surfaces.
Claude Code supports OAuth for remote MCP servers directly - no key needed:
```bash
claude mcp add --transport http floyi https://mcp.floyi.com/mcp
```
On first use, run `/mcp` and follow the authentication prompt - your browser opens Floyi's authorization page for the same sign-in, workspace choice, and approval. (Prefer an API key instead? See Part 4.)
### Managing your connections
Approved connections appear in Floyi under **Settings → API Keys → Connected Apps**, showing the app, workspace, and last-used date. **Disconnect** there revokes access immediately.
- **One active connection per app, per workspace, per user.** Reconnecting the same app to the same workspace replaces your previous authorization - no duplicate entries. Teammates each have their own connections; a whole team can connect Claude to one team workspace simultaneously.
- **Removing an app, connector, or MCP server inside a client does not always notify Floyi.** If you want access cut off, disconnect it in Floyi - that is the authoritative revocation and takes effect immediately.
- **Workspace binding is permanent per connection.** You choose the workspace on the approval screen; to work in a different workspace, add a separate connection (e.g. name one connector "Floyi - Personal" and another "Floyi - Agency Team").
- **ChatGPT web and Codex connections are separate.** Each has its own OAuth grant and permission settings, even when you use both through the ChatGPT desktop app.
---
## Part 4: Developer Clients with API Keys
Scripts, headless automations, and MCP clients that send custom headers can authenticate with an API key instead of OAuth. The MCP server shares keys with [Floyi's REST API](/docs/api/reference/) - one key works for both.
### Create your API key
1. Switch Floyi to the Personal or team workspace the key should use - **a key is permanently bound to the workspace active when it is created**.
2. Go to **Settings > API Keys**.
3. Click **Create API Key** and give it a descriptive name (e.g., "Reporting script").
4. Choose the key type. **Integration** defaults to the full read/write pipeline; **Developer** defaults to read-only access. Scopes control which tool calls succeed - a key without `content:write` cannot generate drafts, even though the client may still list the tool.
5. **Copy the key immediately** - it is shown only once.
:::tip
One key holds all the scopes you grant it - you never need separate keys per feature. Create separate keys per _person or tool_ instead, so you can revoke them independently. Scopes cannot currently be edited after creation; create a replacement key when the permission set needs to change.
:::
### Connect a developer client
Set your key as an environment variable, then add this `.mcp.json` file at the root of your project:
```json
{
"mcpServers": {
"floyi": {
"type": "http",
"url": "https://mcp.floyi.com/mcp",
"headers": {
"X-API-Key": "${FLOYI_API_KEY}"
}
}
}
}
```
Launch Claude Code with `FLOYI_API_KEY` set in its environment, approve the project-scoped server when prompted, then use `/mcp` to verify the connection.
Clients that only support local stdio servers can use the third-party `mcp-remote` bridge:
```json
{
"mcpServers": {
"floyi": {
"command": "npx",
"args": [
"-y",
"mcp-remote@latest",
"https://mcp.floyi.com/mcp",
"--header",
"X-API-Key:${FLOYI_API_KEY}",
"--transport",
"http-only"
],
"env": {
"FLOYI_API_KEY": "fyi_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
}
}
}
```
The bridge requires Node.js and stores the key in your local configuration, so protect the file and never commit it.
Any client that supports **Streamable HTTP** transport can connect:
- **URL:** `https://mcp.floyi.com/mcp`
- **Auth:** OAuth (spec-compliant clients discover Floyi's sign-in automatically), or the header `X-API-Key: fyi_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
The server is self-describing - once connected, your client fetches the full tool list with parameter schemas automatically.
:::caution
Never share your API key or commit it to a repository. If a key is exposed, revoke it in **Settings > API Keys** and create a new one - revocation takes effect immediately.
:::
### Verify the connection
Start a new conversation and ask:
```
Show which Floyi workspace this connection is bound to, then list its brands.
```
Confirm the returned workspace name before trusting the brand list. A good second
prompt is **"Read the Floyi capabilities first"** - the `floyi_capabilities` tool
teaches the assistant Floyi's ground rules (which actions are irreversible, how
long generations really take, and how credits work) before it starts working.
---
## Part 5: How Credits Work Over MCP
**Tool calls themselves are free.** Reading your map, searching topics, checking pipeline status, listing briefs - none of it costs credits, no matter how often the assistant calls.
Credits are spent only when a tool triggers a configured paid generation or data action. Most reuse the app's pricing and workflow; the catalog calls out MCP-specific pricing where it differs, such as node-metrics fetching.
| Action | Priced like the web app |
| ----------------------------------------------- | ---------------------------------------------------------------------------- |
| Brief generation | Brief cost x AI model multiplier |
| Draft generation | Draft cost x AI model multiplier |
| Keyword generation (research step) | Per topic x model multiplier |
| SERP clustering | Per keyword, charged only on successful completion |
| Content info generation (map building) | Per topic x model multiplier |
| Topic silo research | Model-based |
| Authority refresh | Per topic for SERPs, plus the same per-topic cost for each enabled AI engine |
| AIRS analysis | Report bundle x model multiplier, deducted on completion |
| AI Search Gaps | Fixed analysis stages plus five queries per selected engine |
| Node metrics fetch (search volume) | Batched pricing: 5 keywords per credit at the base rate, rounded up |
| Draft quality re-analysis | 10 credits, settled only when the run succeeds |
| Fresh AI-engine results during brief generation | 1 credit per selected engine |
Built-in cost safety:
- **Upfront balance checks** - paid tools check the available balance before starting. If credits are insufficient, the error states the shortfall.
- **Estimates and confirmations** - high-blast-radius operations such as pipeline clustering and authority refresh enforce a confirmation step. Other paid tools expose their cost or support an estimate call, and the assistant is instructed to confirm that cost with you before starting.
- **Balance visibility** - paid responses return the cost and current available or remaining balance where the workflow provides it. Use `floyi_credits` for the authoritative current balance.
- **Refund and settlement rules** - a pending brief can be cancelled through MCP and its reserved credits refunded. Failed or cancelled pipeline clustering does not charge, and quality re-analysis settles only on success.
- **Model choice** - the assistant can list available AI models with their multipliers and choose a lower-cost model for an individual run or a one-at-a-time production sequence.
- **Fair-use caps on free AI actions** - a small set of free tools that trigger AI work on Floyi's side (persona generation, brand-from-URL analysis, slug generation, research dedup, knowledge-base imports) have per-minute, daily, and monthly fair-use caps. The limits are generous for normal use; if a cap is reached, the tool says so and when to retry.
In a team workspace, credits come from the team owner's pools - the same as in the app. This applies to OAuth connections bound to a team workspace too.
---
## Part 6: Security, Workspaces & Guardrails
**Access control**
- **OAuth connections** - approved on a consent screen that shows the app and permissions; secured with short-lived, automatically rotating tokens. Revoke anytime in **Settings > API Keys > Connected Apps**.
- **Scopes** - each API key can execute only the tool calls its scopes allow (OAuth connections carry the standard full-pipeline permission set, shown on the approval screen). A client may still display tools the connection cannot run.
- **Workspace isolation** - a connection sees only its workspace's brands. Team connections verify membership on every call; if you leave a team, your connections to it stop working.
- **Plan enforcement** - every call re-checks plan eligibility. A downgraded account's connections and keys stop working immediately.
- **Audit logging** - every tool call is logged. Settings shows each connection's last-used date; detailed audit records are retained server-side.
- **Instant revocation** - revoke a key or disconnect an app in Settings and it stops working immediately.
**Guardrails on actions**
The MCP server enforces the same rules as the app, plus agent-specific protections:
- High-blast-radius overwrites and paid runs use confirmation or estimate flows. Other destructive tools state their impact so the assistant can get your approval before acting.
- Map edits snapshot the map before applying, and hierarchy changes are revertible overrides.
- WordPress publishing defaults to WordPress-side **draft** status - nothing goes live without review.
- GitHub publishing commits directly to the configured branch, so the assistant must confirm the repository and branch first.
- Assistants can make targeted plain-text edits to draft sections, intros, and key takeaways. Full rich-text structure, formatting, links, embeds, visual review, and version restoration remain in the Floyi editor.
- Pipeline stage changes move forward by default. A guarded recovery path can return clustering or map-building stages to Topical Research; returning from Topical Authority remains blocked.
**Rate limits**
Every connection is rate limited per minute:
| Connection type | Requests per minute |
| --------------------- | ------------------- |
| OAuth connection | 60 |
| Developer key | 60 |
| Integration key | 120 |
| Admin / Internal key | 300 |
---
## Part 7: Troubleshooting
| Problem | What to check |
| -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| App or MCP connection fails before sign-in opens | Confirm the URL is exactly `https://mcp.floyi.com/mcp` - the Floyi app or website URL will not work. |
| "This authorization request has expired" | The approval window is time-limited. Start the connection again from your assistant. |
| Approval screen says a Scale plan is required | MCP connections require the Scale plan (legacy Agency accounts remain eligible). Upgrade, then retry the connection. |
| Connection stopped working after a plan change | Plan eligibility is re-checked on every call. Restore a Scale plan and the existing connection resumes. |
| `401 Unauthorized` (API key) | The key is wrong, expired, or revoked. Create a fresh key and update your client config. |
| `403 IP not allowed` (API key) | The key has a server-configured IP allowlist. Use an allowed network or contact Floyi support. |
| `429 Rate limit exceeded` | Too many calls in one minute. Wait 60 seconds and retry. |
| Scope denied | The API key lacks the required scope. Check the [Tool Catalog](/docs/mcp/tools/), then create a replacement key with the correct permissions. |
| Assistant can't see a recently added tool | The client may cache the tool list. Refresh or reconnect the app/MCP server, then start a new conversation. |
| One tool appears stuck while others work | Check for a pending tool-approval prompt, then verify whether the operation is a long-running task that should be polled with its matching status tool. |
| Assistant says a brand is missing | Check the connection's workspace - personal connections don't see team brands and vice versa. Ask for `floyi_get_workspace` to see which workspace is bound. |
| A disconnected app still shows in Connected Apps | Removing it inside the client doesn't always notify Floyi. Disconnect it in **Settings > API Keys > Connected Apps** - reconnecting also replaces the old entry. |
---
## Frequently Asked Questions
**How is this different from the Floyi REST API?**
The [REST API](/docs/api/reference/) is for code - scripts, integrations, and custom dashboards you build and maintain. The MCP server is for conversation - you (or a scheduled agent) direct the work in natural language and the assistant picks the right tools. They share the same data and permission model; use whichever fits the job.
**Does using MCP cost extra?**
There is no MCP connection fee or generic per-tool-call charge. Credits are spent only when you start one of the paid generation or data actions listed above.
**Which AI assistants work with it?**
Claude (web and Desktop) via a custom connector, ChatGPT web via a developer-mode app, Codex in the ChatGPT desktop app, Claude Code, and any MCP client that supports Streamable HTTP. These clients can use OAuth; developer clients that support custom headers can use an API key instead.
**Can my whole team use it?**
Yes. Each member connects their own assistant while the team workspace is selected on the approval screen - everyone gets their own connection, all scoped to the team's brands, and paid actions draw from the team owner's credit pools. For scripts and automations, create a separate API key per person or tool instead of sharing one.
**Do I need an API key to use Claude, ChatGPT, or Codex with Floyi?**
No. These connection flows use OAuth - you sign in and approve without creating, copying, or managing an API key. API keys are only for developer clients and scripts.
**What can't it do?**
Complete rich-text editing and visual review, article images, connection setup, billing, team management, API-key management, and several app-specific import or analytics workflows remain in the app. See [what still needs the web app](/docs/mcp/use-cases/#what-still-needs-the-web-app).
---
## MCP Tool Catalog
Source: https://floyi.com/docs/mcp/tools/
:::caution[Beta]
The Floyi MCP server is currently in **beta** and available on the **Scale plan**. See the [MCP overview](/docs/mcp/overview/) for setup.
:::
This page lists every tool the Floyi MCP server exposes, grouped by where it sits in your workflow. You don't need to memorize any of this - the server is **self-describing**, so your AI assistant fetches the full tool list with parameter schemas the moment it connects. Use this catalog to understand what's possible and what each tool costs.
_Last updated: 2026-07-21 (99 tools)_
**How to read the tables:**
- **Credits** - `Free` means the tool never spends credits. Tools marked **Credits** trigger a configured paid generation or data action; the row states the current pricing model, including MCP-specific pricing where applicable. Paid tools return a cost or estimate; use `floyi_credits` for the authoritative current balance. See [how credits work over MCP](/docs/mcp/overview/#part-5-how-credits-work-over-mcp).
- **Scope** - the permission the connection needs for the call to succeed. **OAuth connections** (Claude, ChatGPT, Codex) carry the full standard permission set shown on the approval screen, so every scope below is covered. **API keys** hold the scopes selected at creation in **Settings > API Keys** (not currently editable afterward) - your client may still list tools the key cannot execute.
---
## Start Here
Orientation tools your assistant should use early in a session.
| Tool | What it does | Credits | Scope |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------------- |
| `floyi_get_workspace` | Show the Personal or team workspace permanently bound to the API key. Call before brand discovery. | Free | `user:read` |
| `floyi_capabilities` | Floyi's ground rules for agents: irreversible actions, real generation timings, hard limits, and which tool does what. Assistants should read this first. | Free | `user:read` |
| `floyi_credits` | Check remaining credits across all pools, plus plan and workspace. | Free | `user:read` |
| `floyi_list_models` | List available AI models with their credit cost multipliers. | Free | `user:read` |
| `floyi_check_task` | Poll the progress of a brief or draft generation task. | Free | `briefs:read` |
## Brands
| Tool | What it does | Credits | Scope |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- | -------------- |
| `floyi_list_brands` | List all brands in the workspace with summary stats. | Free | `brands:read` |
| `floyi_get_brand_overview` | Detailed brand overview: context, map summary, authority metrics, pipeline health. | Free | `brands:read` |
| `floyi_create_brand` | Create a new brand. | Free | `brands:write` |
| `floyi_create_brand_from_url` | Create a brand from a website URL using Floyi's scrape + AI analysis. | Free | `brands:write` |
| `floyi_update_brand` | Update brand foundation fields. | Free | `brands:write` |
| `floyi_set_brand_stage` | Route the brand through the app's Continue transitions, including Resources Only, site architecture + resources, or architecture-only. Forward by default; a guarded recovery path can return clustering/map building to Topical Research, but cannot revert from Topical Authority. | Free | `brands:write` |
## Audience & Personas
| Tool | What it does | Credits | Scope |
| ------------------------- | --------------------------------------------------------------------------------------------------------------- | ------- | -------------- |
| `floyi_generate_personas` | AI-generate and add 1-5 buyer personas, optionally steered with your input. Existing personas are not replaced. | Free | `brands:write` |
| `floyi_edit_persona` | Update or delete a buyer persona. | Free | `brands:write` |
| `floyi_list_personas` | List buyer personas (also used to pick personas for briefs). | Free | `brands:read` |
## Site Architecture
| Tool | What it does | Credits | Scope |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- | -------------- |
| `floyi_get_site_architecture` | Read the site architecture, pages by kind, and the available site-type options. | Free | `brands:read` |
| `floyi_set_site_type` | Set the brand's site type (local, services, SaaS, e-commerce, content). | Free | `brands:write` |
| `floyi_generate_site_architecture` | Generate site architecture pages from your business inputs for local, services, SaaS, or e-commerce sites. Content-only sites take their structure from the topical map and do not use this generator. | Free | `brands:write` |
| `floyi_update_site_page` | Update one page's primary tracking query or authority-tracking status. | Free | `brands:write` |
| `floyi_edit_site_pages` | Add, update, or delete architecture pages, or extract a location taxonomy from a source URL. | Free | `brands:write` |
## Topical Research
| Tool | What it does | Credits | Scope |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | ---------------- |
| `floyi_get_research_setup` | Research config, plan allocation status, and where you are in the 4-step research workflow. | Free | `research:read` |
| `floyi_set_research_setup` | Set the core topic, seed keywords, and persona selection. | Free | `research:write` |
| `floyi_generate_research` | Run one of the 4 research generation steps. Topic steps are free within your plan's research allocation; the keyword step charges credits (per topic x model multiplier). | Free / Credits | `research:write` |
| `floyi_get_research` | Read the topical research tree (or just its stats). | Free | `research:read` |
| `floyi_modify_research` | Add, rename, move, merge, or delete research nodes and edit their keywords. | Free | `research:write` |
| `floyi_research_dedup` | Free embedding-based scan for near-duplicate topics across the tree - feeds merge operations. | Free | `research:write` |
| `floyi_run_ai_search_gaps` | Run AI Search Gaps discovery: persona-grounded questions are asked across AI search engines and matched against your research tree. Pricing includes fixed analysis stages plus 5 queries per selected engine; `estimate_only` returns the exact price first. | Credits (fixed + per engine) | `research:write` |
| `floyi_check_ai_search_gaps` | Poll a discovery run, read its gap topics when complete, or list a brand's runs. | Free | `research:read` |
| `floyi_apply_ai_search_gaps` | Add reviewed gap topics into the research tree at their suggested placement, or take a previously added one back out. | Free | `research:write` |
## Clustering (Pipeline)
Takes the research tree's keywords through SERP-based clustering - the step before map building.
| Tool | What it does | Credits | Scope |
| --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | ------------------ |
| `floyi_get_clustering_status` | Clustering state, clusterable keyword count, and the exact cost before you start. | Free | `clustering:read` |
| `floyi_start_pipeline_clustering` | Start the SERP fetch + clustering run. Requires a spend confirmation; charged per keyword **only on success**. Recluster mode (recompute from stored SERPs) is free. | Credits (per keyword) | `clustering:write` |
| `floyi_check_clustering_progress` | Poll progress or cancel the run. | Free | `clustering:read` |
| `floyi_get_clusters` | Read cluster groupings for review, with search and filtering. | Free | `clustering:read` |
| `floyi_edit_clusters` | Targeted cluster merge / move / remove edits - the same validation as the app's cluster editor. | Free | `clustering:write` |
## Map Building
| Tool | What it does | Credits | Scope |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------- | ------------ |
| `floyi_get_map_status` | Stage-aware status: prerequisites, per-topic progress, running tasks, and which actions are available or blocked (with reasons). Call this first at the map stage. | Free | `maps:read` |
| `floyi_generate_map_hierarchy` | Generate or rebuild the topical map structure from the clustering run. Asks for confirmation before overwriting. | Free | `maps:write` |
| `floyi_generate_content_info` | Generate titles, search intent, buyer journey stage, content type, and snippets per topic. | Credits (per topic) | `maps:write` |
| `floyi_generate_url_slugs` | Generate URL slugs for topics - fill missing only, or regenerate all with confirmation. The brand's selected resource URL prefix is baked into generated slugs. | Free | `maps:write` |
| `floyi_modify_map` | Targeted map edits: move a topic, rename a branch, delete a topic (with confirmation). Every edit snapshots the map first. | Free | `maps:write` |
| `floyi_check_map_task` | Poll map-building and persona task progress. | Free | `maps:read` |
## Topical Map & Organizer
Structure management once the brand reaches Topical Authority.
| Tool | What it does | Credits | Scope |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- | ----------------- |
| `floyi_search_topics` | Search topics in the map by keyword, with content status. | Free | `maps:read` |
| `floyi_modify_hierarchy` | Add, rename, move, combine, archive, or restore hierarchy nodes (as revertible overrides). | Free | `maps:write` |
| `floyi_get_overrides` | List the active hierarchy overrides layered on the base map. | Free | `maps:read` |
| `floyi_clear_overrides` | Undo hierarchy overrides - specific nodes or all. | Free | `maps:write` |
| `floyi_add_silo` | Research a new topic silo for the map. Supports `estimate_only` to preview cost without starting. | Credits (model-based) | `maps:write` |
| `floyi_silo_status` | Check silo research progress. | Free | `maps:read` |
| `floyi_approve_silo` | Approve and integrate the researched silo into the map. | Free | `maps:write` |
| `floyi_discard_silo` | Discard a pending silo. | Free | `maps:write` |
| `floyi_manage_keywords` | List, add, or delete anchor keywords on a map node. | Free | `authority:write` |
| `floyi_update_url_slug` | Update a single node's URL slug. | Free | `authority:write` |
| `floyi_fetch_node_metrics` | Fetch search volume, CPC, and competition onto topic nodes. Supports an estimate-only call; pricing is 5 keywords per credit at the base rate, rounded up. | Credits (batched keywords) | `authority:write` |
## Topical Authority & Competitive Intelligence
| Tool | What it does | Credits | Scope |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ----------------- |
| `floyi_find_content_gaps` | Find gaps across the map: missing content, weak coverage, low rankings. | Free | `authority:read` |
| `floyi_get_pillars` | Pillar-level authority breakdown: TAS, coverage, visibility. | Free | `authority:read` |
| `floyi_get_competitors` | Competitor comparison metrics. | Free | `authority:read` |
| `floyi_get_internal_links` | Internal link suggestions for a topic, grouped by relation with relevance and reasoning. | Free | `authority:read` |
| `floyi_get_ai_visibility` | AI search visibility: where you (or a competitor domain) are cited or mentioned in AI Overviews, AI Mode, Gemini, and ChatGPT results. | Free | `authority:read` |
| `floyi_get_gsc_insights` | Read connected Google Search Console summaries, snapshots, query trends, and page performance. | Free | `authority:read` |
| `floyi_get_ta_settings` | Read the aliases, query strategy, schedule, locale, and engine settings that define authority tracking. | Free | `authority:read` |
| `floyi_update_ta_settings` | Update authority tracking settings. Enabling a recurring schedule requires explicit approval because scheduled runs spend credits. | Free | `authority:write` |
| `floyi_refresh_authority` | Fetch fresh SERPs and AI Overviews, optionally track AI Mode, ChatGPT, and Gemini, then recompute authority. Requires cost confirmation; each enabled optional engine adds the same per-topic cost as the SERP run. | Credits (per topic x enabled sources) | `authority:write` |
| `floyi_recompute_authority` | Recompute authority scores from existing stored data without fetching fresh SERPs. | Free | `authority:write` |
| `floyi_check_authority_task` | Poll authority task progress. | Free | `authority:read` |
| `floyi_classify_intents` | Classify search intent and funnel stage for unclassified topics in the map. | Free | `authority:write` |
## Content Briefs
Brief generation mirrors the app's 4-step modal: competitors, personas, keywords + knowledge base, links.
| Tool | What it does | Credits | Scope |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------- | -------------- |
| `floyi_get_serp_data` | Read stored standard SERP results and stored AI-response availability for competitor selection, or fetch fresh standard SERP results for free. | Free | `briefs:read` |
| `floyi_get_knowledge_base` | List knowledge base categories and documents for brief scoping (Step 3). | Free | `brands:read` |
| `floyi_add_kb_document` | Import a knowledge-base document from a URL or pasted text for use in briefs and drafts. | Free | `brands:write` |
| `floyi_get_kb_document` | Read a knowledge-base document's full text and metadata. | Free | `brands:read` |
| `floyi_manage_kb` | Categorize or delete knowledge-base documents and create, rename, or delete categories. | Free | `brands:write` |
| `floyi_generate_brief` | Generate a content brief with all four selection steps: competitors, personas, keywords + knowledge base, and links. Optional fresh AI Mode, ChatGPT, and Gemini inputs add 1 credit each. | Credits (x model multiplier + selected engines) | `briefs:write` |
| `floyi_cancel_task` | Cancel a pending brief generation task and refund its reserved credits. Draft cancellation is not exposed. | Free | `briefs:write` |
| `floyi_list_briefs` | List briefs with status. | Free | `briefs:read` |
| `floyi_get_brief` | Read the full brief: outline and brief content (curated version if one exists). | Free | `briefs:read` |
| `floyi_edit_brief` | Targeted brief curation edits - versioned and revertible. | Free | `briefs:write` |
| `floyi_get_optimizer_data` | Content Optimizer terms (ranked by relevance, with usage ceilings) and entities for a brief. | Free | `briefs:read` |
## Drafts & Publishing
| Tool | What it does | Credits | Scope |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | --------------- |
| `floyi_generate_draft` | Generate a first draft from a completed brief, with intent, custom prompt, personas, and optional Research Agent or intro/key-takeaways specialists. Conversion Coach is automatic for architecture pages. | Credits (base + specialists, x model multiplier) | `content:write` |
| `floyi_list_articles` | List valid completed drafts (`draft_done`) only. Ungenerated `ready` scaffolds are excluded; an empty list means no drafts/articles. | Free | `content:read` |
| `floyi_get_article` | Read a valid completed draft section by section, plus its integrated body. A scaffold returns `ARTICLE_NOT_GENERATED`; editor-only rich-text changes may return `content_location: "editor"` when the latest prose cannot be safely projected. | Free | `content:read` |
| `floyi_edit_draft_section` | Make a surgical plain-text edit to one draft section's human-revision layer. Refuses while the draft is generating or open in the app editor. | Free | `content:write` |
| `floyi_edit_article_block` | Edit the article's intro or key-takeaways block as plain text. Refuses while the draft is generating or open in the app editor. | Free | `content:write` |
| `floyi_get_draft_quality` | Read a draft's Page Quality Scorecard (overall score, bucket, five dimensions with reasoning and evidence) plus the brief's information-gain targets. | Free | `content:read` |
| `floyi_reanalyze_draft_quality` | Re-score the draft's current content against the quality rubric. Same price as the app's Re-analyze button; a failed run never charges. | 10 credits | `content:write` |
| `floyi_set_editorial_state` | Set the review state to Awaiting Review, Needs Editing, Approved, or Published. The Published state records a fact; it does not publish to a CMS. | Free | `content:write` |
| `floyi_check_pipeline` | Content pipeline status across brands: briefs, drafts, and failures. | Free | `content:read` |
| `floyi_list_wordpress_connections` | List connected WordPress sites. | Free | `content:read` |
| `floyi_publish_wordpress` | Publish an article to WordPress - defaults to WordPress-side draft status. | Free | `content:write` |
| `floyi_check_wordpress_task` | Poll a WordPress publish task. | Free | `content:read` |
| `floyi_list_github_connections` | List connected GitHub repositories with their publish defaults (branch, content path, file format). | Free | `content:read` |
| `floyi_publish_github` | Publish an article to a connected GitHub repo as Markdown/MDX. Commits directly to the configured branch with no draft staging and does not mark the article Published until the live deployment is confirmed separately. | Free | `content:write` |
| `floyi_check_github_task` | Poll a GitHub publish task. | Free | `content:read` |
## Content Guide
| Tool | What it does | Credits | Scope |
| -------------------------------- | --------------------------------------------------------------------------------- | ------- | --------------- |
| `floyi_get_content_guide` | Read a brand's content guide entries. | Free | `content:read` |
| `floyi_add_content_guide_entry` | Add a terminology, compliance, competitor-policy, messaging, or boilerplate rule. | Free | `content:write` |
| `floyi_edit_content_guide_entry` | Update or delete a content guide entry. | Free | `content:write` |
## Toolbox: AIRS Analyzer
Runs a query across AI search engines and synthesizes per-engine analysis, comparative synthesis, and strategic recommendations.
| Tool | What it does | Credits | Scope |
| --------------------------- | -------------------------------------------------------------------------------------------- | ----------------------- | --------------- |
| `floyi_run_airs_analysis` | Run an AIRS analysis for a query. Supports `estimate_only` to preview cost without starting. | Credits (on completion) | `toolbox:write` |
| `floyi_check_airs_analysis` | Poll analysis progress. | Free | `toolbox:read` |
| `floyi_get_airs_result` | Get results by stage - defaults to the strategic recommendations. | Free | `toolbox:read` |
| `floyi_list_airs_analyses` | Browse past analyses. | Free | `toolbox:read` |
## Toolbox: Keyword Clustering (Standalone)
Cluster any keyword list - independent of the brand pipeline.
| Tool | What it does | Credits | Scope |
| ----------------------------- | ----------------------------------------------------------------------------------------------------- | --------------------- | ------------------ |
| `floyi_start_clustering` | Start a clustering run for a keyword list. Supports `estimate_only` to preview cost without starting. | Credits (per keyword) | `clustering:write` |
| `floyi_check_clustering` | Poll clustering progress. | Free | `clustering:read` |
| `floyi_serp_cluster_report` | SERP feature report for a finished run: domain frequency and SERP feature counts. | Free | `clustering:read` |
| `floyi_serp_keyword_analysis` | Keyword-level SERP feature analysis, including AI Overview presence. | Free | `clustering:read` |
---
## Resources & Prompts
Beyond tools, the server provides MCP **resources** (raw data your assistant can read as context) and **prompts** (pre-built report templates).
| Resource | What it provides | Scope |
| ---------------------------- | -------------------------------------------------------------------------------------------------- | ------------------------ |
| `floyi://guide` | The server's full agent guide: data semantics, stage routing, costs, timing, and safety rules. | Authenticated connection |
| `floyi://brands` | All brands with summary data. | `brands:read` |
| `floyi://brand/{id}/context` | Brand voice, positioning, and strategy context. | `brands:read` |
| `floyi://brand/{id}/map` | The topical map hierarchy with resource and architecture scopes; very large maps return a summary. | `maps:read` |
| Prompt | What it generates | Scope |
| ------------------- | ----------------------------------------------------------------------------------------------------------------- | ------------- |
| `weekly_report` | Weekly content status report for a brand: pipeline, gaps, progress. | `brands:read` |
| `gap_analysis` | Prioritized content gap report, optionally filtered to a cluster. | `brands:read` |
| `content_gap_audit` | Per-node brief and valid-draft audit, joined by node ID and split between resource topics and architecture pages. | `maps:read` |
| `pipeline_overview` | Cross-brand pipeline overview with credit balance. | `user:read` |
---
## Permission Scopes
| Scope | Grants |
| -------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `brands:read` / `brands:write` | Read / manage brands, personas, site architecture, and pipeline stage |
| `research:read` / `research:write` | Read / manage topical research setup, generation, and the research tree |
| `clustering:read` / `clustering:write` | Read / run keyword clustering (pipeline and standalone) and SERP reports |
| `maps:read` / `maps:write` | Read / build and edit topical maps, hierarchy, and silos |
| `authority:read` / `authority:write` | Read / refresh authority metrics, node keywords, slugs, and intents |
| `briefs:read` / `briefs:write` | Read / generate and curate content briefs |
| `content:read` / `content:write` | Read / generate and target-edit drafts, manage the content guide, publish to WordPress or GitHub |
| `toolbox:read` / `toolbox:write` | Read / run standalone tools (AIRS Analyzer) |
| `user:read` | Bound-workspace identity, credits, AI models, and user-profile reads |
:::tip
A reporting-only assistant needs just the `:read` scopes. Grant `:write` scopes only to keys that should generate content or change structure.
:::
---
## MCP Use Cases & Workflows
Source: https://floyi.com/docs/mcp/use-cases/
:::caution[Beta]
The Floyi MCP server is currently in **beta** and available on the **Scale plan**. See the [MCP overview](/docs/mcp/overview/) for setup.
:::
Everything on this page is a real prompt you can type into a connected AI assistant. Single tools answer single questions; the real power is in compositions - the assistant chains tools together to run the workflows an SEO team actually runs.
_Last updated: 2026-07-21_
:::note[How writes work]
When you ask your assistant to generate a brief or draft, Floyi's own generation pipeline does the work - the exact same process as clicking Generate in the app. The result lands in your workspace with correct sections, internal links, and map position, and the assistant reads it back to you.
:::
---
## Getting Oriented
**"What brands do I have and where do they stand?"**
| Ask | What happens |
| ----------------------------------------------- | ---------------------------------------------------------------------- |
| "List all my Floyi brands" | Every brand with summary stats |
| "Tell me everything about [brand]" | Full context: strategy, map summary, authority scores, pipeline health |
| "What's the brand voice for [brand]?" | Reads the brand context resource |
| "Compare the authority scores of my two brands" | Side-by-side comparison |
| "How many credits do I have left?" | Balance across all pools, plus plan |
Good for starting a planning session, briefing a new team member, or checking which brand needs attention.
## Finding Opportunities
**"Where am I weak and what should I write next?"**
| Ask | What happens |
| ----------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| "Find the biggest content gaps for [brand]" | Gaps ranked across the map: missing content, weak coverage, low rankings |
| "Find gaps in the '[cluster]' cluster" | Scoped to one part of the map |
| "Run a gap analysis for [brand]" | Prioritized gap report (built-in prompt) |
| "Audit which topics have briefs and articles" | Authoritative per-node content audit, split by content topics vs. site pages (built-in prompt) |
| "Generate a weekly report for [brand]" | Pipeline status, top gaps, and progress in one summary |
| "Search for topics about '[keyword]' in my map" | Existing topics with content status - check before you write |
Three gap types come back: **missing** (no published content), **weak coverage** (content exists but covers the topic thinly), and **low ranking** (published but ranking past position 20). Missing is your net-new queue; the other two are your refresh queue.
## Generating Briefs & Drafts
**"Create a brief for this topic, then draft it."**
Brief generation mirrors the app's four-step modal: competitors, personas, keywords + knowledge base, then links. The last three inputs are optional at the API level, but the assistant should walk through every step and only skip one when you explicitly choose to:
| Ask | What happens |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| "Get the SERP data for [topic] - how old is it?" | Stored SERP results with age, so you can decide whether to refresh |
| "That's stale - fetch fresh SERP data" | Free refetch, saved to the same storage the app uses |
| "Brief this topic using results 1, 2, 4, and 6" | The assistant selects competitors the way you would with checkboxes |
| "Use persona [name] and pull in the knowledge base" | Personas and KB scope included in the brief |
| "Is my brief done yet?" | Progress check |
| "Generate a draft from the completed brief" | Floyi drafts it natively |
| "Show me the full draft" | Reads the current MCP-readable text section by section; if the latest content exists only in the rich-text editor, the assistant tells you to review it in the app |
| "Which AI models can I use and what do they cost?" | Models with credit multipliers - choose a lower-cost model for this run if needed |
| "What terms should the draft for brief [id] cover?" | Content Optimizer terms and entities, ranked by relevance |
| "Replace the weak competitor-comparison section in this brief" | Free, versioned brief curation without regenerating the whole brief |
| "Use the Research Agent and add an intro with key takeaways" | Enables the draft specialists before generation; specialist costs are included in the estimate |
| "Fix the inaccurate claim in section 4" | Targeted plain-text section edit, provided the article is not open in the app editor |
| "Re-score the draft after that fix" | Runs the Page Quality Scorecard again for 10 credits, charged only if the run succeeds |
Paid generation checks the available balance before starting. The assistant should confirm the displayed cost with you first. A pending brief can be cancelled through MCP and its reserved credits refunded; draft cancellation is not currently exposed.
## Running the Full Pipeline
An assistant can take a brand from zero to Topical Authority - creating the brand, generating personas, building the site architecture, running topical research, clustering keywords, and building the map:
```
1. "Create a brand for acme.com - analyze the site" (brand foundation)
2. "Generate 3 buyer personas" (audience insights)
3. "Set the site type to SaaS. Build a SaaS Site + Resources, then generate the architecture"
4. "Set the core topic and run topical research" (4 generation steps)
5. "Find duplicate topics in the research tree and merge them"
6. Optional: "Run AI Search Gaps - what do the AI engines cover that my tree doesn't?"
(persona-grounded, cost confirmed first; review the gaps, add the keepers)
7. "Cluster the keywords" (confirms cost first)
8. "Review the clusters - merge anything that overlaps"
9. "Generate the topical map"
10. Decide whether the optional content info snapshots (planning metadata) are useful, then generate them if wanted; confirm the resource URL prefix and generate URL slugs
11. "Advance to Topical Authority"
```
Things the assistant knows (and will tell you):
- **Costs are surfaced before spending.** Pipeline clustering enforces a confirmation flag; research, AI Search Gaps, content info, briefs, and drafts expose their cost or estimate so the assistant can get your approval before starting.
- **Some steps are one-way.** Building the map locks clustering - the assistant surfaces irreversible steps before taking them.
- **Research topic steps are free within your plan's allocation**; keyword generation is the stage's main credit spend.
- **Site architecture has a scope choice.** A site can continue as "[Site] + Resources", "Resources Only", or "[Site] Only" - the labels match your site type (e.g. "SaaS Site + Resources"). The site-only route goes directly to Topical Authority and skips topical research.
- **Content info is optional planning metadata.** It is useful for prioritization and stakeholder handoffs, but briefs and drafts do not depend on it. Make the choice before Topical Authority, where content-info generation becomes locked.
## Managing the Map
**"Restructure my topical map."**
These commands drive the Authority Organizer, so they apply once the brand reaches Topical Authority. Before that, map-stage editing is limited to moving, renaming, and deleting clusters.
| Ask | What happens |
| ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| "Move 'link building strategies' under the 'off-page SEO' pillar" | Re-parents the topic |
| "Combine 'SEO audit' and 'site audit' into 'SEO Site Audit'" | Merges duplicates, keeping both as anchor keywords |
| "Rename 'SEO tips' to 'Enterprise SEO Best Practices'" | Renames the topic |
| "Show me all my hierarchy overrides" | Lists the active overrides layered on the base map - each revertible |
| "Clear all hierarchy overrides" | Undo |
| "Research and add a silo for 'programmatic SEO'" | Researches the new cluster; preview the clustering in the app, then the assistant approves the integration |
| "Add 'spf record, dkim setup' to the [topic] node" | Keyword management per node |
| "Set the slug for that node to 'email-deliverability-guide'" | Slug update (keep slugs evergreen - no years) |
| "Fetch search volume for the topics in [cluster]" | Volume, CPC, and competition fetched onto the nodes - estimate shown first |
## Monitoring Authority & Competitors
**"How strong is my topical authority, and who's beating me?"**
| Ask | What happens |
| ------------------------------------------------------- | ------------------------------------------------------------------------ |
| "Refresh SERP data and recompute authority for [brand]" | Fresh SERPs, updated scores |
| "Show me TAS scores for each pillar" | Pillar-level breakdown - find the weak areas |
| "How do I compare against my competitors?" | Competitor metrics side by side |
| "Which topics cite my brand in AI Overviews?" | AI search citations by topic |
| "Which topics cite competitor.com in AI Overviews?" | The same view for any domain |
| "Show internal linking opportunities for [topic]" | Parent, sibling, and child link targets with relevance and reasoning |
| "Classify search intents for all topics" | Informational / commercial / transactional / navigational across the map |
## Loading Client Context
**"Load the client's style guide into Floyi."**
Paste a client's style guide document into the conversation and have the assistant extract it into Floyi's Content Guide in one session:
| Ask | What happens |
| -------------------------------------------------------- | ----------------- |
| "Flag 'cheap' as forbidden, prefer 'affordable'" | Terminology rule |
| "Add a compliance rule: never promise specific rankings" | Compliance rule |
| "Never mention [competitor] in content" | Competitor policy |
| "No exclamation marks in body copy" | Messaging rule |
| "Add our standard CTA snippet" | Boilerplate |
Guide entries feed every subsequent brief and draft for that brand.
## Publishing
**"Publish this finished draft."**
| Ask | What happens |
| ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| "Which WordPress sites can I publish to?" | Connected sites for the workspace |
| "Publish draft [title] to [site] as a WordPress draft" | Publishes - defaults to WordPress-side draft status, so nothing goes live without review |
| "Which GitHub repos can I publish to?" | Connected repositories with their branch, content path, and file-format defaults |
| "Publish draft [title] to my blog repo" | Commits the article as Markdown/MDX straight to the configured branch - the assistant confirms the publish and branch first, since most repos auto-deploy |
| "Did the publish finish?" | Task status for either channel |
## Standalone Toolbox
| Ask | What happens |
| ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| "Run an AIRS analysis for 'best crm for agencies'" | Queries AI search engines, then synthesizes per-engine analysis and strategic recommendations |
| "Give me the strategic recommendations from that analysis" | Stage-3 output - feed it straight into a brief |
| "Cluster these 40 keywords for the US market" | Standalone keyword clustering, cost confirmed first |
| "Which SERP features dominate this keyword set?" | Feature report on a clustering run: top domains and SERP feature counts, with AI Overview presence per keyword |
---
## Workflow Recipes
### Recipe 1: Content Gap to Published Draft
```
1. "Find content gaps for [brand]"
2. "Generate a brief for the top gap topic"
3. "Check the brief status" (assistant polls until complete)
4. "Generate a draft from the completed brief"
5. "Show me the full draft"
6. "Publish it to my WordPress site as a draft"
```
### Recipe 2: Weekly Content Review
```
1. "Run a weekly report for [brand]"
2. "Show the pipeline overview with credits"
3. "Find the top 5 content gaps"
4. For the top 3, one at a time: generate the brief, review it, then continue to the next
```
### Recipe 3: Content Refresh Triage
Refreshing a page ranking #15 usually beats a net-new article.
```
1. "Find gaps for [brand], but only weak coverage and low rankings"
2. "For each, confirm the ranking URL and current position"
3. "Show internal linking opportunities for the top 3"
4. After updating: "Refresh authority and check for movement"
```
### Recipe 4: Cannibalization Check
Before writing something new, check whether the map already targets it.
```
1. "Search my map for topics about '[keyword]'"
2. If a published topic already targets it -> refresh that page instead (Recipe 3)
3. If two unpublished topics overlap -> "Combine them into one topic"
```
### Recipe 5: Competitor & AI Citation Gap
```
1. "Who leads on authority - me or my competitors?"
2. "Find contested gaps: topics with high competitor presence where I'm missing"
3. "Which topics cite my domain in AI Overviews? Now the same for competitor.com"
4. "Diff the two lists - where are they cited and I'm not?"
5. Brief the highest-priority topic, review it, then continue through the remaining topics one at a time
```
### Recipe 6: AI Search (GEO) Monitoring
```
1. "Where am I cited in AI Overviews? Where am I only mentioned?"
2. "Repeat for AI Mode, Gemini, and ChatGPT"
3. Mentioned-but-not-cited topics = citability gap - add stats, definitions,
and quotable passages to those pages
4. Weekly: "Refresh authority and re-pull the citation counts"
```
### Recipe 7: Production Sprint
Floyi generates deliberately one piece at a time - every brief and draft gets
its own cost confirmation and a review before the next starts, so a sprint is
a loop, not a batch:
```
1. "Find all missing topics in the '[cluster]' cluster"
2. "Check my credit balance and estimate the briefs for this list"
3. For each topic: "Generate the brief" -> review it -> curate weak sections
4. "Generate the draft from that brief" -> check its quality scorecard
5. "Stage it in WordPress as a draft" (or commit it to the blog repo)
6. Next topic
```
### Recipe 8: Agency Monday-Morning Digest
Agencies are natural MCP power users when their client brands live in the same Floyi workspace - one conversation can cover every brand visible to that connection.
```
1. "List all brands with their authority scores"
2. Per brand: "Run the weekly report"
3. "Show competitor movement for each"
4. "Pull AI citation wins to showcase"
5. "Assemble a client-facing summary email for each brand"
```
This can also become a scheduled digest when the MCP client supplies the scheduler and an email or Slack delivery integration. Floyi MCP provides the brand data and analysis tools; it does not send email or Slack messages by itself.
### Recipe 9: Pre-Publish Internal Linking Pass
```
1. "Show me draft [title]"
2. "Get internal link suggestions for its topic"
3. Add the links in the editor (or verify the draft already includes them)
4. "Publish it as a WordPress draft"
```
---
## What Still Needs the Web App
The MCP server is built for strategy, production, and monitoring. A few things stay in the app on purpose:
| Operation | Why |
| ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Full rich-text editing, editor-only readback, and visual polish | Assistants can read MCP-readable draft text, curate briefs, and make targeted plain-text edits to sections, intros, and key takeaways. A draft whose body exists only in the rich-text editor is flagged and pointed back to the app. Document structure, rich formatting, links, embeds, visual review, and complete version restore remain in the editor. |
| Importing a full existing draft | Bring Your Own Draft paste/import remains in the app until Floyi has a safe server-side conversion path into the canonical editor document. |
| Article images and standalone schema editing | Image generation, placement, cropping, alt-text review, and the complete schema editor remain visual app workflows. |
| Silo and map visual preview | Assistants can inspect and edit cluster membership and run the coarse silo workflow, while judgment-heavy visual preview steps keep their purpose-built UIs. |
| Final editorial review | Assistants can set the editorial state, but final visual review and polish still happen in the editor. MCP publishing defaults to a WordPress-side draft. |
| Team management, billing, API keys | Account administration stays in Settings. |
| Creating publishing connections (WordPress, GitHub) | Connections and their credentials are created in the app's Settings; MCP lists and publishes to them. |
| Connecting Google Search Console | MCP can read imported GSC insights. OAuth connection, uploads, and reanalysis stay in the Organic Audit app flow. |
| Historical authority trends and several standalone toolbox screens | MCP exposes current authority data and the AIRS and keyword-clustering toolboxes. Historical TA trends, SERP Insights, Analyze URL, PAA Explorer, and Topical Audit are not currently exposed. |
For supported capabilities, connect and ask. The assistant should point you back to the app when a workflow requires visual review, account administration, credentials, or an unexposed import or analytics surface.
---
## Teams Overview
Source: https://floyi.com/docs/teams/
Teams in Floyi allow you to collaborate with colleagues on brand strategy, topical maps, briefs, and content-all within a shared workspace.
---
## Personal vs Team Workspaces
Floyi gives every user two distinct workspace contexts:
| Workspace | What You See | Who Can Access |
| ------------ | --------------------------------------------- | ----------------------- |
| **Personal** | Your own briefs, drafts, brands, and research | Only you |
| **Team** | Shared team content created by any member | All active team members |
When you switch workspaces, the entire view changes. Personal and team content are never mixed.
:::tip
Use the workspace switcher in the sidebar to move between your Personal Workspace and any teams you belong to.
:::
---
## How Workspace Isolation Works
Content stays strictly within the workspace where it was created:
- **Personal content** is visible only to you, even if you're a Team Owner.
- **Team content** is visible to all active team members, regardless of who created it.
This separation means:
- Your personal drafts won't accidentally appear in team searches.
- Team members can see each other's work without accessing private personal content.
---
## Team Roles
Every team member has one of three roles:
| Role | Description |
| ---------- | -------------------------------------------------------------------- |
| **Owner** | Full control including billing and team deletion |
| **Admin** | Same as Owner, except cannot manage billing or delete the team |
| **Member** | Can view and create content; cannot delete content or manage members |
See the [full permissions breakdown](https://floyi.com/docs/teams/roles-permissions/) for details.
---
## Transferring Brands Between Workspaces
You can move brands between your Personal Workspace and a Team Workspace directly from the **Projects / All Brands** page.
### Identifying Brand Ownership
- **Personal brands** display a **lock icon** in the top-right corner of their card.
- **Team brands** display a **multi-user icon** in the top-right corner of their card.
### Moving a Brand
1. Go to the **Projects / All Brands** page.
2. Find the brand you want to transfer.
3. Click the **lock icon** on the brand card.
4. Select whether to keep it as **Personal** or move it to the **Team**.
:::caution
Only the **Team Owner** can transfer brands between Personal and Team workspaces. Admins and Members cannot perform this action.
:::
---
## Next Steps
- [Roles & Permissions](https://floyi.com/docs/teams/roles-permissions/) - What each role can do
- [Managing Members](https://floyi.com/docs/teams/managing-members/) - Invite, remove, and change roles
- [Team Settings](https://floyi.com/docs/teams/settings/) - Manage seats and team configuration
---
## Managing Members
Source: https://floyi.com/docs/teams/managing-members/
[Team Owners and Admins](/docs/teams/roles-permissions/) can invite new members, remove existing members, and change member roles. This page covers all member management tasks within your [team workspace](/docs/teams/).
---
## Inviting Members
To invite someone to your team:
1. Switch to your Team Workspace using the sidebar switcher.
2. Open **Settings** from the bottom-left corner.
3. Go to the **Team** tab.
4. In the **Invite members** section, enter the email address of the person you want to invite.
5. Select the **Role**: Admin or Member.
6. Click **Send Invite**.
The invited user will receive an email with instructions to join. Once they accept, they'll appear in your team member list.
:::tip
Each team member requires a seat. Make sure you have enough seats available before inviting new members. See [Team Settings](https://floyi.com/docs/teams/settings/) for seat management.
:::
---
## Viewing Team Members
To see who's on your team:
1. Open **Settings** → **Team**.
2. View the member list showing each person's name, email, role, and status.
---
## Changing a Member's Role
To change someone's role (Owner and Admin only):
1. Open **Settings** → **Team**.
2. Find the member in the list.
3. Click the role dropdown next to their name.
4. Select the new role: **Admin** or **Member**.
:::caution
Only the current Owner can promote someone else to Owner. This action transfers ownership and cannot be undone without the new Owner's cooperation.
:::
---
## Removing Members
To remove a member from your team (Owner and Admin only):
1. Open **Settings** → **Team**.
2. Find the member in the list.
3. Click the **Remove** button next to their name.
4. Confirm the removal.
Once removed:
- The member loses access to all team content immediately.
- Any content they created in the Team Workspace remains with the team.
- Their Personal Workspace content is unaffected.
---
## Leaving a Team
If you're a Member or Admin and want to leave a team:
1. Open **Settings** → **Team**.
2. Click **Leave Team**.
3. Confirm your decision.
:::note
Team Owners cannot leave their team. To leave, first transfer ownership to another member.
:::
---
## Roles & Permissions
Source: https://floyi.com/docs/teams/roles-permissions/
Every team member is assigned one of three roles: **Owner**, **Admin**, or **Member**. This page explains what each role can do. For how team workspaces fit together, see the [Teams overview](/docs/teams/).
---
## Role Definitions
| Role | Description |
| ---------- | ------------------------------------------------------------------------------------------------------------- |
| **Owner** | Full control over the team, including billing management and team deletion. Every team has exactly one Owner. |
| **Admin** | Same permissions as Owner, except cannot manage billing or delete the team. |
| **Member** | Standard access for viewing and creating content. Cannot delete content or manage team membership. |
---
## Permissions by Action
### Content Permissions
All team members can view and create content. Only Owners and Admins can delete.
| Action | Owner | Admin | Member |
| ----------------------------- | :---: | :---: | :----: |
| **View** team briefs | ✅ | ✅ | ✅ |
| **View** team articles/drafts | ✅ | ✅ | ✅ |
| **View** team brands | ✅ | ✅ | ✅ |
| **View** SERP analyses | ✅ | ✅ | ✅ |
| **Create** briefs | ✅ | ✅ | ✅ |
| **Create** articles/drafts | ✅ | ✅ | ✅ |
| **Create** brands | ✅ | ✅ | ✅ |
| **Edit** briefs | ✅ | ✅ | ✅ |
| **Edit** articles/drafts | ✅ | ✅ | ✅ |
| **Edit** brands | ✅ | ✅ | ✅ |
| **Delete** briefs | ✅ | ✅ | ❌ |
| **Delete** articles/drafts | ✅ | ✅ | ❌ |
| **Delete** brands | ✅ | ✅ | ❌ |
### Team Management Permissions
| Action | Owner | Admin | Member |
| ----------------------- | :---: | :---: | :----: |
| **Invite** members | ✅ | ✅ | ❌ |
| **Remove** members | ✅ | ✅ | ❌ |
| **Change** member roles | ✅ | ✅ | ❌ |
| **Manage** billing | ✅ | ❌ | ❌ |
| **Delete** team | ✅ | ❌ | ❌ |
---
## Personal Workspace Access
Regardless of team role, every user has their own Personal Workspace that remains completely private. Team Owners and Admins cannot see other members' personal content.
:::note
When you switch from Team to Personal workspace, you only see content you created in Personal mode-nothing from the team.
:::
---
## Next Steps
- [Invite, remove, and re-role members](/docs/teams/managing-members/)
- [Manage seats and team configuration](/docs/teams/settings/)
---
## Team Settings
Source: https://floyi.com/docs/teams/settings/
Team Settings is where Owners manage seats, view team configuration, and access team-level billing. This page covers the key settings available to team administrators. If you're new to team workspaces, start with the [workspace and collaboration overview](/docs/teams/).
---
## Accessing Team Settings
1. Switch to your Team Workspace using the sidebar switcher.
2. Open **Settings** from the bottom-left corner.
3. Select the **Team** tab.
---
## Managing Seats
Each team member requires one seat. The Team Owner can purchase additional seats or reduce the seat count as needed.
### Viewing Current Seats
In Team Settings, you'll see:
- **Seats Used**: How many seats are currently occupied by active members
- **Seats Total**: How many seats you've purchased
- **Included Seats**: The number of seats included in your subscription
- **Current paid extras**: The number of seats you've purchased above the included seats
### Adding Seats
1. In Team Settings, see the **Total seats** field.
2. Enter the new total number of seats desired.
3. Review the prorated cost for the additional seats in **Est. Cost preview**.
4. Click **Update seats**.
5. Confirm the purchase.
New seats are available immediately and billed on a prorated basis for the current billing cycle.
### Reducing Seats
1. In Team Settings, see the **Total seats** field.
2. Enter a lower number of total seats.
3. Review the adjustment details.
4. Click **Update seats**.
5. Confirm the purchase.
:::caution
You cannot reduce seats below the number of active team members. [Remove members](/docs/teams/managing-members/) first if you need fewer seats.
:::
---
## Team Billing
Team billing is managed by the [Team Owner](/docs/teams/roles-permissions/) and is the same as personal subscription billing. If the user has a personal subscription, the team billing is the same as the personal subscription billing. If the user has a Pro subscription, the team billing is the same as the Pro subscription billing.
- **Team seats** are billed based on how many seats you've purchased.
- **Credits** used for briefs, drafts, and analyses are deducted from the Team Owner's credit balance when working in Team Workspace.
To view team billing history or manage payment methods, go to **Settings** → **Billing** while in your Team Workspace.
:::note
Only the Team Owner can access billing settings and manage payment methods for the team.
:::
---
## Deleting a Team
Only the Team Owner can delete a team.
1. In Team Settings, scroll to the bottom.
2. Click **Delete Team**.
3. Confirm the action.
:::danger
Deleting a team is permanent. All team content (briefs, drafts, brands, maps) will be permanently deleted and cannot be recovered. Member access is revoked immediately.
:::
---
## Floyi Features and Tools Overview
Source: https://floyi.com/docs/tools/
## Floyi Overview
Floyi is the operating system for topical authority. Teams build strategic topical maps, not keyword clusters, then generate briefs and drafts that inherit the map's structure, intent and linking. One closed-loop system replaces 5-7 disconnected SEO tools with authority tracking across Google and AI search.
Floyi is evidence-first. By evidence, we mean live SERP patterns, competitor coverage signals and AI mention and citation signals across Google AI Overviews, AI Mode, ChatGPT, Perplexity, Gemini, Copilot and more.
Floyi is built around three strategic pillars:
1. **Brand strategy** -- codify your mission, voice, positioning and content rules once. Every downstream output follows them.
2. **Audience strategy** -- turn personas into live inputs that flow through every brief and draft, not static PDFs nobody reopens.
3. **Topic strategy** -- build a topical map up to four levels deep that defines how humans and AI search engines read your expertise. This is your knowledge architecture.
On top of those pillars, Floyi measures topical authority across content, the market and AI search, surfaces priorities and generates briefs and drafts that inherit your strategy end to end.
---
## How the Closed Loop Works
Most teams lose because their workflow drops context. Brand and persona work sits in a document nobody reopens. Topic research lives in a spreadsheet. SERP analysis lives in another tool. AI visibility is not measured consistently. Briefs get rebuilt from scratch.
Floyi keeps strategy connected through execution so results compound instead of resetting every sprint:
1. **Codify your brand, voice and audience** -- structured once, reused everywhere
2. **Build your topical map from research and clustering** -- up to four levels of depth
3. **Measure Coverage, Visibility, Share of Voice and AI Authority across that map**
4. **Prioritize the next topics to ship in the Authority Planner**
5. **Generate briefs and drafts that follow the map**
6. **Publish directly to WordPress or GitHub** with SEO metadata, formatting and schema markup
7. **Coverage and authority metrics update** -- signals refine the next cycle
8. **Repeat with a smarter, more complete map each cycle**
The rest of this page introduces each part of that loop and links to dedicated docs for deeper detail.
---
## 1. Brand and Audience Strategy
### Brand Foundation
**What it is**
Brand Foundation is the single source of truth for your brand inside Floyi. Mission, positioning, voice, values, competitors and site context are stored once, then reused by Audience Insights, Topical Research, Topical Authority, Briefs and the Content Creation workspace.
Brand Foundation has four tabs:
- **Brand Identity** -- core strategic statements about your brand (mission, vision, positioning, voice, values, competitors)
- **Content Guide** -- rules and guidelines for AI content generation (terminology, compliance, competitor policies, brand messaging, approved snippets)
- **Brand Voice** -- AI-powered voice analysis that profiles your writing style from real samples and generates a prompt directive applied to all briefs and drafts
- **Knowledge Base** -- upload documents to give AI agents brand-specific context during brief and draft generation
**What you can do**
- Generate a Brand Foundation from your homepage URL plus an optional second URL, or enter it manually
- Edit and regenerate with notes as your positioning evolves
- Define terminology rules, compliance rules, competitor comparison guidelines, brand messaging pillars and approved snippets in the Content Guide
- Analyze writing samples (upload, URL import or Knowledge Base selection) to build a seven-dimension voice profile in Brand Voice
- Upload documents (PDF, DOCX, TXT, MD, HTML) to the Knowledge Base for semantic retrieval during content generation
- Export to XLSX, DOCX or Google Docs for legal, PMM or agencies
**Where it flows**
Brand Foundation feeds Audience Insights, Topical Research, Briefs, Topical Authority and the Content Creation workspace. Content Guide rules, Voice directives and Knowledge Base context are automatically applied during brief and draft generation.
See: [Brand Foundation](https://floyi.com/docs/tools/brand-foundation/)
---
### Audience Insights
**What it is**
Audience Insights generates and manages detailed buyer personas that Floyi treats as live inputs, not static slides. Real audience context shows up in every brief and every draft.
**What you can do**
- Generate 1 to 5 personas per run using Brand Foundation as context
- Refine personas with optional guidance such as roles, industries or regions
- Search, select, delete and export personas to XLSX, DOCX or Google Docs
**Where it flows**
Personas are available inside Topical Research, Briefs and authority workflows, so topics and drafts align with real people and their pain points.
See: [Audience Insights](https://floyi.com/docs/tools/audience-insights/)
---
### Site Architecture (Local, Agency, SaaS)
**What it is**
Site Architecture is the planning tool for structuring your website's pages. Choose from three site types - Local Business for multi-location service businesses, Service Agency for agencies and professional firms, or SaaS for software products - and Floyi generates a complete URL blueprint with proper hierarchy. Enter your services, locations, features, or integrations, click generate, and map your entire site structure automatically.
**What you can do**
- Choose your site type: Local Business, Service Agency, or SaaS
- Choose your content scope: Site + Resources, Site Only, or Resources Only
- Local Business: define services, subservices and location hierarchies (state, city, neighborhood) with service+location cross-product pages
- Service Agency: define services, industries and solutions with service+industry cross-product pages
- SaaS: define features, use cases, integrations and solutions with feature+use case cross-product pages
- Set page types like pricing, process, FAQ, reviews and case studies (30+ page types available across all site types)
- Sync business info from Google Business Profile or fetch locations from a URL
- Import existing page lists from CSV or Excel with automatic column mapping
- Preview in Tree or Table views before committing
- Connect architecture pages to Topical Authority for tracking with site-type-specific query strategies
**Where it flows**
Site Architecture pages integrate with Topical Authority for coverage and visibility tracking. The Authority Planner separates architecture pages and resource pages into distinct views with different brief and draft generation workflows for each site type.
See: [Site Architecture](https://floyi.com/docs/tools/site-architecture/)
---
## 2. Topic Strategy: From Ideas to a Structured Map
Your topical map is not a keyword list. It is the blueprint of your expertise and the knowledge architecture that defines how search systems interpret your domain.
### Topical Research
**What it is**
Topical Research is your structured ideation engine. It turns a core topic plus brand and persona context into a four-level topic hierarchy (Main Topics, Subtopic Tier 2, Subtopic Tier 3, Subtopic Tier 4) with scoped keyword generation.
**What you can do**
- Generate Main Topics and up to three levels of subtopics asynchronously
- Add scoped keyword sets at the map, topic or custom selection level
- Work across three views: Silo, Outline and Spreadsheet
- Detect duplicates with semantic analysis
- Edit inline, paginate large outlines and round-trip via XLSX or Google Sheets import and export
**Where it flows**
The Topical Research outline is the input for Topical Clustering.
See: [Topical Research](https://floyi.com/docs/tools/topical-research/)
---
### Topical Clustering
**What it is**
Topical Clustering groups your keywords into SERP-aware clusters with centroids, tuned by country, language and optional location.
**What you can do**
- Fetch SERPs and cluster keywords in one operation
- Adjust overlap to control how tight clusters feel
- Re-cluster for free using saved SERPs, so you refine structure without extra credits
- Import your own clusters from Excel or CSV
- Inspect SERPs for any centroid or keyword inside a modal
**Where it flows**
Clusters feed the Topical Map, which becomes your knowledge architecture.
See: [Topical Clustering](https://floyi.com/docs/tools/serp-clustering/)
---
### Topical Map
**What it is**
Topical Map merges your research hierarchy and clusters into a single, validated topical map. It is your knowledge architecture for humans and AI search engines, and the foundation for Topical Authority.
**What you can do**
- Generate a vector-based hierarchy from clusters and research
- Validate names and structure, then apply safe fixes
- Generate URL slugs and optional content info for each page-level topic
- Export both a hierarchical XLSX and a Markdown outline for review
**Where it flows**
Once validated and slugged, the Topical Map is promoted into Topical Authority. Later, you can [add a new topic silo](https://floyi.com/docs/tools/add-topic-silo/) to grow the map without starting a separate project.
See: [Topical Map](https://floyi.com/docs/tools/topical-map/)
---
## 3. Topical Authority: Measure Reality and Set Priorities
Topical Authority is Floyi's system for measuring how completely and visibly you cover your topical map and how you compare against competitors. It answers the fundamental question: where are we winning or losing, and what should we ship next?
It has five main parts: metrics, Scorecard, Silo Analysis, Planner and Organic Audit.
### Core Metrics
Floyi tracks authority as a model, not a single metric:
- **Content Authority** -- combines Coverage (importance-weighted share of your plan that is published) and Performance (how well those published pages rank)
- **Market Authority** -- your share of ranking value across the map versus all competing domains
- **AI Authority** -- mentions and citations across AI search surfaces including Google AI Overviews, AI Mode and ChatGPT
- **Topical Authority Score (TAS)** -- a combined score that rewards balanced Content Authority, Market Authority and AI Authority
- **Share of Voice (SOV)** -- your visibility share versus all ranking domains
### Topical Authority Scorecard
**What it is**
Scorecard is your diagnostic view. It tells you how strong your position is across a topical map, where you are weak and which competitors own the gaps.
**What you can do**
- See TAS, Coverage, Visibility and SOV trends over time
- Inspect SOV leaderboards for Top 10, 20 or 100 domains plus a full modal with thousands
- Drill into domain rankings, common topics, AI Overview mentions and citations
- Compare your authority against any competitor on the topics that matter to your audience
- Export CSV or Excel for slides and stakeholder reports
See: [Topical Authority Scorecard](https://floyi.com/docs/tools/topical-authority-scorecard/)
---
### Silo Analysis
**What it is**
Silo Analysis is the competitive intelligence layer. It breaks your Topical Authority metrics down by silo so you can see which topic areas you lead, where the fight is close and where competitors are ahead.
**What you can do**
- See every silo classified as Leading, Contested or Trailing at a glance
- Rank silos by investment priority based on gap size and opportunity
- Compare your SERP and AI Search presence against competitors across silos in heatmaps
- Drill into any silo for a competitor leaderboard, hub breakdown with every topic and action buttons for briefs and drafts
**Where it flows**
Silo Analysis reads the same authority data as Scorecard. Its content gap actions connect directly to brief generation and the Content Creation workspace.
See: [Silo Analysis](https://floyi.com/docs/tools/topical-authority-silo-analysis/)
---
### Topical Authority Planner
**What it is**
Planner is your command center. It turns Scorecard insights into an ordered list of "what to ship next" across your map.
**What you can do**
- Work inside a full hierarchy from Pillar to Page, with coverage counters at each level
- Switch between Local Pages (from Site Architecture) and Resource Pages (from Topical Map) views
- Filter for high-impact work such as high importance, not published, not found in SERP or under-covered pillars
- Open SERP modals, AI Overview Viewer, AI Mode and ChatGPT views per topic
- See and manage content info, keywords, internal link suggestions, anchors and brief status in a single drawer
- Generate URL slugs and bulk briefs with upfront cost estimates
- Launch different brief workflows for Local versus Resource pages
See: [Topical Authority Planner](https://floyi.com/docs/tools/topical-authority-planner/)
---
## 4. Content Execution: Briefs, Drafts, Optimization and Publishing
Briefs and drafts should inherit strategy, not lose it. Every brief knows where the article sits in the map, which topics it relates to, what to link to and which audience it serves.
### Content Briefs
Floyi supports two paths for briefs:
- **Topical Authority integrated briefs** -- generated directly from Planner nodes for topic-anchored execution
- **Standalone briefs** -- query-anchored, research-heavy briefs with full SERP analysis and outline review
**What you can do**
- Select Top 20 SERP competitors, your buyer personas, add user keywords, internal links, anchors and external links
- Include AI Overview, AI Mode and ChatGPT context where available
- Review and approve outlines before full generation in the standalone flow
- Export briefs for writers in TXT or work entirely inside Floyi
See: [Content Briefs](https://floyi.com/docs/tools/content-briefs/)
---
### Content Creation
**What it is**
The Content Creation workspace turns briefs into connected drafts that stay tied to your brand, audience and topical map.
**What you can do**
- Use Writer and Editor agents to generate complete drafts
- Optionally run Specialist agents for fact checking, web research, conversion improvements and evidence integration
- Edit in a rich text environment with autosave and version history
- Manage editorial states like "Draft done" or "Approved"
- Generate bulk drafts across selected topics (Pro and Scale plans)
See: [Content Creation](https://floyi.com/docs/tools/content-creation/)
---
### Content Editor and Optimizer
**What it is**
The Content Editor and Optimizer is the production environment where strategy becomes published content. It combines a rich text editor with AI writing assistance and deep competitive optimization.
**What you can do**
- Write and edit with a full rich text editor (formatting, links, images, tables, code blocks)
- Use the AI Writing Assistant to simplify, expand, shorten, fix grammar, optimize or run custom rewrites on selected text
- Set Strategic Intent per article: Human-First, LLM-Friendly or Executive Summary
- Run the Optimizer to see a Coverage Matrix comparing your content against top competitors and AI sources
- Identify missing entities and topics, heading structure issues and reading level
- Use Specialist Agents to fact-check, enrich and polish drafts
- Export to HTML, Markdown, Plain Text or PDF
- Publish directly to WordPress from the editor
**Where it flows**
Published content feeds back into coverage metrics, authority scores and future audits.
See: [Content Editor and Optimizer](https://floyi.com/docs/tools/content-editor-optimizer/)
---
### WordPress Publishing
**What it is**
WordPress Publishing lets you push finished content from the Content Editor or the Authority Planner straight to your WordPress site. No copy-pasting, no reformatting.
**What you can do**
- Connect WordPress sites using the Floyi Connect plugin with secure token-based authentication
- Publish to Posts, Pages or custom post types
- Set status to Draft, Publish Now or Schedule for a future date
- Assign categories, tags and authors
- Map SEO metadata to Yoast, Rank Math, AIOSEO or SEOPress
- Auto-convert content to native Gutenberg blocks or Classic HTML
- Update existing posts and sync status changes back to Floyi via webhooks
- Bulk publish multiple completed drafts from the Authority Planner with global defaults and per-article overrides
**Where it flows**
Every publish cycle feeds back into Topical Authority. Coverage and performance signals update automatically, so the next planning cycle starts with fresh data.
See: [WordPress Publishing](https://floyi.com/docs/tools/wordpress-publishing/)
---
### GitHub Publishing
**What it is**
GitHub Publishing lets you push finished content from the Content Editor to any Git-based static site. Your articles arrive as properly formatted Markdown or MDX files with customizable frontmatter, images and optional schema markup, committed directly to your repository.
**What you can do**
- Connect GitHub repositories using the Floyi GitHub App with minimal permissions (contents write, metadata read)
- Choose a framework preset (Astro, Next.js, Hugo, Jekyll, Docusaurus) or configure everything manually
- Define your own frontmatter template with variables that Floyi fills from article and brand data at publish time
- Publish articles with images committed alongside the content file in a single operation
- Include JSON-LD schema markup as a script tag or frontmatter field
- Override branch, file path, frontmatter and image settings per publish without changing saved defaults
- Update previously published articles with change detection that shows which articles need refreshing
**Where it flows**
Every publish cycle feeds back into Topical Authority. Coverage and performance signals update automatically. If your repo has CI/CD configured (Cloudflare Pages, Vercel, Netlify), your site deploys automatically after each commit.
See: [GitHub Publishing](https://floyi.com/docs/tools/github-publishing/)
---
### Organic Audit
**What it is**
The Organic Audit connects your Google Search Console data to your Topical Map to show how Google actually sees your content. It maps real search queries and pages to your topical hierarchy so you can see which topics are earning clicks and impressions and which are invisible.
**What you can do**
- Connect Google Search Console via OAuth or import data via CSV
- See search queries and pages attributed to each node in your topical hierarchy
- View per-topic metrics including clicks, impressions and average position
- Classify topics as Strong, Emerging, Broad Reach or Weak Signal
- Discover opportunity clusters of unmatched queries that suggest new topics
- Track trends over time with sparkline charts per topic
- Export query-level and page-level data to CSV
**Where it flows**
Organic Audit shows how Google's search reality aligns with your topical strategy. Use it to validate your map, find gaps and prioritize the next topics to publish.
See: [Organic Audit](https://floyi.com/docs/tools/organic-audit/)
---
## 5. Research and Analysis Tools
### PAA Explorer
**What it is**
PAA Explorer is a recursive People Also Ask research tool. It takes any search query and expands the PAA questions Google shows for it, then searches each of those questions to find more, building a visual topic tree up to five levels deep.
**What you can do**
- Enter a seed query with country, language and optional location targeting
- Set depth (1-5 levels) and branches (3-5 per level) to control tree size
- Watch the tree build in real time as each depth level completes
- Click any node to see the full question, answer snippet, source URL and metadata
- Collapse and expand branches, pan and zoom the canvas
- Cancel in-progress explorations and retry failed branches
- Export to PNG, XLSX, CSV or Google Sheets
- Load and manage past explorations
**Where it flows**
PAA data surfaces across Floyi. The Topic Details Sidebar in Authority Planner shows PAA questions from SERP data. Content Briefs use PAA questions to shape heading structure, FAQ sections and content depth. Draft generation references related questions for comprehensive topic coverage.
See: [PAA Explorer](https://floyi.com/docs/tools/paa-explorer/)
---
### AIRS Analyzer: AI Search Visibility
**What it is**
The AIRS (AI Results) Analyzer lets you see how any query is answered across multiple AI platforms and traditional SERPs. Understand where your brand appears and what sources AI tools are citing.
AIRS queries across Google SERPs, Bing SERPs, Google AI Mode, Google AI Overview, Bing Copilot, Claude, Gemini, OpenAI Web, Perplexity and ChatGPT.
**What you can do**
- Run an analysis on any query with optional language and brand context
- See a comparison matrix showing visibility across all engines
- Read strategic insights with actionable recommendations
- Drill into individual tool responses and source citations
- Track visibility as High, Medium, Low or Not Visible per engine
- View past reports and re-run or retry failed engines
- Export to DOCX or PDF for clients and stakeholders
**Where it flows**
AIRS results inform your content strategy by showing where your brand appears in AI answers and where competitors have visibility you do not. Use these insights to prioritize topics in the Authority Planner.
See: [AIRS Analyzer](https://floyi.com/docs/tools/airs-analyzer/)
---
### More Standalone Tools
Beyond PAA Explorer and AIRS, Floyi includes focused utilities you can use with or without a full strategy flow:
- [Briefs & Drafts (standalone)](https://floyi.com/docs/tools/briefs-and-drafts/) - query-anchored briefs and drafts with SERP competitor analysis, outside the Topical Authority flow
- [SERP Insights analysis](https://floyi.com/docs/tools/serp-insights/) - break down search results pages to understand the competition for any query
- [URL content analysis](https://floyi.com/docs/tools/analyze-url/) - scrape and analyze any webpage for structure, topics and entities
- [Stand-alone SERP clustering](https://floyi.com/docs/tools/serp-clustering-tool/) - upload any keyword list and group it by SERP overlap, no project required
- [Site-wide topical audit](https://floyi.com/docs/tools/topical-audit/) - crawl a site to reveal its hidden topical structure with semantic analysis
- [Inline AI writing assistant](https://floyi.com/docs/tools/ai-writing-assistant/) - simplify, expand and optimize text directly inside the Content Editor
- [Supported countries reference](https://floyi.com/docs/tools/supported-countries/) - which countries and regions each SERP and AI provider covers
---
## 6. Automation, Credits and Models
### Automation and Scheduling
Floyi treats expensive operations as background jobs with clear controls.
Examples:
- Scheduled SERP refresh and recompute for Topical Authority by brand and locale
- Automatic email notifications when long-running tasks finish, such as SERP refresh, authority recompute or brief generation
- Brand aliases to improve AI Overview detection for different versions of your brand name
---
### Credits and Cost Controls
Floyi uses a transparent credit system for AI and SERP work.
- Every major action has a named credit type with AI model multipliers
- You see an upfront estimate before running a job
- Re-clustering using existing SERPs is free, so you can refine structure without burning credits
- Insufficient credit states show a clear modal instead of failing mid-flow
See: [Credits and Billing](https://floyi.com/docs/billing/credits/)
---
### Multi-Model AI Support
Floyi supports multiple AI providers and models so you can balance quality and cost per workflow.
Available families include:
- **OpenAI**
- GPT-5.1
- GPT-5
- GPT-5 Mini
- GPT-4.1
- GPT-4.1 Mini
- GPT-4o
- GPT-4o Mini
- **Anthropic**
- Claude 3.5 Haiku
- Claude 4.5 Haiku
- Claude 4.5 Sonnet
- Claude 4 Sonnet
- **Google**
- Gemini 3 Pro
- Gemini 2.5 Pro
- Gemini 2.5 Flash
You can pick different models for different jobs, such as heavier models for authority briefs and lighter ones for exploratory research.
---
## 7. Programmatic Access: API and MCP Server
Floyi is not only a web app. Two developer surfaces let you read your data and drive your workflows from outside the app, both authenticated with the same API keys and scoped to the same personal and team workspaces.
### REST API
**What it is**
A versioned REST API for reading your Floyi data and triggering work programmatically. Use it to build custom dashboards, wire Floyi into Zapier or Make, or automate reporting.
**What you can do**
- Query brands, topical maps, research trees, authority metrics and content
- Generate briefs and drafts through the same pipeline the app uses
- Manage keys, scopes, rate limits and audit logging
See: [API Reference](https://floyi.com/docs/api/reference/)
---
### MCP Server
**What it is**
The MCP (Model Context Protocol) server connects AI assistants - Claude, Claude Code and any MCP-compatible client - directly to your Floyi workspace. Instead of switching between your assistant and the app, you work in one conversation: ask for your content gaps, generate a brief for the biggest one, turn it into a draft and publish it, all in natural language. It exposes tools across the full pipeline: brand setup, personas, site architecture, research, clustering, map building, briefs, drafts, publishing and authority monitoring.
**What you can do**
- Run the whole closed loop from a chat, from brand foundation through to a published WordPress draft
- Explore strategy and find opportunities: content gaps, competitor gaps, AI citation gaps
- Read finished briefs and drafts back out for review or reuse
- Run scheduled agents, such as an agency Monday-morning digest across every client
Writes run through Floyi's own generation pipeline, so briefs and drafts keep correct sections, internal links and map position. Tool calls are free; credits are spent only on the same credit-bearing actions the app charges for, at the same prices. Available on the Scale plan.
See: [MCP Server Overview](https://floyi.com/docs/mcp/overview/), [Tool Catalog](https://floyi.com/docs/mcp/tools/) and [Use Cases](https://floyi.com/docs/mcp/use-cases/)
---
## 8. Who Floyi Is For and Typical Outcomes
Floyi is built for teams that need strategy and execution to stay aligned in a world where AI search fragments everything.
Common roles:
- **SEO consultants and agency owners** who need defensible roadmaps, clear priorities and reporting that holds up in client reviews
- **Heads of Content and CMOs** who want a single system of record instead of scattered tools and the confidence that content investment builds durable authority
- **Senior SEOs and content strategists** who care about topical authority across SERPs and AI answers, not just single keywords
- **Agencies** that need to productize strategy, briefs, drafts and reports across many clients
Typical outcomes:
- A structured topical map up to four levels deep that connects brand, audience and topics to real SERPs
- A Topical Authority Scorecard that shows exactly where you stand across content, market and AI authority
- An Authority Planner that turns that scorecard into a clear publishing queue
- Briefs and drafts that inherit strategy instead of re-creating it from scratch
- Direct publishing to WordPress or GitHub-based static sites so every publish cycle strengthens the next plan
- AIRS reports that show visibility across Google and AI search engines for any query
- Exports and reports that clients and executives can read without translation
From here, the individual docs for each module will walk through setup, workflows and advanced options in detail.
---
## Add Topic Silo
Source: https://floyi.com/docs/tools/add-topic-silo/
Add Topic Silo lets you grow your topical authority coverage by adding a new main topic pillar to a project that is already in the Topical Authority stage. The new silo goes through the full pipeline - topical research, keyword clustering, and map merge - and appears in the Planner alongside your existing pillars.
Use this page to learn how to add a silo, review and edit at each stage, and merge the results into your topical map.
---
## What Add Topic Silo does
When you want to cover a new topic area, you no longer need to create a separate project. Add Topic Silo runs a scoped pipeline for a single new Main Topic and appends the results to your existing map.
The flow:
1. Enter a new Main Topic name and optional seed keywords
2. Review and edit the generated topic research
3. Review and edit the keyword clusters
4. Preview the new pillar in your map hierarchy
5. Merge into your topical map
The flow is forward-only. There are no back buttons between stages. If you need to start over, cancel the silo and begin a new one from the input form.
After merging, the new pillar appears in your Planner, Scorecard, and Organizer like any other pillar.
---
## Where to find Add Topic Silo
1. Open your project in Floyi.
2. Go to **Topical Authority** > **Planner**.
3. Switch to the **Organizer** view.
4. Click **+ Add Topic Silo** in the Organizer toolbar.
The button only appears when:
- Your project is in the Topical Authority stage
- No other silo addition is already in progress for this project
---
## Prerequisites
Before adding a silo, your project needs:
- A validated [Topical Map](https://floyi.com/docs/tools/topical-map/) that has been promoted to Topical Authority
- At least one [Topical Authority](https://floyi.com/docs/tools/topical-authority-scorecard/) calculation run
You should also have your [Brand Foundation](https://floyi.com/docs/tools/brand-foundation/) and [Buyer Personas](https://floyi.com/docs/tools/audience-insights/) set up so the research aligns with your positioning.
---
## Step 1: Input
When you click **+ Add Topic Silo**, the Organizer content area is replaced by an input form.
| Field | Required | Description |
| ----------------- | -------- | ------------------------------------------------------------------------- |
| **Main Topic** | Yes | The name of your new pillar (e.g., "email marketing", "content strategy") |
| **Seed Keywords** | No | Comma-separated keywords to guide the research |
| **Personas** | No | Select personas from your brand to tailor the research |
The form shows an estimated credit cost for each stage. A credit notice below the **Generate Topic Silo** button confirms that credits will be deducted when you proceed. Actual costs depend on the topical research results and the number of keywords generated.
Click **Generate Topic Silo** to start topical research for the new Main Topic.
> The Main Topic name must be unique. If a pillar with the same name already exists, you will see an error.
---
## Step 2: Research review
After the research task completes, you see the results in the same views you already know from [Topical Research](https://floyi.com/docs/tools/topical-research/):
- **Silo view** - kanban column showing the new Main Topic and its subtopics
- **Outline view** - hierarchical table with expand/collapse
- **Spreadsheet view** - flat table of all generated topics
You can:
- Rename, delete, or add topics using the inline context menu
- Switch between Silo, Outline, and Spreadsheet views
- Regenerate a specific level (ST3, ST4) if the results need adjustment
A summary bar shows the total count of subtopics at each level.
When you are satisfied with the research, click **Continue to Clustering**. A credit notice below the button confirms that SERP data will be fetched and keywords clustered, and that credits will be deducted.
---
## Step 3: Clustering review
Floyi fetches SERPs for the keywords in your new silo and runs keyword clustering. This step costs credits - typically around 260 keywords are fetched and clustered for a single Main Topic. Once complete, you see the same clustering table used on the [SERP Clustering](https://floyi.com/docs/tools/serp-clustering/) page:
- Cluster number, cluster head, keyword, search volume, CPC, and similarity score
- Edit cluster head names inline
- Remove keywords you do not want
- Click any keyword to open the SERP data modal
- Re-cluster if you want to try a different grouping
A summary shows the total cluster and keyword counts.
When you are satisfied with the clusters, click **Continue to Map Preview**. A notice below the button confirms that topic hierarchy and URL slugs will be generated at no additional credit cost.
---
## Step 4: Map preview
The map preview shows how the new pillar will look inside your topical map. You see the same Organizer views you already use:
- **Table view** - indented tree with expand/collapse
- **Columns view** - Miller columns focused on the new pillar
- **Tree view** - visual tree diagram
Existing pillars are shown above the new one for context, but they are read-only and visually muted. The new pillar is fully editable - you can rename topics, reorder them, or add child nodes.
A summary shows what is being added: pillar count, cluster count, topic count, and page count.
When you are satisfied with the structure, click **Add to Map** to merge.
---
## Step 5: Merge
When you confirm the merge:
1. Floyi creates a snapshot of your current topical map (for rollback if needed)
2. The new pillar nodes are appended to your topical map
3. The Topical Authority hierarchy cache is refreshed
4. You return to the normal Organizer view
A toast notification confirms the silo was added.
---
## After merging
The new pillar is now part of your project. A few things to know:
- **No SERP data yet.** New nodes appear as uncovered in the Planner and Scorecard. You need to trigger a **SERP refresh** to fetch SERP rankings and the optional AI search data for the new topics. This costs credits depending on the number of topics.
- **Briefs and drafts.** You can generate briefs and drafts for the new topics the same way you do for existing ones.
---
## Resuming and cancelling
### Resuming an in-progress silo
If you refresh the page, close the tab, or navigate to another section while a silo addition is in progress, your work is saved. Any running research or clustering tasks continue in the background.
When you return to Add Topic Silo, you always land on the input form. If there is an in-progress silo, you see a notice with two options:
- **Resume** - picks up where you left off, jumping to the correct stage with your data intact
- **Start new** - enter a different Main Topic. Floyi discards the existing silo before starting the new one.
### Explicitly cancelling (discard)
If you click the **Cancel** button inside the silo flow, Floyi discards the in-progress silo:
- The staging record is marked as discarded
- The new Main Topic entry is removed from your research data
- Any clustering results created for the silo are deleted
- If a research or clustering task is still running, it detects the discard and stops
- Your existing topical map is not affected
Cancelling is permanent - you cannot undo a discard. If you want to add the same topic again, start a new silo flow.
> If you are unsure, navigate away instead of cancelling. Your progress will be there when you come back.
---
## Edge cases
| Situation | What happens |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| Duplicate Main Topic name | Rejected at input - you see an error asking for a unique name |
| Task gets stuck (no progress for 30+ minutes) | The status endpoint detects the stall. You see **Retry** and **Cancel** options instead of the progress spinner. |
| Empty clustering result | The silo moves to a failed state with a message suggesting more seed keywords. Cancel and start a new silo with different seed keywords. |
| Another user edits the map during your silo flow | The merge checks the map version. If someone else changed the map, you see a conflict message asking you to refresh and try again. |
| Only one silo at a time | Each project allows one active silo addition. The button is hidden while a silo flow is in progress. |
---
## Credit usage
Credits are consumed at two points during the silo flow:
| Stage | What costs credits | Estimate |
| ----------------------- | ----------------------------------------------------------- | --------------------------------------- |
| **Research** (Step 1) | Generating subtopics (ST2, ST3, ST4) for the new Main Topic | Varies by model; shown on input form |
| **Clustering** (Step 3) | SERP fetching + keyword clustering for ~260 keywords | 1 credit per keyword × model multiplier |
The input form shows a per-stage credit breakdown before you start. Each action button shows a credit notice so you know when credits will be deducted.
The following stages are free - no credits are consumed:
- Reviewing and editing research results (Step 2)
- Reviewing and editing clusters (Step 3 review)
- Building the topic hierarchy and URL slugs (Step 4)
- Previewing and merging the map (Step 4 and Step 5)
After merging, a Topical Authority refresh is a separate action with its own credit cost (5 credits per topic).
---
## Tips
- **Start with seed keywords.** Even a few seed keywords help the research produce more focused subtopics.
- **Edit at the research stage.** It is easier to remove irrelevant topics before clustering than after.
- **Check for overlap.** Before adding a silo, review your existing pillars. If the new topic overlaps heavily with an existing one, you may get better results by expanding the existing pillar instead.
- **Refresh selectively.** After merging, you can refresh Topical Authority for the entire map or wait until your next scheduled refresh. The new topics will be picked up either way.
---
## AI Writing Assistant
Source: https://floyi.com/docs/tools/ai-writing-assistant/
> **Edit smarter, not harder.** Select any text and let AI simplify, expand, or polish it-without leaving your editor.
The **AI Writing Assistant** is your in-editor copilot, built into [Floyi's Content Editor](/docs/tools/content-editor-optimizer/). Unlike standalone AI tools that require copying and pasting, Floyi brings intelligent editing directly into your content workflow. It knows your SEO strategy, preserves your links, and helps you optimize for specific entities and topics.
## Core Features
- **Inline Editing**: Works directly in the content editor. No tab switching.
- **6 Preset Actions**: One-click transformations for common tasks.
- **Optimize Mode**: Dedicated mode to incorporate SEO entities from your brief.
- **Preview & Control**: Always see a side-by-side comparison before accepting changes.
- **Formatting Preservation**: Links, lists, bold, and italic styles are retained.
- **Cost Transparency**: See exactly how much each action costs before you click.
---
## How it Works
1. **Select Text**
Highlight any text in the editor (up to ~400 words). The AI bubble will automatically appear above your selection.
2. **Choose an Action**
Select a preset action like **Simplify** or **Fix Grammar**, or type your own instructions in the **Custom** field.
3. **Preview Result**
The AI generates a new version of your text. You can toggle between the **Original** and **Generated** tabs to compare.
4. **Accept or Reject**
Click **Accept** to replace your selection with the polished version, or **Reject** to discard the changes.
---
## Available Actions
### 1. Preset Actions
Floyi includes six one-click actions for the edits you make every day:
| Action | Description | Best For |
| :-------------- | :---------------------------------------------- | :------------------------------------- |
| **Simplify** | Makes complex text clearer and more accessible. | Improving readability scores. |
| **Expand** | Adds depth, examples, or supporting detail. | Fleshing out thin sections. |
| **Shorten** | Condenses text without losing meaning. | Concise summaries. |
| **Fix Grammar** | Corrects error and polishes prose. | Final proofreading. |
| **Optimize** | Incorporates specific terms from your brief. | Boosting topical authority. |
| **Custom** | Any instruction you can describe. | Tone adjustments, specific formatting. |
### 2. Optimize Mode
The **Optimize** action is unique to Floyi. It connects the AI assistant directly to your content brief.
1. Click **Optimize** in the AI bubble.
2. The input field will change to "Select terms from the right panel...".
3. Click any **missing** or **important** terms in the right-hand **Optimizer** panel.
4. The AI will rewrite your selection to naturally include those terms contextually.
### 3. Custom Instructions
Go beyond presets using the **Custom** input field. Describe exactly what you want:
- _"Make it punchier and use active voice."_
- _"Rewrite this as a bulleted list."_
- _"Add emojis where appropriate."_
---
## Comparison Features
| Feature | Floyi AI Writing Assistant | Standard AI Tools (ChatGPT/Jasper) |
| :--------------------------- | :------------------------: | :--------------------------------: |
| **Inline Editor** | ✅ | ❌ |
| **SEO Workflow Integration** | ✅ | ❌ |
| **Preserves Links** | ✅ | ❌ |
| **Preview Before Accept** | ✅ | ❌ |
| **Context Aware** | ✅ | ❌ |
---
## Frequently Asked Questions
**Does it preserve my links?**
Yes. Internal and external Markdown links `[text](url)` are preserved during transformation. We specifically instruct the model to retain your link structure.
**What is the character limit?**
For best performance, we recommend selecting chunks of text under **2,000 characters** (approx. 400 words) at a time. This ensures faster response times and higher quality output.
**Can I undo a change?**
Yes. Even after clicking **Accept**, you can use `Cmd+Z` (Mac) or `Ctrl+Z` (Windows) in the editor to undo the change and revert to your original text.
**How is usage charged?**
Floyi believes in no surprises. You will always see the exact [credit cost](/docs/billing/credits/) of an action displayed in the AI bubble _before_ you run it.
---
## AIRS Analyzer
Source: https://floyi.com/docs/tools/airs-analyzer/
The AIRS (AI Results) Analyzer lets you see how any query is answered across multiple AI platforms-from Google's AI Overviews to ChatGPT, AI Mode, Gemini, Perplexity, Claude, Grok, and more. Understand where your brand appears and what sources AI tools are citing. For the strategic view of AI visibility monitoring, see [AI Visibility and Competitors](/solutions/ai-visibility-and-competitors/).
## What You'll Learn
- How to run an AIRS analysis
- Understanding the comparison matrix
- Tracking brand mentions and citations
- Reading strategic insights
- Analyzing individual tool responses
- Managing past reports
- Exporting your findings
---
## Getting Started
### What AIRS Reveals
AIRS answers critical questions:
- Does your brand appear in AI-generated answers?
- Which sources are AI engines citing?
- How do AI answers compare to traditional SERPs?
- Where should you focus content efforts?
### Running a New Analysis
1. Navigate to **AIRS Analyzer** from the Toolbox
2. Enter your search query (e.g., "best project management software")
3. Optionally select:
- **Language** - Target language for results
- **Country** - Geographic location the query is run from
- **Brand** - Select a brand to track mentions and citations of it throughout the report
4. Click **Analyze** to start
:::tip
Selecting a brand is what unlocks the brand mention tracking described below. Without it, the report still shows every cited source, just not which of them are yours.
:::
### Analysis Stages
The analyzer runs through multiple stages:
| Stage | Description |
| -------------------------- | ------------------------------------------ |
| **1. Fetching Answers** | Queries all AI search tools simultaneously |
| **2. Analyzing Responses** | Processes each tool's response |
| **3. Comparing Results** | Cross-references sources and citations |
| **4. Generating Insights** | Creates strategic recommendations |
A full analysis usually takes several minutes, and complex queries can run 15 minutes or longer. Every AI engine is queried live before the analysis stages can begin, and the AI search platforms have been making their answers progressively harder to fetch, so those requests take longer than they used to.
You do not have to sit and watch it:
- **Leave the page or refresh** - the analysis keeps running, and returning to the AIRS Analyzer picks the progress display back up where it left off.
- **We email you** when the report is ready, so you can start one and come back later.
- **Start another report** while one is running - the first keeps processing in the background and appears in Past Reports when it finishes.
---
## Understanding Your Results
### Report Tab
The Report tab provides a strategic overview:
#### Strategic Summary
- **Overall AI Visibility** - How often your brand/domain appears
- **Key Findings** - Most important takeaways
- **Opportunities** - Where you could improve visibility
- **Threats** - Competitive concerns to address
#### Source Analysis
See which domains are most frequently cited:
- **Domain Frequency** - How often each domain appears
- **URL Frequency** - Specific pages that are cited
- **Citation Context** - How sources are referenced
---
### Comparison Tab
The comparison matrix shows visibility across all platforms:
| Column | What It Shows |
| ---------------- | ---------------------------------- |
| **Google SERPs** | Traditional organic rankings |
| **Bing SERPs** | Bing organic search positions |
| **AI Mode** | Google's AI Mode responses |
| **AIO** | Google's AI Overview citations |
| **Bing Copilot** | Microsoft's AI assistant |
| **Claude Web** | Anthropic's Claude with web search |
| **Gemini** | Google's Gemini with grounding |
| **Grok** | xAI's Grok with web search |
| **OpenAI Web** | OpenAI's web search integration |
| **Perplexity** | Perplexity AI citations |
| **ChatGPT** | ChatGPT search results |
#### Reading the Matrix
- checkmark = Source appears in this tool
- Empty = Source not cited
- **Engines** = How many surfaces cite that source, shown as a coloured count in the first column
- **You** badge = the source is on your brand's domain
The table sorts by Engines (highest first) by default, so the most widely cited sources are at the top. Click any column heading to sort by that platform instead.
### Results Tab
Deep-dive into individual tool responses:
- Full AI-generated text for each tool, with your brand mentions highlighted
- Tool performance matrix scoring each engine on depth, accuracy, intent match, and source quality
- Brand Mentions panel showing whether each engine named or cited you
- Cited sources with links
- Error states if any tools failed
---
## Brand Mentions and Citations
When you run an analysis with a brand selected, AIRS tracks two separate signals for every engine. They sound similar but mean very different things:
| Signal | What it means |
| ---------- | ---------------------------------------------------------------- |
| **Named** | The engine wrote your brand name (or an alias, or your domain) into the answer itself |
| **Cited** | The engine used a page on your domain as a source, without necessarily naming you |
An engine can cite your page as a source and still credit the answer to someone else. That is a very different problem from not being in the answer at all, so AIRS never merges the two.
### Where you'll see it
- **Brand column** - in the tool performance matrix on the Results tab, next to Overall. A filled badge means Named (with the mention count), an outlined badge means Cited only, and a dash means neither. Sort by it to see which engines know you.
- **Report summary** - a single line above the matrix: named in X of Y answers, cited by Z.
- **Brand Mentions panel** - for each engine, the mention count, citation count, which terms matched (brand name, aliases, or domain), and a quote showing the first mention in context.
- **Highlighted responses** - mentions are highlighted directly inside the AI answer so you can scan a long response and find them instantly. Use the **Highlight in response** checkbox to turn it off.
- **Source Comparison table** - rows on your own domain are marked with a **You** badge, so you can see at a glance which of your URLs the engines are pulling from.
### How mentions are counted
- The mention count reflects your brand in the **answer text only**. Sources are counted separately as citations, so a page title that happens to contain your name never inflates the mention count.
- Matching covers your brand name, any aliases set in [Topical Authority settings](https://floyi.com/docs/tools/topical-authority-scorecard/), and your domain (including variations like `www.` and the bare domain name). This is the same matching Topical Authority uses, so the two tools agree on whether you were mentioned.
:::note
Brand data appears throughout the report and in every export format. Reports run before a brand was selected will not have it - re-run the analysis with a brand selected to add it.
:::
---
## Strategic Insights
AIRS provides actionable recommendations:
### Visibility Scores
- **High Visibility** - Appearing in 7+ tools
- **Medium Visibility** - Appearing in 4-6 tools
- **Low Visibility** - Appearing in 1-3 tools
- **Not Visible** - Not cited anywhere
### Opportunity Areas
The analyzer identifies:
- Topics where competitors appear but you don't
- Platforms where you're underrepresented
- Content gaps to fill for better AI visibility
:::tip
Track your AI visibility over time with the [Topical Authority Scorecard](https://floyi.com/docs/tools/topical-authority-scorecard/), which includes AI Authority metrics across your topical map.
:::
---
## Managing Past Reports
### Past Reports Tab
Access your analysis history:
- Search by query or date
- View previously analyzed topics
- Reload any past report
### History Actions
- **Load** - Restore a previous analysis to view
- **Delete** - Remove reports you no longer need
- **Bulk Delete** - Select multiple reports to delete
### Pagination
Reports are paginated. Click **Load More** to view additional history.
---
## Regenerating Reports
### Refresh Strategy
If results seem outdated or you want fresh analysis:
1. Click **Regenerate Strategy**
2. The system re-analyzes with current AI responses
3. New insights are generated
:::note
Regeneration incurs additional credits but uses cached tool responses where available. You should also download your first report to have a copy of the original results.
:::
### Retry Failed Tools
If any AI tools failed during initial analysis:
1. Click **Retry Failed Tools**
2. Only failed tools are re-queried
3. Results are merged with existing data
---
## Exporting Reports
### Export Formats
Click the **Export** button on the report:
| Format | Best For |
| --------------- | ----------------------------------- |
| **DOCX** | Word documents, editing, white-labelling |
| **PDF** | Sharing, presentations |
| **HTML** | Self-contained file for the web or email |
| **Google Docs** | Collaborating with your team |
The Source Comparison table exports separately as **XLSX**, **CSV**, or straight to **Google Sheets**, using its own Export button.
### Export Contents
Exports include:
- Strategic summary and insights
- Tool performance matrix, including the Brand column
- Brand mention and citation status for each engine, with mention context
- Individual tool responses, with links, tables, and formatting preserved
- Keyword and entity analysis
- Source citations
The Source Comparison spreadsheet exports include a **Your Brand** column marking rows on your own domain.
:::note
Word and PDF exports are generated in the background and download when ready. Larger reports take longer to build than the HTML export, which is generated immediately.
:::
---
## Frequently Asked Questions
### What AI tools does AIRS query?
AIRS queries: Google SERPs, Bing SERPs, Google AI Mode, Google AI Overview, Bing Copilot, Claude Web Search, Gemini Grounding, Grok, OpenAI Web Search, Perplexity, and ChatGPT.
### Why don't some tools show results?
Some AI tools may not return results for certain queries, or may experience temporary outages. Failed tools are marked and can be retried.
If a provider has an extended outage, we temporarily disable that engine so you are not charged for runs that cannot succeed. Disabled engines are hidden from new reports, while past reports keep the data they already collected.
Additionally, some AI search providers have geographic restrictions. For example, AI Mode and AI Overview are not available in Russia or Belarus, and ChatGPT has limited availability in certain regions. See [Supported Countries & Regions](https://floyi.com/docs/tools/supported-countries/) for the full list.
### How often do AI answers change?
AI responses can change frequently. Run periodic analyses to track how your visibility evolves over time.
### Can I analyze competitor visibility?
Yes! Enter any query to see which domains appear. Compare your brand against competitors to identify gaps.
### What's the difference between this and traditional rank tracking?
Traditional rank tracking only shows organic SERP positions. AIRS shows where sources appear in AI-generated answers-an increasingly important visibility metric.
### How are credits calculated?
AIRS uses a single bundle cost covering all 11 surfaces in one analysis: 9 AI engines plus Google and Bing SERPs. The exact cost depends on your AI model selection, and credits are only deducted when the analysis completes successfully.
### What is the difference between being named and being cited?
Being **named** means an engine wrote your brand into its answer. Being **cited** means it used one of your pages as a source without necessarily naming you. Engines regularly do the second without the first, which is why AIRS reports them separately. See [Brand Mentions and Citations](#brand-mentions-and-citations).
---
## Analyze URL
Source: https://floyi.com/docs/tools/analyze-url/
Analyze URL scrapes any webpage and provides AI-powered analysis of its content structure, topics, entities, and optimization opportunities. Use it to study competitor pages or audit your own content.
## What You'll Learn
- How to analyze any URL
- Understanding the analysis results
- Using search query context
- Managing past analyses
- Interpreting AI insights
---
## Getting Started
### Analyzing a Page
1. Navigate to **Analyze URL** from the Toolbox
2. Enter the full URL to analyze (including `https://`)
3. Optionally enter a **search query** for contextual analysis
4. Click **Analyze**
### Why Include a Search Query?
Adding a search query helps the AI:
- Evaluate how well the page targets that topic
- Rate relevance to the query intent
- Identify optimization opportunities
- Assess search intent alignment
:::tip
For competitive analysis, enter the keyword you're targeting to see how well competitors address it.
:::
---
## Understanding Results
### Content Data
Basic page information:
| Metric | Description |
| -------------------- | ------------------------ |
| **Title** | Page title tag |
| **Meta Description** | Meta description content |
| **Word Count** | Total content length |
| **Header Structure** | H1-H6 breakdown |
| **Internal Links** | Links within the domain |
| **External Links** | Links to other domains |
| **Images/Videos** | Media counts |
### AI Analysis
When AI analysis is enabled:
#### Summary
A concise overview of what the page covers and its main purpose.
#### Main Topics & Subtopics
- **Main Topics** - Primary themes covered
- **Subtopics** - Secondary themes and supporting content
#### Entities
Key entities mentioned:
- People, companies, products
- Concepts and technical terms
- Locations and events
#### Tone of Voice
How the content is written:
- Professional, casual, technical
- Persuasive, informational, educational
#### Search Intent
What users are likely looking for:
- **Informational** - Learning about a topic
- **Navigational** - Finding a specific page
- **Commercial** - Researching before purchase
- **Transactional** - Ready to take action
#### Content Type
Classification of the page:
- Blog post, product page, landing page
- Documentation, tutorial, review
### Search Query Rating
When you provide a search query:
- Rating of how well the page targets the query
- Relevance assessment
- Optimization suggestions
### Key Takeaways
Bullet points summarizing the most important findings.
### Buyer's Journey Stage
Where the content fits in the customer journey:
- Awareness, Consideration, Decision
---
## Managing Past Analyses
### Past Analyses Tab
View your analysis history:
- URL analyzed
- Search query used
- Analysis date
- Status (completed or in progress)
### Actions
- **Load** - Restore a previous analysis
- **Refresh** - Update the list
- **Delete** - Remove selected analyses
### Selection & Bulk Delete
1. Check the boxes next to analyses
2. Click **Delete Selected**
3. Confirm deletion in the modal
---
## Best Practices
### Competitive Analysis
- Analyze top 3-5 competitors for your target keyword
- Compare content structure and depth
- Note entity coverage differences
### Content Auditing
- Run analyses on your own pages
- Include the target keyword as search query
- Review AI ratings for optimization opportunities
### Research Workflow
Combine with other tools:
1. Use [SERP Insights](https://floyi.com/docs/tools/serp-insights/) to identify top URLs for your target keyword
2. Analyze those URLs for content patterns
3. Create [Briefs & Drafts](https://floyi.com/docs/tools/briefs-and-drafts/) based on findings
---
## Frequently Asked Questions
### What pages can I analyze?
Any publicly accessible webpage. Password-protected or dynamically loaded content may not be fully captured.
### How long does analysis take?
Typically 30-60 seconds. Larger pages may take longer.
### Why is analysis "in progress"?
AI analysis runs in the background. Check back in the Past Analyses tab when complete.
### Can I re-analyze the same URL?
Yes! Running a new analysis on the same URL creates an updated entry.
### What's the difference between this and SERP Insights?
| Tool | Purpose |
| ----------------- | ------------------------------------ |
| **Analyze URL** | Deep-dive into a single page |
| **SERP Insights** | Analyze an entire SERP for a keyword |
### How are credits calculated?
Credits are charged per URL analyzed, with a multiplier based on your selected AI model.
---
## Audience Insights
Source: https://floyi.com/docs/tools/audience-insights/
Audience Insights turns your buyers into structured personas that Floyi can reuse across research, planning and content.
Instead of static PDFs, personas become live inputs you can select in Topical Research, Briefs and the Content Creation workspace.
Use this page as a guide for creating, editing and managing personas inside Floyi.
---
## What Audience Insights Does
Audience Insights helps you:
- Generate customized buyer personas that align with your Brand Foundation
- Capture demographics, goals, pains, triggers, values and objections in a structured format
- Keep personas up to date as your product, market or strategy changes
Personas created here are available wherever Floyi asks you to choose an audience, including:
- [Topical Research](https://floyi.com/docs/tools/topical-research/)
- Content Briefs
- The Content Creation workspace
---
## Where to Find Audience Insights
1. Open your project in Floyi.
2. In the left navigation, select **Audience Insights**.
3. You will see your existing personas for this project, if any.
Most teams start with one primary buyer persona, then add a few more to cover secondary buyers, users or influencers.
---
## Before You Start: Use Brand Foundation
You will get the best results if you create a Brand Foundation first.
1. Go to [Brand Foundation](https://floyi.com/docs/tools/brand-foundation/) and create a profile for your brand.
2. When generating personas, select that Brand Foundation so Floyi uses your real positioning and language.
You can technically generate personas without a Brand Foundation, but they will be less aligned with your strategy.
---
## How To Generate Buyer Personas
### 1. Choose context
1. Open **Audience Insights**.
2. Click **Generate personas** or the equivalent button in the UI.
3. Select:
- The Brand Foundation you want to use
- Language and country, if prompted
### 2. Set optional preferences
You can optionally narrow the generation with extra hints, for example:
- Roles or job titles
- Industries or company sizes
- Regions or markets
- Typical maturity level or adoption stage
Use this when you already know who you sell to. If you are still exploring, you can leave these fields empty and let Floyi propose a mix of likely buyers.
> If you do not have specific preferences yet, you can skip this step.
### 3. Set the number of personas
Use the control in the UI to choose how many personas to generate in one run.
- Minimum: 1
- Maximum: 5
For a first pass, start with 1 or 2 personas. You can always generate more later.
### 4. Generate personas
1. Review the AI model and the credit estimate.
2. Click **Generate personas**.
3. Wait for the generation to complete. Personas created in this run will appear in the list, often marked as **New**.
> Generating personas uses credits. The cost depends on the AI model you pick.
---
## Persona Fields and Structure
When you open a generated persona, you will typically see fields similar to:
- **Name**
- **Age or age range**
- **Job title and role**
- **Seniority or decision power**
- **Company type and size**
- **Location or region**
- **Goals**
- **Pains and triggers**
- **Values and priorities**
- **Fears and risks they want to avoid**
- **Buying process and decision drivers**
- **Information sources and research habits**
- **Common objections**
- **Representative quotes**
You can adjust both wording and structure. The goal is not to have every possible detail, but to capture the pieces that will actually change how you write and what you prioritize.
---
## How To Edit Buyer Personas
Editing is free and usually the first thing to do after generation.
1. Open **Audience Insights**.
2. Click on the persona you want to modify.
3. Click **Edit**.
4. Update any fields that need refinement, for example:
- Correct job titles or industries
- Tighten goals and pains
- Replace generic values with concrete ones you hear in sales calls
- Add real phrasing to the quotes section
5. Click **Save** in the persona drawer or card.
You can edit personas as often as needed. Floyi will use the latest saved version in future workflows.
---
## How To Delete Buyer Personas
If a persona is no longer relevant or was created as an experiment, you can remove it.
1. Open **Audience Insights**.
2. Select one or more personas using the checkboxes or selection controls.
3. Click **Delete** or **Delete selected personas**.
4. Confirm the deletion.
Deleted personas are removed from the project and will no longer be available as options in research, briefs or drafts.
---
## Exporting Personas
You can export personas if you need to share them with stakeholders outside Floyi.
Typical export options include:
- **XLSX**
- Each persona as a row, with fields as columns
- Useful for spreadsheets, research summaries and intake forms
- **DOCX or text export**
- Structured sections per persona
- Useful for onboarding documents, client deliverables or playbooks
Exports are snapshots. Edit personas in Floyi, then re export if you want a refreshed copy.
---
## Credit Usage and AI Models
Audience Insights uses credits only when generating new personas.
- Editing and deleting personas is free.
- Each generation run shows a clear credit estimate before you confirm.
- Heavier models cost more credits but may give richer, more nuanced personas.
Common patterns:
- Use a stronger model for your primary personas that will influence most of your content.
- Use smaller or faster models for exploratory personas or early experiments.
If you do not have enough credits, Floyi will show an error or a billing prompt instead of starting the job.
---
## How Personas Connect To Other Tools
Once you have at least one persona, you can use it across the platform.
Some key connections:
- **Topical Research**
- Select one or more personas so topic generation reflects their pains, language and journey
- **Content Briefs**
- Attach personas to briefs so goals, objections and research habits shape the outline and talking points
- **Content Creation workspace**
- Drafts can inherit persona context so the tone and angle match the intended reader
- **Topical Authority planning**
- Choose topics that map to specific personas, not just generic search volume
If you are new to Floyi, a simple approach is:
1. Set up your [Brand Foundation](https://floyi.com/docs/tools/brand-foundation/).
2. Create one strong primary persona in Audience Insights.
3. Use that persona in your first [Topical Research](https://floyi.com/docs/tools/topical-research/) and brief runs.
You can always come back to add more personas once you see how the first one performs.
---
## Brand Foundation
Source: https://floyi.com/docs/tools/brand-foundation/
Brand Foundation is the single source of truth for your brand inside Floyi. Mission, positioning, voice, competitors, and site context are stored once, then reused by Audience Insights, Topical Research, Topical Authority, Briefs, and the Content Creation workspace.
The Brand Foundation page has five tabs:
- **Brand Identity**: Core strategic statements about your brand
- **Content Guide**: Rules and guidelines for AI content generation
- **Brand Voice**: AI-powered voice analysis and profile for consistent writing style
- **Visual Style**: AI-powered visual identity analysis for brand-consistent image generation
- **Knowledge Base**: Upload documents to give AI agents brand-specific context during brief and draft generation
---
## What Brand Foundation Does
Brand Foundation turns scattered brand notes into a structured profile that Floyi can apply everywhere.
A Brand Foundation profile typically includes:
- Brand name and website URL
- High-level description and focus
- Mission and vision statements
- Tagline and value pillars
- Target audiences and segments
- Brand voice and tone guidelines
- Market context and key competitors
- Differentiators and positioning
- Brand story and site information
This profile is what Floyi uses when it generates personas, topics, briefs, drafts, and internal link suggestions.
---
## Part 1: Brand Identity
Your Brand Identity consists of core strategic statements. You can generate these using Floyi's AI or enter them manually.
### How to Create Your Brand Identity
#### Method A: Generate from URLs (Recommended)
Best if your site already has decent positioning and product copy.
1. Click the **Generate from URLs** button.
2. Enter your **Homepage URL** (Required).
3. Optionally, add a **Second URL** (e.g., your "About" or "Services" page) for deeper context.
4. Select your **Primary Country** and **Output Language**.
5. Optionally, add **Project Notes** for internal reference.
6. Click **Generate from URLs**.
7. Floyi will scrape your website, analyze the content, and automatically populate the identity fields.
URL generation typically takes 1-3 minutes depending on website complexity.
#### Method B: Manual Entry
Best if your site copy is weak, very new, or still in flux.
1. Click the **Manual Input** button.
2. In the **Brand Context** box, provide a detailed description of your brand, audience, and market position.
3. Select your **Primary Country** and **Output Language**.
4. Optionally, add **Project Notes** for internal reference.
5. Click **Generate Brand Identity**.
### Brand Identity Fields Defined
Every field in this section is used by Floyi's AI to understand your brand's DNA.
- **Brand Name**: The official name of your business or project.
- **Website URL**: Your primary domain.
- **Add trailing slash to internal links**: A checkbox directly under Website URL, editable while the identity card is in edit mode. Turn it on when your site's canonical URLs end in a slash, so Floyi writes internal links as `/page/` instead of `/page`. Off by default. The setting applies wherever Floyi builds an internal link - briefs, drafts, the content editor, and exports - so links match your site's canonical form instead of relying on a redirect. It affects links Floyi builds from that point onward; content already generated and saved keeps the URLs it was written with.
- **Mission Statement**: Why your brand exists and what it aims to achieve today.
- **Vision Statement**: The long-term impact or future state your brand strives for.
- **Tagline**: A short, memorable phrase that captures your brand essence.
- **Target Audience**: A high-level description of who you serve (e.g., "SaaS founders and marketing managers").
- **Brand Voice**: The personality and style of your writing. You can use adjectives (e.g., "Professional, authoritative, yet accessible") or full sentences describing your tone.
- **Core Values**: The fundamental beliefs that guide your brand's actions.
- **Marketplace**: The industry or economic space where you operate.
- **Market Position**: Where you sit in the competitive landscape (e.g., "Premium, luxury" or "Affordable, entry-level").
- **Key Competitors**: A list of brands you compete against for attention and market share.
- **Unique Selling Proposition (USP)**: The one thing that makes you different and better than everyone else.
- **Brand Personality**: Human-like traits attributed to your brand (e.g., "The Innovator" or "The Helpful Neighbor").
- **Brand Story**: A narrative account of your brand's origin, challenges, and purpose.
- **Site Information**: Technical or contextual details about the website itself.
### Managing and Updating Identity
- **Edit/Save**: Click **Edit** to modify any field. Once finished, click **Save Changes** to update the database.
- **Cancel**: Click **Cancel** to discard changes and revert to the last saved version.
Manual edits are free and do not consume credits.
Use manual editing when:
- The structure looks right but some wording feels off
- You have legal or stakeholder feedback that needs precise changes
- You only want to refine a few lines or add internal notes
### Sidebar Panels
The right sidebar contains additional settings and tools:
**Locale Settings:**
- **Primary Country**: Used for SERP locale defaults across clustering, topical authority, and content generation.
- **Output Language**: Determines the language used for every AI-generated asset tied to this brand.
**Source URLs:**
- **Homepage URL**: The primary URL used for generating brand content.
- **Secondary URL**: An optional additional page for deeper context.
**Original Brand Info:**
- A read-only view of the original text or context provided during brand creation.
**Project Notes:**
- Internal-only notes for your team. This field is never consumed by AI; it is purely for your own reference.
### Regenerating Your Brand
If the profile misses the mark in a more fundamental way, you can regenerate it.
1. Optionally, add **Regeneration Notes** with specific instructions (e.g., "Make the tone more aggressive and focus more on our eco-friendly initiatives" or "Emphasize enterprise buyers, not solo users").
2. Toggle **Fetch fresh content from website** to re-scrape your source URLs if your website copy has changed.
3. Click **Regenerate Brand**.
Important details:
- Regeneration uses credits, similar to the first generation.
- Regeneration replaces the AI-generated content for that profile.
- Always review the new version before sharing or exporting.
Use regeneration when:
- The initial profile frames the brand incorrectly
- You pivot positioning or target a different segment
- You want a significantly different voice or emphasis, not minor edits
---
## Part 2: Business Info & Local SEO
The **Business Info** section handles your structured business data. This is critical for physical businesses and for generating **Local Business Schema** (JSON-LD) to improve your visibility in local search results.
### Configuring Business Info
You can find the **Business Info** card in the sidebar of the Brand Identity tab.
1. **Manual Entry**: Click **Edit** on the Brand Identity card to unlock fields in the Business Info card.
2. **Sync from GBP**: Click **Sync from GBP** to pull your business data directly from your verified **Google Business Profile**. You must connect your Google account in Settings > Integrations first.
### Business Info Fields
- **Business Legal Name**: The registered name of your company.
- **Primary Phone**: Your main contact number for customers.
- **Public Email**: The primary support or contact email for the business.
- **Street Address**: Your physical location.
- **Suite, floor, unit**: Additional address details.
- **City / State / Postal Code**: Standard geographic details.
- **Opening Hours**: Specify Open, Closed, Open 24 Hours, or By Appointment for each day of the week, including specific opening and closing times.
- **Business Type**: Select your Schema.org business category (e.g., "Dentist", "Restaurant", or "LocalBusiness").
- **Price Range**: Select from $ (Budget) to $$$$ (Luxury).
- **Year Established**: The year your business was founded.
- **Logo URL / Image URL**: Links to your brand assets for schema markup.
- **Google Business Profile URL**: Link to your public Google map listing.
- **Social Profiles**: Add links to your LinkedIn, X (Twitter), Facebook, etc.
- **Latitude & Longitude**: Precise coordinates for map placement.
- **Service Area Business**: Enable this if you serve customers at their location rather than your own physical office.
- **Service Areas**: A list of regions, cities, or areas where your business provides services.
### Local Business Schema (JSON-LD)
Floyi automatically generates technical **JSON-LD structured data** based on your Business Info.
- **Copy Schema**: Click the **Copy** icon in the Business Info header to copy the JSON-LD code to your clipboard. You can paste this directly into your website's HTML to help search engines understand your local presence.
- **Schema Export**: Your schema is also automatically included in XLSX and DOCX exports of your Brand Foundation.
---
## Part 3: Exporting Your Foundation
You can export your Brand Foundation to share with stakeholders outside Floyi.
1. Click the **Export** button in the header.
2. Choose your format:
- **XLSX**: A spreadsheet containing all identity fields and a separate tab for your LocalBusiness Schema. Suitable for strategy docs, intake forms, and internal planning.
- **DOCX**: A professionally formatted Word document with structured headings. Suitable for brand books, onboarding packets, and client deliverables.
- **Google Docs**: Creates a new document directly in your Google Drive.
Exports are read-only snapshots. Edit the Brand Foundation inside Floyi, then re-export if you need an updated version.
---
## Part 4: Content Guide
Click the **Content Guide** tab to define the specific rules and terminology that Floyi's AI must follow when drafting content. The Content Guide consists of five sections that control how AI generates content for your brand.
### AI-Generated Content Guide
Instead of building your Content Guide from scratch, you can use AI to generate a complete starting point based on your Brand Foundation.
**How to generate:**
1. Click **Generate with AI** (sparkles icon) in the Content Guide header.
2. Review the confirmation modal, which shows the credit cost and your selected AI model.
3. Click **Generate** to start. Floyi reads your Brand Foundation - voice, positioning, competitors, audience - and creates entries across all five sections.
4. Generation runs in the background. Progress messages appear in the modal.
5. When complete, all generated entries are saved and the Content Guide refreshes automatically.
**What gets generated:**
- Terminology rules with severity levels and preferred terms
- Compliance rule sets with banned claims and required disclosures
- Competitor policies with mention policies and talking points
- Brand messaging rules covering name usage, differentiators, pillars, and tone
- Boilerplate snippets for bios, CTAs, and disclaimers
Every generated entry is fully editable. Use the AI output as a starting point and customize to match your exact standards.
AI generation uses credits. The exact cost is shown in the confirmation modal before you proceed.
### Using the Starter Kit
If you are starting from scratch, click **Use starter kit**. This will populate your Content Guide with a set of industry-standard best practices, which you can then customize. You can also click **Start blank** to build your guide from scratch.
### 1. Terminology Rules (Brand Lexicon)
Define specific words to avoid and what to use instead.
**How to Add Rules:**
1. Expand the **Terminology Rules** section.
2. Click **Add Rule** or **Bulk Add** for multiple rules.
3. Enter the **Term to Avoid**.
4. Enter the **Preferred Term** (required for "Must Replace").
5. Set the **Severity Level**:
- **Must Replace**: Strict substitution (e.g., "cellphone" → "mobile")
- **Forbidden**: Never allow this term
- **Discouraged**: Avoid if possible
6. Optionally add an **Internal Note** explaining the rationale.
**Drag-and-Drop Reordering:**
Drag rules to reorder them by priority. The first 10 rules are sent to AI during content generation.
**Limits:**
- Maximum 10 rules are sent to AI per generation
- Rules beyond the 10th are dimmed in the UI
**Examples:**
- Avoid "cellphone" → Use "mobile" (Must Replace)
- Avoid "cheap" → (Forbidden)
- Avoid "blacklist" → Use "blocklist" (Discouraged)
### 2. Compliance Rules
Ensure your content adheres to legal or safety standards.
**How to Add Rule Sets:**
1. Expand the **Compliance Rules** section.
2. Click **Add Rule Set**.
3. Enter a **Name** for the rule set (e.g., "Marketing Compliance").
4. Enter **Banned Claims** (one per line) - phrases AI must never use.
5. Enter **Required Disclosures** (one per line) - text AI must include when relevant.
**Limits:**
- Maximum 3 rule sets are sent to AI per generation
- Rule sets beyond the 3rd are dimmed in the UI
**Examples:**
- Banned Claims: "Guaranteed results", "100% risk-free", "Cures any disease"
- Required Disclosures: "Results may vary", "Consult a professional before use", "This is a sponsored post"
### 3. Competitor & Comparison Guidelines
Control how your brand is compared to others. This section has two parts:
**A. General Comparison Standards**
Set rules that apply to all comparison content:
1. Click **Add Standard**.
2. Enter your rule (e.g., "Always acknowledge legitimate competitor strengths").
**B. Specific Competitor Watchlist**
Set policies for individual competitors:
1. Click **Add Competitor**.
2. Enter the **Competitor Name**.
3. Select a **Mention Policy**:
- **Neutral mention allowed**: Fact-based only, no praise or criticism
- **Comparison articles only**: Only allow mentions in direct "Vs" articles
- **Positive/neutral only**: High-road approach, never criticize
- **Never mention**: Total blackout, do not acknowledge existence
4. Add **Specific Talking Points / Instructions** for this competitor.
**Limits:**
- Maximum 10 competitor policies are sent to AI per generation
**Examples:**
- Competitor A: Never mention (internal policy)
- Competitor B: Comparison articles only (focus on our superior speed)
### 4. Brand Messaging
Define core brand messaging, tone of voice, and messaging pillars.
**How to Add Rules:**
1. Expand the **Brand Messaging** section.
2. Click **Add Rule** or **Bulk Add**.
3. Select the **Rule Type**:
- **Brand Name Usage**: Capitalization and naming conventions
- **Key Differentiator**: What makes your brand unique
- **Messaging Pillar**: Core value propositions to emphasize
- **Tone - Do**: Guidelines for desired tone
- **Tone - Don't**: Guidelines for tone to avoid
4. Enter the rule **Content**.
**Best Practice:**
Create separate entries for each distinct rule (e.g., one entry for "Use active voice" and a separate entry for "Avoid jargon"). Small, distinct rules help the AI understand and apply your guidelines more accurately.
**Limits:**
- Maximum 15 rules are sent to AI per generation
- Rules beyond the 15th are dimmed in the UI
**Examples:**
- Brand Name Usage: "Always capitalize 'Floyi'. Never use 'floyi'."
- Tone - Do: "Use active voice and short, punchy sentences."
- Tone - Don't: "Avoid using jargon or overly academic language."
- Key Differentiator: "We are the only platform that connects brand strategy to content creation in one system."
### 5. Approved Snippets (Boilerplate)
Create reusable text blocks for common sections.
**How to Add Snippets:**
1. Expand the **Approved Snippets** section.
2. Click **Add Snippet**.
3. Provide a **Snippet Name** (e.g., "About Us", "Standard CTA").
4. Select a **Snippet Type**:
- **Bio**: Company/author bios
- **CTA**: Call-to-action blocks
- **Disclaimer**: Legal disclaimers
- **Other**: Any other reusable content
5. Enter the **Snippet Content**.
**Using Snippets:**
Snippets are inserted manually via the Content Editor toolbar when editing articles. They are NOT automatically sent to AI during content generation.
**Copy to Clipboard:**
Click the copy icon next to any snippet to quickly copy it to your clipboard.
**Examples:**
- About Floyi: "Floyi is a topic-first content strategy platform that takes you from brand strategy to published drafts in one system."
- Standard CTA: "Ready to scale? Sign up for your free trial today."
- Affiliate Disclosure: "This post contains affiliate links. We may earn a commission at no extra cost to you."
---
## Part 5: Brand Voice
Click the **Brand Voice** tab to create an AI-powered voice profile that captures your brand's writing style. When a voice profile exists, Floyi automatically applies it to every content brief and draft so generated content sounds like your brand.
### What Brand Voice Does
Brand Voice analyzes 3-5 writing samples that represent your brand's style and produces a structured voice profile. This profile replaces (or enhances) the plain-text Brand Voice field in Brand Identity with a detailed, multi-dimensional analysis that AI agents use as a directive when generating content.
Without a voice profile, Floyi uses the short Brand Voice description from Brand Identity (e.g., "Professional, authoritative, yet accessible"). With a voice profile, Floyi uses a richer, more specific directive that captures nuances like sentence patterns, vocabulary level, and rhetorical techniques.
### How to Create a Voice Profile
1. Click the **Brand Voice** tab.
2. Click **Analyze My Voice**.
3. Choose your input method:
**Method A: Upload Files**
Upload 3-5 documents that represent your brand's writing style.
1. Drag and drop files into the upload area, or click to browse.
2. Supported formats: PDF, DOCX, TXT, MD, HTML.
3. Maximum file size: 10MB per file.
4. You need at least 3 and at most 5 samples.
5. Click **Analyze Voice**.
**Method B: Select from Knowledge Base**
If you have already uploaded documents to the Knowledge Base tab, you can select them directly instead of re-uploading.
1. Switch to the **Select from Knowledge Base** tab in the modal.
2. Browse or search your existing Knowledge Base documents.
3. Select 3-5 documents using the checkboxes.
4. Click **Analyze Voice**.
Only documents with status "Ready" and a word count greater than zero appear in the list.
### Voice Profile Dimensions
After analysis, Floyi produces a profile with seven dimensions:
| Dimension | What It Captures |
| ------------------------ | -------------------------------------------------------------------------------------------- |
| **Tone** | The overall emotional quality (e.g., confident, conversational, formal) |
| **Vocabulary Level** | Word complexity and register (e.g., accessible everyday language vs. specialized jargon) |
| **Sentence Patterns** | Structure and rhythm (e.g., short punchy sentences, compound-complex, varied length) |
| **Perspective** | Point of view and framing (e.g., first-person plural "we", second-person "you") |
| **Rhetorical Patterns** | Persuasion techniques (e.g., data-driven claims, storytelling, social proof) |
| **Personality Traits** | Human-like characteristics (e.g., approachable expert, bold challenger) |
| **Distinctive Patterns** | Unique stylistic markers specific to your brand (e.g., trademark phrases, formatting habits) |
Each dimension field is editable. Click **Edit** on any dimension to adjust its value directly without re-running the full analysis. This is useful when the analysis captures your voice correctly overall but one dimension needs fine-tuning - for example, shifting the Tone from "formal" to "confident and conversational" or updating Perspective to match a new editorial direction.
Editing dimension fields is free and does not consume credits.
### AI Prompt Directive
Below the seven dimensions, a summary **AI Prompt Directive** is displayed. This is the exact instruction that Floyi sends to AI agents during content generation. It condenses the full analysis into actionable writing guidance.
You can edit the prompt directive to fine-tune it:
1. Click **Edit** next to the AI Prompt Directive.
2. Modify the text in the textarea.
3. Click **Done** to save.
Editing the directive is free and does not consume credits.
### Managing Your Voice Profile
- **Re-analyze**: Click **Re-analyze** to run the analysis again with new or different samples. This replaces the existing profile.
- **Clear Profile**: Click **Clear Profile** and confirm to remove the voice profile entirely. Floyi will revert to using the plain-text Brand Voice field from Brand Identity.
### Tips for Best Results
- Use writing samples that reflect the voice you **want**, not necessarily everything you have published.
- Choose samples from the same content type (e.g., all blog posts, or all white papers) for a consistent analysis.
- If your brand voice differs across content types, analyze the type you produce most frequently.
- After generating, review the AI Prompt Directive and edit it if any nuance is missing or overstated.
---
## Part 6: Visual Style
Click the **Visual Style** tab to define your brand's visual identity for AI image generation. When a visual style guide exists, Floyi automatically applies it to every AI-generated image prompt so images match your brand's look and feel.
### What Visual Style Does
Visual Style captures your brand's visual identity - image types, photography and illustration styles, mood, lighting, composition, and color palette - and converts it into a directive that Floyi injects into every image generation prompt. Without a visual style guide, AI-generated images use a generic professional style. With one, every image reflects your specific brand aesthetic.
### How to Create a Visual Style Guide
#### Method A: Analyze from Website (Recommended)
Best if your website already has established visual design and branding.
1. Click the **Visual Style** tab.
2. Click **Analyze** in the analysis panel at the top.
3. Floyi screenshots your website using a headless browser, then sends the screenshot to an AI vision model (Gemini 3 Flash) which extracts:
- Dominant color palette with hex codes and color names
- Whether your brand uses photography, illustrations, or both
- Visual mood and tone (professional, playful, elegant, etc.)
- Lighting and composition characteristics
4. The form is pre-filled with the analysis results.
5. Review and adjust any fields, then click **Save Visual Style**.
Website analysis requires a website URL set in Brand Identity and consumes credits.
#### Method B: Manual Configuration
Best if you have a specific visual direction in mind or no website URL.
1. Click the **Visual Style** tab.
2. Fill in the style dropdowns directly:
- **Image Type**: Photography, Illustration, or Mixed
- **Photography Style**: Editorial, Corporate, Lifestyle, Product, Abstract, or Landscape
- **Illustration Style**: Flat, Isometric, Watercolor, Line Art, Hand-drawn, Infographic, or Realistic
- **Mood**: Professional, Warm, Bold, Elegant, Playful, Technical, or Calm
- **Lighting**: Natural, Studio, Dramatic, Warm Golden, Cool Blue, or Backlit
- **Composition**: Clean, Detailed, Centered, Dynamic, or Wide
3. Add your brand colors using the color palette editor (up to 6 colors with hex code, name, and role).
4. Optionally add a custom directive for anything the structured fields don't cover.
5. Click **Save Visual Style**.
Manual configuration is free and does not consume credits.
### Visual Style Fields Defined
| Field | What It Controls |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| **Image Type** | Whether AI generates photographs, illustrations, or a mix of both |
| **Photography Style** | The photographic approach (editorial, corporate, lifestyle, etc.) |
| **Illustration Style** | The illustration approach (flat, isometric, watercolor, etc.) - hidden when Image Type is Photography |
| **Mood** | The emotional tone of generated images |
| **Lighting** | How light is used in the images |
| **Composition** | Layout and framing characteristics |
| **Color Palette** | Brand colors that should appear in generated images, with hex codes, names, and roles (primary, secondary, accent, background) |
| **Custom Directive** | Free text for any additional visual instructions not covered by the dropdowns |
### Visual Prompt Directive
Below the form, a **Visual Prompt Directive** is displayed. This is the exact text that Floyi injects into the AI system prompt when generating image suggestions for your articles. It is auto-generated from your style selections and updates in real time as you change dropdowns.
You can edit the directive manually by clicking the edit toggle. If you manually edit the directive and then change a dropdown, Floyi will ask for confirmation before overwriting your custom text.
### How Visual Style Connects to Image Generation
When you click **Analyze Draft** in the Content Creation workspace to generate image placements:
1. Floyi loads your brand's visual style directive.
2. The directive is injected into the AI system prompt that generates image placement suggestions.
3. The AI writes image prompts that match your brand's visual style - using your colors, preferred image type, mood, and composition.
4. When images are generated, the generic style suffix is suppressed since your brand-specific style is already embedded in the prompts.
A small **Brand style active** banner appears in the image generation sidebar confirming that your visual style is being applied.
### Managing Your Visual Style Guide
- **Re-analyze**: Click **Re-analyze** to capture a fresh screenshot and run the vision analysis again.
- **Clear**: Click **Clear** and confirm to remove the visual style guide entirely. Floyi will revert to using a generic professional style for image generation.
- **Edit anytime**: All dropdowns and the directive are always editable. Changes are saved when you click **Save Visual Style**.
Editing fields and saving is free. Only the AI website analysis consumes credits.
### Tips for Best Results
- Analyze your website first to get a solid baseline, then fine-tune the dropdowns manually.
- Name your colors descriptively (e.g., "Deep Ocean Blue" not just "Blue") - color names are used in image prompts and descriptive names produce better results.
- If your brand uses both photography and illustrations, select "Mixed" as the Image Type so both style dropdowns appear.
- Review the generated Visual Prompt Directive to make sure it reads naturally. The auto-generated text is a starting point - you can refine it.
---
## Part 7: Knowledge Base
Click the **Knowledge Base** tab to upload documents that Floyi's AI agents use as context when generating content briefs and drafts. This is your brand's private reference library.
### What Knowledge Base Does
Knowledge Base allows you to upload proprietary documents, import web pages, or paste text that becomes searchable context for AI content generation. When Floyi generates a brief or draft, it searches your Knowledge Base for relevant passages and includes them as context so the output reflects your brand's expertise, data, and terminology.
This means your generated content can reference your own research, case studies, product documentation, style guides, and other materials that are not publicly available on the web.
### How Knowledge Base Works Behind the Scenes
1. You upload a document (or import a URL, or paste text).
2. Floyi extracts the text, splits it into chunks, and generates vector embeddings.
3. When a brief or draft is generated, Floyi searches your Knowledge Base for the most relevant chunks using semantic similarity.
4. Matching chunks are included as context for the AI agents, grounded in your actual materials.
You do not need to configure any of this. It happens automatically once documents are in the Knowledge Base.
### Adding Documents
Click **Add Knowledge** to open the upload modal. Three input methods are available:
**Method A: Upload Files**
1. Click the **Upload File** tab.
2. Drag and drop files, or click to browse.
3. Supported formats: PDF, DOCX, TXT, MD, HTML.
4. Maximum file size: 10MB per file. You can upload multiple files at once (up to 10 per batch).
5. Click **Upload**.
6. Each file is processed independently. If some files succeed and others fail, you will see per-file status messages.
7. The modal stays open so you can upload additional files. Click **Done** when finished.
**Method B: Import URL**
1. Click the **Import URL** tab.
2. Enter the full URL of the web page you want to import.
3. Optionally, enter a custom title. If left blank, the page title is used.
4. Click **Import**.
5. Floyi fetches the page content, extracts the text, and processes it.
**Method C: Paste Text**
1. Click the **Paste Text** tab.
2. Enter a title for the document.
3. Paste your text content into the text area.
4. Click **Save**.
**Assigning Categories During Upload:**
The upload modal includes a category selector so you can assign categories at upload time instead of categorizing documents later.
1. Before clicking Upload/Import/Save, click the **Categories** dropdown in the modal.
2. Select one or more categories from the list.
3. Selected categories are applied to all documents in the current upload batch.
This works across all three upload methods (file, URL, paste). You can still change categories later using the bulk categorize feature in the document list.
### Replacing Existing Documents
If you import a URL or upload a file that already exists in your Knowledge Base, Floyi will detect the duplicate and ask what you want to do.
**What happens:**
1. You submit a URL or file that matches an existing document (by URL for imports, by filename for uploads).
2. The modal shows a warning with the existing document's title, word count, and import date.
3. You choose one of two options:
- **Replace with Fresh Content**: Deletes the old document and its embeddings, then imports the new version. Use this when the source content has been updated.
- **Back**: Returns to the upload form without making changes. Use this if you did not intend to re-import.
Replacing a document does not count as an additional document against your plan limit since the old one is removed first.
Paste text does not have duplicate detection because titles are user-defined and may legitimately repeat.
### Document Statuses
After uploading, each document shows one of three statuses:
| Status | Meaning |
| -------------- | -------------------------------------------------------------------------------------------------------------- |
| **Processing** | The document is being chunked and embedded. This typically takes 10-30 seconds. |
| **Ready** | The document has been processed and is available for AI retrieval. |
| **Failed** | Processing encountered an error. The document will not be used for retrieval. You can delete it and try again. |
The document list auto-refreshes while any documents are processing.
### Managing Documents
**Refreshing the List:**
Click the refresh icon next to **Add Knowledge** to manually reload the document list and usage stats.
**Selecting Documents:**
- Click the checkbox next to individual documents to select them.
- Click the checkbox in the table header to select or deselect all documents.
**Deleting Documents:**
1. Select the documents you want to remove.
2. Click **Delete Selected**.
3. Confirm the deletion in the dialog.
Deleting a document permanently removes it along with all its associated chunks and embeddings. This action cannot be undone.
### Organizing Documents with Categories
Categories let you group related documents so you can filter and browse your Knowledge Base more easily. Categories also power the **Knowledge Base Scope** filter in brief generation (see [Content Briefs](/docs/tools/content-briefs/) for details).
**Creating Categories:**
1. Click **Manage Categories** above the document list.
2. Click **Add Category**.
3. Enter a category name (e.g., "Case Studies", "Product Docs", "Industry Research").
4. Choose a color to visually distinguish categories in the list.
5. Click **Save**.
**Assigning Categories to Documents:**
- Select one or more documents using the checkboxes.
- Click the **Categorize** dropdown that appears in the toolbar.
- Check or uncheck the categories you want to assign.
- Changes are saved immediately.
A single document can belong to multiple categories.
**Filtering by Category:**
Use the category filter bar above the document list to show only documents in specific categories. You can also filter by source type (PDF, URL, Paste, etc.) alongside category filters.
**Reordering and Editing Categories:**
- Open **Manage Categories** to rename, recolor, reorder (drag and drop), or delete categories.
- Deleting a category removes the label from documents but does not delete the documents themselves.
### Document Limits by Plan
Knowledge Base is available on paid plans only. Free plan users see a message indicating that an upgrade is required.
| Plan | Document Limit |
| ------------ | --------------- |
| Creator Plan | 100 documents |
| Pro Plan | 500 documents |
| Scale Plan | 2,000 documents |
The usage bar at the top of the Knowledge Base tab shows your current document count against your plan limit.
### What Types of Content Work Best
Upload materials that contain expertise, data, or context you want reflected in your generated content:
- Product documentation and feature guides
- Case studies and customer success stories
- White papers, research reports, and industry analysis
- Internal style guides and writing standards
- FAQ documents and knowledge articles
- Existing blog posts or articles that represent your brand's expertise
- Competitive analysis and market research
Avoid uploading content that is purely administrative (contracts, invoices) or that contains sensitive information you would not want referenced in published content.
---
## Part 8: How Brand Foundation Connects to Other Tools
Once you have a solid Brand Foundation, you can:
- Preselect it when generating **Audience Insights personas** so personas match your positioning
- Use it as context for **Topical Research** so topics fit your product, buyer stage, and language
- Feed it into **Content Briefs** so goals, tone, and differentiators carry into every outline
- Apply it automatically in the **Content Creation** workspace so Writer and Editor agents use the same voice
- Keep **Topical Authority** analysis grounded in your real positioning, not generic category language
- Let **Brand Voice** profiles ensure generated content matches your writing style automatically
- Let **Visual Style** guides ensure AI-generated images match your brand's visual identity - colors, mood, and image style applied automatically
- Let **Knowledge Base** documents provide brand-specific context so briefs and drafts reference your own expertise, data, and terminology
If you are new to Floyi, set up Brand Foundation before you run large topic or brief workflows. It is easier to fix strategy once than to correct dozens of misaligned outputs later.
---
## Part 9: Continuing to the Next Step
After completing your Brand Foundation:
1. Review your Brand Identity and Content Guide.
2. Set up a Brand Voice profile for consistent writing style.
3. Set up a Visual Style guide for consistent image generation.
4. Upload key documents to your Knowledge Base for richer, more informed content.
5. Click **Next: Create Buyer Personas** to continue to Audience Insights.
6. Build your buyer personas based on your brand foundation.
---
## Credit Usage and AI Models
Brand Foundation uses credits for generation and regeneration.
- Each action shows a clear credit estimate before you start.
- URL-based generation may cost more than input-based generation because of additional analysis.
- Editing existing fields is always free.
- Voice analysis consumes credits. Editing the AI Prompt Directive after analysis is free.
- Visual style website analysis consumes credits. Manual configuration and editing the Visual Prompt Directive are free.
- Knowledge Base document uploads and processing do not consume credits. The embedding process is handled automatically.
For most teams:
- Use a stronger model for your primary Brand Foundation, since this profile will influence many downstream workflows.
- Use smaller or faster models for quick experiments or alternative positioning drafts if you are testing options.
If you hit an insufficient credits state, Floyi will show a modal instead of starting the job.
---
## Recommended Starting Point
For most users:
1. Create one Brand Foundation per brand or domain you care about.
2. Use the URL-based method if your site copy roughly matches your current strategy.
3. Use the input-based method if your site is early, messy, or in the middle of a reposition.
4. Edit the output until it feels accurate enough for internal use.
5. Only regenerate when your strategy shifts or the first version is far off.
6. Upload 3-5 writing samples to the **Brand Voice** tab to capture your style.
7. Analyze your website in the **Visual Style** tab or configure your image style manually.
8. Add your most important reference documents to the **Knowledge Base** tab.
From there, move on to Audience Insights and Topical Research with your Brand Foundation selected as context.
---
## Quick Reference: Content Guide Limits
| Section | Max Sent to AI | Notes |
| ------------------- | -------------- | ---------------------------------------- |
| Terminology Rules | 10 rules | Drag to reorder priority |
| Compliance Rules | 3 rule sets | Each set can have multiple items |
| Competitor Policies | 10 policies | General standards + specific competitors |
| Brand Messaging | 15 rules | Create small, distinct rules |
| Approved Snippets | N/A | Manual insertion only |
## Quick Reference: Knowledge Base Limits
| Plan | Document Limit | Supported Formats |
| ------- | -------------------- | ------------------------------------ |
| Free | 0 (upgrade required) | - |
| Creator | 100 | PDF, DOCX, TXT, MD, HTML, URL, Paste |
| Pro | 500 | PDF, DOCX, TXT, MD, HTML, URL, Paste |
| Scale | 2,000 | PDF, DOCX, TXT, MD, HTML, URL, Paste |
Maximum file size per upload: 10MB. Maximum files per batch: 10.
---
## Briefs & Drafts
Source: https://floyi.com/docs/tools/briefs-and-drafts/
The Briefs & Drafts tool creates comprehensive content briefs by analyzing top-ranking competitors and aligning recommendations with your brand strategy, personas, and target keywords.
Briefs & Drafts is the standalone, query-anchored path among Floyi's [research and content tools](/docs/tools/). If you're working from a topical map, use the [map-connected brief workflow](/docs/tools/content-briefs/) instead. To dig into how a SERP is composed before briefing, run a [SERP-level analysis](/docs/tools/serp-insights/) on the query first.
## What You'll Learn
- How to generate a content brief
- Understanding brief components
- Customizing with personas and keywords
- Managing brief versions
- Creating drafts from briefs
- Exporting and sharing briefs
---
## Getting Started
### Prerequisites
Before generating a brief, you should have:
- At least one **Brand** configured in Floyi
- Optionally, **Buyer Personas** defined for your brand
### Creating a New Brief
Navigate to **Briefs & Drafts** and follow the guided workflow:
#### Step 1: Define Your Topic
1. **Select your brand** from the dropdown
2. **Enter your target keyword** or topic (e.g., "content marketing strategy")
3. Click **Fetch SERP** to retrieve search results
#### Step 2: Select Competitors
After fetching SERP data:
1. Review the organic search results displayed
2. **Select up to 7 competitors** to analyze
3. Optionally add manual competitor URLs if needed
:::tip
Select competitors that represent the content style and depth you want to match or exceed.
:::
#### Step 3: Choose Personas (Optional)
If you have buyer personas defined:
1. Select up to **2 personas** to target
2. The brief will include persona-specific recommendations
#### Step 4: Add Keywords (Optional)
Add additional keywords to include:
1. Type keywords and press Enter to add
2. Or paste bulk keywords (one per line)
3. These will be incorporated into content recommendations
#### Step 5: Add Internal Links (Optional)
Suggest internal links to include:
1. Add URLs from your site to link to
2. Optionally specify anchor text
3. These will appear in your brief's linking recommendations
#### Step 6: Add Custom Instructions (Optional)
Add strategic instructions to guide the Brief Agents:
1. Expand the **Custom Instructions** field
2. Type your instructions (up to 1,000 characters)
3. Examples:
- "Write this as a listicle, not a comprehensive guide"
- "Focus on beginner audiences, avoid technical jargon"
- "Emphasize our product's speed advantage over competitors"
Custom instructions override the AI's default content type and structure decisions. If SERP competitors are split between formats, your instructions tell the Agents which direction to take.
Instructions are saved with the brief and preserved when you regenerate.
#### Step 7: Set Knowledge Base Scope (Optional)
If you have documents in your Knowledge Base, you can control which ones are used as context for this brief:
1. Expand the **Knowledge Base Scope** section
2. Choose a mode:
- **All Documents** (default) - searches every Knowledge Base document for relevant context
- **By Category** - restrict to documents in selected categories
- **By Document** - search and select specific documents by title
- **None** - skip Knowledge Base entirely for this brief
3. When using "By Document", selected documents appear as removable chips above the search results
This is useful when your brand has many Knowledge Base documents and you want the brief to reference only specific materials (e.g., only case studies or only product documentation).
---
## Understanding SERP Features
When you fetch SERP data, you'll see rich information about the search landscape:
### Available SERP Data
| Feature | Description |
| --------------------- | ------------------------------------------------------ |
| **Organic Results** | Top-ranking pages with titles, snippets, and positions |
| **AI Overview** | Google's AI-generated summary (if present) |
| **Gemini** | Google Gemini AI search analysis (optional, toggle on) |
| **People Also Ask** | Common questions related to your topic |
| **Related Searches** | Additional search queries to consider |
| **Knowledge Graph** | Entity information if applicable |
| **Featured Snippets** | Answer box content |
| **Videos** | Video results if present |
### Top Domains Analysis
See which domains appear most frequently in search results, helping you understand the competitive landscape.
---
## Brief Generation
### Starting Generation
Once configured, click **Generate Brief**. The system will:
1. Analyze selected competitor content
2. Extract structural patterns
3. Identify key topics and entities
4. Generate comprehensive recommendations
### Generation Time
Brief generation typically takes 1-3 minutes depending on:
- Number of competitors selected
- Content length of competitor pages
- Current system load
You can navigate away-generation continues in the background.
---
## Brief Components
A completed brief includes:
### Strategic Overview
| Section | Contents |
| -------------------------- | ---------------------------- |
| **Target Topic** | Your primary keyword/topic |
| **Search Intent** | Identified user intent type |
| **Recommended Word Count** | Based on competitor analysis |
| **Difficulty Assessment** | Content complexity rating |
### Content Structure
- **Recommended Outline** - Suggested H2/H3 structure
- **Key Points to Cover** - Must-include topics
- **Questions to Answer** - From People Also Ask
- **Entities to Mention** - Important terms and concepts
### Optimization Guidance
- **Primary Keywords** - Main terms to target
- **Secondary Keywords** - Supporting terms
- **Internal Linking Suggestions** - Pages to link to
- **External Sources** - Authoritative references to cite
### Persona Insights
If personas were selected:
- Pain points to address
- Goals to align with
- Tone and language recommendations
---
## Managing Briefs
### Brief Versions
Each new generation creates a version:
- **v1.0** - First generated brief
- **v1.1, v1.2...** - Edited/curated versions
- **v2.0** - Regenerated brief
Switch between versions using the version dropdown.
### Editing Briefs
Click **Edit Brief** to:
- Modify the outline
- Add or remove sections
- Update recommendations
- Save as a new version
### Past Briefs
Access previous briefs in the **Past** tab:
- Search by keyword or brand
- Load any brief to view or continue editing
- Delete briefs you no longer need
---
## Creating Drafts
Transform your brief into a full article draft:
### From Brief to Draft
1. Open a completed brief
2. Click **Create Draft**
3. The AI will generate a full article following your brief's structure
### Draft Features
- Full article content matching your brief
- Proper heading hierarchy
- Incorporated keywords and entities
- Internal links as specified
:::note
Drafts are generated separately and can be accessed in the Content Creation workspace.
:::
---
## Exporting Your Brief
### Export Formats
Click **Export** to download your brief:
| Format | Best For |
| --------------------- | ---------------------- |
| **Markdown (.md)** | Writers, documentation |
| **Copy to Clipboard** | Quick sharing |
### What's Included
Exports contain:
- Full outline with all sections
- Keyword recommendations
- Word count targets
- Linking suggestions
- Persona insights (if applicable)
---
## Loading from SERP Insights
If you've previously run SERP analysis:
1. Click **Load from SERP Insights**
2. Search for your saved queries
3. Select one to auto-populate competitors and SERP data
This saves time by reusing existing research.
---
## Frequently Asked Questions
### How many competitors should I select?
Select 3-7 competitors for targeted content and best results. More competitors provide richer analysis but increase processing time.
### Can I generate briefs for any topic?
Yes! Enter any keyword or topic. The system will fetch fresh SERP data and analyze current rankings.
### Why don't I see AI Overview or Gemini data?
AI Overviews only appear for certain queries where Google includes them. Not all searches have AI-generated summaries. Gemini analysis is an optional toggle during brief generation and costs additional credits per engine.
### Can I edit the generated brief?
Absolutely. Use the Edit Brief feature to customize the outline, add sections, or refine recommendations before creating content.
### How are word count recommendations calculated?
Word count is based on the average length of top-ranking competitor content, adjusted for content type and intent.
### Do I need to select personas?
Personas are optional but recommended. They help tailor content recommendations to your target audience's needs and language.
---
## Content Briefs
Source: https://floyi.com/docs/tools/content-briefs/
Content Briefs turn topics or queries into structured outlines with clear goals, headings, entities and link plans.
Floyi supports multiple paths to briefs:
1. **Topical Authority strategy flow** - briefs generated from the Planner for topics in your Topical Map or Site Architecture
2. **Standalone briefs** - research heavy, query anchored briefs that are not tied to the map
Within the Topical Authority flow, briefs behave differently for **Local Pages** (from Site Architecture) versus **Resource Pages** (from Topical Map).
This page explains all paths and when to use each. For an overview of how briefs fit into Floyi's content production system, see [Briefs and Drafts](/solutions/briefs-and-drafts/).
---
## Two briefing modes at a glance
### 1. Topical Authority strategy flow
Briefs created from the **Topical Authority Planner**:
- Start from a topic in your validated map
- Use existing SERP and AI data from Scorecard and Planner
- Sit next to internal links, anchors and publish state
- Are ideal when your plan is already defined and you want to ship inside it
These briefs are part of the integrated "Topical Authority briefs and drafts" workflow available on all paid plans.
### 2. Standalone briefs
Briefs created in the **Briefs & Drafts** page:
- Start from a search query, not a map topic
- Run their own SERP scraping and competitor analysis
- Include an outline review stage before full generation
- Are ideal when you are testing new query spaces or creating one off content
Standalone briefs and their connected drafts are available to Pro and Scale plans.
---
## Where to find Content Briefs
- **Topical Authority integrated briefs**
- Go to **Topical Authority → Planner**
- Open a page level topic in the hierarchy and use the brief controls in the topic drawer
- **Standalone briefs**
- Go to the **Content Briefs** tool in the main navigation (name may appear as "Briefs & Drafts")
- This opens the standalone briefing workspace
Both paths share a similar brief output format so writers can switch between them easily.
---
## Topical Authority strategy flow
### When to use this mode
Use Planner based briefs when:
- You already have a vetted Topical Map
- You are working inside the authority plan for a brand
- You want internal links, anchors and publish state tied to every brief
- You want predictable costs based on existing SERP and AI data
This is your default for ongoing authority work.
### Prerequisites
Before using this flow:
- A [Topical Map](https://floyi.com/docs/tools/topical-map/) must be validated and promoted into Topical Authority
- Topical Authority Scorecard must have at least one recent run for that map and domain
- Planner must show topics with URL slugs and metrics
### Steps: generate a Planner based brief
1. Open **Topical Authority → Planner**.
2. Use filters to find topics to work on, for example:
- High importance and not published
- Ranked on page 2 and missing from AI search
3. Click a page level topic to open the details drawer.
4. Review existing content info:
- Suggested title
- Content type
- Buyer journey stage
5. Click **Generate brief**.
6. Confirm:
- Brand Foundation
- Persona
- Any internal links and anchors you want locked in
7. Review the credit estimate and start generation.
Floyi uses:
- The map topic and URL slug
- SERP and AI context already stored for that topic
- Your brand and persona inputs
to generate the brief.
### What a Planner based brief includes
Exact sections can vary, but a typical brief contains:
- Topic summary and goals
- Title and meta description
- Primary and secondary target queries
- Audience and persona notes
- Page role within the map (pillar, cluster, supporting piece)
- Outline with H2 and H3 structure
- Entities and concepts to cover
- Internal link targets and anchor suggestions
- External link notes if available
- Recommended content type and length guidance
- Competitor Content Gaps with Information Gain and AI citation scores
The brief is linked back to the topic in Planner. The node's "Has brief" status updates automatically so filters stay accurate.
### Competitor Content Gaps
Briefs include a scored list of competitor content gaps - topics and angles that existing ranking pages do not cover well. Each gap is scored on two dimensions:
| Score | What It Measures |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **IG (Information Gain)** | A novelty score from 0 to 1. Higher scores mean fewer competitors cover this topic, so it represents a bigger opportunity to stand out. |
| **AI Cite** | The estimated likelihood that filling this gap earns citations in AI search. A **high** rating means AI search mentions the topic but no competitor provides a definitive source. Ratings are **low**, **medium**, or **high**. |
Use these scores to prioritize which gaps are worth covering in your content. Gaps with high IG and high AI Cite represent the strongest opportunities to differentiate and earn visibility in both traditional and AI search.
### Information Gain research
Beyond scoring gaps, every brief runs a dedicated information gain research pass. Floyi inventories the facts the current top results already cover, then identifies net-new angles your page can add that none of them say.
- **Grounded in your brand**: net-new angles come from your Brand Foundation (your USP, market position, and values) and your Knowledge Base - Floyi searches your uploaded documents for supporting data, so the additions are things only you can credibly say
- **No invented facts**: promising angles that nothing can back up are never stated as fact. Instead they appear as **Blocked Opportunities** on the brief, so you can decide whether to supply the proof (see below)
- **Carried into the draft**: the draft writer weaves the grounded angles into your content, and the editor's Quality tab verifies which ones actually made it in through its Information Gain dimension
This applies to both Planner based and standalone briefs. It is how Floyi ensures each page adds something original instead of repeating what already ranks, which matters for both traditional rankings and AI search citations.
### Blocked Opportunities
Sometimes Floyi finds a strong angle no competitor covers, but nothing in your Brand Foundation or Knowledge Base can back it up - for example, before-and-after results from your own client work. Floyi will not invent numbers, so instead of stating the claim it lists the angle under **Blocked Opportunities** on the brief, marked _needs your data_.
Each blocked opportunity has an **Add data** button. Enter the facts, statistics, or first-hand results you want the article to use, choose which section they belong in, and save. Floyi then:
- Writes your data into that section of the brief as a required point, exactly as you entered it - your numbers are never altered
- Promotes the angle to a grounded net-new target, so the next draft states it and the Quality tab tracks whether it landed
This turns a gap only you can fill into publishable, differentiated content, and it is the fastest way to add first-hand expertise - which both Google and AI search reward. Blocked Opportunities appear anywhere you view a brief: the brief results view, the Planner's brief view, and the brief panel in the content editor. If your Knowledge Base already covers the angle, Floyi grounds it automatically and no blocked opportunity appears.
### Alternate Titles
For Resource Page briefs (from your Topical Map) and standalone briefs, Floyi generates several title options instead of a single title, then ranks them and puts the strongest one forward as the brief's title. Each option is written with a different strategy - one that matches your exact query, one phrased the way the pages already ranking say it, one that leads with a reader benefit, one that mirrors the dominant format on the SERP, and a contrarian angle - so you can compare genuinely different directions.
- **Phrased for how pages actually rank**: title generation studies how the top results and AI answers name the topic, so it uses natural wording that matches the search instead of forcing your keyword into an awkward line
- **Pick any option in one click**: open the brief in edit mode to see every candidate with a one-line reason, and select a different one as the brief's title
- **No repeated formulas**: Floyi checks the titles already used on your brand's other pages and avoids reusing the same structure, keeping titles varied across your site
Site Architecture pages - such as Local service and location pages - use a single conversion-focused title instead of alternate options. The title you select becomes the draft's title when you create content from the brief; you can still change it later in the Content Editor without affecting the brief.
### Local Pages vs Resource Pages
Planner briefs work differently depending on where the page originated:
#### Resource Pages (from Topical Map)
Resource Pages use the **full 6-agent research workflow**:
- Deep SERP analysis and competitor research
- Comprehensive outline with entities and concepts
- Full brief with internal/external link plans
- Leads to drafts with optional Specialist Agents (Fact Check, Research, Intro & Key Takeaways)
This is ideal for educational content, blog posts, and thought leadership pieces.
#### Local Pages (from Site Architecture)
Local Pages use a **streamlined local workflow**:
- Focused on service/location page best practices
- Conversion-optimized structure
- Leads to drafts with a **Conversion Coach** agent instead of research specialists
- Optimized for converting visitors into leads or customers
Local Page briefs are tailored for:
| Page Type | Brief Focus |
| -------------------- | ------------------------------------------- |
| **Service** | Service benefits, process, trust signals |
| **Location** | Local relevance, service areas, local proof |
| **Service+Location** | Combined service value + local targeting |
:::tip
Local Pages skip research-heavy agents because service/location pages need conversion copy, not deep educational content.
:::
### Bulk briefs (Pro / Scale)
On Pro and Scale plans you can generate multiple Planner based briefs in one operation.
Typical pattern:
1. Filter in Planner for a set of topics.
2. Select several nodes.
3. Use **Bulk brief** controls.
4. Confirm shared options (brand, persona, model).
Floyi queues separate jobs for each topic and updates Planner as they complete.
---
## Standalone briefs in Briefs & Drafts
### When to use Briefs & Drafts
Use standalone briefs when:
- You are investigating a new query or topic that is not in your map yet
- You want deeper SERP scraping and competitor analysis
- You need rich external link ideas and a research heavy baseline
- You want an outline review step before committing credits for a full brief
Standalone briefs are useful for:
- New categories and experiments
- Pages that do not belong in the main map, such as campaign pages
- Detailed sales assets and lead magnets
### Inputs: setting up a standalone brief
In the Standalone Content Briefs page you have three main sections.
1. **Input**
- **Search query**
- The main query you want to target, plus country, language and optional location
- **Brand selector**
- Pick the brand so the brief matches your positioning and defaults
- **User links**
- Add internal or external URLs with short descriptions and preferred anchors
- **Options**
- Set brief options such as content type and strategy knobs
- **User keywords**
- Add entities, phrases or related queries that matter to you
2. **Analysis and generation**
- Floyi fetches SERPs and scrapes selected competitor pages
- You see status for the SERP and analysis tasks
- Once enough data is collected, an outline is drafted
- You review and approve or adjust the outline before full brief generation
3. **Results and history**
- The final brief is displayed with sections for:
- Goals and angle
- Outline
- Entities and key topics
- Competitor Content Gaps with IG and AI Cite scores
- Link plan and media notes
- Past briefs are stored with tabs for current and previous runs
- You can export the brief as TXT for writers or partners
### Outline review
The outline review step is a key difference from Planner based briefs.
You can:
- Accept the suggested outline
- Edit headings and order
- Request a new outline if something is off
Only after this step do you commit full generation credits.
---
## Credit usage
Both modes use credits, but in different ways.
- **Planner based briefs**
- Use Topical Authority data you already pulled for the map where possible
- Still charge credits for the analysis and generation work needed per topic
- **Standalone briefs**
- Always fetch their own SERPs and scrape competitors for the specific query
- Use more analysis stages, so they usually cost more credits per brief
Floyi shows a clear credit estimate before you start any run. Editing an existing brief or reviewing history is free.
---
## Working with briefs in the Content Creation workspace
Content Briefs connect directly into the Content Creation workspace.
From either mode you can:
1. Open the brief.
2. Click **Create draft** or **Open in Content Creation**.
3. Configure draft settings (model, tone, intent mode, length).
4. Generate a first draft that follows the brief.
### For Planner based briefs (Resource Pages)
- The draft is linked back to the map topic and Planner node
- Status badges in Planner reflect draft progress and editorial state
- You can optionally enable Specialist Agents:
- **Fact Check** - verifies claims against web sources
- **Web Research** - enriches content with additional sources
- **Intro & Key Takeaways** - polishes opening and summary sections
### For Planner based briefs (Local Pages)
- The draft is linked back to the Site Architecture node
- Uses a **Conversion Coach** agent instead of research specialists
- Focuses on conversion optimization: CTAs, trust signals, local proof
- Streamlined workflow with lower credit cost per draft
### For standalone briefs
- Drafts are stored in the same "Briefs & Drafts" area
- They do not include internal link suggestions from the Planner, since they are not anchored to the map
- Full Specialist Agent options available
For details on drafting, editing, versions and statuses, see [Content Creation](https://floyi.com/docs/tools/content-creation/).
---
## Content Creation
Source: https://floyi.com/docs/tools/content-creation/
Content Creation is the execution layer in Floyi's closed loop.
It takes you from **map to brief to draft** in the same system so you do not lose context in a Franken stack of disconnected tools.
Every draft can be powered by:
- Your Brand Foundation
- Your Audience personas
- The topic's exact position in your Topical Map or Site Architecture
- The brief you approved in Floyi
Floyi uses different content workflows depending on page type:
- **Resource Pages** (from Topical Map) use full research agents with optional specialists
- **Local Pages** (from Site Architecture) use a streamlined workflow with Conversion Coach
You get drafts that reflect strategy, not just a one off prompt.
---
## Three paths into Content Creation
Floyi supports three drafting flows that share the same editor but use different AI workflows.
### 1. Resource Pages (Topical Authority strategy flow)
Drafts for **Resource Pages** created from **Topical Authority Planner** briefs:
- Are tied to a specific topic and URL in your Topical Map
- Use existing SERP and AI data (AI Overviews, AI Mode, Gemini, ChatGPT) from Topical Authority
- Respect internal link and anchor plans from the Planner
- Update coverage and status back in the Planner
- Use the **full 6-agent research workflow** with optional Specialist Agents
This is the default way to create educational content, blog posts, and thought leadership for your main authority plan.
### 2. Local Pages (Site Architecture flow)
Drafts for **Local Pages** created from **Site Architecture** nodes in Planner:
- Are tied to a service, location, or service+location page in your Site Architecture
- Use a **streamlined local workflow** with Conversion Coach
- Focus on conversion optimization rather than deep research
- Do not include Fact Check, Research, or Intro & Key Takeaways agents
- Update coverage and status back in the Planner
This is the recommended way to create service pages, location pages, and combined service+location pages.
### 3. Standalone briefs and drafts
Drafts created from the **Content Briefs / Briefs and Drafts** tool:
- Start from a search query instead of a map topic
- Run their own SERP and competitor analysis
- Live in the standalone Briefs and Drafts workspace
- Do not affect coverage in your Topical Map
- Support full Specialist Agent options
Use this flow for experiments, campaigns and one off pieces that sit outside the map.
Standalone briefs and drafts are available on Pro and Scale plans.
---
## Where to start a draft
### From Planner (Topical Authority flow)
1. Go to **Topical Authority → Planner**.
2. Filter for a page level topic you want to work on.
3. Open the topic drawer.
4. If there is no brief yet, click **Generate brief**, review and approve it.
5. Click **Create draft** or **Open in Content Creation**.
This creates a draft that is tied to that topic and URL.
### From standalone briefs
1. Go to **Content Briefs / Briefs and Drafts** in the navigation.
2. Open a standalone brief.
3. Click **Create draft**.
This creates a draft that follows the standalone brief but is not attached to the map.
---
## Strategic Intent: Guide, Architect, Advisor
Content Creation uses the Strategic Intent recommended in the brief.
Floyi's Brief Agents suggest one of three missions based on search intent and gaps:
- **Teach (The Guide)**
Helpful educational content for earlier stage readers.
- **Define (The Authority)**
A definitive, semantically rich resource that search engines and AI systems can rely on.
- **Convince (The Advisor)**
A persuasive, evidence based piece that moves the reader toward a decision.
You can keep the recommendation or change it before generating the draft.
The chosen Intent shapes tone, depth and structure.
---
## Generating the first draft
When you are ready to move from plan to draft:
1. Open the article in **Content Creation**.
2. Confirm the linked brief in the sidebar.
3. Open the AI draft panel.
4. Check or adjust:
- Strategic Intent
- Brand Foundation
- Persona
- Target length or range
- Model and quality settings
5. Review the credit estimate.
6. Click **Generate draft**.
Floyi then executes the brief:
- It follows the approved outline.
- It places entities and topics where they belong.
- It applies the internal link and anchor plan.
- It respects brand and audience settings.
- It works in the net-new information angles the brief research identified, so your draft adds something the current top results do not already say.
- If the brief includes **custom instructions**, those carry through to draft generation and shape the AI's content type, structure, and focus.
You do not start from a blank page. You start from a strategic blueprint that you already approved.
Because the draft is generated inside Floyi, it enforces your Content Guide rules, brand voice and lexicon, persona targeting, and the optimizer's competitor-derived coverage terms - enforcement a draft written from scratch in a blank AI chat can't carry, because it doesn't have your brand's context. That is why a Floyi draft starts on-brand and coverage-complete instead of needing a rebuild.
The draft's title starts as the one you selected on the brief. If the brief generated alternate title options, you can switch to a different one; you can also edit the title and meta description directly in the Content Editor. Changes in the editor apply to the article only and do not affect the brief's own title.
---
## Brief and draft side by side
To make review easier, Content Creation can show:
- The full brief on one side
- The live draft on the other side
Use this view to check that:
- Each section in the brief has a matching section in the draft
- Every planned internal link appears in the right place
- Entities, examples and talking points are covered
You can scroll both panels together and mark items off as you review.
---
## Specialist Agents for Resource Pages
Resource Pages (from Topical Map) can use optional Specialist Agents to enhance drafts:
### Fact Checker
- Highlights claims and checks them against web sources
- Flags items that need revision or a supporting citation
- Best for content making specific claims or statistics
### Web Research
- Pulls sources and extra context for specific sections
- Helps you deepen examples and explanations without leaving Floyi
- Available in **Basic** or **Advanced** mode (advanced uses more credits)
### Intro & Key Takeaways
- Polishes the opening section and summary
- Ensures readers immediately understand the value
- Adds scannable takeaways for busy readers
All Specialist Agents operate inside the same editor so you do not have to copy text into separate tools.
:::note
Specialist Agents are only available for Resource Pages and standalone drafts. Local Pages use the Conversion Coach workflow instead.
:::
---
## Conversion Coach for Local Pages
Local Pages (from Site Architecture) use a different AI workflow optimized for converting visitors into leads or customers.
### What Conversion Coach does
Instead of research-heavy specialists, Local Pages use a **Conversion Coach** that:
- Optimizes copy for conversions, not just information
- Adds trust signals and social proof placeholders
- Structures content around user intent and action
- Includes clear calls-to-action throughout
- Follows local SEO best practices
### Why Local Pages skip research agents
Service and location pages have different goals than educational content:
| Resource Pages | Local Pages |
| ------------------------------------ | ------------------------------ |
| Educate and inform | Convert and capture leads |
| Deep research and citations | Trust signals and proof points |
| Long-form comprehensive content | Focused, action-oriented copy |
| Fact Checker, Research, Intro agents | Conversion Coach agent |
### Page types and Conversion Coach focus
| Page Type | Conversion Coach Focus |
| -------------------- | -------------------------------------------------- |
| **Service** | Benefits, process, trust signals, service CTA |
| **Location** | Local relevance, service areas, local testimonials |
| **Service+Location** | Combined value prop + local targeting + CTA |
Local Pages cost less credits per draft because they use a streamlined workflow without the research overhead.
### Agency Pages (Service Agency Architecture)
Agency pages created from a **Service Agency** site architecture also use a similar streamlined workflow with Conversion Coach. These pages follow the same conversion-focused approach as Local Pages, optimizing for lead generation and trust signals rather than deep research.
Conversion Coach runs automatically during site-page draft generation and is included in the draft price. It is not exposed as a separate specialist toggle or paid **Run Specialists** action. In the editor, the Conversion Coach panel reports whether optimization was recorded for the current draft; older drafts that predate automatic routing may show that no run was recorded.
---
## The editor
The Content Creation editor is a rich text workspace designed for long form articles.
Core capabilities include:
- Headings, paragraphs, lists and tables
- Links and basic media support
- Keyboard shortcuts and inline formatting
- Autosave with clear saving and saved states
- **AI image generation** - analyze your draft, generate images, and insert them inline
You can let AI draft the full article, generate sections, or write manually and only use AI for assistance.
### AI Image Generation
The editor includes built-in AI image generation. Click the **AI Images** button in the toolbar or switch to the **Images** tab in the right sidebar to:
1. **Analyze your draft** for optimal image placements
2. **Generate images** using Flux 2 Max, Seedream 5, or Nano Banana 2
3. **Insert images** directly into your article at the right positions
Choose from multiple aspect ratios (16:9, 3:2, 4:3, and more) and models at different price points. Generated images are stored permanently and linked to your article.
If your [Brand Foundation](https://floyi.com/docs/tools/brand-foundation/) includes a visual style analysis, it guides image generation to match your brand aesthetic.
For the full guide, see [AI Image Generation](https://floyi.com/docs/tools/content-editor-optimizer/#ai-image-generation) in the Content Editor docs.
---
## Page Quality Scorecard
Every generated draft is scored automatically when generation finishes. An AI judge reads the full draft and scores it using the quality signals Google's patents describe:
- **Overall score** (0-100) on a four-bucket scale: Excellent, Good, Average, Poor
- **Five dimensions**: relevance, content quality, information gain (also known as originality), next step or call to action, and trust and authorship
- **Clickable evidence**: every dimension shows reasoning with quotes from your draft, and clicking a quote jumps to that section in the editor
- **Information gain verified**: the scorecard checks which net-new angles from your brief research actually made it into the draft
Open the **Quality** tab in the editor's right panel to see the scorecard. After editing, click **Re-analyze** to score the updated draft (10 credits per run). The baseline scorecard on a new draft is included with generation at no extra cost.
For the full guide, see [Page Quality Scorecard](https://floyi.com/docs/tools/content-editor-optimizer/#page-quality-scorecard) in the Content Editor docs.
---
## Exporting and publishing content
Floyi supports multiple ways to get finished drafts out of the workspace.
### Publishing to WordPress
If you have connected a WordPress site, you can publish drafts directly from the Content Creation workspace without exporting. Categories, tags, author, and SEO metadata are set in the publish modal. See [WordPress Publishing](https://floyi.com/docs/tools/wordpress-publishing/) for the complete setup and publishing guide.
### Export formats
Click the **Download** icon in the editor header to export your draft:
| Format | Best for |
| --------------- | ------------------------------------------- |
| **DOCX** | Microsoft Word editing, client handoffs |
| **HTML** | CMS paste, email templates |
| **Markdown** | Developer workflows, static site generators |
| **TXT** | Plain text archives, simple sharing |
| **Google Docs** | Collaborative editing in Google Workspace |
### Clipboard copy
Click the **Copy** icon for quick clipboard actions:
- **Copy Markdown** - Paste into markdown-compatible editors
- **Copy HTML** - Paste into rich text fields or CMS editors
All exports and copies include the article title and meta description at the top.
---
## LocalBusiness JSON-LD for Local Pages
Local Pages (service, location, city, neighborhood) can include structured data to help search engines understand your business.
### What is LocalBusiness JSON-LD
JSON-LD (JavaScript Object Notation for Linked Data) is a structured data format that search engines use to understand page content. The LocalBusiness schema tells Google and other engines about your:
- Business name and legal entity
- Address and service areas
- Phone, email, and contact info
- Opening hours
- Social profiles and Google Business Profile
### Inserting JSON-LD in the editor
For Local Pages, the **Insert Snippet** dropdown includes a **LocalBusiness JSON-LD** option as the first item:
1. Click the **Insert Snippet** button in the toolbar.
2. Select **LocalBusiness JSON-LD**.
3. Floyi inserts the schema as a code block in your draft.
The schema is pre-populated from your Brand Foundation business information. You can edit it before publishing if needed.
### JSON-LD in exports
When you export or copy a Local Page draft, the LocalBusiness JSON-LD is automatically appended at the bottom of the document with instructions for embedding it in your page's `
` section.
This ensures your developer or CMS workflow has the structured data ready to implement.
:::note
JSON-LD insertion and export is only available for Local Pages (service, location, city, neighborhood). Resource Pages and standalone drafts do not include LocalBusiness schema because they typically cover topics rather than business locations.
:::
### Setting up business information
The JSON-LD schema pulls from your **Brand Foundation** settings. To ensure complete structured data:
1. Go to **Brand Foundation** in the navigation.
2. Fill in the **Business Information** section:
- Legal business name
- Address (street, city, state, postal code)
- Phone numbers
- Email
- Opening hours
- Business type and category
3. Add your **Google Business Profile URL** and social profiles.
The more complete your Brand Foundation, the richer your LocalBusiness schema.
---
## Machine states and editorial states
Floyi separates technical progress from human decisions so you know what is happening.
### Machine states
Examples of machine driven states:
- **Ready**
Draft exists, no AI run has started yet.
- **In progress**
AI is currently generating content.
- **Incomplete**
A generation run had issues and needs review or retry.
- **Draft done**
AI has finished and the draft is ready for editing.
You cannot set these directly. They reflect the lifecycle of AI tasks.
### Editorial states
Editorial states are controlled by your team, for example:
- **Not yet**
Draft has not been fully reviewed.
- **Needs editing**
Requires more work before it can be approved.
- **Approved**
Ready to publish in your CMS.
- **Published**
Live on your site.
Changing editorial states does not use credits.
Planner surfaces a single combined status per topic so you can scan progress at a glance.
---
## Version history
Content Creation keeps a version history for each article.
You can:
- Create snapshots at key moments.
- View differences between any two versions.
- Restore a previous version if a change does not work out.
Version history is especially useful when multiple editors touch the same article or when you are testing bolder rewrites.
---
## How drafts connect back to Topical Authority
### Resource Page drafts
For drafts created from Topical Map topics:
- Each draft is mapped to one topic and URL slug in your Topical Map
- Planner shows whether that topic:
- Has a brief
- Has a draft
- Is marked published
### Local Page drafts
For drafts created from Site Architecture nodes:
- Each draft is mapped to a service, location, or combined page in Site Architecture
- Planner shows the same status indicators in the Local Pages view
- Page Details (URL path, page type, primary query) connect the draft to SERP tracking
### Keeping Topical Authority accurate
When you publish on your site, set the article's editorial state to **Published** and update the publish toggle in Planner.
This keeps Coverage and Content Authority accurate for the Scorecard.
### Standalone drafts
Standalone drafts:
- Live only in the Briefs and Drafts area
- Do not appear in Planner or influence Topical Authority scores
- Are still fully supported by the editor, AI drafting and versioning
---
## Credit usage
Credits are used when you:
- Generate a full draft from a brief
- Run Specialist Agents (Fact Checker, Research, Intro & Key Takeaways) for Resource Pages
- Generate AI images (1-3 credits per image depending on model)
- Re-analyze quality in the Quality tab (10 credits per run)
Credits are not used when you:
- Write or edit manually
- Change editorial states
- View versions or use the brief and draft side by side
- View the automatic quality scorecard on a new draft (included with generation)
### Different costs for Local vs Resource Pages
| Page Type | Workflow | Cost |
| ----------------- | --------------------------------- | -------------------------------- |
| **Local Page** | Streamlined with Conversion Coach | Flat rate per draft (lower cost) |
| **Resource Page** | Full workflow | Base cost per draft |
| **Resource Page** | Full workflow + Specialist Agents | Base cost + Specialist add-ons |
Local Pages cost less because they skip the research-heavy agents and use a conversion-focused workflow instead.
Every AI action shows a clear estimate before you confirm.
If you do not have enough credits, Floyi stops the job and prompts you to add more instead of failing mid draft.
---
## Recommended way to work
### For Resource Pages (educational content)
A simple pattern that keeps the loop closed:
1. Use **Topical Map**, **Scorecard** and **Planner** to decide what to publish.
2. Generate a Planner based brief for that topic.
3. Approve the Strategic Intent and outline.
4. Create a draft in **Content Creation** from that brief.
5. Use Fact Checker and Research where needed.
6. Edit, approve, and [publish to WordPress](https://floyi.com/docs/tools/wordpress-publishing/) or export to your CMS, then mark the topic as published in Planner.
7. Rerun Topical Authority to see how Content Authority, Market Authority and AI Authority move.
### For Local Pages (service/location content)
1. Build your service and location structure in **Site Architecture**.
2. Use **Planner** (Local Pages view) to prioritize which pages to create.
3. Generate briefs for selected Local Pages.
4. Create drafts using the **Conversion Coach** workflow.
5. Edit for your specific offers, locations, and CTAs.
6. Publish and mark as published in Planner.
7. Rerun Topical Authority to track local page performance.
### For experiments
For campaigns and experiments outside the map, use standalone briefs and drafts, then adopt them into your map later if they prove valuable.
---
## Content Editor & Optimizer
Source: https://floyi.com/docs/tools/content-editor-optimizer/
> The complete guide to writing, editing, and optimizing content in Floyi.
---
## Getting Started
The Content Editor is Floyi's all-in-one workspace for creating, editing, and optimizing content. You can access it by:
1. **From Topical Authority** → Click "Create Draft" on any keyword
2. **From Content Briefs** → Click "Generate Draft" after brief generation
3. **From Projects** → Open any existing article draft
The workspace consists of three main areas:
- **Left Panel** (collapsed by default): View your content brief
- **Center**: The rich text editor
- **Right Panel**: Settings, Optimizer, Images, Research & Quality tabs (resizable - drag the panel edge to adjust width)
---
## Content Editor Overview
### Workspace Layout
### Split Screen Mode
Click **Split Screen** in the header to view your content brief alongside the editor. This helps you:
- Reference brief recommendations while writing
- Check structural suggestions
- Verify term coverage against competitor targets
- Stay aligned with strategic intent
Use the **draggable divider** to adjust panel widths.
---
## Editor Toolbar
The toolbar provides all formatting options for your content.
### Text Formatting
| Button | Function | Shortcut |
| :-------- | :---------------- | :---------------- |
| **B** | Bold | `Cmd + B` |
| _I_ | Italic | `Cmd + I` |
| Underline | Underline text | `Cmd + U` |
| ~~S~~ | Strikethrough | `Cmd + Shift + S` |
| `Code` | Inline code | `Cmd + E` |
| Clear | Remove formatting | `Cmd + \` |
### Block Formatting
| Button | Function |
| :----------------- | :------------------------------------- |
| Paragraph dropdown | Convert to Paragraph, H2, H3, H4, etc. |
| Bullet List | Create unordered list |
| Numbered List | Create ordered list |
| Task List | Create checkboxes |
| Blockquote | Create quote block |
| Code Block | Create multi-line code |
| Horizontal Rule | Insert divider line |
### Alignment
| Button | Function |
| :------ | :--------------- |
| Left | Align text left |
| Center | Center align |
| Right | Align text right |
| Justify | Justify text |
### Links & Media
| Button | Function |
| :------------ | :--------------------------------------------------- |
| Link | Insert or edit link (opens modal) |
| **AI Images** | Open the Images tab to generate and insert AI images |
| Table | Insert table |
### Link Modal Options
When inserting a link, you can configure:
- **URL** - The destination URL
- **Link Text** - Display text for the link
- **Open in new tab** - Whether to open externally
- **Nofollow** - Add rel="nofollow" attribute
### Tables
After inserting a table:
- Click any cell to edit
- Use the table menu to add/remove rows and columns
- Drag to resize columns
- Merge cells for complex layouts
### Find & Replace
Click the **Search icon** or press `Cmd + F` to open Find:
- Search for text in your content
- Navigate between matches with arrows
- Replace individual or all occurrences
### Undo/Redo
| Button | Function | Shortcut |
| :----- | :--------------- | :---------------- |
| Undo | Undo last action | `Cmd + Z` |
| Redo | Redo last action | `Cmd + Shift + Z` |
### Zoom
Use the **Zoom dropdown** (bottom right) to adjust editor zoom level:
- 75%, 90%, 100%, 110%, 125%, 150%
- Helps readability without affecting actual content
---
## AI Writing Assistant
The **AI Writing Assistant** is your in-editor AI copilot. Select any text and transform it instantly-simplify complex sentences, expand ideas, fix grammar, or give custom instructions.
For a deep dive into all features, see the [AI Writing Assistant guide](https://floyi.com/docs/tools/ai-writing-assistant).
### How to Use
1. **Select text** in the editor (up to ~400 words)
2. **AI bubble appears** above your selection
3. **Choose an action** or type custom instructions
4. **Preview the result** before accepting
### Available Actions
| Action | What It Does |
| :-------------- | :------------------------------------------------------ |
| **Simplify** | Makes text clearer and easier to understand |
| **Expand** | Adds detail, examples, or depth to your selection |
| **Shorten** | Condenses text while keeping key points |
| **Fix Grammar** | Corrects grammar, spelling, and punctuation |
| **Optimize** | Mode to incorporate specific terms from your brief |
| **Custom** | Your own instructions (e.g., "Make it more persuasive") |
### Preview & Accept
After the AI generates a result:
- **Original tab** → See your original text
- **Generated tab** → Preview the AI's version (with proper formatting for lists, tables, links)
**Actions:**
- ✓ **Accept** → Replaces your selection with the AI version
- ✗ **Reject** → Keeps your original text, closes the panel
### Tips & Best Practices
- **Keep selections focused** - 1-2 paragraphs work best
- **Use Optimize Mode** - Click Optimize, then select terms from the right panel to fill gaps
- **Use Custom for tone** - "Make it sound more confident" or "Use active voice"
- **Links are preserved** - Any links in your selection stay intact after transformation
- **Works with formatting** - Lists, bold, italic all render correctly in the preview
---
## Content Settings Panel
The right panel has five tabs: **Settings**, **Optimizer**, **Images**, **Research**, and **Quality**.
### Settings Tab
#### Article Details
| Field | Description |
| :----------------------- | :----------------------------------------------- |
| **Title** | Your article's title (auto-populated from brief) |
| **Meta Description** | SEO meta description for search results |
| **Article URL** | The target URL/slug for publishing |
| **Estimated Word Count** | Target word count based on competitor analysis |
#### Editing the Title & Meta Description
Click **Edit** next to the title and meta description to open the editor modal. If the brief generated alternate title options, the modal lists them - each labeled by its strategy with a one-line reason - so you can switch to a different option in one click. You can always type your own instead. Changes here update the article only; the brief keeps its own title.
#### Strategic Intent
Choose how the AI writes your content:
| Intent | Writing Style | Best For |
| :-------------------- | :---------------------------------- | :------------------------------- |
| **Human-First** | Warm, conversational, friendly | Blog posts, thought leadership |
| **LLM-Friendly** | Clear, chunked, citation-ready | SEO content targeting AI search |
| **Executive Summary** | Concise, scannable, action-oriented | Business audiences, busy readers |
**Note:** You can only change Strategic Intent before generating your first draft.
#### Specialist Agents
After generating an initial draft, you can run Specialist Agents to enhance specific aspects:
| Agent | Function |
| :------------------------ | :----------------------------------------- |
| **SEO Optimizer** | Improves keyword placement and on-page SEO |
| **Data Enricher** | Adds statistics, studies, and data points |
| **Fact Checker** | Verifies claims and adds citations |
| **Web Researcher** | Finds and adds external references |
| **Conversion Coach** | Adds CTAs and conversion elements |
| **Intro & Key Takeaways** | Polishes introduction and summary sections |
**How to use:**
1. Select one or more specialists
2. (Optional) Add custom instructions
3. Click "Run Specialists"
4. Review the enhanced content
#### Custom Prompt
Add specific instructions for the AI:
- Click **Edit Prompt** to open the custom instructions modal
- Add guidance like "Include a comparison table" or "Focus on small businesses"
- These instructions apply to drafts and specialist runs
---
## Content Optimizer
The Optimizer tab provides real-time content analysis and scoring.
### Optimization Score
The circular gauge shows your overall optimization score (0-100). Unlike simple keyword-count tools, Floyi's score reflects multiple dimensions of content quality:
- How well you cover the terms and entities that matter most to your topic, prioritizing the most relevant ones
- Whether you use those terms naturally, rather than repeating them for the sake of it
- Content structure and heading hierarchy
- How easy your content is for AI to parse and cite
- Reading level appropriateness for your audience
The score reflects your actual writing, so it climbs as you add real content - an outline of headings alone stays low until you write the body. Your score and competitor scores use the same model, so the comparison in the coverage heatmap is always apples-to-apples.
**Tip:** Aim for a green score for well-optimized content.
### Source Overview
Shows the data sources used for optimization:
- **Competitors (6)** - Top-ranking SERP pages analyzed
- **AI (3)** - Google AI Overview, AI Mode, ChatGPT responses
Click to expand and see individual sources with word counts.
**Buttons:**
- **View Sources** - See full content from each source
- **Coverage** - Open the term coverage heatmap
### Terms Tab
Lists all recommended terms and entities extracted from competitors and AI sources, organized in two groups:
- **Terms** - topical phrases, concepts, and keywords found across competitor and AI content
- **Entities** - named entities like companies, tools, frameworks, and people
Each term shows:
| Column | Description |
| :------------ | :-------------------------------------------------------------------- |
| **Count/Max** | Your usage count vs. the competitor-derived target (e.g., "5/23") |
| **Term** | The term or entity name |
| **R** | Relevance score (0-100) - how central this term is to your core topic |
| **S / AI** | How many SERP competitors and AI sources mention this term |
Use the **Sort** menu to choose how terms and entities are ordered:
- **Relevance** - highest relevance score first
- **Source - Competitor** - highest number of SERP competitor sources first
- **Sources - AI** - highest number of AI sources first
- **A-Z** - alphabetical order
**Color-coded usage indicators:**
- ⬜ Gray = Not yet used in your content
- 🟢 Green = Used and within the target range
- 🟡 Yellow = Slightly above the competitor target
- 🔴 Red = Significantly over the target - likely keyword stuffing
The target for each term is based on how often top-ranking competitors actually use it, so you're always benchmarking against real content that ranks.
**Actions:**
- **Click term** → Jump to first occurrence in editor
- **Highlight icon** → Toggle term highlighting in editor
- **Hide icon** → Remove term from list (can restore later)
- **Highlight All** → Highlight all terms at once
### GSC Queries Tab
For pages that already have a matched URL with Search Console data, the Optimizer pulls every GSC query
driving traffic to your URL and lists them with the same coverage UI as the Terms list. This lets you
optimize toward the queries Google already associates with your page, not just competitor-derived terms.
Each query shows:
| Column | Description |
| :-------------- | :----------------------------------------------------------------- |
| **Coverage** | Green check when your draft already mentions the query, gray when missing |
| **Query** | The exact Search Console query |
| **Clicks** | Clicks the query has driven to this URL |
| **Impressions** | Impressions the query has earned |
| **Position** | Your average ranking position for the query |
**When the tab appears:**
- Your topic must have a matched URL (manual match or planned URL slug)
- The matched URL must have GSC query data imported
If those conditions aren't met, the tab guides you to match a URL or import GSC data first.
**Actions:**
- **Click query** → Jump to first occurrence in editor
- **Highlight icon** → Toggle query highlighting in editor
- **Highlight All / Clear** → Highlight or clear all GSC queries in the editor at once, just like the Terms list
- **Copy icon** → Copy any query to your clipboard with one click
**Tooltips:**
Hover over column headers (Clicks, Impressions, Position) to see what each metric means and how it is calculated from your Search Console data.
**Why this matters:**
- **Refresh and rank recovery** - see which ranking queries you've drifted away from and patch them in the same editor
- **Optimize toward real demand** - every edit moves you toward queries that already send traffic
- **No spreadsheet juggling** - your GSC data lives next to the draft, not in a separate tool
### Issues Tab
Shows content structure issues:
#### Heading Structure
- Validates H2/H3/H4 hierarchy
- Flags skipped heading levels
- Recommends adding more sections if needed
#### AI Chunkability
- Identifies paragraphs that run too long to be easily scanned or cited
- Click any flagged paragraph to navigate to it
- Long paragraphs are harder for AI to cite - break them into shorter chunks or lists
#### Reading Ease
- Shows Flesch-Kincaid grade level
- Recommends improvements for accessibility
- Target: 8th-10th grade for general audiences depending on the topic. Keep the reading level appropriate for the target audience.
### Coverage Heatmap
Click **Coverage** to open the full term coverage matrix:
- Numbers show frequency of each term per source
- Green = present, Red = missing
- Compare your coverage to competitors at a glance
### Source Content Viewer
Click **View Sources** to see full content from each source:
- **Competitors**: Full extracted text, summary, key claims, terms, entities
- **AI Sources**: Complete AI responses with extracted insights
- **Expand/Collapse** individual sources
- **Expand All / Collapse All** buttons at top
### Schema Markup Tab
The **Schema** tab generates JSON-LD structured data for your article and links its entities to the Knowledge Graph. Floyi auto-detects which schema types apply (Article, FAQ, HowTo, and more) and builds them from your content. Use the per-type toggle to include or exclude any schema type.
#### Entity Disambiguation
Beyond the standard Article fields, Floyi connects the entities in your article to their canonical Knowledge Graph identifiers and groups them by role:
| Role | What it is |
| :------------- | :-------------------------------------------------- |
| **mainEntity** | The single primary subject your article is about |
| **about** | Secondary subjects the article also covers |
| **mentions** | Supporting entities the article references |
Each entity includes its canonical name, description, image, a specific schema.org type (Person, Organization, Diet, and so on), `sameAs` links to Wikipedia and Wikidata, and `identifier` values for the Google Knowledge Graph MID and Wikidata QID. This is the same entity disambiguation that dedicated entity-SEO tools charge for - built in.
**How it works:**
- **AI-assisted subject detection** - Floyi reads your title, topic, and the entities in your draft to pick the primary subject, expanding abbreviations to the canonical entity (e.g., an "IBS Guide" resolves to _Irritable bowel syndrome_) even when the full name isn't written out.
- **Verified against your content** - only entities that actually appear in your article body are included, so competitor-research terms that didn't make it into your draft never leak into your schema.
- **Regenerate** - click **Regenerate** to re-run detection after major edits. The tab shows an "Article edited" hint when your draft has changed since the schema was last generated. Re-running the AI subject detection uses 1 credit.
**Export:**
Schema flows automatically into WordPress and GitHub publishing and HTML copy through the **Include Schema** option - no separate step.
---
## AI Image Generation
Generate AI images directly inside the editor and insert them into your article without leaving Floyi.
### Getting Started
Click the **AI Images** button in the toolbar (or switch to the **Images** tab in the right sidebar) to open the image generation panel.
### Step 1: Analyze Your Draft
Click **Analyze Draft** to scan your article structure. Floyi identifies optimal image placements based on your H2 headings and content sections. Each suggested placement includes:
- **Position** - Which section the image belongs under (e.g., "After: Introduction")
- **AI-generated prompt** - A detailed image description based on the section content
- **Alt text** - SEO-friendly alternative text for accessibility
You can edit any prompt before generating to fine-tune the image you want.
### Step 2: Select and Configure
- **Select/Deselect** individual placements using checkboxes, or use **Select All / Deselect All**
- **Choose a model** from the dropdown at the bottom of the panel:
| Model | Resolution | Best For | Credits |
| :---------------- | :--------- | :-------------------------------- | :------ |
| **GPT Image 2** | 1K | Fast, affordable editorial images | 2/img |
| **Nano Banana 2** | 1K | Wide aspect ratio support | 3/img |
- **Choose an aspect ratio** - Options vary by model. Default is 16:9 (landscape), which works best for article content. Nano Banana 2 supports a wide range of ratios (1:1, 4:3, 3:4, 16:9, 9:16, 3:2, 2:3, 21:9, and more); GPT Image 2 supports 1:1, 3:2, and 2:3.
### Step 3: Generate
Click **Generate N Images** to start. The button shows the total credit cost. During generation:
- A progress bar shows completion status
- Images appear as thumbnails in a grid when ready
- Partial failures show per-image error messages with retry options
### Step 4: Review and Insert
After generation, you have two options:
- **Click any thumbnail** to open the full-size **lightbox preview**. Use arrow keys or click the arrows to navigate between images. Click **Insert** to place the image in your article below its target heading.
- **Click "Insert All Remaining"** to batch-insert all un-inserted images at once.
Inserted images show a green checkmark. If you delete an image from the article, the checkmark updates in real time so you can re-insert it.
### Image Persistence
- **Generated images** are stored permanently on Floyi's CDN (Cloudflare R2) and linked to your article
- **Inserted images** are saved as part of your article content (doc_json) and persist across page refreshes
- **Previously generated images** load automatically when you return to the Images tab - no need to regenerate
- Click **"Generate more"** to create additional images while keeping your existing ones
### Visual Style from Brand Foundation
If your [Brand Foundation](https://floyi.com/docs/tools/brand-foundation/) includes a visual style analysis, Floyi uses it to guide image generation - maintaining consistency with your brand's aesthetic, color palette, and visual identity across all generated images.
### Tips
- **Use 16:9 or 3:2 aspect ratios** for article images - they fit naturally in content flow
- **Edit prompts before generating** - the AI suggestions are a starting point, not final
- **Start with GPT Image 2** for drafts (cheapest), switch to Nano Banana 2 when you need wider aspect ratios
- **Featured Image** inserts at the top of your article with its own H2 heading
---
## Research Tab
The Research tab surfaces the research inputs behind every article, so writers can see exactly what AI agents used during brief and draft generation.
### Internal Link Suggestions
Internal link suggestions from your topical map, grouped into three relation types:
| Relation | Description |
| :------------ | :----------------------------------------------------------------- |
| **Parent** | Links to parent topics in your topical map hierarchy |
| **Sibling** | Links to topics at the same level within the same parent |
| **Subtopic** | Links to child topics beneath the current article's topic |
Each suggestion includes:
- **Anchor text options** - Multiple anchor text choices tagged by source (Map, AI, or custom)
- **Click to select** - Choose the anchor text you want, then place it in your article
- **Real-time tracking** - Links already placed in the editor show a green checkmark. Remove a link and the checkmark updates instantly.
### Researcher Agent Queries
A list of the fan-out queries the Researcher Agent used during draft generation. These show the exact searches the AI performed to gather information for your article, giving full transparency into the research process.
### Top SERP Competitors
The top-ranking competitor URLs that were selected and analyzed during brief and draft creation. These are the same sources the AI used to inform content structure, entity coverage, and topic depth.
### How to Use the Research Tab
1. Open the **Research** tab in the right panel
2. Review **Internal Link Suggestions** - click any suggestion to expand anchor text options
3. Select an anchor text, then place the link in your article using the editor's link tool
4. Watch the green checkmarks update as you place links
5. Review **Researcher Agent Queries** to understand what the AI searched for
6. Check **Top SERP Competitors** to see which pages informed your brief and draft
---
## Page Quality Scorecard
The **Quality** tab scores your draft using the quality signals Google's patents describe. An AI judge reads your full draft and returns an overall score with per-dimension breakdowns, reasoning, and evidence quotes you can click to jump to the exact section in the editor.
### Overall Score
The overall score (0-100) maps to the four-bucket scale Google's patents describe:
| Bucket | Score Range |
| :------------ | :---------- |
| **Excellent** | 85-100 |
| **Good** | 65-84 |
| **Average** | 40-64 |
| **Poor** | 0-39 |
The overall number is a weighted blend of the five dimensions below. When a dimension can't be scored for your article, the remaining weights rebalance, so a missing signal never counts against you.
### The Five Quality Dimensions
| Dimension | What It Measures |
| :----------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Relevance** | How completely the page answers the target query and its intent |
| **Content Quality** | Depth, accuracy, structure, and the effort visible in the writing |
| **Information Gain** | Net-new information compared to what already ranks. Also known as originality |
| **Next Step / Call to Action** | Whether readers get a clear path forward. Content and editorial sites are judged on a soft next step, commercial sites on a real call to action |
| **Trust & Authorship** | Expertise signals, sourcing, and author presence |
### Reading the Scorecard
- **Click any dimension** to expand its reasoning and supporting evidence
- **Click an evidence quote** to jump to that section in the editor
- Use **Expand all / Collapse all** to open or close every dimension at once
- Hover the info icons to see the Google research behind each dimension
### Information Gain Evidence
If your article was generated from a brief, the brief research already identified net-new angles the current top results miss. The Information Gain dimension checks which of those angles actually made it into your draft and lists them as evidence, so you can see exactly what your page adds that competitors don't.
### Re-Analyze After Edits
Click **Re-analyze** to score your draft again after making changes:
- Scores the latest saved version of your draft (auto-save keeps this current)
- Costs 10 credits per run
- Takes about a minute, and the tab updates automatically when the new scorecard is ready
- One analysis runs at a time per article
New drafts are scored automatically when generation finishes, so every article starts with a baseline scorecard at no extra cost.
### Quality vs. Optimizer
The two tabs answer different questions. The **Optimizer** measures coverage: terms, entities, and structure compared to competitors, updating as you type. The **Quality** tab is a judge: it reads the finished page the way Google's quality systems do and tells you how it holds up as a whole. Use the Optimizer while writing, then run Quality before you ship.
---
## Publishing to WordPress
If you have a WordPress site connected in **Settings > Integrations**, you can publish your article directly from the editor.
### Publish Button
The **WordPress publish button** appears in the editor header. It shows your current WordPress status:
| Button State | Meaning |
| :------------------------- | :--------------------------------------- |
| **Globe icon (gray)** | Not yet published to WordPress |
| **Globe icon (green dot)** | Published to at least one WordPress site |
| **Globe icon (blue dot)** | Saved as draft on WordPress |
Click the button to open the **Publish to WordPress** modal.
### Publishing an Article
1. Select the **WordPress site** from the dropdown.
2. Choose the **post type** (Post, Page, or custom type).
3. Set the **publish status** (Draft, Publish Now, or Schedule).
4. Assign **categories and tags** (for Post type).
5. Choose an **author** from your WordPress site.
6. Expand **SEO Metadata** to review or edit the SEO title, meta description, and focus keyword. These are auto-filled from your brief.
7. Click **Publish**, **Save as Draft**, or **Schedule**.
Floyi converts your editor content to native Gutenberg blocks (or Classic HTML if your site uses the Classic Editor) and sends it with your configured metadata.
### Updating Published Content
After editing a published article, the publish modal shows a blue **"Published on WordPress"** banner with the current status and a link to view the live page. Click **Update** to push the latest version. The WordPress post ID and URL remain the same.
### Publish from Multiple Sites
If you have multiple connected WordPress sites, you can publish the same article to each one separately. Each site maintains its own publish record.
For full details, see the [WordPress Publishing guide](https://floyi.com/docs/tools/wordpress-publishing/).
---
## Saving & Exporting
### Auto-Save
Content is automatically saved a moment after you stop typing. You'll see:
- "Saving..." - Save in progress
- "Saved" - Content saved successfully
- "Save" button - Click to save immediately
### Manual Save
Click **Save** or press `Cmd + S` to save immediately. If a save is already running, your click queues another save right after it.
### Copy to Clipboard
Click **Copy** to copy your content:
- Copies as rich text (formatted)
- Paste directly into Google Docs, WordPress, etc.
- Preserves headings, lists, links, and formatting
### Export Options
Click **Export** to download your content:
| Format | Description |
| :------------- | :----------------------- |
| **HTML** | Full HTML markup |
| **Markdown** | Standard markdown format |
| **Plain Text** | Text only, no formatting |
| **PDF** | Print-ready document |
### View Brief
Click **View Brief** to open your content brief in a new tab:
- See complete brief recommendations
- Review structural suggestions
- Check keyword targets
---
## Keyboard Shortcuts
### Formatting
| Action | Mac | Windows |
| :--------------- | :---------------- | :----------------- |
| Bold | `Cmd + B` | `Ctrl + B` |
| Italic | `Cmd + I` | `Ctrl + I` |
| Underline | `Cmd + U` | `Ctrl + U` |
| Strikethrough | `Cmd + Shift + S` | `Ctrl + Shift + S` |
| Inline Code | `Cmd + E` | `Ctrl + E` |
| Clear Formatting | `Cmd + \` | `Ctrl + \` |
| Link | `Cmd + K` | `Ctrl + K` |
### Editing
| Action | Mac | Windows |
| :--------- | :---------------- | :--------- |
| Undo | `Cmd + Z` | `Ctrl + Z` |
| Redo | `Cmd + Shift + Z` | `Ctrl + Y` |
| Save | `Cmd + S` | `Ctrl + S` |
| Find | `Cmd + F` | `Ctrl + F` |
| Select All | `Cmd + A` | `Ctrl + A` |
### Navigation
| Action | Mac | Windows |
| :--------------- | :-------------------- | :--------------------- |
| Go to start | `Cmd + Home` | `Ctrl + Home` |
| Go to end | `Cmd + End` | `Ctrl + End` |
| Select paragraph | `Cmd + Shift + Arrow` | `Ctrl + Shift + Arrow` |
---
## Tips & Best Practices
### Writing Workflow
1. **Start with the brief** - Open split screen and review recommendations
2. **Follow the structure** - Use suggested H2s as your outline
3. **Cover high-priority terms** - Work the recommended terms into your writing, starting with the highest-relevance ones near the top of the list
4. **Check issues** - Fix heading and chunkability issues
5. **Run specialists** - Enhance with SEO, data, or conversion focus
6. **Final review** - Aim for a green optimization score
7. **Check Quality** - Re-analyze in the Quality tab and aim for Good or Excellent before publishing
### Optimization Tips
- **Watch the color indicators** - green means you're in range, yellow means ease off, red means you're overusing a term
- **Break up long paragraphs** - AI struggles to cite walls of text
- **Use clear headings** - H2 → H3 → H4 hierarchy helps both readers and search engines
- **Match competitor depth** - check competitor word counts in Source Overview
- **Focus on high-relevance terms first** - the most relevant terms sit near the top of the list and have the biggest impact on your score
### Strategic Intent Selection
| Choose This | When You Want |
| :---------------- | :--------------------------------------------- |
| Human-First | Friendly, relatable content for brand building |
| LLM-Friendly | Maximum AI search visibility and citations |
| Executive Summary | Quick-read content for busy professionals |
### Specialist Best Practices
- **Run one at a time** first to see individual improvements
- **Use custom prompts** to guide specific enhancements
- **Review changes** - specialists suggest improvements, you control final output
- **Combine strategically** - SEO + Data Enricher for authoritative content
---
## Need Help?
- **In-app tooltips** - Hover over ℹ️ icons for quick explanations
- **Documentation** - Visit docs.floyi.com for detailed guides
- **Support** - Contact support@floyi.com for assistance
---
## GitHub Publishing
Source: https://floyi.com/docs/tools/github-publishing/
Floyi's GitHub Publishing integration lets you push [finished drafts](/docs/tools/content-creation/) from the Content Creation workspace straight to any Git-based static site. Your articles arrive as Markdown or MDX files with frontmatter, images, and schema markup, committed atomically to your repository. If your repo has CI/CD configured (Cloudflare Pages, Vercel, Netlify), your site deploys automatically. Publishing to WordPress instead? See the [WordPress publishing walkthrough](/docs/tools/wordpress-publishing/).
## What You'll Learn
- How to install the Floyi GitHub App on your GitHub account or organization
- How to connect a repository and configure it for your static site framework
- How to publish, update, and manage articles
- How to customize frontmatter templates for any framework
- How to use framework presets for Astro, Next.js, Hugo, Jekyll, and Docusaurus
- How to manage connected repos and troubleshoot issues
---
## Part 1: Installing the Floyi GitHub App
Before you can connect a repository, you need to install the **Floyi GitHub App** on your GitHub account or organization.
### Requirements
| Requirement | Detail |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| **GitHub account** | Personal account or organization |
| **Repository access** | You must be able to grant the app access to the target repo |
| **Floyi Plan** | Any paid plan |
| **Static site framework** | Any framework that reads Markdown/MDX files (Astro, Next.js, Hugo, Jekyll, Docusaurus, Eleventy, VitePress, Nuxt Content, etc.) |
| **CI/CD** (optional) | Cloudflare Pages, Vercel, Netlify, or any platform that auto-deploys on push |
:::note
CI/CD is not required. Floyi commits files to your repo regardless. However, without CI/CD, you'll need to manually build and deploy your site after publishing.
:::
### What Permissions Does the App Need?
The Floyi GitHub App requests minimal permissions:
| Permission | Level | Purpose |
| ------------ | ------------ | ---------------------------------------------------- |
| **Contents** | Read & Write | To commit Markdown/MDX files and images to your repo |
| **Metadata** | Read | To list repositories and branches |
Floyi does not request access to issues, pull requests, actions, or any other GitHub features.
### Installation Steps
1. In Floyi, go to **Settings > Integrations**.
2. Scroll to the **GitHub** section.
3. Click **Connect**.
4. You are redirected to GitHub to install the Floyi app.
5. Choose which account or organization to install on.
6. Select **All repositories** or choose specific repos you want Floyi to access.
7. Click **Install**.
8. GitHub redirects you back to Floyi with a confirmation.
After installation, Floyi stores your installation ID. You can now connect individual repositories.
:::tip
If you're installing on an organization, an organization admin may need to approve the installation first. Check your org's GitHub App policy if the install is blocked.
:::
---
## Part 2: Connecting a Repository
After installing the GitHub App, you connect individual repositories and configure how Floyi publishes to each one.
### Step-by-Step Connection
1. In **Settings > Integrations**, under the GitHub section, click **+ Connect**.
2. The connection modal opens with two steps.
**Step 1: Select Repository**
- If you've already installed the Floyi app, your accessible repos appear in a dropdown.
- If you haven't installed the app yet, click **Install Floyi on GitHub** to start the installation flow.
- Select the repository you want to publish to.
- Select the target **branch** (e.g., `main`, `develop`).
**Step 2: Configure Publishing Settings**
Choose a **framework preset** (optional) to pre-fill settings, or configure manually:
- **File Extension** -- `.md` or `.mdx`
- **File Naming Pattern** -- How article files are named (e.g., `{slug}.mdx`, `{date}-{slug}.md`, `{slug}/index.md`)
- **Content Path** -- Where Markdown/MDX files are committed (e.g., `src/content/blog/`)
- **Image Path** -- Where images are committed (e.g., `src/assets/blog/`)
- **Frontmatter Template** -- The YAML frontmatter template with `{{ variable }}` placeholders
- **Schema Embed Mode** -- How JSON-LD schema markup is included: as a script tag after frontmatter, inside frontmatter, or not at all
Click **Connect** to save the configuration. A success screen confirms the connection with a summary of your settings.
### Framework Presets
Presets pre-fill all settings with sensible defaults for popular frameworks. You can edit everything after selecting a preset.
| Preset | Extension | Content Path | Image Path | File Naming |
| -------------- | --------- | ------------------- | ---------------------- | ------------------- |
| **Astro** | `.mdx` | `src/content/blog/` | `src/assets/blog/` | `{slug}.mdx` |
| **Next.js** | `.mdx` | `content/blog/` | `public/images/blog/` | `{slug}.mdx` |
| **Hugo** | `.md` | `content/posts/` | `static/images/posts/` | `{slug}/index.md` |
| **Jekyll** | `.md` | `_posts/` | `assets/images/posts/` | `{date}-{slug}.md` |
| **Docusaurus** | `.mdx` | `blog/` | `static/img/blog/` | `{date}-{slug}.mdx` |
If your framework isn't listed, skip the preset and configure settings manually. The integration is framework-agnostic -- it works with any static site that reads Markdown or MDX files.
:::tip
You can change all connection settings later from **Settings > Integrations** by clicking the settings icon on the connected repo card.
:::
---
## Part 3: Managing Connected Repositories
After connecting, your repositories appear in **Settings > Integrations** under the GitHub section.
### Connection Card
Each connected repo shows:
- **Repository name** in `owner/repo` format
- **Branch** being published to
- **Content path** where files are committed
- **File extension** (`.md` or `.mdx`)
- **Framework preset** badge (if one was used)
- **Last publish date** and article count
- **Settings** button to modify connection configuration
- **Disconnect** button to remove the connection
### Health Check
Click the health check icon on any connected repo to verify the connection is working. A successful check confirms that:
- The Floyi GitHub App still has access to the repository
- The configured branch exists
- Floyi can write to the repository
If the check fails, review the error message. Common causes include:
- The Floyi app was uninstalled from GitHub
- The repository was deleted or renamed
- Repository access was revoked from the app's installation settings
### Publishing Sites Limits
WordPress and GitHub connections share a single **publishing sites** limit based on your Floyi plan. The connection count appears as a badge (e.g., "2/3") next to the Publishing section header.
| Plan | Max Publishing Sites |
| --------- | -------------------------------- |
| **Free** | 0 |
| **Pro** | 3 (WordPress + GitHub combined) |
| **Scale** | 10 (WordPress + GitHub combined) |
Disconnecting a site frees up a slot immediately.
### Disconnecting a Repository
1. Click the **Disconnect** button (trash icon) on the repo card.
2. Confirm the disconnection in the dialog.
Disconnecting removes the active link between Floyi and your repository. Files already committed to the repo remain untouched. You can reconnect the same repo later.
---
## Part 4: Publishing Content to GitHub
You can publish any article from the Content Creation workspace to a connected GitHub repository.
### Opening the Publish Modal
1. Open an article in the **Content Editor**.
2. Click the **Publish** dropdown in the toolbar.
3. Select **Publish to GitHub**.
4. The GitHub publish modal opens.
### Selecting a Repository
If you have multiple connected repos, choose the target repo from the **Repository** dropdown. The dropdown shows each repo's name, branch, and framework preset.
If only one repo is connected, it is selected automatically.
### Publish Settings
When you select a repository, the publish settings are pre-filled from your connection configuration. You can override any setting for this specific publish without changing the connection defaults:
- **Branch** -- The branch to commit to
- **File extension** -- `.md` or `.mdx`
- **Content path** -- Where the article file goes
- **File naming pattern** -- How the file is named
- **Image path** -- Where images are committed
- **Schema markup** -- Script tag, frontmatter, or none
- **Include images** -- Toggle to include or exclude images from the commit
### File Path Preview
Below the settings, a file path preview shows exactly where the article will be committed:
```
src/content/blog/seo-topical-map-mistakes.mdx
```
This updates live as you change the content path, file naming pattern, or file extension.
### Frontmatter Preview
If a frontmatter template is configured, it appears in an editable text area. You can review and modify the template before publishing. Variables like `{{ title }}`, `{{ slug }}`, and `{{ tags_array }}` are replaced with actual article data at publish time.
### Publishing
Click **Publish to GitHub**. A loading state appears while Floyi:
1. Compiles your article to Markdown
2. Renders the frontmatter template with article data
3. Downloads images from Floyi's CDN
4. Creates Git blobs for all files
5. Commits everything atomically to your repo
Once complete, a success screen shows:
- **Repository name** and branch
- **File path** of the committed article
- **Commit SHA** with a link to view the commit on GitHub
- A note that your site will deploy automatically if CI/CD is configured
### How the Commit Works
Floyi uses the Git Trees API to create a single atomic commit containing the article file and all images. This means either all files are committed together or none are -- there are no partial commits.
The commit is authored by `Floyi` with a message like:
```
Publish: 10 Common SEO Topical Map Mistakes
Published via Floyi
```
---
## Part 5: Updating Published Content
When you edit an article in Floyi after it has been published to GitHub, the publish modal shows that the article was previously published.
### How Updates Work
1. Open the previously published article in the Content Editor.
2. Click the **Publish** dropdown and select **Publish to GitHub**.
3. The modal shows:
- A **Previously published** indicator with a green checkmark
- The commit SHA of the last publish (clickable link to GitHub)
- An **Update** badge if the article content has changed since the last publish
4. Modify any publish settings if needed.
5. Click **Update on GitHub** to push the latest version.
The updated content replaces the existing file in your repo. A new commit is created -- the file path remains the same.
### Change Detection
Floyi tracks a content hash for each published article. When you edit the article in Floyi, the publish modal shows whether the content has changed since the last publish. This helps you know at a glance which articles need updating.
---
## Part 6: Frontmatter Template System
The frontmatter template is the core of Floyi's framework-agnostic approach. You write a YAML template with `{{ variable }}` placeholders, and Floyi fills them in with article data at publish time.
### How It Works
1. When you connect a repo (or select a framework preset), a frontmatter template is saved.
2. At publish time, Floyi replaces each `{{ variable }}` with the corresponding article data.
3. The rendered frontmatter is prepended to the Markdown body.
4. The assembled file is committed to your repo.
### Example: Astro Template
**Template (what you configure):**
```yaml
---
title: '{{ title }}'
description: '{{ meta_description }}'
pubDate: { { publish_date } }
slug: '{{ slug }}'
heroImage: '{{ hero_image_path }}'
heroAlt: '{{ hero_image_alt }}'
author: '{{ brand_name }}'
tags: { { tags_array } }
---
```
**Rendered output (what gets committed):**
```yaml
---
title: '10 Common SEO Topical Map Mistakes to Avoid'
description: 'Validate seed topics, align search intent, and avoid common pitfalls when building your topical map.'
pubDate: 2026-04-17
slug: 'seo-topical-map-mistakes'
heroImage: './images/seo-topical-map-mistakes-hero.jpg'
heroAlt: 'Topical map structure diagram'
author: 'Floyi'
tags: ['seo', 'topical-maps', 'content-strategy']
---
```
### Available Template Variables
| Variable | Description | Example Output |
| --------------------------- | ----------------------------------- | --------------------------------------- |
| `{{ title }}` | Article title | `10 Common SEO Topical Map Mistakes` |
| `{{ meta_description }}` | SEO meta description | `Validate seed topics, align search...` |
| `{{ slug }}` | URL slug from topic node or article | `seo-topical-map-mistakes` |
| `{{ publish_date }}` | Current date (YYYY-MM-DD) | `2026-04-17` |
| `{{ updated_date }}` | Article last updated date | `2026-04-17` |
| `{{ brand_name }}` | Your brand name | `Floyi` |
| `{{ hero_image_path }}` | Relative path to hero image | `./images/hero.jpg` |
| `{{ hero_image_filename }}` | Hero image filename only | `hero.jpg` |
| `{{ hero_image_alt }}` | Hero image alt text | `Topical map structure diagram` |
| `{{ tags_array }}` | JSON array of tags | `["seo", "topical-maps"]` |
| `{{ word_count }}` | Total word count | `2500` |
| `{{ topic_level }}` | Hierarchy level in topical map | `hub` |
| `{{ schema_json }}` | Combined JSON-LD string | `[{"@context":...}]` |
| `{{ language }}` | Primary language code | `en` |
### Editing the Template
You can edit the frontmatter template in two places:
1. **Connection settings** -- Go to Settings > Integrations, click settings on a connected repo. Changes here apply to all future publishes from that repo.
2. **Publish modal** -- Edit the frontmatter directly before publishing. Changes here apply only to the current publish and do not modify the saved template.
---
## Part 7: Image Handling
When you publish with images included, Floyi downloads each image from its CDN and commits it to your repository alongside the article file.
### How Images Are Committed
1. Floyi downloads images from the Cloudflare R2 CDN where they are stored.
2. Each image is encoded as a Git blob (base64).
3. Images are placed in the configured **image path**, organized in a subdirectory named after the article slug.
4. Image references in the Markdown body and frontmatter are rewritten to use relative paths.
### Image Directory Structure
For an article with slug `seo-topical-map-mistakes`, images are committed as:
```
src/assets/blog/
└── seo-topical-map-mistakes/
├── hero.jpg
├── image-1.jpg
└── image-2.jpg
```
This prevents filename collisions between articles.
### Image Source Priority
Floyi selects the hero/featured image in this order:
1. **User-selected featured image** set explicitly in Floyi
2. **First image in the article body** auto-detected from the editor content
3. **AI-generated image** if image generation was used
4. **No featured image** if none of the above exist
### Excluding Images
If you prefer to manage images separately (e.g., through a CMS or image CDN), uncheck **Include images in commit** in the publish modal. The article file will still be committed, but image paths in the Markdown will reference their Floyi CDN URLs instead of local paths.
---
## Part 8: Schema Markup (JSON-LD)
Floyi can embed structured data (JSON-LD schema markup) in your published files. This is the same schema data generated by Floyi's Schema Generator.
### Embed Modes
| Mode | How It Works | Best For |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| **Script tag** (default) | JSON-LD is inserted as an inline `