{"openapi":"3.0.3","info":{"title":"SEOLadders API","version":"1.1.0","description":"Programmatic access to keyword research, article generation, optimization, and refresh. Same backend that powers the SEOLadders dashboard.\n\n## Multi-site\n\nA single API key works across every site on your account. Pick which site each call runs against by either:\n\n- Setting the `X-Site` header to a canonical hostname (e.g. `X-Site: acme.com`), or\n- Adding a `?site=acme.com` query string parameter.\n\nIf you omit both, calls run against your *active site* — the one you last switched to in the dashboard sidebar. Legacy keys created before the multi-site release stay locked to a single site and ignore the `X-Site` override.","contact":{"name":"SEOLadders","url":"https://www.seoladders.com"}},"servers":[{"url":"https://www.seoladders.com","description":"Production"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key generated on /dashboard/developers. One key works across every site on your account; specify the target site per request via the `X-Site` header or `?site=` query parameter (see info.description for details)."}},"parameters":{"Site":{"name":"X-Site","in":"header","required":false,"description":"Canonical hostname of the site to run this call against (e.g. `acme.com`). Optional — omit to use the user's active site. Equivalent to passing `?site=acme.com` in the query string.","schema":{"type":"string","example":"acme.com"}},"SiteQuery":{"name":"site","in":"query","required":false,"description":"Alias for the `X-Site` header — handy for curl one-liners. If both are set, the header wins.","schema":{"type":"string","example":"acme.com"}}},"schemas":{"Error":{"type":"object","required":["error","message"],"properties":{"error":{"type":"string"},"message":{"type":"string"},"details":{"type":"object","additionalProperties":true}}},"Usage":{"type":"object","properties":{"used":{"type":"integer"},"limit":{"type":"integer"}}},"Coverage":{"type":"object","description":"Coverage rollup for a topic's keywords against the site's articles.","properties":{"total":{"type":"integer"},"covered":{"type":"integer","description":"Keywords with a published article."},"planned":{"type":"integer","description":"Keywords queued or drafting (calendar / unpublished)."},"gap":{"type":"integer","description":"Keywords with no article yet."},"coveragePct":{"type":"integer","description":"covered / total, 0–100. What was WRITTEN for the topic. Unchanged: see TopicAuthority for what it has won."}}},"TopicAuthority":{"type":"object","description":"What the topic has earned, as opposed to what was written for it. Search positions come from rank tracking and Search Console; citations from the AI runs.","properties":{"authority":{"type":"integer","description":"0–100. A weighted blend of searchScore and aiScore."},"searchScore":{"type":"integer","description":"0–100. Keywords ranking, banded by position and weighted by search volume."},"aiScore":{"type":"integer","description":"0–100. Share of the topic's tracked prompts whose answers name the brand."},"stage":{"type":"string","enum":["planned","published","indexed","ranking","winning","cited"],"description":"The furthest point reached. Useful where a young topic's score is honestly near zero."},"evidence":{"type":"object","description":"The counts the score is computed from.","properties":{"keywordsTracked":{"type":"integer"},"keywordsRanking":{"type":"integer","description":"Position 20 or better."},"keywordsTopThree":{"type":"integer"},"keywordsWithImpressions":{"type":"integer","description":"Shown in Google at least once, whatever the position."},"promptsTracked":{"type":"integer"},"promptsCiting":{"type":"integer"}}}}},"Topic":{"type":"object","properties":{"id":{"type":"string"},"product_id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"pillar_post_id":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"coverage":{"$ref":"#/components/schemas/Coverage"},"authority":{"$ref":"#/components/schemas/TopicAuthority"}}},"TopicKeyword":{"type":"object","properties":{"id":{"type":"string"},"keyword":{"type":"string"},"intent":{"type":"string","nullable":true},"searchVolume":{"type":"integer","nullable":true},"keywordDifficulty":{"type":"integer","nullable":true},"coverage":{"type":"string","enum":["covered","planned","gap"],"description":"Present on GET responses (not on research candidates)."},"origin":{"type":"string","enum":["dataforseo","ai"],"description":"Present on research candidates."}}},"TopicPrompt":{"type":"object","description":"An AI prompt (buyer question) tracked under a topic across AI engines.","properties":{"id":{"type":"string"},"text":{"type":"string"},"intent":{"type":"string","enum":["category","comparison","problem","evaluative","organic","brand_specific","competitor_comparison"]},"isActive":{"type":"boolean"}}},"Keyword":{"type":"object","properties":{"keyword":{"type":"string"},"searchVolume":{"type":"integer"},"keywordDifficulty":{"type":"integer"},"intent":{"type":"string"},"cpc":{"type":"number","nullable":true},"recommendation":{"type":"string","enum":["recommended","stretch","high_competition"]}}},"ArticleStatus":{"type":"string","enum":["generating","ready","published","failed","canceled"]},"ArticleType":{"type":"string","enum":["Explainer","Guide: How-to","Listicle"]},"ArticleStub":{"type":"object","properties":{"articleId":{"type":"string"},"status":{"$ref":"#/components/schemas/ArticleStatus"},"keyword":{"type":"string"},"articleType":{"$ref":"#/components/schemas/ArticleType"}}},"Article":{"type":"object","properties":{"articleId":{"type":"string"},"status":{"$ref":"#/components/schemas/ArticleStatus"},"keyword":{"type":"string"},"title":{"type":"string"},"slug":{"type":"string","nullable":true},"metaDescription":{"type":"string","nullable":true},"articleType":{"$ref":"#/components/schemas/ArticleType"},"source":{"type":"string"},"wordCount":{"type":"integer","nullable":true},"readingTime":{"type":"integer","nullable":true},"externalUrl":{"type":"string","nullable":true},"batchId":{"type":"string","nullable":true},"articleMarkdown":{"type":"string","nullable":true,"description":"Full article rendered as markdown. Present only when status is `ready` or `published`."},"articleContentJson":{"type":"object","nullable":true,"additionalProperties":true},"jsonLd":{"type":"object","nullable":true,"additionalProperties":true},"error":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Batch":{"type":"object","properties":{"batchId":{"type":"string"},"status":{"type":"string","enum":["pending","partial","completed","failed"]},"totalCount":{"type":"integer"},"pendingCount":{"type":"integer"},"completedCount":{"type":"integer"},"failedCount":{"type":"integer"},"metadata":{"type":"object","nullable":true,"additionalProperties":true},"webhookUrl":{"type":"string","nullable":true},"articles":{"type":"array","items":{"$ref":"#/components/schemas/ArticleStub"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"WebhookSecret":{"type":"object","properties":{"secret":{"type":"string","description":"HMAC-SHA256 signing secret prefixed with `whsec_`. Use to verify the `X-SeoLadders-Signature` header on incoming webhook deliveries."}}},"WebhookDeliveryStatus":{"type":"string","enum":["pending","delivered","failed","abandoned"]},"WebhookDelivery":{"type":"object","properties":{"id":{"type":"string"},"event_type":{"type":"string","description":"The event that triggered this delivery (e.g. `article.completed`, `batch.completed`)."},"target_url":{"type":"string"},"status":{"$ref":"#/components/schemas/WebhookDeliveryStatus"},"attempt_count":{"type":"integer"},"response_status":{"type":"integer","nullable":true},"last_error":{"type":"string","nullable":true},"next_retry_at":{"type":"string","format":"date-time","nullable":true},"delivered_at":{"type":"string","format":"date-time","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}}},"security":[{"bearerAuth":[]}],"paths":{"/api/v1/keywords/search":{"post":{"operationId":"postKeywordsSearch","summary":"Find related keywords by seed term","tags":["Research"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["seed"],"properties":{"seed":{"type":"string"},"longTail":{"type":"boolean","default":false},"filterByDR":{"type":"boolean","default":true}}}}}},"responses":{"200":{"description":"Keyword results","content":{"application/json":{"schema":{"type":"object","properties":{"keywords":{"type":"array","items":{"$ref":"#/components/schemas/Keyword"}},"count":{"type":"integer"},"domainRank":{"type":"integer","nullable":true},"recommendedKdCap":{"type":"integer"},"isLocalBusiness":{"type":"boolean"},"usage":{"$ref":"#/components/schemas/Usage"}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/keywords/competitor-gap":{"post":{"operationId":"postKeywordsCompetitorGap","summary":"Find keywords competitors rank for that you don't (max 3 competitors)","tags":["Research"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["competitors"],"properties":{"competitors":{"type":"array","minItems":1,"maxItems":3,"items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Gap keywords","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/keywords/discover":{"post":{"operationId":"postKeywordsDiscover","summary":"Auto-discover rankable keywords from product context","tags":["Research"],"responses":{"200":{"description":"Discovered keywords","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/articles":{"post":{"operationId":"postArticles","summary":"Start a single article generation","tags":["Articles"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["keyword"],"properties":{"keyword":{"type":"string"},"articleType":{"$ref":"#/components/schemas/ArticleType"},"subDescription":{"type":"string"},"referenceUrl":{"type":"string"}}}}}},"responses":{"202":{"description":"Article generation started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArticleStub"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/articles/batch":{"post":{"operationId":"postArticlesBatch","summary":"Submit up to 10 article generations in one request","tags":["Articles"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","minItems":1,"maxItems":10,"items":{"type":"object","required":["keyword"],"properties":{"keyword":{"type":"string"},"articleType":{"$ref":"#/components/schemas/ArticleType"},"subDescription":{"type":"string"},"referenceUrl":{"type":"string"}}}},"metadata":{"type":"object","additionalProperties":true,"description":"Caller-supplied metadata returned verbatim in batch responses + webhook payloads."},"webhookUrl":{"type":"string","description":"When set, we POST the batch.completed event to this URL when all articles finish. Signed with HMAC-SHA256 + your product's webhook_signing_secret."}}}}}},"responses":{"202":{"description":"Batch accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Batch"}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/articles/{id}":{"get":{"operationId":"getArticlesById","summary":"Fetch an article by id (returns content when status=ready)","tags":["Articles"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Article","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Article"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/articles/{id}/publish":{"post":{"operationId":"postArticlesByIdPublish","summary":"Publish a ready article to your connected CMS","description":"Pushes a generated article (status=ready) to the connected CMS or webhook destination. Requires a CMS connected.\n\nReturns 409 `replaces_pre_join_page` when the article is a rewrite of a page published before you joined. We hold no copy of that page, so the rewrite replaces nothing and publishing it alongside the live original creates two pages competing for the same query. Either paste the article's content over your existing post (keeps the URL, its backlinks and its rankings), or take the original down and retry with `replacesOriginal: true` — the draft already carries the original's URL path, so it publishes at the same address.","tags":["Articles"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"replacesOriginal":{"type":"boolean","description":"Only for a pre-join rewrite, and only once the original page has been taken down. Confirms this publish replaces it rather than competing with it."}}}}}},"responses":{"200":{"description":"Published — { url? , status }"},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/batches/{id}":{"get":{"operationId":"getBatchesById","summary":"Fetch batch status + per-article progress","tags":["Articles"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Batch","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Batch"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/optimizations":{"post":{"operationId":"postOptimizations","summary":"Start an optimization analysis (existing article, paste, or URL)","tags":["Optimizer"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["keyword"],"properties":{"keyword":{"type":"string"},"blogPostId":{"type":"string"},"sourceContent":{"type":"string"},"sourceUrl":{"type":"string"}},"description":"Provide exactly one of blogPostId, sourceContent, or sourceUrl."}}}},"responses":{"202":{"description":"Optimization started"},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/optimizations/{id}":{"get":{"operationId":"getOptimizationsById","summary":"Fetch optimization analysis","tags":["Optimizer"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Optimization"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/refresh-candidates":{"get":{"operationId":"getRefreshCandidates","summary":"List published articles needing a refresh (rank decay or stale)","description":"Deprecated. Content Refresh has been folded into Optimize — use POST /api/v1/optimizations (it also refreshes stale content in place). These routes remain for backward compatibility but are no longer the recommended path.","deprecated":true,"tags":["Refresh"],"responses":{"200":{"description":"Candidates"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/refreshes":{"post":{"operationId":"postRefreshes","summary":"Diagnose a published article's decay","description":"Deprecated. Content Refresh has been folded into Optimize — use POST /api/v1/optimizations instead.","deprecated":true,"tags":["Refresh"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["blogPostId"],"properties":{"blogPostId":{"type":"string"}}}}}},"responses":{"202":{"description":"Refresh started"},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/refreshes/{id}":{"get":{"operationId":"getRefreshesById","summary":"Fetch a refresh diagnosis","description":"Deprecated. Content Refresh has been folded into Optimize — use GET /api/v1/optimizations/{id} instead.","deprecated":true,"tags":["Refresh"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Refresh"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/webhook-secret":{"get":{"operationId":"getWebhookSecret","summary":"Get the webhook signing secret","description":"Returns the product's HMAC-SHA256 webhook signing secret. The secret is generated lazily on first call. Receivers store this value and use it to verify the `X-SeoLadders-Signature` header on incoming webhook deliveries.","tags":["Webhooks"],"responses":{"200":{"description":"Signing secret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSecret"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/webhook-secret/rotate":{"post":{"operationId":"postWebhookSecretRotate","summary":"Rotate the webhook signing secret","description":"Generates a fresh signing secret. Any deliveries already in flight will continue to be signed with the OLD secret and may fail receiver-side verification — coordinate the rotation with your receiver so it accepts both old and new during a brief window.","tags":["Webhooks"],"responses":{"200":{"description":"New signing secret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSecret"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/webhook-deliveries":{"get":{"operationId":"getWebhookDeliveries","summary":"List webhook deliveries","description":"Returns this product's webhook deliveries newest-first. Useful for debugging when a receiver missed an event or for monitoring failure rates.","tags":["Webhooks"],"parameters":[{"name":"status","in":"query","required":false,"schema":{"$ref":"#/components/schemas/WebhookDeliveryStatus"},"description":"Optional status filter."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"description":"Number of deliveries to return (max 200)."}],"responses":{"200":{"description":"List of deliveries","content":{"application/json":{"schema":{"type":"object","properties":{"deliveries":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}},"count":{"type":"integer"}}}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/webhook-deliveries/{id}/retry":{"post":{"operationId":"postWebhookDeliveriesByIdRetry","summary":"Retry a failed webhook delivery","description":"Re-enqueues a `failed` or `abandoned` delivery. Resets status to `pending`, resets attempt count to 0, clears any next-retry timestamp, and dispatches a fresh delivery event so the worker picks it up immediately. Returns 400 if the delivery is already `delivered` or still `pending`.","tags":["Webhooks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Delivery re-enqueued","content":{"application/json":{"schema":{"type":"object","properties":{"delivery":{"$ref":"#/components/schemas/WebhookDelivery"}}}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/topics":{"get":{"operationId":"getTopics","summary":"List topical-authority topics","description":"Every topic on the site, each with a coverage rollup (covered / planned / gap keyword counts + coveragePct) and an authority block (what it ranks and is cited for).","tags":["Topics"],"responses":{"200":{"description":"Topics","content":{"application/json":{"schema":{"type":"object","properties":{"topics":{"type":"array","items":{"$ref":"#/components/schemas/Topic"}},"count":{"type":"integer"}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postTopics","summary":"Create a topic","tags":["Topics"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Pillar topic name."},"description":{"type":"string","nullable":true}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"topic":{"$ref":"#/components/schemas/Topic"}}}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/topics/{id}":{"get":{"operationId":"getTopicsById","summary":"Get a topic with its keywords, prompts + coverage","description":"A topic bundles a pillar keyword, its supporting keywords, and the AI prompts (buyer questions) tracked under it — the same cluster shown in the dashboard.","tags":["Topics"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Topic detail","content":{"application/json":{"schema":{"type":"object","properties":{"topic":{"$ref":"#/components/schemas/Topic"},"coverage":{"$ref":"#/components/schemas/Coverage"},"keywords":{"type":"array","items":{"$ref":"#/components/schemas/TopicKeyword"}},"prompts":{"type":"array","items":{"$ref":"#/components/schemas/TopicPrompt"}}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"patchTopicsById","summary":"Rename a topic, edit its description, or set its pillar post","tags":["Topics"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string","nullable":true},"pillarPostId":{"type":"string","nullable":true}}}}}},"responses":{"200":{"description":"Updated"},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteTopicsById","summary":"Delete a topic","tags":["Topics"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/topics/{id}/research":{"post":{"operationId":"postTopicsByIdResearch","summary":"Research keyword candidates for a topic","description":"DataForSEO keyword candidates for the topic (not saved). Metered against the keyword-research quota — returns 429 when spent. Add the ones you want via POST /api/v1/topics/{id}/keywords.","tags":["Topics"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Candidates","content":{"application/json":{"schema":{"type":"object","properties":{"candidates":{"type":"array","items":{"$ref":"#/components/schemas/TopicKeyword"}},"count":{"type":"integer"}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/topics/{id}/keywords":{"post":{"operationId":"postTopicsByIdKeywords","summary":"Add keywords to a topic","description":"Accepts plain strings or objects with metrics. De-duplicates and respects the 30-per-topic cap (only free slots are filled).","tags":["Topics"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["keywords"],"properties":{"keywords":{"type":"array","items":{"oneOf":[{"type":"string"},{"$ref":"#/components/schemas/TopicKeyword"}]}},"source":{"type":"string","enum":["ai","manual","favorite"]}}}}}},"responses":{"200":{"description":"Added","content":{"application/json":{"schema":{"type":"object","properties":{"added":{"type":"array","items":{"$ref":"#/components/schemas/TopicKeyword"}},"count":{"type":"integer"}}}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/topics/{id}/keywords/{keywordId}":{"delete":{"operationId":"deleteTopicsByIdKeywordsByKeywordId","summary":"Remove a keyword from a topic","tags":["Topics"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"keywordId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Removed"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/topics/{id}/prompts":{"get":{"operationId":"getTopicsByIdPrompts","summary":"List the AI prompts tracked under a topic","tags":["Topics"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Topic prompts","content":{"application/json":{"schema":{"type":"object","properties":{"prompts":{"type":"array","items":{"$ref":"#/components/schemas/TopicPrompt"}},"count":{"type":"integer"}}}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postTopicsByIdPrompts","summary":"Track AI prompts under a topic","description":"Adds AI prompts (buyer questions) scoped to the topic. Requires AI Visibility to be set up (an ai_monitor must exist) — returns 409 otherwise. `intent` defaults to \"category\".","tags":["Topics"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["prompts"],"properties":{"prompts":{"type":"array","items":{"type":"string"}},"intent":{"type":"string","enum":["category","comparison","problem","evaluative","organic","brand_specific","competitor_comparison"]}}}}}},"responses":{"200":{"description":"Added","content":{"application/json":{"schema":{"type":"object","properties":{"added":{"type":"array","items":{"$ref":"#/components/schemas/TopicPrompt"}},"skipped":{"type":"array","items":{"type":"string"}},"count":{"type":"integer"}}}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/topics/{id}/prompts/{promptId}":{"delete":{"operationId":"deleteTopicsByIdPromptsByPromptId","summary":"Stop tracking a prompt under a topic","tags":["Topics"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"promptId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Removed"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/projects":{"get":{"operationId":"getProjects","summary":"List your sites (products)","tags":["Account"],"responses":{"200":{"description":"{ projects: [{ id, name, website_url, domain, country }], count }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/integrations":{"get":{"operationId":"getIntegrations","summary":"Connection status for CMS, GSC and webhooks","tags":["Account"],"responses":{"200":{"description":"{ cms: { type, connected, enabled }, gsc: { connected, siteUrl }, webhook: { configured } }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/jobs/{id}":{"get":{"operationId":"getJobsById","summary":"Poll an async job's status","description":"Poll a job started by another endpoint (e.g. a site audit). Keep polling until status is \"completed\" or \"failed\".","tags":["Account"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ id, type, status, output, error, created_at, completed_at }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/rankings":{"get":{"operationId":"getRankings","summary":"Keywords a domain ranks for on Google","tags":["Research"],"parameters":[{"name":"domain","in":"query","schema":{"type":"string"},"description":"Defaults to the resolved site's own domain."},{"name":"limit","in":"query","schema":{"type":"integer","default":50}}],"responses":{"200":{"description":"{ domain, totalCount, itemsCount, keywords: [...], count }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/search-console":{"get":{"operationId":"getSearchConsole","summary":"Google Search Console performance (queries or pages)","description":"The queries or pages the site ranks for, with clicks, impressions, ctr (0–1) and average position. Requires GSC connected (400 otherwise).","tags":["Research"],"parameters":[{"name":"dimension","in":"query","schema":{"type":"string","enum":["query","page"],"default":"query"}},{"name":"days","in":"query","schema":{"type":"integer","default":90}},{"name":"limit","in":"query","schema":{"type":"integer","default":100}}],"responses":{"200":{"description":"{ dimension, days, rows: [...], count }"},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/audit":{"post":{"operationId":"postAudit","summary":"Trigger a technical SEO site audit (async)","description":"Starts an async audit. Poll the returned jobId via GET /api/v1/jobs/{id}, or read the latest with GET /api/v1/audit.","tags":["Research"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"Defaults to the resolved site's domain."}}}}}},"responses":{"200":{"description":"{ jobId, status }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"getAudit","summary":"Read the most recent site audit","tags":["Research"],"responses":{"200":{"description":"{ audit: {...} | null }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/posts":{"get":{"operationId":"getPosts","summary":"List generated / published articles","tags":["Content"],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["draft","published","ready","all"]}},{"name":"limit","in":"query","schema":{"type":"integer","default":50}}],"responses":{"200":{"description":"{ posts: [{ id, blogPostId, title, keyword, status, url, created_at }], count }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/calendar":{"get":{"operationId":"getCalendar","summary":"List content calendar entries","tags":["Content"],"parameters":[{"name":"month","in":"query","schema":{"type":"string"},"description":"Optional YYYY-MM filter."}],"responses":{"200":{"description":"{ entries: [...], count }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postCalendar","summary":"Add a content calendar entry","tags":["Content"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["keyword"],"properties":{"keyword":{"type":"string"},"date":{"type":"string","nullable":true},"status":{"type":"string","nullable":true},"article_type":{"type":"string","nullable":true}}}}}},"responses":{"200":{"description":"{ entry: {...} }"},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/knowledge":{"get":{"operationId":"getKnowledge","summary":"List knowledge sources","tags":["Content"],"responses":{"200":{"description":"{ sources: [...], count }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postKnowledge","summary":"Add a knowledge source (note or URL)","tags":["Content"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["note","url"]},"title":{"type":"string"},"content":{"type":"string","description":"Note body (type=note)."},"url":{"type":"string","description":"URL to crawl (type=url)."}}}}}},"responses":{"200":{"description":"{ source: {...} }"},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/content-radar":{"get":{"operationId":"getContentRadar","summary":"Pages worth acting on (from GSC + rank history)","description":"One unified list of pages to refresh or optimize, bucketed by opportunity. Requires GSC connected — `connected` is false with empty rows otherwise.","tags":["Content"],"responses":{"200":{"description":"{ connected, rows: [...], count }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/content-radar/recommendations":{"post":{"operationId":"postContentRadarRecommendations","summary":"On-page improvement checklist for an external page","tags":["Content"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url","keyword"],"properties":{"url":{"type":"string"},"keyword":{"type":"string"},"bucket":{"type":"string"},"position":{"type":"number"},"ctr":{"type":"number"},"impressions":{"type":"integer"}}}}}},"responses":{"200":{"description":"{ recommendations: [{ title, detail, priority }] }"},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/ai-visibility":{"get":{"operationId":"getAiVisibility","summary":"AI-visibility (GEO) overview across engines","description":"Mentions, share-of-voice, sentiment and per-engine breakdown for the product's primary monitor. `hasData` is false with zeros/empty when there's no monitor or completed run yet.","tags":["AI Visibility"],"responses":{"200":{"description":"{ hasData, monitorId, lastRunAt, visibilityScore, sentiment, perEngine: [...], shareOfVoice: [...], topCitations: [...] }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/ai-visibility/citations":{"get":{"operationId":"getAiVisibilityCitations","summary":"Sources AI cites when answering","tags":["AI Visibility"],"responses":{"200":{"description":"{ hasData, monitorId, citations: [{ domain, count, owned, sourceType, pct }], count }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/ai-visibility/sentiment":{"get":{"operationId":"getAiVisibilitySentiment","summary":"Sentiment breakdown across engines","tags":["AI Visibility"],"responses":{"200":{"description":"{ hasData, monitorId, current, trend: [...], byType: [...], byEngine: [...], distribution: {...}, responses: [...] }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/ai-visibility/sources":{"get":{"operationId":"getAiVisibilitySources","summary":"Where AI pulls answers (socials / offsite / owned pages)","tags":["AI Visibility"],"responses":{"200":{"description":"{ hasData, monitorId, socials: [...], offsite: [...], pages: [...] }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/ai-visibility/content-gaps":{"get":{"operationId":"getAiVisibilityContentGaps","summary":"Buyer questions where AI names rivals, not you","tags":["AI Visibility"],"responses":{"200":{"description":"{ hasData, monitorId, gaps: [{ promptId, prompt, intentLabel, brandPct, missing, total, competitors, severity }], count }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postAiVisibilityContentGaps","summary":"Mark a content gap done, or reopen it","description":"Body: { promptId, status: 'done' | 'reopen' }. Marks the gap for that prompt as handled so it drops off the open list — or reopens it.","tags":["AI Visibility"],"responses":{"200":{"description":"{ ok: true }"},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/prompts":{"get":{"operationId":"getPrompts","summary":"List tracked AI prompts + cap usage","tags":["AI Visibility"],"responses":{"200":{"description":"{ prompts: [{ id, text, intent, isActive }], used, cap, remaining }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postPrompts","summary":"Track new AI prompts (cap-aware)","description":"Adds up to `remaining`; anything over the plan cap is reported in `skipped`.","tags":["AI Visibility"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["prompts"],"properties":{"prompts":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"{ added: [...], skipped: [string], used, cap, remaining, message? }"},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/prompts/explorer":{"get":{"operationId":"getPromptsExplorer","summary":"Suggested prompts to track (from real demand)","description":"source=gsc (from Search Console queries) | keywords (from ranked + saved keywords) | paa (Google People-Also-Asked for `seed`, seed required).","tags":["AI Visibility"],"parameters":[{"name":"source","in":"query","required":true,"schema":{"type":"string","enum":["gsc","keywords","paa"]}},{"name":"seed","in":"query","schema":{"type":"string"},"description":"Required for source=paa."}],"responses":{"200":{"description":"{ source, suggestions: [{ text, intentType }], sourceLabel, note?, needsConnect? }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/competitors":{"get":{"operationId":"getCompetitors","summary":"Tracked + suggested competitors","tags":["AI Visibility"],"responses":{"200":{"description":"{ tracked, ignored, suggestions: [{ name, count }], slots: { used, cap, remaining } }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postCompetitors","summary":"Track competitors (cap-aware)","tags":["AI Visibility"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"names":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"{ added, skipped, tracked, slots }"},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteCompetitors","summary":"Untrack a competitor","tags":["AI Visibility"],"parameters":[{"name":"name","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ tracked, slots }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/actions":{"get":{"operationId":"getActions","summary":"Recommended actions / suggestions","tags":["Autopilot"],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["suggested","dismissed","todo","in_progress","done"],"default":"suggested"}}],"responses":{"200":{"description":"{ actions: [{ id, type, priority, title, body }], count }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/autoblog/autofill":{"post":{"operationId":"postAutoblogAutofill","summary":"Toggle AutoBlog calendar auto-refill","description":"When on, the scheduler refills the content calendar each billing cycle.","tags":["Autopilot"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["enabled"],"properties":{"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"{ autofill: boolean, message: string }"},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/link-building":{"get":{"operationId":"getLinkBuilding","summary":"List link-building prospects","description":"Page-level link opportunities seeded from AI-visibility citations: the specific pages AI cites for your prompts, classified by action motion, with exempt sources (yours, competitors, infra, pages that already list you) filtered out. Each carries a quality score (0-100, weighted toward citation demand over raw DR); top targets are enriched with DR, a contact discovered from the page's byline, a mapped owned page, and a drafted pitch. You send it yourself.","tags":["Link Building"],"responses":{"200":{"description":"{ targets: [{ id, domain, source_url, source_title, page_type, motion, enriched, source_type, citation_count, dr, quality_score, quality_reason, contact_email, contact_name, contact_confidence, contact_depth, mapped_page_url, draft_subject, draft_body, status, link_live, link_anchor, link_dofollow, ... }], count }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postLinkBuilding","summary":"Refresh link-building prospects from the latest AI-visibility run","description":"(Re)builds targets from the non-owned domains AI cites for your prompts — enriches DR + drafts emails, preserving existing workflow. Needs a completed AI-visibility run.","tags":["Link Building"],"responses":{"200":{"description":"{ ok, added, targets } — or { ok:false, reason, message } when there's no monitor/run/targets yet"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/link-building/{id}":{"patch":{"operationId":"patchLinkBuildingById","summary":"Update a prospect (status, notes, draft, contact)","tags":["Link Building"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["prospect","drafted","contacted","replied","won","lost","rejected"]},"notes":{"type":"string"},"draftSubject":{"type":"string"},"draftBody":{"type":"string"},"followupSubject":{"type":"string"},"followupBody":{"type":"string"},"contactEmail":{"type":"string"},"contactUrl":{"type":"string"}}}}}},"responses":{"200":{"description":"{ target }"},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/link-building/{id}/followup":{"post":{"operationId":"postLinkBuildingByIdFollowup","summary":"Draft a follow-up email for a contacted target","description":"Grounded in the first email. Persists followup_subject/body on the target. You send it yourself.","tags":["Link Building"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ target }"},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/settings/auto-publish":{"post":{"operationId":"postSettingsAutoPublish","summary":"Toggle auto-publish to your connected CMS","description":"When on, newly-generated (ready) articles are pushed to the connected CMS. Requires a CMS connected first.","tags":["Autopilot"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["enabled"],"properties":{"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"{ autoPublish: boolean, message: string }"},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"tags":[{"name":"Research","description":"Keywords, rankings, Search Console + site audit"},{"name":"Articles","description":"Single + batch article generation"},{"name":"Optimizer","description":"Pre-publish article analysis"},{"name":"Refresh","description":"Deprecated — folded into Optimizer"},{"name":"Topics","description":"Topical authority — topic clusters, keyword coverage + tracked AI prompts"},{"name":"AI Visibility","description":"GEO — score, citations, sentiment, sources, content gaps, prompts + competitors"},{"name":"Content","description":"Posts, content calendar, knowledge base + content radar"},{"name":"Autopilot","description":"Recommended actions + automation toggles"},{"name":"Get Cited","description":"Earn citations in the sources AI trusts — page-level targets across publishers, communities, reviews + video, with drafted outreach + status"},{"name":"Account","description":"Sites, integrations status + async jobs"},{"name":"Webhooks","description":"Signing secrets and delivery introspection"}]}