{"openapi":"3.0.3","info":{"title":"AIContent API","description":"API for managing sites and content automation on the AIContent platform.\n\n## Authentication\n\nAPI requests require authentication using an API key. Include your API key in the Authorization header:\n\n```\nAuthorization: Bearer aicontent_xxxxxxxxxxxxx\n```\n\nAPI keys are scoped to an organization and can only manage sites within that organization.\n\n## Rate Limiting\n\nAPI requests are rate limited based on your plan. The default limit is 60 requests per minute.\n\n## Site Setup Flow\n\n1. Create a site using `POST /api/sites`\n2. Trigger the automated setup using `POST /api/sites/{id}/setup`\n3. Poll setup status using `GET /api/sites/{id}/setup` until status is \"ready\"\n","version":"1.0.0","contact":{"name":"AIContent Support","url":"https://aicontent.com/support"},"license":{"name":"Proprietary","url":"https://aicontent.com/terms"}},"servers":[{"url":"https://app.aicontent.com/api","description":"Production server"},{"url":"http://localhost:6001/api","description":"Development server"}],"security":[{"BearerAuth":[]}],"tags":[{"name":"Sites","description":"Site management operations"},{"name":"Organizations","description":"Organization management (requires user auth)"},{"name":"Setup","description":"Site setup automation"}],"paths":{"/sites":{"get":{"tags":["Sites"],"summary":"List sites","description":"List all sites in the organization associated with your API key.\n\n**Note:** When using user authentication instead of API keys, returns all sites for the user.\n","operationId":"listSites","parameters":[{"name":"org_id","in":"query","description":"Filter sites by organization ID (optional, defaults to API key's org)","schema":{"type":"string","format":"uuid"}},{"name":"include_archived","in":"query","description":"Include archived (inactive) sites","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"List of sites","content":{"application/json":{"schema":{"type":"object","properties":{"sites":{"type":"array","items":{"$ref":"#/components/schemas/Site"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"tags":["Sites"],"summary":"Create a new site","description":"Create a new site in your organization.\n\n**Required fields:**\n- `name`: Display name for the site\n- `domain`: The domain (e.g., \"example.com\")\n\n**Optional but recommended:**\n- `sitemap_url`: URL to the site's XML sitemap\n- `rss_feed_url`: URL to the site's RSS feed\n\n**Response includes:**\n- `id`: The site's unique ID (store as `aicontent_site_id`)\n- `rss_token`: Token for accessing the generated RSS feed (store as `aicontent_rss_token`)\n- `rss_url`: Full URL to the site's AIContent RSS feed (store as `aicontent_rss_url`)\n\nAfter creating a site, call `POST /api/sites/{id}/setup` to trigger the automated setup process.\n","operationId":"createSite","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSiteRequest"},"example":{"name":"My Client Site","domain":"client.com","sitemap_url":"https://client.com/sitemap.xml","rss_feed_url":"https://client.com/feed.xml"}}}},"responses":{"201":{"description":"Site created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"site":{"$ref":"#/components/schemas/SiteWithRss"}}},"example":{"site":{"id":"550e8400-e29b-41d4-a716-446655440000","name":"My Client Site","domain":"client.com","rss_token":"abc123xyz789","rss_url":"https://app.aicontent.com/rss/abc123xyz789","sitemap_url":"https://client.com/sitemap.xml","site_rss_url":"https://client.com/feed.xml","organization_id":"660e8400-e29b-41d4-a716-446655440000","setup_status":"pending","is_active":true,"created_at":"2024-01-18T12:00:00Z"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Site limit reached or API key organization mismatch","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/sites/{id}":{"get":{"tags":["Sites"],"summary":"Get site details","description":"Get detailed information about a specific site.","operationId":"getSite","parameters":[{"$ref":"#/components/parameters/SiteId"}],"responses":{"200":{"description":"Site details","content":{"application/json":{"schema":{"type":"object","properties":{"site":{"$ref":"#/components/schemas/Site"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"tags":["Sites"],"summary":"Update a site","description":"Update site properties. Only provided fields will be updated.","operationId":"updateSite","parameters":[{"$ref":"#/components/parameters/SiteId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSiteRequest"}}}},"responses":{"200":{"description":"Site updated","content":{"application/json":{"schema":{"type":"object","properties":{"site":{"$ref":"#/components/schemas/Site"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"tags":["Sites"],"summary":"Delete a site (USER AUTH ONLY)","description":"Permanently delete a site and all associated data.\n\n**RESTRICTED:** This endpoint requires user authentication (session cookie or JWT).\n**API keys CANNOT delete sites** - use `POST /api/sites/{id}/stop` to disable instead.\n\n**Warning:** This action is irreversible. All articles, categories, and settings will be deleted.\n\nRequires confirmation in the request body.\n","operationId":"deleteSite","security":[{"SessionAuth":[]}],"parameters":[{"$ref":"#/components/parameters/SiteId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["confirm"],"properties":{"confirm":{"type":"string","enum":["DELETE"],"description":"Must be \"DELETE\" to confirm deletion"}}}}}},"responses":{"200":{"description":"Site deleted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"deleted":{"type":"object","properties":{"site":{"type":"string"},"articles":{"type":"integer"},"subscribers":{"type":"integer"}}}}}}}},"400":{"description":"Deletion not confirmed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"API keys cannot delete sites","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Site deletion requires user authentication. API keys cannot delete sites. Use POST /api/sites/{id}/stop to disable instead."}}}},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/sites/{id}/stop":{"post":{"tags":["Sites"],"summary":"Disable a site","description":"Disable a site by setting `is_active` to false.\n\nThis is the safe alternative to DELETE for API key integrations.\nDisabled sites will not generate new content but data is preserved.\n\nSupports both user authentication and API keys (requires `write` scope).\n","operationId":"stopSite","parameters":[{"$ref":"#/components/parameters/SiteId"}],"responses":{"200":{"description":"Site disabled","content":{"application/json":{"schema":{"type":"object","properties":{"site":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"is_active":{"type":"boolean","example":false}}},"message":{"type":"string","example":"Site has been disabled. No new content will be generated."}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Insufficient permissions (API key needs write scope)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/sites/{id}/setup":{"post":{"tags":["Setup"],"summary":"Trigger site setup","description":"Trigger the automated 9-step setup process for a site.\n\n**Setup Steps:**\n1. Detect/validate sitemap & RSS URLs\n2. Parse sitemap to discover pages\n3. Parse RSS to extract articles and categories\n4. Fetch page content and generate embeddings\n5. Discover ranked keywords (DataForSEO)\n6. Generate AI keyphrases (fallback)\n7. Generate ICP (Ideal Customer Profile)\n8. Discover competitors from SERP\n9. Finalize (favicon, mark ready)\n\n**Response:** Server-Sent Events (SSE) stream with progress updates.\n\n**After setup:** Poll `GET /api/sites/{id}/setup` to verify status is \"ready\".\n","operationId":"triggerSiteSetup","parameters":[{"$ref":"#/components/parameters/SiteId"}],"responses":{"200":{"description":"SSE stream with setup progress","content":{"text/event-stream":{"schema":{"type":"string"},"example":"event: step\ndata: {\"step\": 1, \"name\": \"Detecting Sitemap\", \"status\": \"running\"}\n\nevent: step\ndata: {\"step\": 1, \"name\": \"Detecting Sitemap\", \"status\": \"complete\"}\n\nevent: complete\ndata: {\"setup_status\": \"ready\", \"pages_found\": 523}\n"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"get":{"tags":["Setup"],"summary":"Get setup status","description":"Check the current setup status of a site.","operationId":"getSiteSetupStatus","parameters":[{"$ref":"#/components/parameters/SiteId"}],"responses":{"200":{"description":"Setup status","content":{"application/json":{"schema":{"type":"object","properties":{"setup_status":{"type":"string","enum":["pending","running","ready","error"],"description":"Current setup status"},"error_message":{"type":"string","description":"Error message if setup failed"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/organizations":{"get":{"tags":["Organizations"],"summary":"List organizations","description":"List all organizations for the authenticated user.\n\n**Note:** This endpoint requires user authentication (session cookie or JWT), not API keys.\n","operationId":"listOrganizations","security":[{"SessionAuth":[]}],"responses":{"200":{"description":"List of organizations","content":{"application/json":{"schema":{"type":"object","properties":{"organizations":{"type":"array","items":{"$ref":"#/components/schemas/Organization"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Organizations"],"summary":"Create organization","description":"Create a new organization.","operationId":"createOrganization","security":[{"SessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrganizationRequest"}}}},"responses":{"201":{"description":"Organization created","content":{"application/json":{"schema":{"type":"object","properties":{"organization":{"$ref":"#/components/schemas/Organization"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/organizations/{id}/api-keys":{"get":{"tags":["Organizations"],"summary":"List API keys","description":"List all API keys for an organization.","operationId":"listOrganizationApiKeys","security":[{"SessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Organization ID","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"List of API keys","content":{"application/json":{"schema":{"type":"object","properties":{"api_keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Organizations"],"summary":"Create API key","description":"Create a new API key for an organization.\n\n**Important:** The full API key is only returned once in this response.\nStore it securely as it cannot be retrieved again.\n","operationId":"createOrganizationApiKey","security":[{"SessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Organization ID","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Descriptive name for the API key","example":"IRWire Integration"},"scopes":{"type":"array","items":{"type":"string","enum":["read","write","admin"]},"default":["read","write"]},"description":{"type":"string","description":"Optional description"}}}}}},"responses":{"201":{"description":"API key created","content":{"application/json":{"schema":{"type":"object","properties":{"api_key":{"allOf":[{"$ref":"#/components/schemas/ApiKey"},{"type":"object","properties":{"key":{"type":"string","description":"The full API key (only shown once)","example":"sk_live_abc123xyz789..."}}}]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}}},"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"API key authentication (sk_live_xxx)"},"SessionAuth":{"type":"apiKey","in":"cookie","name":"session","description":"Session cookie authentication (for user-only endpoints)"}},"parameters":{"SiteId":{"name":"id","in":"path","required":true,"description":"Site ID (UUID)","schema":{"type":"string","format":"uuid"}}},"responses":{"Unauthorized":{"description":"Authentication required or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Unauthorized"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Site not found"}}}},"BadRequest":{"description":"Invalid request parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InternalError":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal server error"}}}}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Error message"}}},"Site":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Unique site identifier"},"name":{"type":"string","description":"Site display name"},"domain":{"type":"string","description":"Site domain"},"slug":{"type":"string","description":"URL-friendly identifier"},"favicon_url":{"type":"string","format":"uri","nullable":true},"sitemap_url":{"type":"string","format":"uri","nullable":true},"site_rss_url":{"type":"string","format":"uri","nullable":true,"description":"The site's own RSS feed URL"},"rss_token":{"type":"string","description":"Token for AIContent's generated RSS feed"},"organization_id":{"type":"string","format":"uuid","nullable":true},"is_active":{"type":"boolean","default":true},"setup_status":{"type":"string","enum":["pending","running","ready","error"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"SiteWithRss":{"allOf":[{"$ref":"#/components/schemas/Site"},{"type":"object","properties":{"rss_url":{"type":"string","format":"uri","description":"Full URL to AIContent's generated RSS feed"}}}]},"CreateSiteRequest":{"type":"object","required":["name","domain"],"properties":{"name":{"type":"string","description":"Site display name","example":"My Client Site"},"domain":{"type":"string","description":"Site domain (without protocol)","example":"client.com"},"sitemap_url":{"type":"string","format":"uri","description":"URL to the site's XML sitemap","example":"https://client.com/sitemap.xml"},"rss_feed_url":{"type":"string","format":"uri","description":"URL to the site's RSS feed","example":"https://client.com/feed.xml"},"organization_id":{"type":"string","format":"uuid","description":"Organization ID (defaults to API key's organization)"}}},"UpdateSiteRequest":{"type":"object","properties":{"name":{"type":"string"},"domain":{"type":"string"},"sitemap_url":{"type":"string","format":"uri"},"site_rss_url":{"type":"string","format":"uri"},"is_active":{"type":"boolean"},"business_description":{"type":"string"},"icp_description":{"type":"string"},"target_audience":{"type":"string"}}},"Organization":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":"string","nullable":true},"color":{"type":"string","enum":["slate","blue","amber","emerald","purple","pink","orange","cyan"]},"is_default":{"type":"boolean"},"site_count":{"type":"integer"},"created_at":{"type":"string","format":"date-time"}}},"CreateOrganizationRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string","example":"IRWire Clients"},"description":{"type":"string","nullable":true},"color":{"type":"string","enum":["slate","blue","amber","emerald","purple","pink","orange","cyan"],"default":"blue"}}},"ApiKey":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","description":"Descriptive name"},"key_prefix":{"type":"string","description":"First characters of the key (for identification)","example":"sk_live_abc123"},"scopes":{"type":"array","items":{"type":"string","enum":["read","write","admin"]}},"description":{"type":"string","nullable":true},"last_used_at":{"type":"string","format":"date-time","nullable":true},"usage_count":{"type":"integer"},"expires_at":{"type":"string","format":"date-time","nullable":true},"created_at":{"type":"string","format":"date-time"}}}}}}