# Surfaced > How to set up Surfaced, read your AI-visibility results, and act on them. - [Welcome](https://docs.getsurfaced.ai/index.md): What Surfaced does, and where to start. - [Quickstart](https://docs.getsurfaced.ai/quickstart.md): From sign-up to your first results, and what to do with them. - [How Surfaced collects data](https://docs.getsurfaced.ai/how-surfaced-collects-data.md): What a tracking run does, what is recorded from each answer, and what that means for how far you can trust a number. - [Map of the app](https://docs.getsurfaced.ai/app-map.md): Every screen in Surfaced, in sidebar order, and the page here that explains it. - [Glossary](https://docs.getsurfaced.ai/glossary.md): The terms Surfaced uses, defined once. - [Workspace](https://docs.getsurfaced.ai/set-up/workspace.md): The brand, the website and the domains you own: the settings everything else is measured against. - [Prompts](https://docs.getsurfaced.ai/set-up/prompts.md): Choosing the questions Surfaced tracks, the highest-leverage decision in the product. - [Competitors](https://docs.getsurfaced.ai/set-up/competitors.md): How rivals get into Surfaced, and what pinning one changes. - [Markets and languages](https://docs.getsurfaced.ai/set-up/markets-and-languages.md): Why the language a question is asked in and the country it is asked from are two separate settings, and how to choose both. - [Tracking defaults](https://docs.getsurfaced.ai/set-up/tracking-defaults.md): Which AI platforms you track, how that drives your monthly response usage, and when to change it. - [Metrics overview](https://docs.getsurfaced.ai/metrics/overview.md): The five numbers on the Analytics page, what each one counts, and which questions each can and cannot answer. - [Brand visibility](https://docs.getsurfaced.ai/metrics/brand-visibility.md): The share of tracked AI answers that name or link your brand. - [Citation rate](https://docs.getsurfaced.ai/metrics/citation-rate.md): Among AI answers that cite sources at all, the share that cite your domain. - [Share of voice](https://docs.getsurfaced.ai/metrics/share-of-voice.md): Your share of all brand mentions in the answers, measured against the competitors you track. - [Average position](https://docs.getsurfaced.ai/metrics/average-position.md): Where in a recommendation list your brand appears, averaged over the answers that listed it. - [Sentiment](https://docs.getsurfaced.ai/metrics/sentiment.md): How your brand is described in the answers that mention it, scored from 0 to 100. - [Audit score](https://docs.getsurfaced.ai/metrics/audit-score.md): The 0–100 grade for how ready your website is to be read and cited by AI assistants. - [Periods and filters](https://docs.getsurfaced.ai/metrics/periods-and-filters.md): The date window, the plan history floor and the branded/unbranded control: the three things that change every number on every Insights screen. - [Analytics](https://docs.getsurfaced.ai/insights/analytics.md): The overview screen: five KPIs, their trends, per-platform breakdowns, the competitor ranking and the market split. - [Prompts](https://docs.getsurfaced.ai/insights/prompts.md): Every tracked question, how you performed on each, and how to add, group and retire them. - [Sources](https://docs.getsurfaced.ai/insights/sources.md): Which domains the AI engines cite in your answers, how often, and which of your own pages are being used. - [Competitors](https://docs.getsurfaced.ai/insights/competitors.md): Every brand detected alongside yours in the answers, and which of them count toward your share of voice. - [Gap trends](https://docs.getsurfaced.ai/insights/gap-trends.md): What the AI answers get wrong or leave out about you, how severe each gap is, and how that is changing. - [Audit report](https://docs.getsurfaced.ai/insights/audit-report.md): Whether AI assistants can reach, understand and quote your website, with the specific fix for each page. - [Content performance](https://docs.getsurfaced.ai/insights/content-performance.md): Which of your published pages the AI assistants cite, and which are being ignored. - [Actions](https://docs.getsurfaced.ai/improve/actions.md): The single queue of work that comes out of your results: what to do, who owns it, and what state it is in. - [Briefs](https://docs.getsurfaced.ai/content/briefs.md): The instruction for a piece of content, and the run that turns it into articles. - [Articles](https://docs.getsurfaced.ai/content/articles.md): Your content library: reviewing drafts, the fact-check, revisions, and archiving. - [Hosted blog](https://docs.getsurfaced.ai/publish/hosted-blog.md): Publishing articles on a Surfaced-hosted site, with your own domain and styling. - [Integrations](https://docs.getsurfaced.ai/publish/integrations.md): Getting content out of Surfaced and into the rest of your stack. - [Members and roles](https://docs.getsurfaced.ai/account/members-and-roles.md): Who can do what, in the organization and in each workspace, and how the two sets of roles fit together. - [Billing and usage](https://docs.getsurfaced.ai/account/billing-and-usage.md): What your plan meters, where to watch it, and what happens when you reach a limit. - [Referrals](https://docs.getsurfaced.ai/account/referrals.md): Your referral link, what the person you refer gets, and what you earn. - [FAQ](https://docs.getsurfaced.ai/troubleshooting/faq.md): Short answers to the questions asked most often in the first month. - [Common issues](https://docs.getsurfaced.ai/troubleshooting/common-issues.md): The situations support hears about most, what causes each, and what to do. - [Public API](https://docs.getsurfaced.ai/api/public-api.md): Authenticate, call the API, and know which parts of the product it reaches. - [Get the authenticated user and accessible workspaces](https://docs.getsurfaced.ai/api-reference/account/get-the-authenticated-user-and-accessible-workspaces.md): Returns the profile of the API key's owner along with every workspace the key can access (filtered by `scoped_workspace_ids` if set). Use the returned `workspaces[].id` for the `X-Workspace-Id` header on workspace-scoped requests. - [Get your account](https://docs.getsurfaced.ai/api-reference/account/get-your-account.md): Returns the profile of the API key's owner plus a per-workspace preferences list (`workspacePreferences`: workspace id, name and preferred language). A workspace-scoped key only sees the workspaces it can access. For the role and capabilities in each workspace use `GET /me` instead; this route carri… - [Update your account](https://docs.getsurfaced.ai/api-reference/account/update-your-account.md): Partial update. `name` renames the profile (must not be blank). `preferredLanguage` sets the language for ONE workspace and is only applied together with `workspaceId`; an empty string clears it. A scoped key may only name a workspace it can access (`WORKSPACE_NOT_ALLOWED`). Nothing is written when… - [List your API keys](https://docs.getsurfaced.ai/api-reference/account/list-your-api-keys.md): Lists the owner's live (not revoked) API keys, newest first. A key sees only keys no broader than itself: a workspace-scoped, read-only or expiring key does not see account-wide, write-capable or non-expiring ones. Only the `keyPrefix` is returned (the snake_case `key_prefix` and the other snake_cas… - [Create an API key](https://docs.getsurfaced.ai/api-reference/account/create-an-api-key.md): Creates a key for the caller's user. The plaintext `key` is returned ONCE in this response; store it, it cannot be retrieved later. A key can never create a key broader than itself (see `scopes`, `scopedWorkspaceIds`, `expiresAt`; the snake_case request names still work, but sending both for one fie… - [Revoke an API key](https://docs.getsurfaced.ai/api-reference/account/revoke-an-api-key.md): Revokes one of the owner's keys immediately; this cannot be undone. A key can only revoke keys with the same or narrower scopes, workspaces and expiry as itself (otherwise 403 `SCOPE_DENIED`), so a scoped key cannot disable the owner's account-wide key. A key may revoke itself. An unknown or already… - [List ideas in the active workspace](https://docs.getsurfaced.ai/api-reference/ideas/list-ideas-in-the-active-workspace.md): Deprecated compatibility alias for `/briefs`. Returns the legacy idea view filtered by state/language with cursor pagination. Use `/briefs` for new integrations. - [Create one or more ideas](https://docs.getsurfaced.ai/api-reference/ideas/create-one-or-more-ideas.md): Deprecated compatibility alias for `/briefs`. Use `/briefs` for new integrations. Requires `write` scope and `admin_section` permission. - [List Content Briefs in the active workspace](https://docs.getsurfaced.ai/api-reference/content/list-content-briefs-in-the-active-workspace.md): Returns Content Briefs with cursor pagination. Each Brief has a lifecycle `status` (`draft`, `awaiting_approval`, `approved`, `writing`, `articles_to_review`, `published`, `didnt_finish`) and, once writing has started, a `run` with one target per market and language and its writing state (`queued`,… - [Create one or more Content Briefs](https://docs.getsurfaced.ai/api-reference/content/create-one-or-more-content-briefs.md): Creates Content Briefs in the active workspace; each is returned as a `draft`. Fields are camelCase. The legacy snake_case names (`idea_text`, `primary_keyword`, ...) are still accepted until the API sunset; one field sent under both names with different values is a 422, as is an unknown field. Send… - [Get a Content Brief](https://docs.getsurfaced.ai/api-reference/content/get-a-content-brief.md): Returns one Content Brief. Each Brief has a lifecycle `status` (`draft`, `awaiting_approval`, `approved`, `writing`, `articles_to_review`, `published`, `didnt_finish`) and, once writing has started, a `run` with one target per market and language and its writing state (`queued`, `writing`, `checking… - [Delete a Content Brief](https://docs.getsurfaced.ai/api-reference/content/delete-a-content-brief.md) - [Update a Content Brief](https://docs.getsurfaced.ai/api-reference/content/update-a-content-brief.md): Changes the fields sent, while `locked` is false; once the Brief's Run has started it is a 409 `CONFLICT`, so create a new Brief for a variation. Fields are camelCase; the legacy snake_case names are still accepted until the API sunset. A field sent under both names takes the one that differs from t… - [List Articles](https://docs.getsurfaced.ai/api-reference/content/list-articles.md): Lists the workspace's Articles, newest first, with cursor pagination. Archived articles are hidden unless `archived=true`. Block bodies are omitted unless `includeBlocks=true`; request them only when you need the text, because they make pages large. Use `GET /articles/{id}` for one article with its… - [Get an Article](https://docs.getsurfaced.ai/api-reference/content/get-an-article.md): Returns one Article including its `blocks`. `contentVersion` is the saved version; pass it as `expectedVersion` when restoring a revision so a concurrent edit is not overwritten. An article in another workspace is a 404. - [Archive an Article](https://docs.getsurfaced.ai/api-reference/content/archive-an-article.md): Archives (soft-deletes) the Article: it disappears from the default list and gets `archivedAt`. Archiving an already-archived article refreshes `archivedAt` rather than failing. Fires the `page.archived` webhook. - [Update Article metadata](https://docs.getsurfaced.ai/api-reference/content/update-article-metadata.md): Partial update of title, description, excerpt, categories, tags and language. Unknown fields are rejected with 422, and so is an empty body. Block content is edited in the app, not here. Requires the `write` scope and the `admin_section` permission. - [List an Article's revisions](https://docs.getsurfaced.ai/api-reference/content/list-an-articles-revisions.md): Revision history, newest first, with cursor pagination. Rows are summaries without block bodies: fetch one revision to see its content. - [Snapshot the current Article as a revision](https://docs.getsurfaced.ai/api-reference/content/snapshot-the-current-article-as-a-revision.md): Records the Article's current saved content as a new revision, with an optional `changeSummary`. It does not change the article. Not idempotent: each call adds a revision. - [Get one revision](https://docs.getsurfaced.ai/api-reference/content/get-one-revision.md): Returns a revision with its title, description and `blocks`. A revision that belongs to another article is a 404. - [Restore an Article to a revision](https://docs.getsurfaced.ai/api-reference/content/restore-an-article-to-a-revision.md): Replaces the Article's content with the revision's. The state just before is saved first as `autoSnapshotRevisionId`, so a restore can itself be undone. `noOp: true` means the article already matched. Send `expectedVersion` (the `contentVersion` you last read) to fail with 409 `CONFLICT` if someone… - [Get an Article's fact-check](https://docs.getsurfaced.ai/api-reference/content/get-an-articles-fact-check.md): The latest stored fact-check: overall `score` (0-100), `summary` and every issue with its dismissal state. `score` and `issues` are empty when the article has not been fact-checked. Running a new fact-check is not exposed. Issues come from the stored report, so an issue dismissed in the app is shown… - [Dismiss a fact-check issue](https://docs.getsurfaced.ai/api-reference/content/dismiss-a-fact-check-issue.md): Marks an issue as dismissed with an optional `reason`. Idempotent: dismissing again updates the reason. The id is not validated against the report, so use ids from `GET /articles/{id}/fact-check`. Requires the `grade_content` permission. - [Restore a dismissed fact-check issue](https://docs.getsurfaced.ai/api-reference/content/restore-a-dismissed-fact-check-issue.md): Undoes a dismissal so the issue counts again. Idempotent: restoring an issue that is not dismissed succeeds. You can only restore dismissals made by the same user (the key's owner). - [Publish an Article to the hosted blog](https://docs.getsurfaced.ai/api-reference/content/publish-an-article-to-the-hosted-blog.md): Publishes the Article to the workspace's hosted blog, the same as the Publish button. Requires the hosted blog to be enabled (`POST /blog/enable`) and the `admin_section` permission. Responds 200 with `status: published` and the live `url` when it went live. Where the article has not passed its chec… - [Take an Article off the hosted blog](https://docs.getsurfaced.ai/api-reference/content/take-an-article-off-the-hosted-blog.md): Unpublishes the Article from the hosted blog. The article itself stays in the workspace. Requires the `admin_section` permission. Calling it on an article that is not published is a 404. - [Link an Article to its live URL](https://docs.getsurfaced.ai/api-reference/content/link-an-article-to-its-live-url.md): For articles published outside Surfaced: records where the article is live so AI citations can be attributed to it. Full replacement: `url` is the new value, `null` unlinks. The URL must be http(s) and unique in the workspace (409 `CONFLICT` otherwise). Pass `expectedVersion` (the article's `content… - [Get the hosted blog](https://docs.getsurfaced.ai/api-reference/content/get-the-hosted-blog.md): The workspace's hosted blog: settings (`site`, null until first enabled), domains and the published post count. `available: false` means the hosted blog is not enabled for this workspace or environment, so `POST /blog/enable` will fail. `entitledToWhiteLabel` says whether the plan allows removing th… - [Update the hosted blog settings](https://docs.getsurfaced.ai/api-reference/content/update-the-hosted-blog-settings.md): Partial update: send only the fields to change. `customCss` is sanitised; anything dropped is listed in `customCssRejected`. Removing the powered-by badge or setting custom CSS needs the white-label entitlement (403 `PERMISSION_DENIED` otherwise). The blog must have been enabled first (404 otherwise… - [Enable the hosted blog](https://docs.getsurfaced.ai/api-reference/content/enable-the-hosted-blog.md): Turns the hosted blog on with a `title` and provisions its default hostname. Idempotent: enabling an already-enabled blog returns the existing site. 403 `PERMISSION_DENIED` when the hosted blog is not rolled out to the workspace; 400 `BAD_REQUEST` when the environment does not support it. Requires t… - [Get a Brief's Run](https://docs.getsurfaced.ai/api-reference/content/get-a-briefs-run.md): A Brief has one current Run, which writes one Article per market and language. This returns the Run's own `state` (`not_started` until it is run) and item `counts`, one `items` entry per target with its writing `state` (`queued`, `writing`, `checking`, `didnt_finish`, `dropped` or `written`, the sam… - [Start a Brief's Run](https://docs.getsurfaced.ai/api-reference/content/start-a-briefs-run.md): Starts generating the Brief's Articles for its saved markets. Returns 202 with a `jobId` to poll (`GET /jobs/{id}`) and the `runId`; read the result with `GET /briefs/{id}/run`. Send an `Idempotency-Key` so a retry after a lost response returns the same Run instead of starting (and billing) a second… - [Cancel a Brief's Run](https://docs.getsurfaced.ai/api-reference/content/cancel-a-briefs-run.md): Stops the Brief's current Run. Targets that already finished keep their Articles; the rest are stopped. `cancelled: false` means the Run had already ended, so there was nothing to cancel. 404 when the Brief has no Run. Requires an owner, manager or editor. - [Retry a Brief's failed targets](https://docs.getsurfaced.ai/api-reference/content/retry-a-briefs-failed-targets.md): Restarts the `didnt_finish` targets of the Brief's current Run whose writing failed; written targets are left alone. `dropped` targets (markets someone stopped) are left alone too unless you send `includeDropped: true`, which resumes them as the app's Resume does: each one then uses article allowanc… - [Approve a Brief's run plan](https://docs.getsurfaced.ai/api-reference/content/approve-a-briefs-run-plan.md): For Briefs set to approve before drafting: approves the saved plan and starts the Run. Send back `planId`, `inputHash` and `expectedVersion` from `plan.id`, `plan.inputHash` and `plan.version` of `GET /briefs/{id}/run`. If the Brief, its settings or the sources changed after the plan was prepared th… - [List pages in the active workspace](https://docs.getsurfaced.ai/api-reference/pages/list-pages-in-the-active-workspace.md) - [Fetch a page](https://docs.getsurfaced.ai/api-reference/pages/fetch-a-page.md) - [Archive a page](https://docs.getsurfaced.ai/api-reference/pages/archive-a-page.md) - [Update page metadata](https://docs.getsurfaced.ai/api-reference/pages/update-page-metadata.md) - [Trigger a content pipeline run](https://docs.getsurfaced.ai/api-reference/runs/trigger-a-content-pipeline-run.md): Queues article-generation tasks for the supplied Content Briefs. Returns 202 with a `runId` and a `jobId`; poll `GET /jobs/{id}` until status is `completed` or `failed`, with a timeout: if the run is cancelled or stopped its job stays `queued` forever, so then check the run. Subject to billing (a pl… - [Get the status of a queued job](https://docs.getsurfaced.ai/api-reference/jobs/get-the-status-of-a-queued-job.md): Polls the status of a job returned by an operation that answers 202 with a `Location` header, such as `POST /briefs/{id}/run` or `POST /tracking-runs`. Final states are `completed` and `failed`. Until then the status stays `queued`, and a job whose run was cancelled or stopped never leaves `queued`… - [List registered webhook endpoints](https://docs.getsurfaced.ai/api-reference/webhooks/list-registered-webhook-endpoints.md) - [Register a webhook endpoint](https://docs.getsurfaced.ai/api-reference/webhooks/register-a-webhook-endpoint.md): Creates a signed webhook subscription. The `whsec_...` secret is returned only in this response; store it securely and verify the HMAC-SHA256 signature over the exact raw request body. - [Delete a webhook endpoint](https://docs.getsurfaced.ai/api-reference/webhooks/delete-a-webhook-endpoint.md) - [`runcompleted` event](https://docs.getsurfaced.ai/api-reference/webhooks/`runcompleted`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. Legacy name: the same payload is also delivered as `brief.run.completed`, which is the successor. A webhook subscribed to both names receives two deliv… - [`runitemcompleted` event](https://docs.getsurfaced.ai/api-reference/webhooks/`runitemcompleted`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. Legacy name: the same payload is also delivered as `brief.run.item.completed`, which is the successor. A webhook subscribed to both names receives two… - [`pagecreated` event](https://docs.getsurfaced.ai/api-reference/webhooks/`pagecreated`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. Legacy name: the same payload is also delivered as `article.created`, which is the successor. A webhook subscribed to both names receives two deliverie… - [`pageready` event](https://docs.getsurfaced.ai/api-reference/webhooks/`pageready`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. Legacy name: the same payload is also delivered as `article.ready`, which is the successor. A webhook subscribed to both names receives two deliveries. - [`pageneeds changes` event](https://docs.getsurfaced.ai/api-reference/webhooks/`pageneeds_changes`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. Legacy name: the same payload is also delivered as `article.needs_changes`, which is the successor. A webhook subscribed to both names receives two del… - [`pagepublished` event](https://docs.getsurfaced.ai/api-reference/webhooks/`pagepublished`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. Legacy name: the same payload is also delivered as `article.published`, which is the successor. A webhook subscribed to both names receives two deliver… - [`pageunpublished` event](https://docs.getsurfaced.ai/api-reference/webhooks/`pageunpublished`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. Legacy name: the same payload is also delivered as `article.unpublished`, which is the successor. A webhook subscribed to both names receives two deliv… - [`pagearchived` event](https://docs.getsurfaced.ai/api-reference/webhooks/`pagearchived`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. Legacy name: the same payload is also delivered as `article.archived`, which is the successor. A webhook subscribed to both names receives two deliveri… - [`pagereviewed` event](https://docs.getsurfaced.ai/api-reference/webhooks/`pagereviewed`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. No longer accepted for new subscriptions; existing subscriptions keep working. - [`trackingruncompleted` event](https://docs.getsurfaced.ai/api-reference/webhooks/`trackingruncompleted`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. Legacy name: the same payload is also delivered as `tracking_run.completed`, which is the successor. A webhook subscribed to both names receives two de… - [`evaluationcompleted` event](https://docs.getsurfaced.ai/api-reference/webhooks/`evaluationcompleted`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. No longer accepted for new subscriptions; existing subscriptions keep working. - [`scancompleted` event](https://docs.getsurfaced.ai/api-reference/webhooks/`scancompleted`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. No longer accepted for new subscriptions; existing subscriptions keep working. - [`articlecreated` event](https://docs.getsurfaced.ai/api-reference/webhooks/`articlecreated`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. Canonical name: emitted alongside the legacy `page.created` with an identical payload. A webhook subscribed to both names receives two deliveries. - [`articleready` event](https://docs.getsurfaced.ai/api-reference/webhooks/`articleready`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. Canonical name: emitted alongside the legacy `page.ready` with an identical payload. A webhook subscribed to both names receives two deliveries. - [`articleneeds changes` event](https://docs.getsurfaced.ai/api-reference/webhooks/`articleneeds_changes`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. Canonical name: emitted alongside the legacy `page.needs_changes` with an identical payload. A webhook subscribed to both names receives two deliveries… - [`articlepublished` event](https://docs.getsurfaced.ai/api-reference/webhooks/`articlepublished`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. Canonical name: emitted alongside the legacy `page.published` with an identical payload. A webhook subscribed to both names receives two deliveries. - [`articleunpublished` event](https://docs.getsurfaced.ai/api-reference/webhooks/`articleunpublished`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. Canonical name: emitted alongside the legacy `page.unpublished` with an identical payload. A webhook subscribed to both names receives two deliveries. - [`articlearchived` event](https://docs.getsurfaced.ai/api-reference/webhooks/`articlearchived`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. Canonical name: emitted alongside the legacy `page.archived` with an identical payload. A webhook subscribed to both names receives two deliveries. - [`briefruncompleted` event](https://docs.getsurfaced.ai/api-reference/webhooks/`briefruncompleted`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. Canonical name: emitted alongside the legacy `run.completed` with an identical payload. A webhook subscribed to both names receives two deliveries. - [`briefrunitemcompleted` event](https://docs.getsurfaced.ai/api-reference/webhooks/`briefrunitemcompleted`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. Canonical name: emitted alongside the legacy `run.item.completed` with an identical payload. A webhook subscribed to both names receives two deliveries… - [`tracking runcompleted` event](https://docs.getsurfaced.ai/api-reference/webhooks/`tracking_runcompleted`-event.md): Delivered as a POST to the subscribed URL. Verify `X-Surfaced-Signature` (HMAC-SHA256 over the raw body); `X-Surfaced-Event` carries the event name. Canonical name: emitted alongside the legacy `tracking.run.completed` with an identical payload. A webhook subscribed to both names receives two delive… - [Read immutable Autopilot policy history](https://docs.getsurfaced.ai/api-reference/autopilot/read-immutable-autopilot-policy-history.md): Returns the newest policy versions for one project in the workspace selected by `X-Workspace-Id`. Requires API read access and `manage_settings` permission. - [Activate a new Autopilot policy version](https://docs.getsurfaced.ai/api-reference/autopilot/activate-a-new-autopilot-policy-version.md): Atomically appends and activates an immutable policy version. Requires API `write` scope, `manage_settings`, and the exact workspace rollout flag. `requestId` is the idempotency identity: replaying the same request returns the original policy and receipt. - [Immediately stop an active Autopilot policy](https://docs.getsurfaced.ai/api-reference/autopilot/immediately-stop-an-active-autopilot-policy.md): Revokes the active policy version atomically. Emergency stop remains available when rollout and execution flags are off. Requires API `write` scope and `manage_settings`. Reusing the same `requestId` with the same request is idempotent. - [List current Autopilot strategy approvals](https://docs.getsurfaced.ai/api-reference/autopilot/list-current-autopilot-strategy-approvals.md): Returns unreviewed, non-stale pre-generation decisions for one project. Each item includes persisted policy reason codes, cost, priority inputs, sanitized frozen observation facts, and prior-learning signals. Prompt text, response excerpts, and model logs are never returned. Reviewed and stale decis… - [Approve or reject one frozen Autopilot strategy](https://docs.getsurfaced.ai/api-reference/autopilot/approve-or-reject-one-frozen-autopilot-strategy.md): Reviews the exact persisted policy version and evidence revision selected by `decisionId`. The decision identity itself is the idempotency boundary: an exact replay returns the existing review, while different policy, evidence, or resolution facts conflict. Approval requires the current rollout and… - [Get a page-action review capability](https://docs.getsurfaced.ai/api-reference/autopilot/get-a-page-action-review-capability.md): Returns a bounded, server-derived review capability for one current metadata, FAQ/schema, or internal-link proposal. The response includes a sanitized reason summary and allowed outcomes, never caller-supplied authority hashes or raw review artifacts. - [Resolve a page-action human review](https://docs.getsurfaced.ai/api-reference/autopilot/resolve-a-page-action-human-review.md): Approves an exact unchanged eligible Managing Editor escalation, rejects it, or requests one bounded fresh repair. The server derives reviewer identity, request id, current attempt, gate, source, policy, and receipt bindings. expectedSourceGateReceiptId optionally constrains the decision to the gate… - [Preview exact saved page improvements](https://docs.getsurfaced.ai/api-reference/autopilot/preview-exact-saved-page-improvements.md): Returns bounded original and proposed content from the exact frozen source and checked proposal, or saved full-rewrite revisions. No current-Page fallback, execution or publication occurs. Missing historical provenance returns unavailable. - [List ranked visibility opportunities](https://docs.getsurfaced.ai/api-reference/autopilot/list-ranked-visibility-opportunities.md): Returns bounded, customer-safe opportunity evidence and deterministic priority components for one workspace project. Agent logs and mutable analyzer payloads are not exposed. - [List Autopilot closure plans and locale progress](https://docs.getsurfaced.ai/api-reference/autopilot/list-autopilot-closure-plans-and-locale-progress.md): Returns each governed plan with its independent locale targets, durable status, published URL when available, and actual versus estimated spend. - [Prepare an independently localized article plan from a content gap](https://docs.getsurfaced.ai/api-reference/autopilot/prepare-an-independently-localized-article-plan-from-a-content-gap.md): Validates the gap's frozen evidence, plans every configured locale independently, and persists one immutable assisted plan without authorizing execution. The server derives idempotency from workspace, evidence revision, and target set; an exact replay returns the same plan. Requires API `write` scop… - [Inspect a closure plan's evidence trail](https://docs.getsurfaced.ai/api-reference/autopilot/inspect-a-closure-plans-evidence-trail.md): Returns the customer-facing plan cockpit together with publication receipts and measured outcomes. Locale lanes remain separate; this endpoint never presents them as translations. - [Authorize persisted plan truth and attempt durable dispatch](https://docs.getsurfaced.ai/api-reference/autopilot/authorize-persisted-plan-truth-and-attempt-durable-dispatch.md): Atomically authorizes only the persisted assisted plan and its required locale targets, then best-effort drains the durable workflow outbox. Authorization and dispatch are reported separately: transport failure never rolls back or disguises committed approval, and scheduled recovery can retry pendin… - [Stop an in-progress Autopilot closure plan](https://docs.getsurfaced.ai/api-reference/autopilot/stop-an-in-progress-autopilot-closure-plan.md): Atomically cancels remaining cancellable locale work and releases pending reservations. The stop remains available when rollout or execution switches are off. Any current workspace editor, manager or owner may stop it; the receipt records who stopped it and the plan keeps its original authorizer. `r… - [Undo an applied local Autopilot page action](https://docs.getsurfaced.ai/api-reference/autopilot/undo-an-applied-local-autopilot-page-action.md): Restores the exact pre-action workspace revision for one applied update, metadata, FAQ, or internal-link target. The server derives strategy, source page, revision, workspace, and apply receipt from the durable plan and target. It refuses recovery after newer local edits, never mutates the live CMS,… - [Get the visibility summary](https://docs.getsurfaced.ai/api-reference/insights/get-the-visibility-summary.md): The headline numbers behind the Analytics page for a window: brand visibility, citation rate, average position, sentiment and share of voice (`current`), the same over the equally long window before it (`previous`, to compute change), a per-AI-platform breakdown and the most-mentioned entities (`com… - [Get the daily visibility trend](https://docs.getsurfaced.ai/api-reference/insights/get-the-daily-visibility-trend.md): Daily measurements for a window, one point per day and AI platform. To chart brand visibility per day, sum `brandVisibilityMentions` and `totalResponses` over the platforms of each day and divide. Same filters, window rules and permission as `GET /analytics/summary`. - [List tracking runs](https://docs.getsurfaced.ai/api-reference/insights/list-tracking-runs.md): Tracking runs of the workspace, newest first. A tracking run measures the brand's active prompts across the tracked AI platforms; it is not a Brief's content run (`/briefs/{id}/run`). Filter by `status`. For the latest run use `?limit=1`. Requires `admin_section`. - [Start a tracking run](https://docs.getsurfaced.ai/api-reference/insights/start-a-tracking-run.md): Starts a run over the brand's active prompts on the workspace's tracked AI platforms, and returns 202 with `runId`, `jobId` and a `Location` header for the run. Poll `GET /tracking-runs/{id}` until `status` is final (`completed`, `completed_with_errors`, `failed`, `cancelled`), with a timeout. This… - [Get a tracking run](https://docs.getsurfaced.ai/api-reference/insights/get-a-tracking-run.md): One tracking run: its `status`, `engines`, progress in `stats` (`total`, `completed`, `failed`) and, when something went wrong, `errorSummary`. Poll this after `POST /tracking-runs`. Requires `admin_section`. - [Cancel a tracking run](https://docs.getsurfaced.ai/api-reference/insights/cancel-a-tracking-run.md): Cancels a `queued` or `running` run and returns it with `status: cancelled`. Responses already collected are kept; unspent quota is not refunded by this call. A run in any other status is 422 `VALIDATION_ERROR`. Requires `write` scope and `admin_section`. - [List the prompts](https://docs.getsurfaced.ai/api-reference/insights/list-the-prompts.md): The prompts the workspace asks the tracked AI platforms, newest first. Add `include=stats` to attach each prompt's measurements over `from`..`to` (default last 30 days) as `stats`; a prompt the stats do not cover has `stats: null`. Stats are computed in one query, so keep `limit` modest. Filter with… - [Create a prompt](https://docs.getsurfaced.ai/api-reference/insights/create-a-prompt.md): Adds a prompt. It starts inactive and is not measured until activated with `PATCH /prompts/{id}` `{ "active": true }`. When `targetCountry` is omitted it follows the workspace's market, then the brand's default country; when `targetLanguage` is omitted it is detected from the text. `targetCountry` i… - [Get a prompt](https://docs.getsurfaced.ai/api-reference/insights/get-a-prompt.md): One prompt with the topics it is tagged with (`topics`). Use `GET /prompts?include=stats` for measurements. A prompt of another workspace is 404. Requires `view_content`. - [Delete a prompt](https://docs.getsurfaced.ai/api-reference/insights/delete-a-prompt.md): Permanently deletes the prompt. To stop measuring it without losing it, `PATCH` it with `active: false` instead. Requires `write` scope and `admin_section`. - [Update a prompt](https://docs.getsurfaced.ai/api-reference/insights/update-a-prompt.md): Partial update, at least one field. `active: true` activates the prompt so runs measure it (422 when the plan's prompt limit is reached). Changing `promptText` marks translations in the same prompt group as stale. Changing `targetCountry` or `targetLanguage` re-targets the prompt without touching it… - [Replace a prompt's topics](https://docs.getsurfaced.ai/api-reference/insights/replace-a-prompts-topics.md): Sets the prompt's complete topic set: topics not listed are removed, `[]` clears all. Idempotent. Every topic must belong to the workspace, else 404. Returns the resulting topics. Requires `write` scope and `admin_section`. - [List topics](https://docs.getsurfaced.ai/api-reference/insights/list-topics.md): Topics group the workspace's prompts so analytics can be filtered by theme (`topics` on the analytics and sources endpoints). All topics, ordered by name, in one page. Requires `view_content`. - [Create a topic](https://docs.getsurfaced.ai/api-reference/insights/create-a-topic.md): Creates a topic. `color` defaults to a blue (`#3B82F6`) and `icon` to `tag`. Tag prompts with it through `PUT /prompts/{id}/topics`. Requires `write` scope and `admin_section`. - [Delete a topic](https://docs.getsurfaced.ai/api-reference/insights/delete-a-topic.md): Deletes the topic and removes it from every prompt it was on; the prompts themselves are kept. Requires `write` scope and `admin_section`. - [Update a topic](https://docs.getsurfaced.ai/api-reference/insights/update-a-topic.md): Partial update, at least one field. `description: null` clears the description. Requires `write` scope and `admin_section`. - [List the sources AI platforms cite](https://docs.getsurfaced.ai/api-reference/insights/list-the-sources-ai-platforms-cite.md): The domains the tracked AI platforms cited in their answers, one row per domain, most cited first by default, with the citation count and its split by AI platform, language and market. Use it to see which sites shape AI answers about the brand and its category. The window is `from`..`to` (default la… - [List tracked competitors](https://docs.getsurfaced.ai/api-reference/insights/list-tracked-competitors.md): The entities the workspace pinned as competitors: what Share of Voice and Rival Share are measured against. The plan caps how many there are, so they come in one page. `id` identifies the pin (use it with `DELETE /competitors/{id}`); `entityId` is the id analytics uses. Requires `view_content`. - [Track a competitor](https://docs.getsurfaced.ai/api-reference/insights/track-a-competitor.md): Pins a competitor. Provide exactly one of `entityId` (an entity seen in analytics, `GET /analytics/summary` `competitors[].entityId`) or `name` with an optional `url` (resolved to an entity first). Returns 201 for a new pin and 200 when it was already tracked. The workspace's own brand cannot be a c… - [Stop tracking a competitor](https://docs.getsurfaced.ai/api-reference/insights/stop-tracking-a-competitor.md): Removes the pin. The entity and its past mentions remain in analytics; it just stops counting as a tracked competitor. `id` is the pin id from `GET /competitors`. Requires `write` scope and `admin_section`. - [Get the Audit report](https://docs.getsurfaced.ai/api-reference/insights/get-the-audit-report.md): The Insights > Audit report: the stored technical and on-page audit of the brand's website as a site-wide score and grade with one check per finding (`severity` is `pass`, `warning` or `error`). Each failing check also appears as an Action with `source: website_check`, referenced by `evidence.auditC… - [Re-run the Audit report](https://docs.getsurfaced.ai/api-reference/insights/re-run-the-audit-report.md): Re-runs the Insights > Audit report: queues a fresh audit of the brand's website (it scrapes up to 15 pages) and answers 202 with a `jobId`; poll `GET /jobs/{id}` until `completed` or `failed`, then read `GET /audit-report`. Failing checks are refreshed as `website_check` actions. At most one audit… - [List actions](https://docs.getsurfaced.ai/api-reference/improve/list-actions.md): Lists every finding as an Action: the improvements Surfaced proposes or the workspace has chosen to do, newest first. Content gaps, failing website checks and Backlink opportunities all appear here, told apart by `source`. Filter with `status`: `new` (suggestions to accept or decline), `in_progress`… - [Create a manual action](https://docs.getsurfaced.ai/api-reference/improve/create-a-manual-action.md): Adds an action of your own (`source: manual`); it starts `in_progress`. Send an `Idempotency-Key` header (a UUID) to make a retry return the same action instead of creating a duplicate; without it every call creates one. Requires write access. - [Get an action with its evidence](https://docs.getsurfaced.ai/api-reference/improve/get-an-action-with-its-evidence.md): Returns one action with the evidence behind it. `evidenceVersion` is the immutable machine proposal (evidence, proposed brief and steps). For `content_gap` actions `gap` is the live measurement of the gap; for `website_check` actions `auditFinding` is the finding. Both are null when that source is g… - [Accept an action](https://docs.getsurfaced.ai/api-reference/improve/accept-an-action.md): Accept only: moves a `new` action to `in_progress` without writing a Brief, and starts measuring the action's outcome from now. An action that already reads `in_progress` stays `in_progress`: if it was a to-do (saved earlier, or created by hand and not started) it moves to the app's In progress tab… - [Mark an action done](https://docs.getsurfaced.ai/api-reference/improve/mark-an-action-done.md): Moves an action to `done`. 422 if it is already archived (`done` or `declined`). Send `expectedVersion` (the action's `version`) to get 409 `CONFLICT` if it changed since you read it; omit it to apply on the current version. Requires write access and an editor-level role. - [Decline an action](https://docs.getsurfaced.ai/api-reference/improve/decline-an-action.md): Moves an action to `declined`. 422 if it is already archived; use `restore` to undo. The optional `reason` decides whether Surfaced brings the action back on its own: `not_relevant` never; `already_covered` once its content gap is 15 points worse than when it was declined; `not_now` 30 days later; `… - [Restore a done or declined action](https://docs.getsurfaced.ai/api-reference/improve/restore-a-done-or-declined-action.md): Returns a `declined` action to the status it had when it was declined. A `done` action, or one declined before Surfaced recorded that status, returns to open work: `new` for a machine-proposed action, `in_progress` for a manual action. 422 if it is not archived. Send `expectedVersion` (the action's… - [Write a Brief for a content-gap action](https://docs.getsurfaced.ai/api-reference/improve/write-a-brief-for-a-content-gap-action.md): Accepts a `content_gap` action and creates the content work for it, like Write Brief in the app: a Content Brief and a plan with one target per market, prepared for approval. It moves the action to `in_progress`. Nothing is written or charged against the article allowance until the plan is approved;… - [Get all workspace settings](https://docs.getsurfaced.ai/api-reference/settings/get-all-workspace-settings.md): One read of everything a client can configure: brand voice, target markets, audiences and categories, SEO rules and the default tracking models. Public fields only; model routing, prompt overlays and integration credentials are never included. Use it to snapshot configuration, then change a section… - [Get the brand voice](https://docs.getsurfaced.ai/api-reference/settings/get-the-brand-voice.md): The structured brand voice that steers how content is written: formality, tone, point of view, jargon, forbidden word categories and a custom blacklist. Needs the `view_content` permission (every workspace role has it). - [Change the brand voice](https://docs.getsurfaced.ai/api-reference/settings/change-the-brand-voice.md): Partial update: send only the fields to change; omitted fields keep their value. Send at least one field, and nothing the schema does not list. Arrays (`emotionalTones`, `customBlacklist`, ...) replace the stored array whole. At most 2 emotional tones, personalities and persuasion styles; at most 20… - [Get the target markets](https://docs.getsurfaced.ai/api-reference/settings/get-the-target-markets.md): The market and language pairs new content is written for. Each entry has either a `marketRef` (an ISO country code or a market preset key) or an inline `market`. Needs the `view_content` permission (every workspace role has it). - [Replace the target markets](https://docs.getsurfaced.ai/api-reference/settings/replace-the-target-markets.md): Full replacement: the list you send becomes the target markets, so include every market you want to keep. At least one and at most 100 entries. Each entry has exactly one of `marketRef` and `market`, plus a `language` code. Unknown countries, languages or market references are rejected. Formality ov… - [Get audiences and categories](https://docs.getsurfaced.ai/api-reference/settings/get-audiences-and-categories.md): The audience (persona) and category presets content can be written for, as plain names. They are identified by name, not by id. Needs the `view_content` permission (every workspace role has it). - [Replace audiences and categories](https://docs.getsurfaced.ai/api-reference/settings/replace-audiences-and-categories.md): Full replacement of both lists: names missing from the body are removed, new names are added. Names are trimmed and de-duplicated; up to 100 per list, 200 characters each. Send both lists even when changing one, or the other is emptied. Needs the `manage_settings` permission (workspace owner or mana… - [Get the SEO rules](https://docs.getsurfaced.ai/api-reference/settings/get-the-seo-rules.md): Title, description and excerpt patterns (or custom templates), keyword placements, target regions and allowed internal-link patterns applied to generated content. Needs the `view_content` permission (every workspace role has it). - [Change the SEO rules](https://docs.getsurfaced.ai/api-reference/settings/change-the-seo-rules.md): Partial update: send only the fields to change, at least one. A `custom` pattern uses the matching `custom*Template`; templates are limited to 150 safe characters and use single braces for placeholders, e.g. `{topic} | {brand}`. Custom templates need a Pro plan or higher (403 otherwise). Needs the `… - [Get the default tracking models](https://docs.getsurfaced.ai/api-reference/settings/get-the-default-tracking-models.md): The AI models visibility tracking asks by default (`models`), the models the plan allows (`availableModels`) and the monthly tracked-response quota forecast. `forecast.limit` is `-1` for unlimited and `null` when it could not be determined. Needs the `view_content` permission (every workspace role h… - [Replace the default tracking models](https://docs.getsurfaced.ai/api-reference/settings/replace-the-default-tracking-models.md): Full replacement: the slugs you send become the active default models; every other model is switched off. At least one slug, each from `availableModels`; a model outside the plan is a 422. Prompts with their own model override are not affected. Enabling a model schedules tracking for existing prompt… - [Get whether Content Agent is on](https://docs.getsurfaced.ai/api-reference/settings/get-whether-content-agent-is-on.md): Reads the Content Agent switch (in the app: Settings › Content). `state` is `on` (it prepares work for approval), `observing` (off, but it keeps watching for opportunities), `stopped` (off after an emergency stop), `setup_required` (nothing to switch on until markets and settings are saved) or `unav… - [Turn Content Agent on or off](https://docs.getsurfaced.ai/api-reference/settings/turn-content-agent-on-or-off.md): Switches Content Agent on or off. Turning it on lets it prepare work for your approval; nothing is published without approval and your plan's article allowance is used only when you approve. Turning it off keeps your settings and works during an emergency stop. Requires `write` scope and owner or ma… - [Get the Content Agent settings](https://docs.getsurfaced.ai/api-reference/settings/get-the-content-agent-settings.md): Returns the current versioned settings: pace, allowed actions, approval rules, markets and the destination route. `version` is 0 and `policy` is null when settings were never saved (the built-in defaults apply). Internal cost ceilings are not exposed. Requires `manage_settings`. - [Save the Content Agent settings](https://docs.getsurfaced.ai/api-reference/settings/save-the-content-agent-settings.md): Replaces the settings with a new version, through the same checks as the dashboard form. Read the settings first, change what you need, and send `policy` with the `version` you read as `expectedVersion`. Only the fields in the request are honoured: `thresholds`, `cooldownDays` and every cost ceiling… - [List the saved Content Agent settings versions](https://docs.getsurfaced.ai/api-reference/settings/list-the-saved-content-agent-settings-versions.md): Returns the saved settings versions, newest first. Versions are immutable: each save, switch on and switch off appends one, so this is the audit trail of who changed what and when (`authorizedBy`, `authorizedAt`, `supersededAt`). Returns at most `limit` versions (default 20, max 50) with no cursor.… - [List the opportunities Content Agent found](https://docs.getsurfaced.ai/api-reference/settings/list-the-opportunities-content-agent-found.md): Returns ranked, customer-safe opportunities with their priority components and the intervention Content Agent recommends. Use it to see what it would work on next; use `GET /content-agent/approvals` for what is waiting for a decision. Returns at most `limit` items (max 50) with no cursor. - [List Content Agent plans](https://docs.getsurfaced.ai/api-reference/settings/list-content-agent-plans.md): Returns plans with their locale targets, status, published URL when available, and actual versus estimated spend. Each market is planned and generated independently: a target is not a translation of another. Returns at most `limit` items (max 50) with no cursor. - [Prepare a plan from a content gap](https://docs.getsurfaced.ai/api-reference/settings/prepare-a-plan-from-a-content-gap.md): Validates the gap's frozen evidence, plans every configured locale independently and saves one plan without starting any generation: approve it with `POST /content-agent/plans/{planId}/approve`. Idempotency is derived from the evidence and the target set, so an exact replay returns the same plan wit… - [Get a plan with its evidence trail](https://docs.getsurfaced.ai/api-reference/settings/get-a-plan-with-its-evidence-trail.md): Returns the plan, its publication receipts and measured outcomes. Locale lanes stay separate: this never presents them as translations. - [Approve a plan and start generation](https://docs.getsurfaced.ai/api-reference/settings/approve-a-plan-and-start-generation.md): Approves the saved plan and its required locale targets, then tries to start generation. Approval and dispatch are reported separately: a dispatch failure never undoes the approval, and a scheduled job retries pending dispatch. Approving an approved plan is a no-op: it is guarded by `expectedStatus`… - [Stop a plan in progress](https://docs.getsurfaced.ai/api-reference/settings/stop-a-plan-in-progress.md): Cancels the remaining cancellable locale work and releases pending reservations. It works even when Content Agent is switched off. Any editor, manager or owner may stop a plan. Send `expectedStatus` (the status you last read), a `reason`, and an `Idempotency-Key` header (or `requestId` in the body):… - [Undo an applied change to an existing article](https://docs.getsurfaced.ai/api-reference/settings/undo-an-applied-change-to-an-existing-article.md): Restores the exact previous version for one applied article update, metadata, FAQ or internal-link target. The server derives everything but `targetId` from the plan. It refuses when the article was edited since, never changes the live CMS (`remoteCmsMutated` is always false; `remoteSyncRequired` sa… - [Get the review state of a proposed change](https://docs.getsurfaced.ai/api-reference/settings/get-the-review-state-of-a-proposed-change.md): For a plan target that changes an existing article (metadata, FAQ or schema, internal links), returns whether a human review is `pending`, `resolved`, `stale` or `unavailable`, the sanitized reason, and which outcomes are allowed now. Read it before `POST` so you know whether to approve, reject or r… - [Approve, reject or repair a proposed change](https://docs.getsurfaced.ai/api-reference/settings/approve-reject-or-repair-a-proposed-change.md): Resolves the human review of one proposed change: `approve` the exact unchanged proposal, `reject` it, or `request_repair` for one bounded fresh attempt (`reject` and `request_repair` need a `reason`). The server derives the reviewer, attempt, gate and receipts. `expectedSourceGateReceiptId` pins th… - [Preview a proposed change to an article](https://docs.getsurfaced.ai/api-reference/settings/preview-a-proposed-change-to-an-article.md): Returns the original and proposed content for one target, from the exact saved source and checked proposal. Nothing is executed or published, and it never falls back to the live article: when the saved history is missing it returns `state: "unavailable"` with a message. Pass the returned `sourceGate… - [List what is waiting for your approval](https://docs.getsurfaced.ai/api-reference/settings/list-what-is-waiting-for-your-approval.md): Returns the current, unreviewed strategy decisions made before any generation spend: the recommended intervention, cost, priority inputs, sanitized observations and prior-learning signals. Reviewed and stale decisions are excluded. Decide each with `POST /content-agent/approvals/{decisionId}/decide`… - [Approve or reject a proposed strategy](https://docs.getsurfaced.ai/api-reference/settings/approve-or-reject-a-proposed-strategy.md): Decides one frozen strategy. Send back the `policyId`, `policyVersion` and `evidenceRevisionHash` you were shown, plus `resolution` `approve` or `reject`. If the settings or evidence changed meanwhile it is a 409: read the queue again. The decision id is the idempotency boundary, so an exact replay… - [List organization members](https://docs.getsurfaced.ai/api-reference/workspace/list-organization-members.md): Every member of the organization that owns the workspace in `X-Workspace-Id`, with `userId`, `role` (`owner`, `admin`, `member`) and, when known, `email` and `name` (omitted, not null, when absent). Not paginated. Use `userId` as `{id}` in `PATCH`/`DELETE /organization/members/{id}`. Pending invitat… - [Invite someone to the organization](https://docs.getsurfaced.ai/api-reference/workspace/invite-someone-to-the-organization.md): Adds a person to the organization that owns the workspace in `X-Workspace-Id`. Someone who already has an account is added at once (`outcome: added`, with `userId`); anyone else gets a pending 7-day invitation (`outcome: invited`, with `invitationId`). `role` defaults to `member`. Needs organization… - [Remove an organization member](https://docs.getsurfaced.ai/api-reference/workspace/remove-an-organization-member.md): `id` is the member's user id. Removes them from the organization. Needs organization owner or admin; the last owner cannot be removed. - [Change an organization member's role](https://docs.getsurfaced.ai/api-reference/workspace/change-an-organization-members-role.md): `id` is the member's user id (`userId` in the member list). Needs organization owner or admin; you cannot change your own role, manage someone above you, or assign a role above yours. A user who is not in this organization is 404. - [List workspace members](https://docs.getsurfaced.ai/api-reference/workspace/list-workspace-members.md): Every member of the workspace in `X-Workspace-Id`, oldest first. `id` is the membership row id, `userId` the user id; either works as `{id}` in `PATCH`/`DELETE /workspace/members/{id}`. `email` and `name` are null when the profile has none. Not paginated. Needs the admin section permission (workspac… - [Add someone to the workspace](https://docs.getsurfaced.ai/api-reference/workspace/add-someone-to-the-workspace.md): Adds a person to the workspace in `X-Workspace-Id` with the given role. Someone with an account is added at once (`outcome: added`); anyone else gets a pending 7-day invitation (`outcome: invited`, with `invitationId` and `expiresAt`). Needs the `invite_members` permission. Repeating the call answer… - [Remove a workspace member](https://docs.getsurfaced.ai/api-reference/workspace/remove-a-workspace-member.md): `id` is the member's user id or their membership row id (looked up as a membership id first, then as a user id); see `PATCH /workspace/members/{id}`. Needs `manage_settings`. You cannot remove yourself, and only an owner can remove an owner or the last owner. - [Change a workspace member's role](https://docs.getsurfaced.ai/api-reference/workspace/change-a-workspace-members-role.md): `id` is the member's user id (`userId` in `GET /workspace/members`) or, for backward compatibility, their membership row id (`id` in that list). It is looked up as a membership id first, then as a user id within this workspace; no match is 404. Needs `manage_settings`. Only an owner can change an ow… - [Approve a join request](https://docs.getsurfaced.ai/api-reference/workspace/approve-a-join-request.md): Approves a pending join request. Account-level: the request carries its workspace, so no `X-Workspace-Id` is needed. Needs workspace owner or manager in that workspace. A request in a workspace you do not belong to, or outside a scoped key's workspaces, is 404. List requests with `GET /workspace/joi… - [Reject a join request](https://docs.getsurfaced.ai/api-reference/workspace/reject-a-join-request.md): Rejects a pending join request. Account-level: the request carries its workspace, so no `X-Workspace-Id` is needed. Needs workspace owner or manager in that workspace. A request in a workspace you do not belong to, or outside a scoped key's workspaces, is 404. List requests with `GET /workspace/join… - [Get the workspace](https://docs.getsurfaced.ai/api-reference/workspace/get-the-workspace.md): The workspace in `X-Workspace-Id`: id, name, `ownerId`, `createdAt`, `settings` (the full normalized settings object: brand tone, SEO rules, models, `accessControl` in snake_case, ...; integration credentials are never included) and `brand`, the brand the workspace tracks: name, website, domain, col… - [Change workspace settings](https://docs.getsurfaced.ai/api-reference/workspace/change-workspace-settings.md): Partial update of the workspace's own settings: `reviewPolicy` (`gate`, `hybrid`, `auto`), `contentPurpose` (`human`, `seo`, `geo`), `reviewerUiLanguage` (BCP-47, e.g. `en-US`) and `quality` (score weights and ship/escalate thresholds), which need `manage_settings`; and `brand`, the brand the worksp… - [Get the workspace access policy](https://docs.getsurfaced.ai/api-reference/workspace/get-the-workspace-access-policy.md): Who may join the workspace: `mode` (`invite_only`, `domain_restricted`, `open`), `allowedDomains` and `defaultRole`, the same camelCase form `PUT /workspace/access` returns. Every key of the stored policy is also kept next to them, so `allowed_domains` and `default_role` are deprecated aliases and a… - [Replace the workspace access policy](https://docs.getsurfaced.ai/api-reference/workspace/replace-the-workspace-access-policy.md): Full replacement of who may join the workspace. `mode`: `invite_only` (invitation required), `domain_restricted` (people with an email on `allowedDomains` can request to join; list at least one domain) or `open`. `defaultRole` (`viewer` or `reviewer`) is what an approved join request gets. Always se… - [Get the organization](https://docs.getsurfaced.ai/api-reference/workspace/get-the-organization.md): The organization that owns the workspace in `X-Workspace-Id`: id, name, `createdAt` and `memberCount`. `created_at` is a deprecated alias of `createdAt`. A workspace with no organization is 404. - [Get the organization's billing summary](https://docs.getsurfaced.ai/api-reference/workspace/get-the-organizations-billing-summary.md): Plan id, whether a Stripe subscription exists and the organization's workspace count. Owner only: org admins get 403, and a platform superadmin counts as owner. No payment details or Stripe ids are returned. `planId` is null on an organization without a plan. - [Cancel an organization invitation](https://docs.getsurfaced.ai/api-reference/workspace/cancel-an-organization-invitation.md): Deletes a pending invitation created by `POST /organization/members`. Needs organization owner or admin. An invitation that belongs to another organization (or does not exist, or was already accepted or cancelled) is 404. The invitation id is the `invitationId` returned when inviting. - [List join requests](https://docs.getsurfaced.ai/api-reference/workspace/list-join-requests.md): Join requests, of every status, for the workspaces the caller owns or manages, newest first. Account-level: spans workspaces and takes no `X-Workspace-Id`; a workspace-scoped key sees only its workspaces. Returns `{ requests: [...] }` with camelCase fields (`workspaceId`, `requestedAt`, ...) plus th… - [List knowledge documents](https://docs.getsurfaced.ai/api-reference/knowledge/list-knowledge-documents.md): The documents the writer can draw on, newest first, without their text. `type` is `uploaded` (files and text you added), `website` (pages indexed from your site, with `sourceUrl`) or `system` (generated by Surfaced, e.g. the product catalogue snapshot). Filter with `?type=`; page with `limit` (defau… - [Add a knowledge document](https://docs.getsurfaced.ai/api-reference/knowledge/add-a-knowledge-document.md): Adds a document and makes it searchable (extraction, chunking and embedding run before the response). Send `multipart/form-data` with `title` and `file` (.txt .md .pdf .docx .csv .json, 1 byte to 4 MB, as Vercel rejects larger request bodies), or `application/json` with `{ title, content }` for plai… - [Delete a knowledge document](https://docs.getsurfaced.ai/api-reference/knowledge/delete-a-knowledge-document.md): Deletes the document and its embeddings. It stops informing new content immediately; pages already written are unchanged. Needs `manage_settings` (workspace owner or manager). - [Search the knowledge base](https://docs.getsurfaced.ai/api-reference/knowledge/search-the-knowledge-base.md): Semantic search across the workspace's documents, best match first (`score` is similarity, recency-weighted). Read-only: accepts `read` or `write` key scope; POST carries the query body. `limit` defaults to 5, max 20. Needs `view_content`. - [Queue website pages for the knowledge base](https://docs.getsurfaced.ai/api-reference/knowledge/queue-website-pages-for-the-knowledge-base.md): With `urls` (1 to 25): those pages become your selected website pages and are queued for indexing. Without `urls`: re-queues the pages already selected (the 25 least recently selected); 409 when none are selected. Returns 202 as soon as the pages are queued: indexing runs in the background, and each… - [Refresh the product catalogue](https://docs.getsurfaced.ai/api-reference/knowledge/refresh-the-product-catalogue.md): Queues a refresh of the workspace's product catalogue (Shopify or WooCommerce feed). A storefront that was detected is re-imported (`queued: import`); one whose last check was blocked is re-checked and imported on success (`queued: detect`); in any other state there is nothing to sync (409). Returns… - [Partner API](https://docs.getsurfaced.ai/api/partner-api.md): Run an AI-visibility scan of any company from your own product, and receive the result as it firms up. - [Start a competitor scan](https://docs.getsurfaced.ai/api-reference/scans/start-a-competitor-scan.md): Starts a scan and holds the request for up to ~110 seconds waiting for completion (sync-with-wait). Fast basic-tier scans return the full result inline as 200. A scan that FAILS inside the window also returns 200, carrying the terminal `PartnerScanFailedOutput` with its `error` block — so a 200 mean… - [Get scan status / result](https://docs.getsurfaced.ai/api-reference/scans/get-scan-status-result.md): Poll a scan by id. Returns 200 with a payload in three cases: completed, preliminary (a mid-run snapshot with live geo_score/band — more useful than an empty acknowledgement), and failed (the terminal `PartnerScanFailedOutput`, `error` block included). 202 is reserved for a scan that is genuinely st… - [List scan history](https://docs.getsurfaced.ai/api-reference/history/list-scan-history.md): Paginated scan history for the authenticated partner, newest first. Defaults to the last 30 days — pass an explicit ?from to reach further back, or ?month for a calendar-month shorthand. Uses cursor pagination within the window: pass the previous page's next_cursor as ?cursor to fetch older entries.… - [Get monthly usage, quota, and billing](https://docs.getsurfaced.ai/api-reference/usage/get-monthly-usage-quota-and-billing.md): Usage rollup for one UTC calendar month: scan counts (total/completed/failed, by tier), remaining quota headroom, this partner's rate limit, and the amount billed for the period. `scans.total` — and therefore `quota.used` — excludes failed scans: failed scans are not billed and do not count toward t… - [Preliminary scan snapshot best effort revision 1](https://docs.getsurfaced.ai/api-reference/preliminary-scan-snapshot-best-effort-revision-1.md): Fired at most once per scan, only when a callback_url was supplied AND the scan outlived the create endpoint's sync-wait window with at least one provider reported. Best-effort: there is deliberately no retry backstop — a scan may skip straight to scan.completed. The payload is a full PartnerScanOut… - [Final scan result guaranteed](https://docs.getsurfaced.ai/api-reference/final-scan-result-guaranteed.md): Fired once per scan on completion when a callback_url was supplied — the guaranteed delivery. The payload is a full PartnerScanOutput with status "completed"; revision is 2 when a scan.preliminary fire was delivered first, otherwise 1. Deduplicate on (scan_id, revision). - [Terminal scan failure guaranteed](https://docs.getsurfaced.ai/api-reference/terminal-scan-failure-guaranteed.md): Fired once per scan when the scan ends without a result and a callback_url was supplied — the terminal counterpart to scan.completed. Exactly one of the two arrives for any scan that reaches an end state, so treat either as your signal to stop waiting. - [Changelog](https://docs.getsurfaced.ai/changelog.md): What changed in Surfaced, newest first. ## OpenAPI Specs - [openapi](https://www.getsurfaced.ai/api/partner/openapi.json) - [openapi](https://www.getsurfaced.ai/api/v1/openapi.json) This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.