{
  "openapi": "3.1.0",
  "info": {
    "title": "BrandBeacon API",
    "description": "AI-powered social media content generation and multi-platform publishing. Generate on-brand content, create posts, and schedule publishing across Facebook, Instagram, X/Twitter, LinkedIn, Google Business, Bluesky, TikTok, and Threads.",
    "version": "1.0.0",
    "contact": {
      "name": "BrandBeacon",
      "url": "https://brandbeacon.dev"
    }
  },
  "servers": [
    {
      "url": "https://brandbeacon.dev/api/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/brands": {
      "get": {
        "operationId": "listBrands",
        "summary": "List all brands",
        "description": "Returns all brands accessible to the authenticated user. If the API key is restricted to specific brands, only those are returned.",
        "tags": ["Brands"],
        "responses": {
          "200": {
            "description": "List of brands",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    { "$ref": "#/components/schemas/SuccessResponse" },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "brands": {
                              "type": "array",
                              "items": { "$ref": "#/components/schemas/Brand" }
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/brands/{id}": {
      "get": {
        "operationId": "getBrand",
        "summary": "Get a brand",
        "description": "Returns a single brand by ID.",
        "tags": ["Brands"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" },
            "description": "Brand UUID"
          }
        ],
        "responses": {
          "200": {
            "description": "Brand details",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    { "$ref": "#/components/schemas/SuccessResponse" },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "brand": { "$ref": "#/components/schemas/Brand" }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/brands/{id}/voice": {
      "get": {
        "operationId": "getBrandVoice",
        "summary": "Get brand voice profile",
        "description": "Returns the extracted brand voice profile including personality traits, tone attributes, language patterns, and content themes.",
        "tags": ["Brands"],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "format": "uuid" },
            "description": "Brand UUID"
          }
        ],
        "responses": {
          "200": {
            "description": "Brand voice profile",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    { "$ref": "#/components/schemas/SuccessResponse" },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "voice": {
                              "$ref": "#/components/schemas/BrandVoice"
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/content/generate": {
      "post": {
        "operationId": "generateContent",
        "summary": "Generate AI content",
        "description": "Generate platform-optimized social media content using the brand's voice profile. Content is tailored to each platform's character limits and best practices. Requires the 'generate' scope.",
        "tags": ["Content"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateContentRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Generated content",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    { "$ref": "#/components/schemas/SuccessResponse" },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "contents": {
                              "type": "array",
                              "items": {
                                "$ref": "#/components/schemas/GeneratedContent"
                              }
                            },
                            "overallBrandConsistency": {
                              "type": "number",
                              "description": "Brand consistency score from 0 to 1"
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": {
            "description": "Brand voice not found. Extract brand voice first.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": {
            "description": "Content generation failed",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/posts": {
      "post": {
        "operationId": "createPost",
        "summary": "Create a post",
        "description": "Create a new post in draft status. Use the schedule endpoint to queue it for publishing. Requires the 'post' scope.",
        "tags": ["Posts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreatePostRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Post created",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    { "$ref": "#/components/schemas/SuccessResponse" },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "post": { "$ref": "#/components/schemas/Post" }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "get": {
        "operationId": "listPosts",
        "summary": "List posts",
        "description": "List posts with filtering and pagination. Requires the 'read' scope.",
        "tags": ["Posts"],
        "parameters": [
          {
            "name": "brand_id",
            "in": "query",
            "schema": { "type": "string", "format": "uuid" },
            "description": "Filter by brand"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": ["draft", "scheduled", "published", "failed"]
            },
            "description": "Filter by status"
          },
          {
            "name": "page",
            "in": "query",
            "schema": { "type": "integer", "default": 1, "minimum": 1 },
            "description": "Page number"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1,
              "maximum": 100
            },
            "description": "Items per page"
          }
        ],
        "responses": {
          "200": {
            "description": "List of posts",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    { "$ref": "#/components/schemas/SuccessResponse" },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "posts": {
                              "type": "array",
                              "items": { "$ref": "#/components/schemas/Post" }
                            },
                            "pagination": {
                              "$ref": "#/components/schemas/Pagination"
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/posts/schedule": {
      "post": {
        "operationId": "schedulePost",
        "summary": "Schedule a post",
        "description": "Schedule a draft post for future publishing. The post will be automatically published at the specified time. Requires the 'schedule' scope.",
        "tags": ["Posts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/SchedulePostRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Post scheduled",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    { "$ref": "#/components/schemas/SuccessResponse" },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "job_id": { "type": "string" },
                            "post_id": { "type": "string", "format": "uuid" },
                            "scheduled_at": {
                              "type": "string",
                              "format": "date-time"
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api-keys": {
      "post": {
        "operationId": "createApiKey",
        "summary": "Create an API key",
        "description": "Create a new API key. The raw key is returned only once. Requires web session authentication (cannot be called with an API key).",
        "tags": ["API Keys"],
        "security": [{ "sessionAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateApiKeyRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "API key created. The key field is returned only once.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    { "$ref": "#/components/schemas/SuccessResponse" },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/ApiKeyWithSecret"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": {
            "description": "API key creation requires session authentication",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listApiKeys",
        "summary": "List API keys",
        "description": "List all active (non-revoked) API keys for the authenticated user.",
        "tags": ["API Keys"],
        "responses": {
          "200": {
            "description": "List of API keys",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    { "$ref": "#/components/schemas/SuccessResponse" },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "keys": {
                              "type": "array",
                              "items": { "$ref": "#/components/schemas/ApiKey" }
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "delete": {
        "operationId": "revokeApiKey",
        "summary": "Revoke an API key",
        "description": "Revoke an API key. The key will immediately stop working.",
        "tags": ["API Keys"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["key_id"],
                "properties": {
                  "key_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "ID of the API key to revoke"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "API key revoked",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    { "$ref": "#/components/schemas/SuccessResponse" },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "properties": {
                            "revoked": { "type": "boolean" },
                            "key_id": { "type": "string", "format": "uuid" }
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key prefixed with bb_live_. Create keys in the BrandBeacon dashboard under Settings > API Keys."
      },
      "sessionAuth": {
        "type": "apiKey",
        "in": "cookie",
        "name": "sb-access-token",
        "description": "Supabase session cookie (web dashboard only)"
      }
    },
    "schemas": {
      "SuccessResponse": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean", "const": true },
          "data": { "type": "object" },
          "meta": { "$ref": "#/components/schemas/ResponseMeta" }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean", "const": false },
          "error": {
            "type": "object",
            "properties": {
              "code": { "type": "string" },
              "message": { "type": "string" }
            }
          },
          "meta": { "$ref": "#/components/schemas/ResponseMeta" }
        }
      },
      "ResponseMeta": {
        "type": "object",
        "properties": {
          "request_id": { "type": "string" },
          "timestamp": { "type": "string", "format": "date-time" },
          "auth_method": { "type": "string", "enum": ["api_key", "session"] },
          "rate_limit": {
            "type": "object",
            "properties": {
              "remaining_rpm": { "type": "integer" },
              "remaining_rpd": { "type": "integer" },
              "reset_at": { "type": "string", "format": "date-time" }
            }
          }
        }
      },
      "Brand": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "website": { "type": "string", "format": "uri" },
          "user_id": { "type": "string", "format": "uuid" },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "BrandVoice": {
        "type": "object",
        "properties": {
          "brand_id": { "type": "string", "format": "uuid" },
          "personality_traits": {
            "type": "array",
            "items": { "type": "string" }
          },
          "tone_attributes": {
            "type": "object",
            "properties": {
              "formality": { "type": "number", "minimum": 0, "maximum": 1 },
              "energy": { "type": "number", "minimum": 0, "maximum": 1 },
              "warmth": { "type": "number", "minimum": 0, "maximum": 1 }
            }
          },
          "language_patterns": {
            "type": "object",
            "properties": {
              "vocabulary_level": { "type": "string" },
              "sentence_structure": { "type": "string" },
              "signature_phrases": {
                "type": "array",
                "items": { "type": "string" }
              }
            }
          },
          "content_themes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "theme": { "type": "string" },
                "keywords": {
                  "type": "array",
                  "items": { "type": "string" }
                }
              }
            }
          },
          "confidence_score": { "type": "number", "minimum": 0, "maximum": 1 },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "GenerateContentRequest": {
        "type": "object",
        "required": ["brand_id", "platforms", "goal"],
        "properties": {
          "brand_id": {
            "type": "string",
            "format": "uuid",
            "description": "Brand UUID to generate content for"
          },
          "platforms": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "facebook",
                "instagram",
                "x_twitter",
                "linkedin",
                "google_business",
                "bluesky",
                "tiktok",
                "threads"
              ]
            },
            "description": "Target social media platforms"
          },
          "goal": {
            "type": "string",
            "description": "What the content should achieve (e.g. 'Announce our new product launch')"
          },
          "content_type": {
            "type": "string",
            "default": "social_post",
            "description": "Type of content to generate"
          },
          "additional_context": {
            "type": "string",
            "description": "Extra context for the AI to consider"
          },
          "variations": {
            "type": "integer",
            "default": 1,
            "minimum": 1,
            "maximum": 5,
            "description": "Number of content variations to generate"
          }
        }
      },
      "GeneratedContent": {
        "type": "object",
        "properties": {
          "platform": { "type": "string" },
          "text": { "type": "string" },
          "hashtags": {
            "type": "array",
            "items": { "type": "string" }
          },
          "characterCount": { "type": "integer" }
        }
      },
      "Post": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "content": { "type": "string" },
          "platforms": {
            "type": "array",
            "items": { "type": "string" }
          },
          "brand_id": { "type": "string", "format": "uuid", "nullable": true },
          "image_url": { "type": "string", "format": "uri", "nullable": true },
          "status": {
            "type": "string",
            "enum": ["draft", "scheduled", "published", "failed"]
          },
          "source": { "type": "string" },
          "scheduled_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "published_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "CreatePostRequest": {
        "type": "object",
        "required": ["content", "platforms"],
        "properties": {
          "content": {
            "type": "string",
            "description": "Post content text"
          },
          "platforms": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "facebook",
                "instagram",
                "x_twitter",
                "linkedin",
                "google_business",
                "bluesky",
                "tiktok",
                "threads"
              ]
            },
            "description": "Target platforms for publishing"
          },
          "brand_id": {
            "type": "string",
            "format": "uuid",
            "description": "Associated brand UUID"
          },
          "image_url": {
            "type": "string",
            "format": "uri",
            "description": "Image URL to attach to the post"
          }
        }
      },
      "SchedulePostRequest": {
        "type": "object",
        "required": ["post_id", "scheduled_at"],
        "properties": {
          "post_id": {
            "type": "string",
            "format": "uuid",
            "description": "Post UUID to schedule"
          },
          "scheduled_at": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 datetime for publishing (must be in the future)"
          }
        }
      },
      "Pagination": {
        "type": "object",
        "properties": {
          "page": { "type": "integer" },
          "limit": { "type": "integer" },
          "total": { "type": "integer" }
        }
      },
      "CreateApiKeyRequest": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": {
            "type": "string",
            "description": "Human-readable name for the key"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": ["read", "write", "generate", "post", "schedule", "admin"]
            },
            "default": ["read"],
            "description": "Allowed API scopes"
          },
          "brand_ids": {
            "type": "array",
            "items": { "type": "string", "format": "uuid" },
            "nullable": true,
            "description": "Restrict key to specific brands (null = all brands)"
          },
          "agent_type": {
            "type": "string",
            "nullable": true,
            "description": "Identifier for the agent type (e.g. 'moltbot', 'custom')"
          },
          "rate_limit_rpm": {
            "type": "integer",
            "default": 60,
            "description": "Requests per minute limit"
          },
          "rate_limit_rpd": {
            "type": "integer",
            "default": 1000,
            "description": "Requests per day limit"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Key expiration date (null = no expiry)"
          }
        }
      },
      "ApiKey": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "key_prefix": { "type": "string" },
          "scopes": {
            "type": "array",
            "items": { "type": "string" }
          },
          "brand_ids": {
            "type": "array",
            "items": { "type": "string", "format": "uuid" },
            "nullable": true
          },
          "agent_type": { "type": "string", "nullable": true },
          "rate_limit_rpm": { "type": "integer" },
          "rate_limit_rpd": { "type": "integer" },
          "last_used_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "revoked_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "ApiKeyWithSecret": {
        "allOf": [
          { "$ref": "#/components/schemas/ApiKey" },
          {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "description": "The full API key. Returned only once at creation time."
              }
            }
          }
        ]
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Invalid or missing authentication",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      },
      "Forbidden": {
        "description": "Missing required scope or brand access",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      },
      "ValidationError": {
        "description": "Invalid request body",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit exceeded",
        "headers": {
          "Retry-After": {
            "schema": { "type": "integer" },
            "description": "Seconds to wait before retrying"
          }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      }
    }
  }
}
