{
  "openapi": "3.0.3",
  "info": {
    "title": "SocialRails Public API",
    "description": "Schedule social media posts, view analytics, generate AI content, and manage integrations with the SocialRails API.",
    "version": "1.5.0",
    "contact": {
      "name": "SocialRails",
      "url": "https://socialrails.com",
      "email": "contact@socialrails.com"
    },
    "license": {
      "name": "Proprietary"
    },
    "x-logo": {
      "url": "https://socialrails.com/images/logo.png"
    }
  },
  "servers": [
    {
      "url": "https://socialrails.com/api/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "tags": [
    { "name": "Health", "description": "API health check" },
    { "name": "Posts", "description": "Create, read, update, and delete social media posts" },
    { "name": "Analytics", "description": "View posting analytics" },
    { "name": "Accounts", "description": "List connected social media accounts" },
    { "name": "AI", "description": "Generate AI-powered social media content" },
    { "name": "Workspace", "description": "Workspace info and plan limits" },
    { "name": "Media", "description": "Upload images and videos for posts" },
    { "name": "Webhooks", "description": "Register and manage webhook subscriptions" }
  ],
  "paths": {
    "/health": {
      "get": {
        "tags": ["Health"],
        "summary": "Health check",
        "description": "Public endpoint — no authentication required. Verify connectivity.",
        "security": [],
        "responses": {
          "200": {
            "description": "API is healthy",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "status": { "type": "string", "example": "ok" },
                        "version": { "type": "string", "example": "1.0" },
                        "timestamp": { "type": "string", "format": "date-time" }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/posts": {
      "get": {
        "tags": ["Posts"],
        "summary": "List posts",
        "description": "List posts in your workspace. Requires `read` scope.",
        "parameters": [
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["scheduled", "posted", "published", "draft", "failed"] }, "description": "Filter by status (use 'posted' or 'published' for completed posts)" },
          { "name": "platform", "in": "query", "schema": { "$ref": "#/components/schemas/Platform" }, "description": "Filter by platform" },
          { "name": "sort", "in": "query", "schema": { "type": "string", "enum": ["created_at", "scheduled_for"], "default": "created_at" }, "description": "Sort field" },
          { "name": "from", "in": "query", "schema": { "type": "string", "format": "date-time" }, "description": "Posts created after this date" },
          { "name": "to", "in": "query", "schema": { "type": "string", "format": "date-time" }, "description": "Posts created before this date" },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 }, "description": "Results per page" },
          { "name": "offset", "in": "query", "schema": { "type": "integer", "minimum": 0, "default": 0 }, "description": "Pagination offset" }
        ],
        "responses": {
          "200": {
            "description": "List of posts",
            "headers": {
              "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
              "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
              "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "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" }
        }
      },
      "post": {
        "tags": ["Posts"],
        "summary": "Create a post",
        "description": "Create a new post. Requires `write` scope. Platform settings are automatically loaded from your workspace defaults.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreatePostRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Post created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "$ref": "#/components/schemas/Post" },
                    "warnings": {
                      "type": "array",
                      "items": { "type": "string" },
                      "description": "Non-fatal advisory messages — e.g. missing optional settings that may affect publishing. The post was still created."
                    }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/posts/batch": {
      "post": {
        "tags": ["Posts"],
        "summary": "Batch create posts",
        "description": "Create the same post for multiple platforms. Each platform counts as one post against your monthly limit. Requires `write` scope.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/BatchPostRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Batch posts created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "batch_id": { "type": "string", "format": "uuid" },
                        "posts": {
                          "type": "array",
                          "items": { "$ref": "#/components/schemas/Post" }
                        }
                      }
                    },
                    "warnings": {
                      "type": "array",
                      "items": { "type": "string" },
                      "description": "Per-platform advisory messages, prefixed with the platform name (e.g. `linkedin: no company page selected`)."
                    }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/posts/{id}": {
      "get": {
        "tags": ["Posts"],
        "summary": "Get a post",
        "description": "Get a single post by ID. Requires `read` scope.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Post details",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "$ref": "#/components/schemas/Post" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "patch": {
        "tags": ["Posts"],
        "summary": "Update a post",
        "description": "Update a draft or scheduled post. Requires `write` scope. Only `draft` and `scheduled` posts can be updated.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/UpdatePostRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Post updated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "$ref": "#/components/schemas/Post" }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "tags": ["Posts"],
        "summary": "Delete a post",
        "description": "Delete a draft or scheduled post. Published or failed posts cannot be deleted. Requires `write` scope.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Post deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "deleted": { "type": "boolean", "example": true }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/analytics": {
      "get": {
        "tags": ["Analytics"],
        "summary": "Get analytics",
        "description": "Get posting analytics for your workspace. Requires `read` scope.",
        "parameters": [
          { "name": "platform", "in": "query", "schema": { "$ref": "#/components/schemas/Platform" }, "description": "Filter by platform" },
          { "name": "period", "in": "query", "schema": { "type": "string", "enum": ["7d", "30d", "90d", "365d"], "default": "7d" }, "description": "Time period" },
          { "name": "post_id", "in": "query", "schema": { "type": "string", "format": "uuid" }, "description": "Get analytics for a specific post" }
        ],
        "responses": {
          "200": {
            "description": "Analytics data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "period": { "type": "string" },
                        "since": { "type": "string", "format": "date-time" },
                        "total_posts": { "type": "integer", "description": "Total unique posts" },
                        "total_platform_posts": { "type": "integer", "description": "Total posts counted per platform" },
                        "by_platform": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "platform": { "type": "string" },
                              "posts_published": { "type": "integer" },
                              "engagement": { "type": "integer", "description": "Total engagement (likes, comments, shares)" },
                              "impressions": { "type": "integer", "description": "Total impressions" },
                              "reach": { "type": "integer", "description": "Total reach" },
                              "followers": { "type": "integer", "description": "Current follower count" }
                            }
                          }
                        },
                        "overview": {
                          "type": "object",
                          "description": "Aggregate engagement metrics across all platforms. Present when engagement data is available.",
                          "properties": {
                            "total_engagement": { "type": "integer" },
                            "total_reach": { "type": "integer" },
                            "total_followers": { "type": "integer" },
                            "engagement_growth": { "type": "number", "description": "Percentage growth vs previous period" },
                            "reach_growth": { "type": "number" },
                            "follower_growth": { "type": "number" }
                          }
                        },
                        "last_updated": { "type": "string", "format": "date-time", "description": "When engagement data was last refreshed" }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/accounts": {
      "get": {
        "tags": ["Accounts"],
        "summary": "List accounts",
        "description": "List connected social media accounts. Never exposes access tokens. Requires `read` scope.",
        "responses": {
          "200": {
            "description": "List of connected accounts",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Account" }
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/accounts/{id}/settings": {
      "get": {
        "tags": ["Accounts"],
        "summary": "Get account settings",
        "description": "Get platform capabilities, default settings, and available tools for a connected account. Requires `read` scope.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Account settings and capabilities",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "account_id": { "type": "string", "format": "uuid" },
                        "platform": { "$ref": "#/components/schemas/Platform" },
                        "capabilities": { "$ref": "#/components/schemas/PlatformCapabilities" },
                        "defaults": { "type": "object", "description": "Workspace default settings for this platform" },
                        "available_tools": { "type": "array", "items": { "type": "string" }, "description": "Tools that can be triggered via POST /accounts/{id}/tools" }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/accounts/{id}/tools": {
      "post": {
        "tags": ["Accounts"],
        "summary": "Trigger account tool",
        "description": "Trigger a platform discovery tool (e.g. list Facebook pages, Pinterest boards). Requires `read` scope.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["tool"],
                "properties": {
                  "tool": { "type": "string", "description": "Tool name: pages (facebook), boards (pinterest), companies (linkedin), communities (twitter)" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Tool results",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "tool": { "type": "string" },
                        "platform": { "type": "string" },
                        "results": { "type": "array", "items": {} }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/ai/generate": {
      "post": {
        "tags": ["AI"],
        "summary": "Generate AI content",
        "description": "Generate AI-powered social media content. Each request deducts 2 AI credits. Requires `ai` scope.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["prompt"],
                "properties": {
                  "prompt": { "type": "string", "maxLength": 2000, "description": "What to generate" },
                  "platform": { "$ref": "#/components/schemas/Platform" },
                  "tone": { "type": "string", "default": "professional", "description": "Tone of voice (e.g. professional, casual, excited, humorous)" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Generated content",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "content": { "type": "string" },
                        "platform": { "type": "string" },
                        "tone": { "type": "string" }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/workspace": {
      "get": {
        "tags": ["Workspace"],
        "summary": "Get workspace info",
        "description": "Get workspace info, plan limits, and current usage. Requires `read` scope.",
        "responses": {
          "200": {
            "description": "Workspace details",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "$ref": "#/components/schemas/Workspace" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/media/upload": {
      "post": {
        "tags": ["Media"],
        "summary": "Upload a file",
        "description": "Upload a file via multipart form data. Images (JPEG, PNG, GIF, WebP): max 10MB. Videos (MP4): max 100MB. Requires `write` scope.\n\nFor video posts, upload the video with `type: video` and a separate thumbnail with `type: thumbnail`, then pass both keys in the `media` array when creating the post.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["file"],
                "properties": {
                  "file": { "type": "string", "format": "binary", "description": "The file to upload" },
                  "type": { "type": "string", "enum": ["image", "video", "thumbnail"], "description": "Media type override. Use 'thumbnail' for video cover images." }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "File uploaded",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "$ref": "#/components/schemas/MediaUpload" }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "413": { "$ref": "#/components/responses/PayloadTooLarge" }
        }
      }
    },
    "/media/upload-url": {
      "post": {
        "tags": ["Media"],
        "summary": "Upload from URL",
        "description": "Provide a publicly accessible URL and SocialRails will fetch and store the media. Images: max 10MB. Videos (MP4): max 100MB. The URL must serve the file with a correct `Content-Type` header (e.g. `video/mp4`). Requires `write` scope.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["url"],
                "properties": {
                  "url": { "type": "string", "format": "uri", "description": "Public URL of the media to fetch" },
                  "type": { "type": "string", "enum": ["image", "video", "thumbnail"], "description": "Media type override" }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "File uploaded from URL",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "$ref": "#/components/schemas/MediaUpload" }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "413": { "$ref": "#/components/responses/PayloadTooLarge" }
        }
      }
    },
    "/media/{id}": {
      "delete": {
        "tags": ["Media"],
        "summary": "Delete uploaded media",
        "description": "Delete a previously uploaded media file from storage by its `media_id`. Requires `write` scope.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "The `media_id` returned by the upload endpoint" }
        ],
        "responses": {
          "200": {
            "description": "Media deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "media_id": { "type": "string", "format": "uuid" },
                        "deleted": { "type": "boolean", "example": true }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/webhooks": {
      "get": {
        "tags": ["Webhooks"],
        "summary": "List webhooks",
        "description": "List registered webhooks. Requires `read` scope.",
        "responses": {
          "200": {
            "description": "List of webhooks",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Webhook" }
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "post": {
        "tags": ["Webhooks"],
        "summary": "Register a webhook",
        "description": "Register a new webhook endpoint. Max 10 per workspace. Requires `webhooks` scope.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["url", "events"],
                "properties": {
                  "url": { "type": "string", "format": "uri", "description": "HTTPS URL to receive events" },
                  "events": {
                    "type": "array",
                    "items": { "type": "string", "enum": ["post.published", "post.failed", "post.scheduled"] },
                    "description": "Event types to subscribe to"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook registered",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "$ref": "#/components/schemas/WebhookCreated" }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/webhooks/{id}": {
      "delete": {
        "tags": ["Webhooks"],
        "summary": "Delete a webhook",
        "description": "Remove a webhook registration. Requires `webhooks` scope.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Webhook deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "deleted": { "type": "boolean", "example": true }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key from Dashboard > Settings > API. Keys start with `sr_live_`."
      }
    },
    "schemas": {
      "Platform": {
        "type": "string",
        "enum": ["twitter", "linkedin", "facebook", "instagram", "tiktok", "bluesky", "pinterest", "threads", "youtube"]
      },
      "Post": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "content": { "description": "Post content as JSON object or string", "example": { "all": "Check out our latest update!" } },
          "platform": { "type": "string" },
          "status": { "type": "string", "enum": ["draft", "scheduled", "posted", "failed"], "description": "`draft` — not yet scheduled. `scheduled` — queued for publishing. `posted` — successfully published. `failed` — publishing failed, see `error_message`." },
          "scheduled_for": { "type": "string", "format": "date-time", "nullable": true },
          "posted_at": { "type": "string", "format": "date-time", "nullable": true },
          "created_at": { "type": "string", "format": "date-time" },
          "media": { "type": "array", "items": { "type": "string" }, "nullable": true, "description": "R2 keys of attached media files" },
          "error_message": { "type": "string", "nullable": true, "description": "Reason for failure when status is `failed`" }
        }
      },
      "CreatePostRequest": {
        "type": "object",
        "required": ["content", "platform"],
        "properties": {
          "content": { "type": "string", "maxLength": 5000, "description": "Post text" },
          "platform": { "$ref": "#/components/schemas/Platform" },
          "scheduled_for": { "type": "string", "format": "date-time", "description": "ISO 8601 date in the future. Omit to save as draft." },
          "media": {
            "type": "array",
            "items": { "type": "string" },
            "description": "R2 keys returned by the media upload endpoint. The post type is determined automatically based on what you pass:\n\n**Video posts:** Pass one video key + one thumbnail key (e.g. `[\"workspace/api-uploads/videos/x.mp4\", \"workspace/api-uploads/thumbnails/x.jpg\"]`). The thumbnail key must be under the `/thumbnails/` path (upload with `type: thumbnail`).\n\n**Instagram carousel:** Pass 2–10 image keys → automatically posted as a carousel.\n\n**Facebook multi-photo:** Pass 2–10 image keys → automatically posted as a multi-photo post.\n\n**TikTok photo post:** Pass 1–35 image keys with no video → posted as a TikTok photo/slideshow. Only JPEG and WebP are supported (not PNG or GIF).\n\n**Stories (Instagram/Facebook):** Pass a single image or video key and set `postType: story` (Instagram) or `videoType: story` (Facebook) in `platform_settings`."
          },
          "platform_settings": { "$ref": "#/components/schemas/PlatformSettings", "description": "Override platform-specific settings. Defaults are loaded from your workspace dashboard settings." },
          "thread": {
            "type": "array",
            "items": { "type": "string" },
            "minItems": 2,
            "maxItems": 25,
            "description": "Thread content. First item = main post, rest = replies. Only supported on twitter and threads."
          },
          "thread_media": {
            "type": "object",
            "additionalProperties": { "type": "array", "items": { "type": "string" } },
            "description": "Media keys per thread item, keyed by index (e.g. {\"0\": [\"key1\"], \"2\": [\"key2\"]})"
          },
          "thread_delay": {
            "type": "number",
            "minimum": 0,
            "maximum": 60,
            "default": 0,
            "description": "Delay between thread items in minutes (0-60)"
          }
        }
      },
      "UpdatePostRequest": {
        "type": "object",
        "properties": {
          "content": { "type": "string", "maxLength": 5000 },
          "platform": { "$ref": "#/components/schemas/Platform" },
          "scheduled_for": { "type": "string", "format": "date-time", "nullable": true, "description": "Set to null to revert to draft" },
          "media": { "type": "array", "items": { "type": "string" } },
          "platform_settings": { "type": "object" }
        }
      },
      "BatchPostRequest": {
        "type": "object",
        "required": ["content", "platforms"],
        "properties": {
          "content": { "type": "string", "maxLength": 5000, "description": "Default post text" },
          "platforms": { "type": "array", "items": { "$ref": "#/components/schemas/Platform" }, "maxItems": 9 },
          "scheduled_for": { "type": "string", "format": "date-time" },
          "platform_content": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Per-platform content overrides" },
          "media": { "type": "array", "items": { "type": "string" } },
          "platform_settings": { "type": "object", "description": "Per-platform settings overrides" }
        }
      },
      "Account": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "provider": { "type": "string" },
          "name": { "type": "string" },
          "status": { "type": "string", "enum": ["connected", "expired", "needs_reauth"] },
          "connected_at": { "type": "string", "format": "date-time" }
        }
      },
      "Workspace": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "created_at": { "type": "string", "format": "date-time" },
          "plan": { "type": "string" },
          "limits": {
            "type": "object",
            "properties": {
              "api_requests_per_hour": { "type": "integer" },
              "api_keys_max": { "type": "integer" },
              "max_posts_per_month": { "type": "integer" },
              "max_ai_credits_per_month": { "type": "integer" }
            }
          },
          "usage": {
            "type": "object",
            "properties": {
              "posts_this_month": { "type": "integer" }
            }
          }
        }
      },
      "MediaUpload": {
        "type": "object",
        "properties": {
          "media_id": { "type": "string", "format": "uuid" },
          "key": { "type": "string", "description": "R2 storage key — use this in the `media` array when creating posts", "example": "workspace-id/api-uploads/images/uuid.jpg" },
          "type": { "type": "string", "enum": ["image", "video", "thumbnail"] },
          "url": { "type": "string", "format": "uri" },
          "content_type": { "type": "string", "example": "image/jpeg" },
          "size": { "type": "integer", "description": "File size in bytes" }
        }
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "url": { "type": "string", "format": "uri" },
          "events": { "type": "array", "items": { "type": "string" } },
          "is_active": { "type": "boolean" },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "WebhookCreated": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "url": { "type": "string", "format": "uri" },
          "events": { "type": "array", "items": { "type": "string" } },
          "secret": { "type": "string", "description": "Signing secret — save this, it is only shown once" },
          "is_active": { "type": "boolean" },
          "created_at": { "type": "string", "format": "date-time" }
        }
      },
      "PlatformCapabilities": {
        "type": "object",
        "properties": {
          "character_limit": { "type": "integer", "description": "Maximum characters per post" },
          "supports_thread": { "type": "boolean" },
          "supports_media": { "type": "boolean" },
          "max_media_images": { "type": "integer" },
          "max_media_videos": { "type": "integer" },
          "available_settings": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Platform-specific setting fields and their descriptions" }
        }
      },
      "PlatformSettings": {
        "type": "object",
        "description": "Platform-specific settings. Pass inside platform_settings keyed by platform name.",
        "properties": {
          "twitter": {
            "type": "object",
            "properties": {
              "selectedCommunities": { "type": "array", "items": { "type": "string" }, "description": "Community IDs to cross-post to" }
            }
          },
          "linkedin": {
            "type": "object",
            "properties": {
              "selectedLocation": { "type": "string", "description": "Company page ID to post as" }
            }
          },
          "facebook": {
            "type": "object",
            "properties": {
              "selectedPage": { "type": "string", "description": "Facebook page ID to post as. **Required** — posts will fail without this. Configure a default in Dashboard > Settings or pass it here." },
              "selectedPages": { "type": "array", "items": { "type": "string" }, "description": "Multiple Facebook page IDs (posts to all of them)" },
              "videoType": {
                "type": "string",
                "enum": ["reel", "video", "story"],
                "default": "reel",
                "description": "`reel` — Facebook Reel (default). `video` — standard video post. `story` — Facebook Story (single image or video, disappears after 24h)."
              }
            }
          },
          "instagram": {
            "type": "object",
            "properties": {
              "postType": {
                "type": "string",
                "enum": ["reel", "image", "story"],
                "default": "reel",
                "description": "`reel` — Instagram Reel (default, video). `image` — single image post; pass 2–10 image keys in `media` for a carousel. `story` — Instagram Story (single image or video, disappears after 24h)."
              }
            }
          },
          "tiktok": {
            "type": "object",
            "properties": {
              "privacy_status": { "type": "string", "enum": ["PUBLIC_TO_EVERYONE", "MUTUAL_FOLLOW_FRIENDS", "FOLLOWER_OF_CREATOR", "SELF_ONLY"], "default": "PUBLIC_TO_EVERYONE" },
              "interactions": {
                "type": "object",
                "properties": {
                  "allow_comment": { "type": "boolean", "default": true },
                  "allow_duet": { "type": "boolean", "default": true },
                  "allow_stitch": { "type": "boolean", "default": true }
                }
              },
              "commercial_content": {
                "type": "object",
                "properties": {
                  "enabled": { "type": "boolean", "default": true },
                  "your_brand": { "type": "boolean", "default": true },
                  "branded_content": { "type": "boolean", "default": true }
                }
              },
              "title": { "type": "string", "description": "Video title (TikTok video posts)" },
              "post_mode": { "type": "string", "enum": ["DIRECT_POST", "UPLOAD_TO_INBOX"], "default": "DIRECT_POST", "description": "`DIRECT_POST` publishes immediately. `UPLOAD_TO_INBOX` saves to drafts for manual review." },
              "photo_cover_index": { "type": "integer", "default": 0, "description": "For photo/slideshow posts: index of the cover image (0-based). Ignored for video posts." }
            }
          },
          "pinterest": {
            "type": "object",
            "properties": {
              "selectedBoard": { "type": "string", "description": "Board ID (required for Pinterest)" },
              "destinationLink": { "type": "string", "description": "URL the pin links to" }
            }
          },
          "threads": {
            "type": "object",
            "properties": {
              "reply_control": { "type": "string", "enum": ["everyone", "accounts_you_follow", "mentioned_only"], "default": "everyone" }
            }
          }
        }
      },
      "Pagination": {
        "type": "object",
        "properties": {
          "total": { "type": "integer" },
          "limit": { "type": "integer" },
          "offset": { "type": "integer" },
          "has_more": { "type": "boolean", "description": "Whether there are more items beyond the current page" }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": { "type": "string" },
              "message": { "type": "string" },
              "documentation_url": { "type": "string", "format": "uri", "description": "Link to relevant documentation for this error" }
            }
          }
        }
      }
    },
    "headers": {
      "X-RateLimit-Limit": {
        "description": "Maximum requests allowed per hour",
        "schema": { "type": "integer", "example": 300 }
      },
      "X-RateLimit-Remaining": {
        "description": "Requests remaining in the current window",
        "schema": { "type": "integer", "example": 247 }
      },
      "X-RateLimit-Reset": {
        "description": "Unix timestamp when the window resets",
        "schema": { "type": "integer", "example": 1709402400 }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Bad request — missing or invalid fields",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Unauthorized": {
        "description": "Missing, invalid, or expired API key",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Forbidden": {
        "description": "API key lacks the required scope, or plan does not include API access",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "PayloadTooLarge": {
        "description": "Request body exceeds size limit",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "RateLimited": {
        "description": "Rate limit exceeded",
        "headers": {
          "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" },
          "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" },
          "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" }
        },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    }
  }
}
