{"info":{"version":"0.3.1","description":"The writing surface (#3966) — base `/api/v0`, unstable, will change (design A §5.7). Composition lives in `Beacon.Writing.Agent`; `x-mcp-*` extensions identify operations with direct MCP peers. Writing-gated operations return 403 writing_not_enabled when writing is disabled for the acting organization; check GET /api/v0/whoami and contact an administrator to enable writing.","title":"Collimer Writing API","contact":{"name":"Collimer","url":"https://app.collimer.com"},"license":{"name":"Proprietary","identifier":"LicenseRef-Proprietary"}},"components":{"parameters":{"Org":{"in":"query","name":"org","description":"Which org to act as, by slug or id. Required when a credential's ceiling spans more than one org.","required":false,"schema":{"type":"string"}}},"securitySchemes":{"bearerAuth":{"scheme":"bearer","type":"http"}},"schemas":{"BrandDetails":{"type":"object","properties":{"handle":{"type":"string"},"name":{"type":"string"},"domain":{"type":"string"},"location":{"type":["string","null"]},"url":{"type":["string","null"]},"business_type":{"type":["string","null"]},"competitor_domains":{"type":"object","additionalProperties":{"type":"string"}},"competitors":{"type":"array","items":{"type":"string"}},"icp":{"type":["string","null"]},"business_type_source":{"type":["string","null"]},"business_type_confidence":{"type":["number","null"]},"voice":{"type":["object","null"],"properties":{"tone":{"type":"string"},"traits":{"type":"array","items":{"type":"string"}}},"additionalProperties":false},"docs_url":{"type":["string","null"]},"allowed_business_types":{"type":"array","items":{"type":"string"}}}},"BrandListEntry":{"type":"object","properties":{"org":{"type":"object","properties":{"slug":{"type":"string"}}},"project":{"$ref":"#/components/schemas/ProjectSummary"},"needs_review":{"type":"integer","description":"Articles a person is sitting on (stage needs_review)."},"needs_attention":{"type":"integer","description":"Articles carrying a fault — an error flag or a grounding gap."},"last_activity":{"type":["string","null"],"format":"date-time"}}},"ClaimCheck":{"type":"object","description":"One claim's verification state. Three states, never a boolean — a claim nobody searched must never read the same as one that was searched and not confirmed.","required":["state"],"properties":{"reason":{"type":["string","null"]},"state":{"type":"string","enum":["confirmed_present","searched_and_not_found","not_searched"]},"query":{"type":["string","null"],"description":"The claim as it was put to the judge. Only set for `searched_and_not_found` — the other two states ran no query."},"feature":{"type":["string","null"],"description":"The comparison-table feature name, where the claim came from one."},"claim":{"type":["string","null"],"description":"The claim text itself; null for a table row that was never judged."},"block_index":{"type":["integer","null"],"description":"The block index anchor_quote resolves to, or null with it."},"anchor_quote":{"type":["string","null"],"description":"The exact sentence in the article's body_md this claim was read from. Null for `not_searched`, or when the anchor could not be verified against the article body."}}},"EditItem":{"type":"object","required":["type"],"properties":{"scope":{"type":"string","enum":["document"],"description":"instruction only. \"document\" applies the instruction to the whole article — same effect as leaving anchor blank, spelled out for clarity. Leave anchor blank when this is set."},"type":{"type":"string","enum":["instruction","verbatim","insert","delete"]},"payload":{"type":"string","description":"The replacement text, instruction, or insertion content. verbatim and insert payloads are stored unchecked — they never go through generation or fact-check, so a numeric claim written here is the caller's responsibility; a fabricated statistic is flagged (unverified_numeric_claims) at approval rather than caught before it is stored (#4398)."},"anchor":{"type":"string","description":"A quote from the article. Required for verbatim/delete; optional for insert and instruction. Matched against the block's rendered text, so markdown syntax in the quote (a `## ` heading marker, `[link](url)` brackets, `**bold**`/`_em_` markers, `` `code` `` ticks) is tolerated — quote straight out of body_md, markup and all (#4396). Leave blank on an instruction to apply it to the whole document instead of one block."}},"additionalProperties":false},"Error":{"type":"object","description":"The envelope for `/api/v0` errors.","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"fields":{"type":"object","description":"Per-field messages for validation_failed responses, keyed by field name.","additionalProperties":{"type":"array","items":{"type":"string"}}},"limit":{"type":"integer"},"candidates":{"type":"array","items":{"type":"object","properties":{"handle":{"type":"string"},"org":{"type":"string"},"last_activity":{"type":["string","null"],"format":"date-time"}}}},"retry_after":{"type":"integer"},"base_revision_id":{"type":"string"}},"additionalProperties":true}}},"ProjectSummary":{"type":"object","properties":{"handle":{"type":"string","description":"Opaque — pass it to later operations."},"name":{"type":"string"},"domain":{"type":"string"}}},"Recommendation":{"type":"object","description":"Belongs to a run, not a project — see GET /work?kind=recommendation&run= for how a list of these is reached.","required":["id","run_id","status"],"properties":{"id":{"type":"string","format":"uuid"},"priority":{"type":"integer","description":"The rank — ascending, so 0/1 is the top recommendation. The one field to sort or filter on for \"most important first\"; `severity` below is a class, not a competing order."},"status":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"effort":{"type":["string","null"]},"severity":{"type":["string","null"],"description":"A finding class (p0/p1/p2), not a rank — one input to `priority`'s calculation alongside effort and confidence, so two recs at the same severity can land at different priority. Use `priority` to sort or find the top recommendations."},"rewrite":{"type":["string","null"]},"inserted_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"issue":{"type":["string","null"]},"evidence":{"type":"array","items":{"type":"string"}},"run_id":{"type":"string","format":"uuid"},"confidence":{"type":"number"},"expected_impact":{"type":["string","null"]},"existing_url":{"type":["string","null"],"description":"The live page this diagnoses; null when no existing page was found."},"verification_status":{"type":"string"},"dismiss_reason":{"type":["string","null"]},"implementation_note":{"type":["string","null"]},"implemented_at":{"type":["string","null"],"format":"date-time"},"verification_checked_at":{"type":["string","null"],"format":"date-time"},"verification_evidence":{"type":"object"},"article":{"type":["object","null"],"description":"The most recently updated article this recommendation produced, if any — kept for callers reading this key alone. See `articles` for the full set.","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"stage":{"type":"string"}}},"articles":{"type":"array","description":"Every live article this recommendation produced, newest-updated first — recommendation_id is 1:many, not 1:1.","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"stage":{"type":"string"}}}}}},"ResolvedBrand":{"type":"object","properties":{"org":{"type":"object","properties":{"slug":{"type":"string"}}},"project":{"$ref":"#/components/schemas/ProjectSummary"},"pages":{"type":"array","items":{"type":"string"}},"latest_run":{"type":["object","null"],"properties":{"id":{"type":"string"},"ci":{"type":["array","null"],"items":{"type":"number"},"maxItems":2,"minItems":2},"finished_at":{"type":["string","null"],"format":"date-time"},"score":{"type":"number"}}}}},"ScanResult":{"type":"object","description":"Shared by createScan and getScanStatus — a receipt or a finished teaser.","required":["status","scan_token","report_url"],"properties":{"error":{"type":["object","null"],"description":"Present only when status is \"failed\".","properties":{"message":{"type":"string"},"reason":{"type":"string"},"retryable":{"type":"boolean"}}},"status":{"type":"string","enum":["running","complete","failed"]},"scan_token":{"type":"string","description":"Pass this to GET /api/v0/scans/{scan_token}."},"brand":{"type":["string","null"]},"score":{"type":["number","null"]},"confidence_interval":{"type":["object","null"],"properties":{"upper":{"type":"integer"},"lower":{"type":"integer"},"plus_minus":{"type":"integer"}}},"crawlability_files":{"type":["object","null"],"description":"Per-scan found, missing, or unknown host file checks.","properties":{"json_ld":{"type":"object"},"llms_txt":{"type":"object"},"robots_txt":{"type":"object"},"sitemap":{"type":"object"}}},"recommendations_total":{"type":["integer","null"]},"report_url":{"type":"string"},"top_gap":{"type":["object","null"],"properties":{"title":{"type":"string"},"impact":{"type":["object","null"]}}}}},"WhoamiAddressableOrg":{"type":"object","required":["slug","name","writing_enabled"],"properties":{"name":{"type":"string"},"slug":{"type":"string"},"writing_enabled":{"type":"boolean"}}},"WhoamiIdentity":{"type":"object","required":["kind","acting_org","addressable_orgs","scopes","effective_scopes","requestable_scopes","writing_enabled","project_limit","plan","audits"],"properties":{"user":{"type":["object","null"],"description":"null for an unowned API key (#4408) — there is nothing to disclose either way. Absent entirely (not present as null) for an OAuth grant, or an owned API key, that does not hold the identity:read scope (#4351).","properties":{"id":{"type":"string"},"email":{"type":["string","null"]}}},"plan":{"type":["string","null"],"description":"The acting org's plan, or null when there is no single acting org."},"kind":{"type":"string","enum":["api_key","oauth_grant"],"description":"Which credential shape answered — never gated on scope (#4408)."},"scopes":{"type":"array","items":{"type":"string"}},"requestable_scopes":{"type":"array","description":"Scopes this authenticated user can request and use now, including staff-only scopes for a live super admin.","items":{"type":"object","required":["name","description"],"properties":{"name":{"type":"string"},"description":{"type":"string"}}}},"writing_enabled":{"type":["boolean","null"],"description":"null alongside a null acting_org — it is a property of one org."},"acting_org":{"description":"null when the ceiling holds anything other than exactly one org — no membership at all, or more than one.","$ref":"#/components/schemas/WhoamiOrg"},"addressable_orgs":{"type":"array","description":"Exactly the live ceiling full_authorized_orgs/2 returns — never broader. Each entry reports whether writing is currently enabled for that org.","items":{"$ref":"#/components/schemas/WhoamiAddressableOrg"}},"audits":{"type":["object","null"],"description":"The acting org's UTC daily audit allowance, or null without one acting org.","required":["used","limit","resets_at"],"properties":{"used":{"type":"integer"},"limit":{"type":"integer"},"resets_at":{"type":"string","format":"date-time"}}},"effective_scopes":{"type":["array","object","null"],"description":"Scopes usable after live role restrictions: a list for one addressable org, a map keyed by addressable org slug for multiple orgs, or null for none.","items":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}}},"project_limit":{"type":["object","null"],"properties":{"used":{"type":"integer"},"cap":{"type":["integer","string"],"description":"An integer, or \"unlimited\"."}}}}},"WhoamiOrg":{"type":["object","null"],"properties":{"name":{"type":"string"},"slug":{"type":"string"}}}},"responses":{"Forbidden":{"description":"The credential lacks permission or access to this org.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Too many requests or the organization's quota is exhausted.","headers":{"RateLimit-Limit":{"description":"Requests allowed in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the window resets.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing or invalid credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/api/v0/articles/{id}/export":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"query","name":"format","required":true,"schema":{"type":"string","enum":["md","html","wxr"]}},{"in":"query","name":"inline","description":"No-op over HTTP — this endpoint always returns the full file inline. Present only for parity with the export_article MCP tool's argument of the same name (#4399), where a client without resources/read opts in to receiving the file bytes in the tool result rather than a link.","schema":{"type":"boolean"}},{"in":"query","name":"preview_lines","description":"Return only the file's first N lines instead of the whole export (#4399).","schema":{"type":"integer","minimum":1}},{"$ref":"#/components/parameters/Org"}],"summary":"Export an article's latest revision as md, html, or wxr","responses":{"200":{"description":"The exported artifact's raw bytes — not the {data, resolved, hint} envelope (A §5.6). `x-collimer-revision-number` and `x-collimer-tables-stripped` response headers carry what `resolved` would otherwise say.","content":{"application/xml":{"schema":{"type":"string"}},"text/html":{"schema":{"type":"string"}},"text/markdown":{"schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks `articles:read`, or writing_not_enabled — writing is disabled for this organization.","$ref":"#/components/responses/Forbidden"},"404":{"description":"Unknown article, wrong org, or no revision yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`format` is missing or not one of md, html, wxr.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"exportArticle","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"articles:read","x-mcp-tool-name":"export_article"}},"/api/v0/runs/{run_id}":{"get":{"parameters":[{"in":"path","name":"run_id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"Run detail, including prompts and scalar results","responses":{"200":{"description":"A run and its prompt results.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object"},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":"string"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks audits:read.","$ref":"#/components/responses/Forbidden"},"404":{"description":"Run missing or outside the credential's ceiling.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getRun","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"audits:read","x-mcp-tool-name":"get_run","x-mcp-title":"Get run"}},"/api/v0/articles/{id}/feedback":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"statuses","description":"Comma-separated feedback statuses, including abandoned.","schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"List reviewer feedback for an article","responses":{"200":{"description":"Reviewer notes.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"type":"object"},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":"null"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Article not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid statuses; use a comma-separated list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"listFeedback","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"articles:read","x-mcp-tool-name":"list_feedback"},"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/Org"}],"summary":"Queue a reviewer note without starting a revision","responses":{"201":{"description":"Queued reviewer note."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Credential lacks articles:write.","$ref":"#/components/responses/Forbidden"},"404":{"description":"Article not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Base revision is stale.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"validation_failed with per-field errors in error.fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"createFeedback","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","block_index"],"properties":{"type":{"type":"string","enum":["instruction","verbatim","insert","delete"]},"payload":{"type":"string"},"block_index":{"type":"integer"},"anchor_quote":{"type":"string"},"base_revision_id":{"type":"string"}}}}}},"security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:write","x-mcp-tool-name":"create_feedback"}},"/api/v0/articles/{id}/stat-candidates/find":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/Org"},{"in":"header","name":"Idempotency-Key","description":"Replays a successful response for the same organization, route and body within five minutes. An overlapping request returns 409; retry after the first completes.","required":false,"schema":{"type":"string","maxLength":255,"minLength":1}}],"summary":"Find sourced statistic candidates for an article","responses":{"202":{"description":"Search queued; poll the receipt endpoint for its result.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object","required":["status","receipt_id"],"properties":{"status":{"type":"string","enum":["pending"]},"receipt_id":{"type":"string"}}},"resolved":{"type":"object"},"hint":{"type":"string"},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid API key.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the `articles:write` scope.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such article for this credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Key in use or reused with different input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"quota_exceeded — this organization's writing quota is exhausted.","$ref":"#/components/responses/RateLimited"},"503":{"description":"The search could not be queued.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"findStatCandidates","security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:write","x-mcp-tool-name":"find_stat_candidates","x-mcp-destructive":false,"x-mcp-hint-template":"Poll the returned receipt for verified candidates.","x-mcp-title":"Find statistic candidates"}},"/api/v0/drafts/score":{"post":{"description":"For a URL, the page title is frozen: data.title_frozen is true and title_alignment is omitted from data.subs and explained in data.omitted; remaining weights are renormalized. Raw content keeps title_alignment and returns title_frozen false.","parameters":[{"$ref":"#/components/parameters/Org"}],"summary":"Stateless citability scoring for a draft or an external URL","responses":{"200":{"description":"The composite score, per-signal detail, and evidence-cited suggestions.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"type":"object","required":["citability","title_frozen","omitted","subs","suggestions"],"properties":{"suggestions":{"type":"array","items":{"type":"object"}},"subs":{"type":"object"},"citability":{"type":"integer"},"title_frozen":{"type":"boolean","description":"True for a URL; title_alignment is omitted from subs."},"omitted":{"type":"object","description":"Reasons for reported omissions, keyed by subscore name.","additionalProperties":{"type":"string"}}}},"resolved":{"type":"object"},"hint":{"type":"string"},"url":{"type":"null","description":"Always null — a stateless score has no persisted page."}}}}}},"401":{"description":"Missing or invalid API key.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks `drafts:score`, or writing_not_enabled — writing is disabled for this organization.","$ref":"#/components/responses/Forbidden"},"404":{"description":"`project` does not resolve for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Neither or both of `content`/`url`, an invalid `type`, or the URL couldn't be fetched/rendered.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"scoreDraft","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["article","buyer_guide","comparison_page","narrative"],"description":"The article type driving the rubric. Defaults to \"article\"."},"url":{"type":"string","description":"A URL not already in Collimer to fetch and score. Mutually exclusive with `content`."},"content":{"type":"string","description":"The draft's raw markdown. Mutually exclusive with `url`."},"project":{"type":"string","description":"Optional project id, scoped to the caller's org."},"target_queries":{"type":"array","description":"Optional search queries to score title alignment against, instead of the project's probe prompts.","items":{"type":"string"}}}}}}},"security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"drafts:score","x-mcp-tool-name":"score_draft","x-mcp-destructive":false,"x-mcp-hint-template":"Every subscore is already at max — nothing to fix. | See `suggestions`, ranked worst subscore first.","x-mcp-title":"Score a draft"}},"/api/v0/brands/details":{"get":{"parameters":[{"in":"query","name":"handle","required":false,"schema":{"type":"string"}},{"in":"query","name":"domain","required":false,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"Read a brand's customer-editable context and classification","responses":{"200":{"description":"Brand context, business classification and allowed types.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"project":{"$ref":"#/components/schemas/BrandDetails"}}},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":"string"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No such brand in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getBrand","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"brands:read","x-mcp-tool-name":"get_brand"}},"/api/v0/articles/{id}/abandon":{"post":{"description":"Cancels live writing-queue jobs before recovering a stuck drafting article. The article returns to idea when no revision exists, otherwise needs_review. In-flight feedback becomes abandoned by default and is returned in discarded_feedback; queued notes outside the pass remain queued. keep_queued true retains all feedback for a later pass.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/Org"}],"summary":"Cancel an article's writing pass and recover its stage","responses":{"200":{"description":"The recovered article stage.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object","required":["id","stage","discarded_feedback"],"properties":{"id":{"type":"string"},"stage":{"type":"string"},"discarded_feedback":{"type":"array","items":{"type":"object","required":["id","type","payload","status"],"properties":{"id":{"type":"string"},"status":{"type":"string","enum":["abandoned"]},"type":{"type":"string"},"payload":{"type":"string"}}}}}},"resolved":{"type":"object","required":["to"],"properties":{"to":{"type":"string"}}},"hint":{"type":"null"},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the required scope.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such article for this credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The article is not drafting (not_drafting).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"keep_queued must be a boolean.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"abandonPass","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"keep_queued":{"default":false,"type":"boolean"}}}}}},"security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:write","x-mcp-tool-name":"abandon_pass"}},"/api/v0/articles/{id}/restart":{"post":{"description":"Returns a scored or needs_review article to idea without deleting its id or revision history, and records the credential's actor in the audit log.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/Org"}],"summary":"Restart a scored or review-stage article","responses":{"200":{"description":"The restarted article at idea stage.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object","required":["id","stage"],"properties":{"id":{"type":"string"},"stage":{"type":"string","enum":["idea"]}}},"resolved":{"type":"object","required":["to"],"properties":{"to":{"type":"string","enum":["idea"]}}},"hint":{"type":"null"},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the required scope.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such article for this credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"not_restartable or stage_conflict — see error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"restartArticle","security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:write","x-mcp-tool-name":"restart_article"}},"/api/v0/articles/{id}/restore":{"post":{"description":"Inserts a new revision whose content equals an earlier revision's — history is never rewritten, so this is an undo that adds to the record rather than erasing anything. Approved, published, or verified articles return to needs_review after a restore and require approval again. The response is the same shape GET /articles/:id returns, so it doubles as an immediate read of the revision this just created.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/Org"}],"summary":"Get back to an earlier body (#4404)","responses":{"200":{"description":"The same envelope GET /articles/:id returns.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"type":"object"},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":"string","description":"The article's review page (#3984)."}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the required scope.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such article for this credential, or no_revision / revision_not_found — see error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"restore_conflict — a concurrent restore won the (article, revision number) race. Retryable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`revision` wasn't a positive integer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"restoreArticle","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["revision"],"properties":{"revision":{"type":"integer","description":"The revision number to restore as a new, current revision.","minimum":1}}}}}},"security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:write","x-mcp-tool-name":"restore_article","x-mcp-destructive":false,"x-mcp-title":"Restore article revision"}},"/api/v0/changes":{"get":{"description":"Call without a cursor to start from now with no backlog. Subsequent calls return up to 100 changes and a new cursor. Cursors belong to one organization and expire after 183 days. Invalid, expired, and wrong-org cursors return their status with a fresh cursor instead of a backlog.","parameters":[{"in":"query","name":"cursor","schema":{"type":"string"}},{"in":"query","name":"org","description":"Acting organization slug or id, required for ambiguous credentials.","schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"Poll for completed work changes in the acting organization","responses":{"200":{"description":"The same payload as list_changes structuredContent.","content":{"application/json":{"schema":{"type":"object","required":["status","org_id","cursor","coverage","uncovered","changes","message"],"properties":{"message":{"type":["string","null"]},"status":{"type":"string","enum":["initialized","changes","empty","partial","expired_cursor","invalid_cursor","wrong_org"]},"coverage":{"type":"array","items":{"type":"string"}},"cursor":{"type":"string"},"changes":{"type":"array","items":{"type":"object"}},"org_id":{"type":"string"},"uncovered":{"type":"array","items":{"type":"string"}}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"Missing articles:read scope or ambiguous organization.","$ref":"#/components/responses/Forbidden"},"422":{"description":"The requested organization is not accessible.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"listChanges","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"articles:read","x-mcp-tool-name":"list_changes"}},"/api/v0/articles/{id}/generate":{"post":{"description":"The idea → draft arrow create_idea has no other route to: no fetch, just a generate pass, so this returns a receipt rather than the article. Refuses if the article already has a revision, or a pass is already running.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/Org"}],"summary":"Queue the first draft for an idea-stage article","responses":{"202":{"description":"Accepted. The generate pass finishes on its own; poll GET /articles/{id} until the expected revision exists.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object","required":["id","eta_seconds"],"properties":{"id":{"type":"string"},"eta_seconds":{"type":"integer"}}},"resolved":{"type":"object","required":["article_id"],"properties":{"article_id":{"type":"string"}}},"hint":{"type":"string"},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the required scope.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such article for this credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"already_has_revision — see error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"generate_in_progress — a pass is already running; retry_after names the wait.","$ref":"#/components/responses/RateLimited"}},"operationId":"generateArticle","security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:write","x-mcp-tool-name":"generate_article"}},"/api/v0/articles/clone":{"post":{"description":"Fetch plus a full generate pass, so this one returns a receipt rather than the article. Behind its own scope: articles:clone is deliberately not part of the advertised catalog while the provenance question is open.","parameters":[{"$ref":"#/components/parameters/Org"},{"in":"header","name":"Idempotency-Key","description":"Replays a successful response for the same organization, route and body within five minutes. An overlapping request returns 409; retry after the first completes.","required":false,"schema":{"type":"string","maxLength":255,"minLength":1}}],"summary":"Write a new version of a page with different context","responses":{"202":{"description":"Accepted. The generate pass finishes on its own; poll GET /articles/{id} until the expected revision exists — the same URI Location names.","headers":{"Location":{"description":"The created (or resolved) resource's own API path.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object","required":["article","eta_seconds"],"properties":{"eta_seconds":{"type":"integer"},"article":{"type":"object","required":["id"],"properties":{"id":{"type":"string"},"source_url":{"type":["string","null"]}}}}},"resolved":{"type":"object","required":["handle"],"properties":{"handle":{"type":"string"},"matched_host":{"type":["string","null"]}}},"hint":{"type":"string"},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the required scope.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No writing-enabled brand for this credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Key in use or reused with different input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request — see error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"cloneArticle","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["project","like_url"],"properties":{"type":{"type":"string"},"context":{"type":"string"},"title":{"type":"string"},"template_id":{"type":"string"},"project":{"type":"string"},"target_queries":{"type":"array","items":{"type":"string"}},"destination_platform":{"type":"string"},"byline_author":{"type":"string"},"image_prompt":{"type":"string"},"like_url":{"type":"string"},"publish_on":{"type":"string"},"recommendation_id":{"type":"string"},"reference_material":{"type":"string"},"structural_exemplar":{"type":"string"},"subject_competitor":{"type":"string"}}}}}},"security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:clone","x-mcp-tool-name":"clone_article"}},"/api/v0/articles/{id}/feedback/{feedback_id}":{"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"feedback_id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"Discard your queued reviewer note","responses":{"200":{"description":"Note discarded."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Credential lacks scope or caller is not the note's author.","$ref":"#/components/responses/Forbidden"},"404":{"description":"Article or note not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Note is no longer queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"discardFeedback","security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:write","x-mcp-tool-name":"discard_feedback"}},"/api/v0/rubric":{"get":{"description":"The full rubric includes title_alignment. URL scoring and article import freeze the page title, omit title_alignment, and renormalize the remaining weights.","parameters":[{"in":"query","name":"type","description":"The article type driving the rubric. article and buyer_guide are identical today — the scorer has never told them apart.","required":false,"schema":{"default":"article","type":"string","enum":["article","buyer_guide","comparison_page","narrative"]}},{"in":"header","name":"If-None-Match","description":"A prior response's ETag. Returns 304 with an empty body when unchanged.","required":false,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"The scoring rubric a score is measured against, as data","responses":{"200":{"description":"Every sub-signal this type's rubric measures, weighted and versioned.","headers":{"ETag":{"description":"A strong hash of the body. Send back as If-None-Match to conditionally refetch.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"type":"object","properties":{"type":{"type":"string"},"rubric_version":{"type":"string"},"subscores":{"type":"array","items":{"type":"object"}}}},"resolved":{"type":"object"},"hint":{"type":"string"},"url":{"type":"null","description":"Always null — the rubric is a reference document."}}}}}},"304":{"description":"Unchanged since the given If-None-Match.","headers":{"ETag":{"description":"A strong hash of the body. Send back as If-None-Match to conditionally refetch.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid API key.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks `articles:read`, or writing_not_enabled — writing is disabled for this organization.","$ref":"#/components/responses/Forbidden"},"422":{"description":"`type` isn't a valid article type.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getRubric","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"articles:read","x-mcp-tool-name":"rubric","x-mcp-destructive":false,"x-mcp-hint-template":"See `subscores[].raises_it` to fix a weak one.","x-mcp-title":"Scoring rubric"}},"/api/v0/projects/{project_id}/recap":{"get":{"description":"Mirrors BeaconWeb.RecapPdfController's paid-plan gate (Beacon.Orgs.paid_plan?/1) — refused for a free-plan org. Returns Beacon.Recap.RecapContent.build/2's structured result plus a markdown rendering.","parameters":[{"in":"path","name":"project_id","required":true,"schema":{"type":"string"}},{"in":"query","name":"month","description":"YYYY-MM. Defaults to the last complete calendar month.","schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"The monthly exec recap for a project (#4734)","responses":{"200":{"description":"The recap envelope.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object"},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"402":{"description":"The org is not on a paid plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential lacks recommendations:read and/or articles:read.","$ref":"#/components/responses/Forbidden"},"404":{"description":"Project missing, outside the credential's ceiling, or no completed scans yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid month; expected YYYY-MM.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getRecap","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":["recommendations:read","articles:read"],"x-mcp-tool-name":"get_recap","x-mcp-title":"Get recap"}},"/api/v0/recommendation-runs/{run_id}/verification":{"post":{"parameters":[{"in":"path","name":"run_id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"},{"in":"header","name":"Idempotency-Key","description":"Replays a successful response for the same organization, route and body within five minutes. An overlapping request returns 409; retry after the first completes.","required":false,"schema":{"type":"string","maxLength":255,"minLength":1}}],"summary":"Queue verification for all recommendations in an audit run","responses":{"202":{"description":"Verification receipt with eta_seconds and poll hint.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object"},"resolved":{"type":"object"},"hint":{"type":"string"},"url":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No such audit run.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Key in use or reused with different input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"verifyRunRecommendations","security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"recommendations:write","x-mcp-tool-name":"verify_recommendation","x-mcp-title":"Verify recommendation","x-mcp-multi-route":true}},"/api/v0/articles/{id}/claim-checks":{"post":{"description":"Queues a fresh fact-check over the article's latest revision. Poll GET /articles/{id}/writing-jobs/claim_check/{receipt_id} for the result. The completed result returns one of three states per claim, never a boolean. `not_searched` means nobody actually checked it — a skipped comparison-table cell, or a run in which no source material was fetched and no judge call ran. Results are persisted onto the article, which is what the approval gate reads. A comparison_page whose competitor has no domain confirmed yet gets a `422 no_source_material` instead of a run — retrying it can never succeed until competitor_domains is set on PATCH /brands/{handle} with the exact comparison-table competitor name.","parameters":[{"in":"path","name":"id","description":"The article id, from get_article or list_work.","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/Org"},{"in":"header","name":"Idempotency-Key","description":"Replays a successful response for the same organization, route and body within five minutes. An overlapping request returns 409; retry after the first completes.","required":false,"schema":{"type":"string","maxLength":255,"minLength":1}}],"summary":"Queue a fact-check of an article's claims against fresh source material","responses":{"202":{"description":"Claim-check receipt. A retry while the job is live returns the same receipt.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"type":"object","required":["article_id","receipt_id","status","eta_seconds"],"properties":{"status":{"type":"string","enum":["pending"]},"article_id":{"type":"string","format":"uuid"},"receipt_id":{"type":"string"},"eta_seconds":{"type":"integer"}}},"resolved":{"type":"object","properties":{"article_id":{"type":"string","format":"uuid"},"receipt_id":{"type":"string"}}},"hint":{"type":"string"},"url":{"type":"null","description":"Always null today — not yet wired for this operation (#3984)."}}}}}},"401":{"description":"Missing or invalid API key.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks `articles:write`, or writing_not_enabled — writing is disabled for this organization.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such article for this credential's org, the article has no revision yet (`no_revision`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Key in use or reused with different input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`no_source_material` — this comparison_page's competitor has no domain confirmed yet, so nothing could be searched.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"description":"`job_conflict_unresolved` — the claim-check job is not visible yet; retry shortly.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"checkClaims","security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:write","x-mcp-tool-name":"check_claims"}},"/api/v0/articles/{id}/stage":{"post":{"description":"published_url is only ever written by a person. Publishing and overriding the approval gate both require a user-bearing credential, not an API key: an org credential acting as an org cannot make the statement those records carry.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/Org"}],"summary":"Move an article's stage — approve, publish, or send back","responses":{"200":{"description":"The article at its new stage.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object","required":["id","stage"],"properties":{"id":{"type":"string"},"stage":{"type":"string","enum":["approved","published","needs_review"]},"override_reason":{"type":["string","null"]},"published_url":{"type":["string","null"]},"published_at":{"type":["string","null"]}}},"resolved":{"type":"object","required":["to"],"properties":{"to":{"type":"string"}}},"hint":{"type":"null"},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the required scope, or is not user-bearing where a person must be named.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such article for this credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"not_approvable for approval outside scored or needs_review; stage_conflict for a stage race; claims not searched, an unverified numeric claim, or a placeholder still in the body — see error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request — see error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"claims_check_in_progress — check_claims is already running for this article; retry_after names the wait (#4368).","$ref":"#/components/responses/RateLimited"}},"operationId":"advanceArticle","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to"],"properties":{"to":{"type":"string"},"override_reason":{"type":"string"},"published_url":{"type":"string"}}}}}},"security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:write","x-mcp-tool-name":"advance_article"}},"/api/v0/audits":{"post":{"parameters":[{"$ref":"#/components/parameters/Org"}],"summary":"Preview or start a full audit for an existing brand","responses":{"200":{"description":"Allowance preview; no audit was queued.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object"},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":"null"}}}}}},"202":{"description":"Audit queued; receipt includes run_id and a poll hint.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object"},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks audits:write.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No brand found for this credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid intake or audit allowance refusal.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"startAudit","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["icp","conversion_goal"],"properties":{"confirm":{"type":"boolean"},"project":{"type":"string","description":"Brand handle (prj_...) or domain."},"competitors":{"type":"array","items":{"type":"string"}},"conversion_goal":{"type":"string"},"icp":{"type":"string"},"brand_handle":{"type":"string","description":"Brand handle (prj_...) or domain."}}}}}},"security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"audits:write","x-mcp-tool-name":"start_audit","x-mcp-title":"Start audit"}},"/api/v0/articles":{"post":{"description":"One of three creators. This one does no work and answers inline. It is also how the engine proposes its own work — there is no separate add_idea.","parameters":[{"$ref":"#/components/parameters/Org"},{"in":"header","name":"Idempotency-Key","description":"Replays a successful response for the same organization, route and body within five minutes. An overlapping request returns 409; retry after the first completes.","required":false,"schema":{"type":"string","maxLength":255,"minLength":1}}],"summary":"Seed an idea into the backlog","responses":{"201":{"description":"The idea, as an article at stage idea.","headers":{"Location":{"description":"The created (or resolved) resource's own API path.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object","required":["article"],"properties":{"article":{"type":"object","required":["id","title","stage"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"stage":{"type":"string","enum":["idea","drafting","scored","needs_review","approved","published","verified"]}}}}},"resolved":{"type":"object","required":["handle"],"properties":{"handle":{"type":"string"}}},"hint":{"type":"string"},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the required scope.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No writing-enabled brand for this credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Key in use or reused with different input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request — see error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"createIdea","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["project","title"],"properties":{"owner":{"type":["string","null"]},"type":{"type":"string"},"title":{"type":"string"},"summary":{"type":"string"},"template_id":{"type":"string"},"project":{"type":"string"},"target_queries":{"type":"array","items":{"type":"string"}},"destination_platform":{"type":"string"},"byline_author":{"type":"string"},"image_prompt":{"type":"string"},"publish_on":{"type":"string"},"recommendation_id":{"type":"string"},"reference_material":{"type":"string"},"structural_exemplar":{"type":"string"},"subject_competitor":{"type":"string"},"source_url":{"type":"string"},"import_instructions":{"type":"string"},"reviewer":{"type":["string","null"]}}}}}},"security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:write","x-mcp-tool-name":"create_idea"}},"/api/v0/articles/{id}/verification":{"post":{"description":"Never a plain pass/fail. The result is one of matched, drifted, unreachable, blocked or never_checked, alongside what the detector matched.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/Org"},{"in":"header","name":"Idempotency-Key","description":"Replays a successful response for the same organization, route and body within five minutes. An overlapping request returns 409; retry after the first completes.","required":false,"schema":{"type":"string","maxLength":255,"minLength":1}}],"summary":"Check a published URL and report what was detected","responses":{"202":{"description":"Accepted. Poll GET /articles/{id} for the verification result.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object","required":["state","prev_status"],"properties":{"state":{"type":"string"},"cited_since":{"type":["string","null"]},"fix_detected":{"type":["object","null"],"properties":{"matched":{"type":["string","null"]},"detector":{"type":"string"}}},"prev_status":{"type":"string"}}},"resolved":{"type":"object"},"hint":{"type":"string"},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the required scope.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such article for this credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Key in use or reused with different input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"no_source_url — the article has no published or source URL to check.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"verifyPublished","security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:read","x-mcp-tool-name":"verify_published"}},"/api/v0/work":{"get":{"description":"Filters are a closed set, not a query language. `run` is how a recommendation id is reached: audit recommendations belong to a run, so `kind=recommendation` defaults to the project's latest run when `run` is omitted. `kind=prompt` reads the probe panel behind a run instead (#4325) — never returned unless requested explicitly — and defaults to the project's plain latest run of any type. Ordering: `kind=recommendation` alone comes back in rank order (ascending `priority`, lower is higher-ranked); every other request comes back newest-first.","parameters":[{"in":"query","name":"project","description":"Brand handle (prj_...) or domain.","schema":{"type":"string"}},{"in":"query","name":"kind","schema":{"type":"string","enum":["recommendation","idea","draft","prompt"]}},{"in":"query","name":"run","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"stage","schema":{"type":"string"}},{"in":"query","name":"needs_attention","schema":{"type":"boolean"}},{"in":"query","name":"owner","schema":{"type":"string"}},{"in":"query","name":"q","description":"Case-insensitive substring match against an idea/draft's title, and an idea's idea_summary.","schema":{"type":"string"}},{"in":"query","name":"source_url_like","schema":{"type":"string"}},{"in":"query","name":"updated_since","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"limit","schema":{"default":25,"maximum":50,"type":"integer"}},{"in":"query","name":"after","schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"The backlog and the board — recommendations, ideas and drafts","responses":{"200":{"description":"A page of work items, plus next_cursor when more exist.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"type":"object"},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":["string","null"],"description":"The board, filtered to this call's project/stage/owner/etc — null when `project` was omitted (#3984)."}}}}}},"400":{"description":"Invalid cursor or filter.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the required scope.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No writing-enabled brand for this credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"listWork","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"articles:read","x-mcp-tool-name":"list_work"}},"/api/v0/runs":{"get":{"parameters":[{"in":"query","name":"project","schema":{"type":"string"}},{"in":"query","name":"run_type","schema":{"type":"string"}},{"in":"query","name":"status","schema":{"type":"string"}},{"in":"query","name":"after","schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"maximum":50,"type":"integer","minimum":1}},{"$ref":"#/components/parameters/Org"}],"summary":"Newest-first run index across the credential's organization ceiling","responses":{"200":{"description":"A cursor-paginated page of runs.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object"},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":"null"}}}}}},"400":{"description":"Invalid filter or cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks audits:read.","$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"listRuns","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"audits:read","x-mcp-tool-name":"list_runs","x-mcp-title":"List runs"}},"/api/v0/recommendation-runs/{run_id}/recommendations":{"get":{"parameters":[{"in":"path","name":"run_id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"The confidence-gated, ranked recommendation plan for one audit run","responses":{"200":{"description":"Gated recommendations in rank order.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object"},"resolved":{"type":"object"},"hint":{"type":"string"},"url":{"type":"string"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No such audit run.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"listRunRecommendations","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"recommendations:read","x-mcp-tool-name":"list_run_recommendations","x-mcp-title":"List run recommendations"}},"/api/v0/articles/import":{"post":{"description":"Fetch plus an import score, both fast enough to answer inline. An import_error prefixed \"thin extraction \" is a SUCCESSFUL fetch of a thin page, not a failure. The imported page title is frozen: data.title_frozen is true, title_alignment is omitted from its score, and remaining weights are renormalized.","parameters":[{"$ref":"#/components/parameters/Org"},{"in":"header","name":"Idempotency-Key","description":"Replays a successful response for the same organization, route and body within five minutes. An overlapping request returns 409; retry after the first completes.","required":false,"schema":{"type":"string","maxLength":255,"minLength":1}}],"summary":"Import an existing post by URL","responses":{"201":{"description":"The imported article and its first revision.","headers":{"Location":{"description":"The created (or resolved) resource's own API path.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object","required":["article","title_frozen"],"properties":{"article":{"type":"object","required":["id","title","stage","thin_extraction"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"stage":{"type":"string","enum":["idea","drafting","scored","needs_review","approved","published","verified"]},"thin_extraction":{"type":"boolean","description":"The fetch worked but there wasn't enough content to score."}}},"title_frozen":{"type":"boolean","description":"True; title_alignment is omitted from the import score."}}},"resolved":{"type":"object","required":["handle"],"properties":{"handle":{"type":"string"},"matched_host":{"type":["string","null"]}}},"hint":{"type":"string"},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the required scope.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No writing-enabled brand for this credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Key in use or reused with different input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request — see error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"importArticle","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["project","source_url"],"properties":{"owner":{"type":["string","null"]},"type":{"type":"string"},"title":{"type":"string"},"template_id":{"type":"string"},"project":{"type":"string"},"target_queries":{"type":"array","items":{"type":"string"}},"destination_platform":{"type":"string"},"byline_author":{"type":"string"},"image_prompt":{"type":"string"},"publish_on":{"type":"string"},"recommendation_id":{"type":"string"},"reference_material":{"type":"string"},"structural_exemplar":{"type":"string"},"subject_competitor":{"type":"string"},"source_url":{"type":"string"},"import_instructions":{"type":"string"},"reviewer":{"type":["string","null"]}}}}}},"security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:write","x-mcp-tool-name":"import_article"}},"/api/v0/articles/{id}/code-checks":{"post":{"description":"Queues deterministic shape and source checks on the current revision. Poll the receipt for findings anchored by zero-based block_index.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/Org"}],"summary":"Check an article's fenced code blocks","responses":{"202":{"description":"Code check queued; poll the receipt endpoint for findings.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object","required":["status","receipt_id"],"properties":{"status":{"type":"string","enum":["pending"]},"receipt_id":{"type":"string"}}},"resolved":{"type":"object"},"hint":{"type":"string"},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid API key.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the `articles:write` scope.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such article for this credential, or no revision yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"description":"The check could not be queued.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"checkCodeBlocks","security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:write","x-mcp-tool-name":"check_code_blocks"}},"/api/v0/brands":{"get":{"parameters":[{"$ref":"#/components/parameters/Org"}],"summary":"Every brand (project) this credential may act on","responses":{"200":{"description":"The caller's org set — one org, three, or all.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"type":"object","properties":{"brands_truncated":{"type":"boolean","description":"True when the estate holds more brands than fit in one response — call GET /api/v0/brands/{domain} to resolve a specific one instead of scanning the list."},"brands":{"type":"array","items":{"$ref":"#/components/schemas/BrandListEntry"}}}},"resolved":{"type":"object"},"hint":{"type":"string"},"url":{"type":"null","description":"Always null — a listing of many brands has no single page (#3984)."}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"listBrands","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"brands:read","x-mcp-tool-name":"list_brands"},"post":{"description":"Idempotent on domain: a second call naming a domain this org already holds a project for returns that project (200, resolved.existing: true) rather than erroring. Returns the same handle GET /brands/{domain} does.","parameters":[{"$ref":"#/components/parameters/Org"}],"summary":"Create a brand (project) — the loop's precondition (#4164)","responses":{"200":{"description":"A project for this domain already existed — returned instead of creating a duplicate (resolved.existing: true). Still carries Location."},"201":{"description":"Created. The new brand, same shape GET /brands/{domain} returns.","headers":{"Location":{"description":"The created (or resolved) resource's own API path.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"$ref":"#/components/schemas/ResolvedBrand"},"resolved":{"type":"object","properties":{"existing":{"type":"boolean"},"domain":{"type":"string"},"matched_host":{"type":"string"}}},"hint":{"type":"string"},"url":{"type":"string","description":"The brand's project dashboard."}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the brands:write scope.","$ref":"#/components/responses/Forbidden"},"422":{"description":"Invalid request, the org's project limit, or its competitor limit — see error.code (project_limit_reached, competitor_limit_reached, or validation_failed).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"createBrand","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","domain"],"properties":{"name":{"type":"string"},"domain":{"type":"string","description":"The brand's domain, e.g. \"example.com\" — a full URL is also accepted and normalized to its host."},"url":{"type":"string"},"competitors":{"type":"array","description":"Competitors to track, subject to the organization's plan limit.","items":{"type":"string"}}}}}}},"security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"brands:write","x-mcp-tool-name":"create_brand"}},"/api/v0/articles/{id}/code-fixes":{"post":{"description":"Applies the curly-quote autofix to one zero-based code block and creates a new revision.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/Org"}],"summary":"Apply a supported code-block autofix","responses":{"200":{"description":"New revision containing the fix.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{},"resolved":{},"hint":{},"url":{}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"invalid_code_fix — no supported autofix.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"applyCodeFix","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["block_index"],"properties":{"block_index":{"type":"integer","minimum":0}}}}}},"security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:write","x-mcp-tool-name":"apply_code_fix"}},"/api/v0/recommendations/{id}/verification":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/Org"}],"summary":"Verification status, evidence, and directional score delta for one recommendation","responses":{"200":{"description":"Verification outcome with request_state to distinguish running, finished, and failed.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object"},"resolved":{"type":"object"},"hint":{"type":"string"},"url":{"type":"string"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No such recommendation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getRecommendationVerification","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"recommendations:read","x-mcp-tool-name":"get_recommendation_verification","x-mcp-title":"Get recommendation verification"},"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/Org"},{"in":"header","name":"Idempotency-Key","description":"Replays a successful response for the same organization, route and body within five minutes. An overlapping request returns 409; retry after the first completes.","required":false,"schema":{"type":"string","maxLength":255,"minLength":1}}],"summary":"Queue a fresh verification for one recommendation","responses":{"202":{"description":"Verification receipt with eta_seconds and poll hint.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object"},"resolved":{"type":"object"},"hint":{"type":"string"},"url":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No such recommendation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Key in use or reused with different input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"description":"enqueue_failed — verification could not be queued.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"verifyRecommendation","security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"recommendations:write","x-mcp-tool-name":"verify_recommendation","x-mcp-title":"Verify recommendation","x-mcp-multi-route":true}},"/api/v0/articles/{id}/rewrite":{"post":{"description":"The pass the web UI's Rewrite button has always run alone. `signals` names which recommendations to apply, using the same names GET /articles/{id}'s signals field returns — omit for every actionable one (the UI's own \"Fix all\"), or send an empty list to rewrite with none applied. Only runs from scored or needs_review; returns a receipt rather than the article.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/Org"}],"summary":"Queue a manifesto-driven rewrite applying structural recommendations","responses":{"202":{"description":"Accepted. The rewrite pass finishes on its own; poll GET /articles/{id} until the expected revision exists.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object","required":["id","eta_seconds"],"properties":{"id":{"type":"string"},"eta_seconds":{"type":"integer"}}},"resolved":{"type":"object","required":["article_id"],"properties":{"article_id":{"type":"string"}}},"hint":{"type":"string"},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the required scope.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such article for this credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"not_rewritable — see error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"invalid_request — signals must be a list of strings.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"rewrite_in_progress or generate_in_progress — a pass is already running; retry_after names the wait.","$ref":"#/components/responses/RateLimited"}},"operationId":"rewriteArticle","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"signals":{"type":"array","items":{"type":"string"}}}}}}},"security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:write","x-mcp-tool-name":"rewrite_article"}},"/api/v0/audits/{run_id}":{"get":{"parameters":[{"in":"path","name":"run_id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"Read an audit's status, progress, and available scores","responses":{"200":{"description":"Audit status and available scores.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object"},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks audits:read.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No audit found for this credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getAudit","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"audits:read","x-mcp-tool-name":"get_audit","x-mcp-title":"Get audit"}},"/api/v0/articles/{id}":{"get":{"description":"Article, latest revision, feedback with statuses, verification, the linked recommendation, the writing engine's own signals, pending_work, and a DERIVED needs_attention. Replaces the four to six round trips the same question used to take. include=blocks adds indexed blocks; section narrows to one section's range; view=summary omits the revision body/score/diagnosis. signals.dismissed (#4403) lists signals dismissed via PATCH's dismissed_signals — display-only: those signals drop out of revision.diagnosis_json.recommendations, but revision.score_json.citability and its subs are computed exactly as if nothing had been dismissed.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"include","description":"Optional extras. A closed set, not arbitrary field selection. A non-array value, or an item outside the enum, is refused with 422. \"revisions\" (#4404) adds data.revisions, a compact history list. \"diff_context\" (#4509) restores the blocks diff_from's :unchanged regions otherwise omit.","schema":{"type":"array","items":{"type":"string","enum":["blocks","revisions","diff_context"]}}},{"in":"query","name":"section","description":"Narrow included blocks to the section containing this index.","schema":{"type":"integer","minimum":0}},{"in":"query","name":"view","description":"summary (default: full) omits revision.body_md, revision.score_json and revision.diagnosis_json. status (#4397) returns only stage, revision: {number, id}, pending_work, and needs_attention — a poll-sized response for checking on queued work.","schema":{"type":"string","enum":["full","summary","status"]}},{"in":"query","name":"revision","description":"A revision number (#4404). Reads that revision instead of the latest; 404 revision_not_found if the article has none with that number.","schema":{"type":"integer","minimum":1}},{"in":"query","name":"diff_from","description":"A revision number (#4404). Adds data.diff: the structured regions between that revision and the one this call resolved to. :unchanged regions omit their blocks by default (#4509) — pass include=diff_context to get the text back; :changed regions always carry their word-level spans. 404 diff_from_not_found if the article has none with that number, 404 no_revision if it has none to diff against at all.","schema":{"type":"integer","minimum":1}},{"$ref":"#/components/parameters/Org"}],"summary":"The whole assess loop in one call","responses":{"200":{"description":"The assembled article picture.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"type":"object","properties":{"revision":{"type":["object","null"],"properties":{"id":{"type":"string","format":"uuid","description":"Pass as edit_article's base_revision_id."},"content_flags":{"type":"array","description":"Two kinds of entry, told apart by the type field. Most are passages the model judged to be a prompt-injection attempt — content engineered to look like an instruction, never a caller request; for those, each quote was already removed from body_md before this revision was stored, so export never contains it either. An entry whose type is unverified_numeric_claim is different: it names a numeric claim a verbatim, insert or instruction edit introduced without a fact-check, and that text is still in body_md — nothing was removed. Empty for the ordinary case where nothing was flagged."},"restored_blocks_count":{"type":["integer","null"],"description":"How many blocks the patch-scope guard put back to their prior content because the model edited outside the anchors it was given, producing this revision. NOT a count of your own edits being undone — a feedback item can show status \"applied\" while this is non-zero, which is the normal, healthy case: overreach elsewhere was caught and reverted while the edit you asked for landed. null means this revision never measured it, not zero."}}},"article":{"type":"object","properties":{"override_reason":{"type":["string","null"],"description":"The reason a reviewer gave for bypassing the claim gate (#3973). null unless the article was approved with one."},"image_prompt":{"type":["string","null"]},"import_instructions":{"type":["string","null"]},"idea_summary":{"type":["string","null"]}}},"feedback":{"type":"array","description":"Outstanding feedback only — items still queued or being sent. A finished item's own outcome (applied/deviated/enforced/reverted) is a separate, per-item fact and drops it out of this list; it is not what revision.restored_blocks_count counts."}}},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":["string","null"],"description":"The article's review page (#3984). null under view=status, which is poll-sized and carries no link (#5363)."}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the required scope.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such article for this credential, or revision_not_found / diff_from_not_found / no_revision (#4404) — see error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`include`, `view`, `revision` or `diff_from` didn't match its schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getArticle","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"articles:read","x-mcp-tool-name":"get_article"},"delete":{"description":"Sets deleted_at; the row survives until the retention pruner reclaims it, 90 days later. Revisions and feedback are left untouched. HTTP repeats this call as a plain 404 (unchanged, #4253) — only the delete_article MCP tool treats a retry of the caller's own already-deleted article as success.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"Soft-delete an article (#4213)","responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"type":"object","required":["deleted"],"properties":{"deleted":{"type":"boolean"}}},"resolved":{"type":"object","properties":{"article_id":{"type":"string"}}},"hint":{"type":["string","null"]},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid API key.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential doesn't hold articles:write.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such article inside the caller's org.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteArticle","security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:write","x-mcp-tool-name":"delete_article","x-mcp-destructive":true,"x-mcp-title":"Delete article"},"patch":{"description":"The same grounding envelope POST /articles takes, applied to an article that already exists. Only the fields present in the body are changed. `dismissed_signals`, when present, is a declarative set: the article ends up with exactly the signals named — a signal already dismissed but missing from the list is restored. Display-only (#4403): a dismissed signal drops out of GET's revision.diagnosis_json.recommendations, but revision.score_json.citability and its subs are unaffected. `published_url` attaches or corrects the live URL after publishing (advance_article's own `published_url` is optional at publish time) and re-queues verification.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"Re-ground an existing article in one call (design A §2.7a)","responses":{"200":{"description":"The article's current grounding state, after the write.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"type":"object"},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":"null","description":"Always null today — not yet wired for this write (#3984)."}}}}}},"401":{"description":"Missing or invalid API key.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential doesn't hold articles:write.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such article inside the caller's org, the org's writing_enabled is false, or the template_id doesn't resolve inside the article's project.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"type_locked — the article is past the idea stage — or not_published — published_url was sent before the article has published.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"invalid_type, or validation_failed with per-field errors.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"updateArticle","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"owner":{"type":["string","null"]},"type":{"type":"string","enum":["article","buyer_guide","comparison_page","narrative"]},"template_id":{"type":["string","null"]},"target_queries":{"type":"array","items":{"type":"string"}},"destination_platform":{"type":"string","enum":["medium","wordpress","other"]},"published_url":{"type":"string"},"byline_author":{"type":"string"},"image_prompt":{"type":"string"},"publish_on":{"type":"string","format":"date"},"reference_material":{"type":["string","null"]},"structural_exemplar":{"type":["string","null"]},"subject_competitor":{"type":"string"},"import_instructions":{"type":["string","null"]},"reviewer":{"type":["string","null"]},"dismissed_signals":{"type":"array","items":{"type":"string","enum":["stat_density","answer_first","question_headings","freshness","extractables","title_alignment"]}}}}}}},"security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:write","x-mcp-tool-name":"update_article","x-mcp-destructive":false,"x-mcp-title":"Update article"}},"/api/v0/recommendations/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/Org"}],"summary":"Full evidence for one audit recommendation","responses":{"200":{"description":"Full evidence for the recommendation — issue, evidence, rewrite, verification history, and every article it produced, if any.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"$ref":"#/components/schemas/Recommendation"},"resolved":{"type":"object"},"hint":{"type":"string"},"url":{"type":"string","description":"The recommendation's own drawer."}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No such recommendation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getRecommendation","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"recommendations:read","x-mcp-tool-name":"get_recommendation","x-mcp-hint-template":"GET /api/v0/articles/{article_id} for the article this recommendation produced.","x-mcp-title":"Get recommendation"},"patch":{"description":"Wraps `Beacon.Recommendations.update_status/4`, the rec family's only writer. Never touches writing signals on an article — see PATCH /api/v0/articles/:id for those.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/Org"}],"summary":"Set status and dismissal for one audit recommendation","responses":{"200":{"description":"The recommendation, re-presented exactly as GET returns it.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"$ref":"#/components/schemas/Recommendation"},"resolved":{"type":"object"},"hint":{"type":"string"},"url":{"type":"string","description":"The recommendation's own drawer."}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks recommendations:write. Marking or dismissing a recommendation does not need writing enabled.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such recommendation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid status, invalid dismiss_reason, or another validation failure.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"updateRecommendation","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["in_progress","implemented","dismissed","open"]},"dismiss_reason":{"type":"string","enum":["too_big","not_relevant","already_fine","later"],"description":"Allowed only when status is \"dismissed\"; otherwise a non-null value returns 422. Changing to another status clears any stored reason."},"implementation_note":{"type":"string","description":"Fed to the LLM verification tier as extra context."}}}}}},"security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"recommendations:write","x-mcp-tool-name":"update_recommendation","x-mcp-destructive":false,"x-mcp-hint-template":"GET /api/v0/articles/{article_id} for the article this recommendation produced.","x-mcp-title":"Update recommendation"}},"/api/v0/articles/{id}/revisions":{"post":{"description":"The batch is the unit of work, not the edit: one batch is one model pass and one revision row. The server resolves each item's anchor quote and echoes back the block index and exact text it will edit; a quote matching zero or two blocks applies NOTHING and returns the candidates. Sends everything queued, including feedback a person left in the UI.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"header","name":"Idempotency-Key","description":"Same key + same body replays the original receipt rather than re-running the batch.","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"Send one atomic batch of edits, producing one revision","responses":{"200":{"description":"No anchor resolved, so nothing was queued — resolved_anchors carries the candidates to re-send against (#3474). A success, not a failure.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object","required":["resolved_anchors"],"properties":{"expect":{"type":"integer"},"eta_seconds":{"type":"integer"},"revision_now":{"type":"integer"},"resolved_anchors":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"text":{"type":"string"},"candidates":{"type":"array","items":{"type":"object","properties":{"block_index":{"type":"integer"},"block_text":{"type":"string"}}}},"anchor":{"type":"string"}}}}}},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":"null"}}}}}},"202":{"description":"Accepted, with revision_now, expect and eta_seconds, plus resolved_anchors.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object","required":["resolved_anchors"],"properties":{"expect":{"type":"integer"},"eta_seconds":{"type":"integer"},"revision_now":{"type":"integer"},"resolved_anchors":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"text":{"type":"string"},"candidates":{"type":"array","items":{"type":"object","properties":{"block_index":{"type":"integer"},"block_text":{"type":"string"}}}},"anchor":{"type":"string"}}}}}},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the required scope.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such article for this credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"stale_base or not_revisable — see error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request — see error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"revise_in_progress — a pass is already running; retry_after names the wait.","$ref":"#/components/responses/RateLimited"}},"operationId":"editArticle","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["base_revision_id","items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/EditItem"}},"base_revision_id":{"type":"string"}}}}}},"security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:write","x-mcp-tool-name":"edit_article"}},"/api/v0/articles/{id}/stat-candidates":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"header","name":"Idempotency-Key","description":"Same key + same body replays the original receipt rather than re-running the batch.","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"Insert a sourced statistic into an article revision","responses":{"200":{"description":"Insert completed synchronously with the new revision.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object"},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":["string","null"]}}}}}},"202":{"description":"Insert queued.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object","properties":{"expect":{"type":"integer"},"eta_seconds":{"type":"integer"},"revision_now":{"type":"integer"},"also_queued":{"type":"array"},"resolved_anchors":{"type":"array"}}},"resolved":{"type":"object"},"hint":{"type":"string"},"url":{"type":"null"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Revision conflict or duplicate request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"validation_failed for missing or non-string source_type, source_id, or quote; unresolvable_provenance for a source-pool miss or quote mismatch.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"insertStatCandidate","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["quote","source_type","source_id"],"properties":{"quote":{"type":"string"},"source_type":{"type":"string"},"anchor":{"type":"string"},"base_revision_id":{"type":"string"},"source_id":{"type":"string"},"source_label":{"type":"string"}}}}}},"security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:write","x-mcp-tool-name":"insert_stat_candidate","x-mcp-destructive":false,"x-mcp-hint-template":"Poll get_article for the new revision.","x-mcp-title":"Insert statistic candidate"}},"/api/v0/impact":{"get":{"parameters":[{"in":"query","name":"project","schema":{"type":"string"}},{"in":"query","name":"after","schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"maximum":50,"type":"integer","minimum":1}},{"$ref":"#/components/parameters/Org"}],"summary":"Published articles and their impact receipts, newest first","responses":{"200":{"description":"Published articles, including those not yet measured.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object"},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":"null"}}}}}},"400":{"description":"Invalid limit or cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the articles:read scope.","$ref":"#/components/responses/Forbidden"},"404":{"description":"The project is not accessible.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"listImpact","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"articles:read","x-mcp-tool-name":"list_impact"}},"/api/v0/templates":{"get":{"description":"Makes create_idea/import_article/update_article's template_id argument discoverable — templates are per-project data with no fixed set, so nothing could otherwise answer what a valid template_id even is.","parameters":[{"in":"query","name":"project","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"A project's saved page templates (#4409)","responses":{"200":{"description":"The project's templates, oldest first.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"type":"object","properties":{"templates":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"sections":{"type":"integer"}}}}}},"resolved":{"type":"object"},"hint":{"type":"string"},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the articles:read scope.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No project found for that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"listTemplates","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"articles:read","x-mcp-tool-name":"list_templates","x-mcp-title":"List templates"}},"/api/v0/whoami":{"get":{"description":"Identity and discovery, not a writing operation — requires no scope and answers regardless of the acting org's writing_enabled (see BeaconWeb.Api.PingController's 'identity and discovery require no scope' rule). Optional org (slug or id) is checked against the credential's live ceiling; a valid org still returns the full identity and an unknown org returns 422 invalid_org.","parameters":[{"$ref":"#/components/parameters/Org"}],"summary":"Who this credential is, what it may act on, and its plan limits","responses":{"200":{"description":"The credential's identity, its org ceiling, its scopes, and the acting org's writing/plan state.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"$ref":"#/components/schemas/WhoamiIdentity"},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"The supplied org is outside this credential's reach (invalid_org).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"whoami","security":[{"bearerAuth":[]}],"x-mcp-exclude":true}},"/api/v0/brands/{brand}/context":{"get":{"description":"Requires brands:read. `domain` accepts a bare domain or the opaque handle — reads accept either. `purpose` selects the priority ordering the card's token budget fills by (default recommendations); `include` force-includes facet kinds regardless of budget, before the greedy fill. See the get_brand_context MCP tool for the full contract.","parameters":[{"in":"path","name":"brand","description":"A bare domain or the brand's opaque handle.","required":true,"schema":{"type":"string"}},{"in":"query","name":"purpose","required":false,"schema":{"type":"string","enum":["recommendations","writing","scan"]}},{"in":"query","name":"include","description":"Comma-separated facet kinds to force into the card.","required":false,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"A brand's assembled context card, plus a catalog of what exists (#4500)","responses":{"200":{"description":"The assembled card, plus the catalog of everything else.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"type":"object"},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":"string"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"Missing brands:read, or the credential spans more than one org and no org argument was given.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such brand.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"An invalid purpose or an unknown include kind.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getBrandContext","security":[{"bearerAuth":[]}],"x-mcp-required-scope":"brands:read","x-mcp-exclude":true},"patch":{"description":"Requires brands:write and a live writing role. The path accepts a handle or domain. facets is keyed by facet kind, each entry carrying body and basis (asserted|derived|extracted, no default); body: null clears that facet and does not require basis. Either every facet in the call lands or none does. principal is stamped from the grant and is never an accepted input key. See the update_brand_context MCP tool for the full contract.","parameters":[{"in":"path","name":"brand","description":"The brand's handle, e.g. \"prj_...\".","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"Write any subset of a brand's context facets in one call (#4500)","responses":{"200":{"description":"Updated.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"type":"object"},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":"string"}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"Missing brands:write, or the credential spans more than one org and no org argument was given.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such brand inside the caller's org.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request — see error.code (unknown_kind, invalid_facets, body_too_long, invalid_basis, validation_failed).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"updateBrandContext","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["facets"],"properties":{"facets":{"type":"object","additionalProperties":{"type":"object","required":["body"],"properties":{"body":{"type":["string","null"]},"basis":{"type":"string","enum":["asserted","derived","extracted"]}}}}}}}}},"security":[{"bearerAuth":[]}],"x-mcp-required-scope":"brands:write","x-mcp-exclude":true}},"/api/v0/scans":{"post":{"description":"The org-attributed door onto the free-scan pipeline that POST /api/v1/scan also runs with scans:write — same guards and result cache, attributed to this credential's org instead of an IP. Returns immediately: \"running\" for a freshly created scan (poll GET /api/v0/scans/{scan_token}), or \"complete\" for a domain served from the result cache. A scan of a domain this org tracks adds a run and recommendations to that brand when the scan completes; cached results from this org do not add a duplicate run. A foreign cached result is skipped for a tracked domain so a fresh scan can add a run.","parameters":[{"$ref":"#/components/parameters/Org"},{"in":"header","name":"Idempotency-Key","description":"Replays a successful response for the same organization, route and body within five minutes. An overlapping request returns 409; retry after the first completes.","required":false,"schema":{"type":"string","maxLength":255,"minLength":1}}],"summary":"collimer_scan's REST counterpart (#4214) — start a visibility scan","responses":{"201":{"description":"Scan created, or complete for a cache-served domain.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"$ref":"#/components/schemas/ScanResult"},"resolved":{"type":"object"},"hint":{"type":"null"},"url":{"type":"string","description":"The scan's report URL."}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the scans:write scope.","$ref":"#/components/responses/Forbidden"},"409":{"description":"Key in use or reused with different input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input or a rejected create — see error.code (invalid_url, invalid_email, url_not_scannable, email_blocked, scan_create_failed, domain_suppressed).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited or at capacity — see error.code.","$ref":"#/components/responses/RateLimited"},"503":{"description":"scan_disabled — free scans are temporarily paused.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"createScan","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string","description":"The website to scan, e.g. 'example.com' or 'https://example.com'."},"email":{"type":"string","format":"email","description":"Optional — emails the report and speeds claiming the account later."}}}}}},"security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"scans:write","x-mcp-tool-name":"collimer_scan","x-mcp-destructive":false,"x-mcp-title":"Run a visibility scan"}},"/api/v0/scans/{scan_token}":{"get":{"description":"Reads the same row GET /api/v1/scan/{token} serves. Not org-scoped — the scan_token identifies the scan after bearer authentication, matching the v1 route and the MCP tool's token lookup.","parameters":[{"in":"path","name":"scan_token","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"collimer_scan_status's REST counterpart (#4214) — poll a scan","responses":{"200":{"description":"running, complete, or failed — see data.status.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"$ref":"#/components/schemas/ScanResult"},"resolved":{"type":"object"},"hint":{"type":"null"},"url":{"type":"string","description":"The scan's report URL."}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks the scans:write scope.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No scan exists for that token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getScanStatus","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"scans:write","x-mcp-tool-name":"collimer_scan_status","x-mcp-title":"Check a scan's status"}},"/api/v0/brands/{brand}":{"get":{"parameters":[{"in":"path","name":"brand","description":"The brand's domain or prj_ handle.","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"Resolve a brand by domain or handle","responses":{"200":{"description":"Org, project, latest audit run, page list, and an opaque project handle.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"$ref":"#/components/schemas/ResolvedBrand"},"resolved":{"type":"object","properties":{"domain":{"type":"string"},"matched_host":{"type":"string"}}},"hint":{"type":"string"},"url":{"type":"string","description":"The brand's project dashboard."}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No brand this credential may act on holds this domain.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"More than one brand this credential may act on holds this domain — `error.candidates` lists them; nothing was resolved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"resolveBrand","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"brands:read","x-mcp-tool-name":"resolve_brand"},"delete":{"description":"Sets deleted_at, which frees the org's project-limit slot immediately (count_for_org/2 already filters deleted rows) — the row itself survives until the retention pruner reclaims it, 90 days later. The path accepts a handle or domain within the credential's single org. Refuses (409) while the brand still has any live (non-deleted) article. HTTP repeats this call as a plain 404 (unchanged, #4253) — only the delete_brand MCP tool treats a retry of the caller's own already-deleted brand as success.","parameters":[{"in":"path","name":"brand","description":"The brand's handle, e.g. \"prj_...\".","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"Soft-delete a brand (#4213)","responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"type":"object","required":["deleted"],"properties":{"deleted":{"type":"boolean"}}},"resolved":{"type":"object","properties":{"handle":{"type":"string"}}},"hint":{"type":["string","null"]},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid API key.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential doesn't hold brands:write.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such brand inside the caller's org.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"project_has_live_articles — the brand still has a live article; delete it first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteBrand","security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"brands:write","x-mcp-tool-name":"delete_brand","x-mcp-destructive":true,"x-mcp-title":"Delete brand"},"patch":{"description":"Only fields present in the body are changed. Customer-editable context fields are icp, voice, competitors, location and docs_url; null clears each one. competitor_domains merges name/hostname pairs for comparison-page claim checks; URLs normalize to lowercase hosts without www., invalid hosts return 422, and null removes an entry. Unknown exact names are accepted with a hint. business_type selects the classification used for future scans. domain goes through the same normalization create_brand applies (#4266): a full URL is accepted and repaired to its host. The path accepts a handle or domain. Returns the same shape GET /brands/{domain} does.","parameters":[{"in":"path","name":"brand","description":"The brand's prj_ handle or domain.","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"Correct or configure a brand — the lifecycle's missing corner (#4267)","responses":{"200":{"description":"Updated. Same shape GET /brands/{domain} returns.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","url"],"properties":{"data":{"$ref":"#/components/schemas/ResolvedBrand"},"resolved":{"type":"object","properties":{"handle":{"type":"string"}}},"hint":{"type":["string","null"]},"url":{"type":"string","description":"The brand's project dashboard."}}}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential doesn't hold brands:write.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such brand inside the caller's org.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid request — see error.code (validation_failed), e.g. a domain this org already holds under a different brand.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"updateBrand","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"domain":{"type":"string","description":"The brand's domain, e.g. \"example.com\" — a full URL is also accepted and normalized to its host."},"location":{"type":["string","null"]},"url":{"type":"string"},"business_type":{"type":"string","enum":["b2b_software","professional_services","local_service","local_destination","ecommerce_product","marketplace_platform","creator_portfolio","media_content"]},"competitor_domains":{"type":"object","description":"Exact competitor name to hostname. URLs normalize to lowercase hosts without www.; invalid hosts return 422. Null removes an entry; other entries merge. Unknown names are accepted with a hint.","additionalProperties":{"type":["string","null"]}},"competitors":{"type":["array","null"],"items":{"type":"string"}},"icp":{"type":["string","null"]},"source_urls":{"type":"array","description":"Source-of-truth file URLs for this brand's real export surface, fetched verbatim and ranked above docs_url for countable/behavioural claims. Up to 10.","items":{"type":"string"}},"voice":{"type":["object","string","null"],"description":"Voice profile object, or the Tone: ... and/or Traits: ... string used by the voice context facet. Null clears it.","properties":{"tone":{"type":"string"},"traits":{"type":"array","items":{"type":"string"}}},"additionalProperties":false},"docs_url":{"type":["string","null"]}}}}}},"security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"brands:write","x-mcp-tool-name":"update_brand","x-mcp-title":"Update brand"}},"/api/v0/articles/{id}/visual-suggestions":{"post":{"description":"Plans visuals without changing the draft. Poll get_article and compare data.visual_plan.job_id with this receipt's job_id; use the stored suggestions only when its status is completed. A failed job leaves the old plan in place. The stored plan includes H2 heading anchors and their derived staleness.","parameters":[{"in":"path","name":"id","description":"The article id, from get_article or list_work.","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/Org"}],"summary":"Queue a stored visual plan for an article's current revision","responses":{"202":{"description":"Visual planning queued; poll get_article's visual_plan for this job_id and use the stored plan when its status is completed.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object","required":["article_id","job_id","eta_seconds"],"properties":{"job_id":{"type":"integer"},"article_id":{"type":"string","format":"uuid"},"eta_seconds":{"type":"integer"}}},"resolved":{"type":"object","required":["article_id"],"properties":{"article_id":{"type":"string","format":"uuid"}}},"hint":{"type":"string"},"url":{"type":"null"}}}}}},"401":{"description":"Missing or invalid API key.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential does not hold `articles:write`.","$ref":"#/components/responses/Forbidden"},"404":{"description":"No such article inside the caller's org, or no revision yet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"suggestVisuals","security":[{"bearerAuth":[]}],"x-mcp-read-only":false,"x-mcp-required-scope":"articles:write","x-mcp-tool-name":"suggest_visuals","x-mcp-destructive":false}},"/api/v0/articles/{id}/writing-jobs/{kind}/{receipt_id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"kind","required":true,"schema":{"type":"string","enum":["stat_candidates","code_check","claim_check"]}},{"in":"path","name":"receipt_id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/Org"}],"summary":"Poll a statistic-candidate, code-check, or claim-check receipt","responses":{"200":{"description":"Pending, done with the saved result, or failed.","content":{"application/json":{"schema":{"type":"object","required":["data","resolved","hint","url"],"properties":{"data":{"type":"object","required":["status","result"],"properties":{"status":{"type":"string","enum":["pending","done","failed"]},"result":{"type":["object","null"]}}},"resolved":{"type":"object"},"hint":{"type":["string","null"]},"url":{"type":"null"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No receipt for this article and credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getWritingJobResult","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":"articles:read","x-mcp-tool-name":"get_writing_job_result","x-mcp-destructive":false,"x-mcp-title":"Get writing job result"}},"/api/v0/runs/{run_id}/report":{"get":{"description":"Requires an org-owned audit run and QA-gate readiness. Failed or cancelled audits and audits with exhausted QA retries return 409. Unsettled audits return 202. Deliberately no plan gate — see Beacon.MCP.GetAuditArtifactTool's moduledoc. Returns the raw file: text/markdown for format=md (default), application/pdf for format=pdf.","parameters":[{"in":"path","name":"run_id","required":true,"schema":{"type":"string"}},{"in":"query","name":"format","schema":{"default":"md","type":"string","enum":["md","pdf"]}},{"$ref":"#/components/parameters/Org"}],"summary":"The assembled AI Visibility Audit deliverable for a completed run (#4734)","responses":{"200":{"description":"The rendered artifact — Markdown text or a PDF binary.","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}},"text/markdown":{"schema":{"type":"string"}}}},"202":{"description":"The QA gate has not cleared this run yet — retry shortly.","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Missing or invalid credential.","$ref":"#/components/responses/Unauthorized"},"403":{"description":"The credential lacks audits:read and/or articles:read.","$ref":"#/components/responses/Forbidden"},"404":{"description":"Run missing, non-audit, or outside the credential's ceiling.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The audit produced no deliverable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid `format`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"description":"pdf_render_failed — PDF rendering failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"operationId":"getAuditArtifact","security":[{"bearerAuth":[]}],"x-mcp-read-only":true,"x-mcp-required-scope":["audits:read","articles:read"],"x-mcp-tool-name":"get_audit_artifact","x-mcp-title":"Get audit artifact"}}},"servers":[{"url":"https://app.collimer.com"}],"openapi":"3.1.0"}