# How Inciteful works

> Inciteful documentation - getting started, the content engine, citation tracking, white-label reports, deployments (WordPress push, exports), the Shopify app, the CLI, the REST API reference and the MCP server.

Canonical: https://tryinciteful.com/docs
This is the markdown twin of the page above, published by Inciteful for AI agents. It is generated from the same source data as the HTML, so the two never diverge. Reviewed: 2026-07-18.

From the first client workspace to the REST API and the MCP server. Everything on this page is checked against the running product - the test suite fails if a documented endpoint stops existing.

## Getting started

Inciteful does two halves of GEO - Generative Engine Optimization - for agencies and web designers. **Citation tracking** measures whether a client's domain is the answer AI assistants actually give for buyer-intent questions, and who wins the answer instead. The **content engine** generates answer-shaped content clusters engineered to win those citations, grounded in the client's real pages.

1. **Create your account.** Start with the [free visibility report](https://tryinciteful.com/report), or begin a 7-day Solo or Pro trial. Agency starts as a paid plan.

2. **Add a client workspace.** One workspace per client: their domain, brand name, and the competitors you want share-of-voice against. Everything - questions, checks, clusters, the report - is scoped to the workspace.

3. **Track the questions that matter.** Add the questions buyers actually ask ("best emergency plumber near me?"). Inciteful refreshes them automatically across ChatGPT, Google AI Overviews and Perplexity.

4. **Generate a cluster.** Give the engine the client's niche and it builds a set of interlinked, answer-shaped pages - with schema, meta and internal links already wired. Hit **Save cluster** when you are happy; the WordPress plugin, CLI, API and MCP all pull *saved* clusters by id.

5. **Ship it and prove the result.** Publish through the client’s detected or confirmed stack. A connector or user reports candidate URLs; Inciteful independently checks the client domain, public response, redirects, canonical and intended content. Only verified intended pages start automatic citation tracking.

**Programmatic access:** the CLI, WordPress plugin, REST API and MCP server all authenticate with an API key. Mint one in [Account - API keys](https://tryinciteful.com/account) and copy the `inc_live_…` value - it is shown once.

## Content engine

A cluster is a set of pages, each answering one buyer question, grouped into topic clusters and interlinked. Every generated page ships with:

- A direct, answer-shaped opening an assistant can lift verbatim - the H1 stays the buyer's question.

- **Schema.org JSON-LD** - Article, plus FAQPage / HowTo where the content supports it.

- A distinct **meta title** and **meta description**.

- **Internal links** to the sibling pages in the cluster.

- A site-level **llms.txt** and a linking map in the bundle exports.

### Grounded generation and verified citations

When a workspace has a client domain, generation grounds itself automatically: Inciteful fetches the client's reachable pages (and, where external discovery is configured, third-party sources on the topic) and constrains the model to that evidence. Public citations are checked for reachability; first-party facts carry an explicit client-attested reference; and high-risk claims must map to one source passage. Missing or unsupported high-risk facts block output rather than being presented as approved.

### Structure score - what the number means

Every page carries separate measures. **Citability** (0-100) covers answer shape, extractability and source presentation. **Source quality** records whether references were reachable or explicitly supplied as first-party evidence. **Claim verification** records passage-level support. **Output approval** is a server-sealed decision and remains blocked after any edit until evidence is reviewed again. A high citability score is neither a truth claim nor a citation prediction.

### The integrity gate on deployment

A deployment attempt and URL report cannot bypass content approval. Every page needs a current server evidence seal; placeholder sources, dead citations and unsupported high-risk claims return `422 integrity_block` with the offending pages. Any content edit invalidates the seal until source and claim review runs again. Even after approval, automatic tracking begins only when the public verifier finds the intended content on the confirmed client domain.

### Bring your own key

Paid plans let you add your own Anthropic API key in [Account](https://tryinciteful.com/account); content generation then runs on your key. Plans and monthly cluster quotas are on the [pricing page](https://tryinciteful.com/pricing).

## Citation tracking

You add the questions buyers actually ask; Inciteful refreshes them automatically and records two separate signals: whether the client is named affirmatively in the answer, and whether its domain appears in the cited sources.

- **Included engines.** Every paid plan includes ChatGPT, Google AI Overviews and Perplexity. Claude, Gemini and Google AI Mode are optional per-client add-ons.

- **Adaptive sampling, honestly reported.** New, changed or contested questions run 3 samples per engine, aggregated by majority. Stable questions can use a single refresh. Each check row records how many samples produced its verdict.

- **What "Presence" means.** Presence counts an affirmative mention of the brand, domain name or configured alias in answer prose. A negated warning does not count.

- **Alerts on confirmed changes only.** A win or loss on an LLM engine emails you once it has been confirmed at 3 samples, so a single flip cannot page you about a change that is not real. Google AI Overviews is the exception: it is a deterministic SERP scrape read once by design, so one observation is already the confirmed reading and alerts on it directly.

- **Share of voice.** The same checks run for the competitors on the workspace, so the report shows who wins each question, not just whether you did.

- **Source intelligence.** Every check records the domains the assistant leaned on - the map of who currently owns the answers in the niche.

The tracked-question pool is account-wide - spread it across clients however you like. Pool sizes per plan are on the [pricing page](https://tryinciteful.com/pricing); on Agency, adding your own OpenAI, Gemini and Perplexity keys moves tracking onto your keys and opens a larger pool.

## White-label reports

Every client workspace has a shareable report at its own private link - `tryinciteful.com/r/ `, where the slug carries a 128-bit random suffix, so it cannot be guessed or enumerated. Anyone with the link can open it - treat it as a shared secret. It shows Presence over time, the per-assistant grid, share of voice against competitors, and the sources assistants lean on.

- **Your brand, not ours.** Set your agency name and brand colour in the report settings; the page renders in them.

- **Badge removal.** On the Pro and Agency plans the "Powered by Inciteful" badge is removed entirely, so the report reads as your own product. Exports are unbranded on every plan.

- **Honest empty states.** A workspace still running sample checks shows an honest "live tracking is being connected" preview - the report never fabricates numbers it does not have.

- **Publish control.** Disable a report and its URL returns 404 until you re-enable it.

## Deployments

A **deployment** is an append-only evidence trail from approval to outcome. It records the delivery channel, candidate URLs, Inciteful’s independent public-page verification, verified crawler fetches and later AI citations without treating one signal as proof of another.

- The state model is `deployment_started` -> `urls_recorded` -> `verified_live` -> `crawler_seen` -> `citation_seen`. A failed check remains `verification_failed` with evidence and a retry action.

- WordPress, Shopify, MCP, CLI, API and manual exports all report through the same deployment spine and the same read-only verifier.

- A reported URL is never called live by itself. Only verified intended content starts the time-to-citation clock and links the cluster questions into automatic tracking.

### AI Traffic evidence

AI Traffic accepts bounded request events from Next.js middleware, a Vercel Log Drain, a Cloudflare Worker, an Nginx/Apache forwarder or a custom backend. It does not ingest raw log files, and stored page paths exclude query strings.

- **Retrieval fetch:** a known assistant retrieval user-agent requested a page. The signal is labelled verified only when the source IP also resolves to the vendor’s published network.

- **Indexing crawl:** a training or indexing crawler requested a page. This proves neither an answer nor a human visit.

- **Assistant referral:** a browser arrived from a known assistant origin. It is browser-reported, stored separately and never promoted into crawler proof.

- **Google Search Console:** a separate Google-search dataset. It is never counted as AI Traffic.

### WordPress push

The smoothest path. The Inciteful Connector plugin (v1.2.1) connects a WordPress site to your account; you can then import clusters from inside wp-admin, push them from Inciteful without touching the site, or apply an additive retrofit to an existing page (layered as post meta, so the original content is never modified and rollback is instant).

[Download the WordPress plugin](https://tryinciteful.com/inciteful-connector.zip)
inciteful-connector.zip - install once per client site

1. **Install it.** In the client's WordPress admin: **Plugins - Add New - Upload Plugin**, choose the `.zip`, then **Activate**.

2. **Connect it.** Open **Inciteful - Connect**, set the API base to `https://tryinciteful.com`, paste your `inc_live_…` key, and click **Save & connect**. Saving registers the site with your account and provisions a per-site receiver token, so the site shows up as a push target.

3. **Import, or push.** From wp-admin: **Inciteful - Import** pulls a cluster in as draft posts you review and publish. From Inciteful: the **Push to WordPress** button on a saved cluster (owner-only) ships it in one step. The site reports candidate permalinks; Inciteful independently verifies the public pages before advancing the deployment.

4. **Re-push safely.** Imports and pushes update the same posts by slug - re-shipping a revised cluster never duplicates pages.

5. **Close the loop.** Verified intended pages start tracking automatically. Deployments then shows vendor-verified crawler fetches and AI citations as separate later evidence.

Pages arrive as native Gutenberg blocks with the meta title, meta description and JSON-LD already attached. If a push cannot reach the site, or the site answers wrongly, Inciteful returns a readable `409` naming the site and the deployment stays `deployment_started`. If WordPress reports URLs that fail the independent check, they remain visibly recorded with verification evidence and can be retried.

**No plugin access?** Export the cluster as **WordPress import (.xml)** and use **Tools - Import - WordPress**. The plugin path is better: it keeps schema and re-syncs by slug.

### Exports and copy-as

Every cluster exports in four formats - from the app's Export tab, the API, or the CLI:

| Format | What you get |
| --- | --- |
| markdown | One `.md` per page with frontmatter, plus `llms.txt`, a linking map and an index - built for static-site generators and Git workflows. |
| html | Standalone, styled HTML pages with the JSON-LD embedded - paste-ready for any builder. |
| wordpress | A WXR import file for **Tools - Import**. |
| full | The Implementation Pack zip: every format plus per-page meta and schema files. |

Per page, the app's **Copy as** menu gives an HTML fragment, Gutenberg blocks, or the meta title + description for a builder's SEO fields. Exported files are unbranded on every plan.

### /answers - Inciteful's product-owned library

[tryinciteful.com/answers](https://tryinciteful.com/answers), the matching [/llms.txt](https://tryinciteful.com/llms.txt) and their sitemap entries are maintained as source-controlled Inciteful product identity. Client workspaces can publish only through their own connector and export routes; generated client content can never redefine Inciteful's public answer corpus. The [live public report](https://tryinciteful.com/r/inciteful-455531) remains a separate dated visibility baseline rather than a publishing target.

## Shopify app

For Shopify stores, Inciteful installs as a native app that optimizes **product and collection pages** for AI shopping assistants - the surface that decides which product gets recommended when a shopper asks an AI what to buy.

1. **Install the app.** Install **Inciteful** from the Shopify App Store (the button on your [Account](https://tryinciteful.com/account) page's Shopify card takes you there) and approve it in your Shopify admin. An Inciteful workspace is created for the store automatically; agencies can link the store to their own account from inside the app.

2. **Optimize products.** In the embedded app, pick products or collections and click **Optimize**. Inciteful writes Product / Offer / FAQ schema (JSON-LD) through metafields, rendered server-side by the theme extension - non-destructive and fully reversible.

3. **Generate buyer-intent content.** Answer-shaped product Q&A and "best X for Y" collection pages, grounded in the live catalog - the same engine behind the content API.

4. **Track it.** Shopping-query citation tracking shows whether the store's products get recommended by ChatGPT, Google AI Overviews and Perplexity. Optional engine add-ons follow the same evidence model.

**Catalog integrity:** rating and review schema is emitted only from values present in the connected catalog; otherwise those fields are withheld. A write requires an explicit user action and Inciteful records the metafields it owns so they can be removed without deleting unrelated store data.

## Site Health for coding agents

Site Health reports what a crawler actually observed on a client’s website. Most of what it
finds is **infrastructure** – server errors, broken or recursive canonicals, redirect chains,
orphan pages, pages still served over HTTP. Inciteful cannot fix any of that, because it lives in the
client’s own repository. Their coding agent, working in that repository, can.

Every finding already carries a severity, a category, an explanation, a recommendation and the
affected URLs, plus an `action` that says whose job it is:

| action | Meaning | Who fixes it |
| --- | --- | --- |
| `technical_review` | Infrastructure: 5xx, 4xx, redirect chains, canonical loops, HTTP still crawlable, orphan pages, slow responses | The client’s repository – your agent |
| `improve_page` | Page content: missing titles, descriptions, H1s, duplicate metadata, invalid schema | Inciteful’s retrofit flow |

### The skill

Drop the skill into the client repo so the agent knows the workflow, the boundaries and the cost
rules without being told each time:

```
mkdir -p .claude/skills/inciteful-site-health
curl -fsSL https://tryinciteful.com/inciteful-site-health-skill.md \
  -o .claude/skills/inciteful-site-health/SKILL.md
```

Then connect Inciteful as an MCP server with an API key from [Account &rarr; API keys](https://tryinciteful.com/account):

```
claude mcp add --transport http inciteful \
  https://tryinciteful.com/api/mcp \
  --header "Authorization: Bearer inc_live_YOUR_KEY"
```

### Tools and commands

| Surface | What it does | Cost |
| --- | --- | --- |
| `inciteful_site_health` (MCP) | Findings for one workspace, as a work queue | Free, read-only |
| `inciteful_site_health_scan` (MCP) | Starts a new crawl to re-check the site | **Paid** – see below |
| `inciteful health ` (CLI) | The same findings, printed; `--json` for all affected URLs | Free, read-only |
| `GET /api/v1/site-health?workspaceId=…` | The same payload over the REST API | Free, read-only |

### Re-scanning costs money

A re-scan is a real crawl against your monthly Site Health page allowance, so an agent should call
it only once its fixes are committed *and live on the public site* – crawling unchanged
pages spends the allowance to tell you nothing.

**Agent scans are capped per client per day**, on top of the monthly page
allowance, so an agent stuck in a retry loop cannot drain a month of crawl budget in an afternoon.
A refusal carries `site_health_agent_day_cap` and is final – the skill instructs the
agent to report what it fixed rather than retry. Scans you start yourself in the app are never
affected by an agent’s usage.

## CLI

Best for static-site generators (Astro, Hugo, Next, Eleventy) and Git-based publishing. The CLI is a zero-dependency single file over the same v1 API - no install step beyond downloading it:

```
curl -fsSL https://tryinciteful.com/inciteful -o inciteful
chmod +x inciteful

./inciteful login          # paste your inc_live_ key (stored in ~/.inciteful)
./inciteful list           # your saved clusters
./inciteful export   --format markdown --out ./content
./inciteful sync --out ./content   # export every cluster at once
```

To run it from anywhere, move it onto your PATH: `sudo mv inciteful /usr/local/bin/` - then it is just `inciteful login`.

| Command | Does |
| --- | --- |
| login | Store an API key in `~/.inciteful/config.json`. |
| whoami | Show the resolved API base and the masked key. |
| list [--workspace ] | List saved clusters - id, niche, pages, updated. |
| get [--out f.json] | Raw cluster JSON. |
| export --format --out./dir | Write the export file. Formats: `markdown`, `html`, `wordpress`, `full`. |
| sync --out./dir [--workspace ] [--format ] | Export every cluster at once. |
| logout | Forget the stored key. |

Auth resolution, first match wins: `--key` flag, the `INCITEFUL_KEY` environment variable, then the stored config. The API base follows the same order via `--api` / `INCITEFUL_API` - handy for CI.

## API reference

The REST surface behind the CLI, the WordPress plugin and any custom build. Base URL `https://tryinciteful.com`. Requests and responses are JSON unless a download is noted; request bodies are capped at 16 MB.

### Authentication

Create an API key in [Account - API keys](https://tryinciteful.com/account) (owner-only; the raw `inc_live_…` value is shown once, and keys can be revoked at any time). Send it as a Bearer token:

```
curl -H "Authorization: Bearer inc_live_YOUR_KEY" https://tryinciteful.com/api/v1/clusters
```

Endpoints marked **Bearer key** below also accept the app's session cookie, so they work from the browser too. The one exception is the MCP endpoint, which accepts *only* a Bearer key by design. A missing or invalid key returns `401 {"error":"Not signed in","code":"unauthenticated"}`.

Rate limits: the API surface - every `/api/v1/*` endpoint and the MCP endpoint - allows 300 requests per minute per account. Exceeding it returns `429` with a `retry-after` header; on `/api/mcp` the 429 body is a JSON-RPC error (code `-32002`) carrying the same `retryAfter`. Generation endpoints (content, scan, strategy) stay limited to 40 calls per hour per account, with the same `429` + `retry-after` contract.

### Public endpoints - no auth

GET `/api/health` No auth

Service status: `{"ok":true, "platformLive":…, "model":…, "billingEnabled":…, "seedNiche":…}`.

GET `/api/plans` No auth

The live plan catalog: `{"plans":[…], "billingEnabled":…, "purchasable":[…]}` - the same data the pricing page renders.

GET `/api/demo` No auth

A full demo cluster (`{"cluster":…}`) - useful for exploring the cluster shape without generating one.

### Identity

GET `/api/v1/whoami` Bearer key

Who this key belongs to - the first call an integration should make to confirm it is wired up.

**Response 200** - `{"ok":true, "email", "plan"}`. A team member's key resolves to the account owner, the same way every other route scopes.

```
curl -H "Authorization: Bearer inc_live_YOUR_KEY" https://tryinciteful.com/api/v1/whoami
```

### Site Health

GET `/api/v1/site-health` Bearer key

The latest Site Health findings for one client, shaped as a work queue for a coding agent
(see Site Health for coding agents). Read-only and free.

| Query | Type | Notes |
| --- | --- | --- |
| workspaceId | string, required | The client workspace. A workspace on another account returns 404. |

**Response 200** - `{"workspaceId","clientDomain","status","score","scope","pagesChecked","findings":[{"id","severity","category","title","explanation","recommendation","action","affectedCount","affectedUrls","providerField"}],"counts":{"total","technicalReview","improvePage"},"definitions"}`.
`action` is `technical_review` (the client’s own repository) or `improve_page` (Inciteful’s retrofit flow).
A client with no completed audit returns `status:"no_audit"` with an empty `findings` array and a `note` - never a silent empty list.

```
curl -H "Authorization: Bearer inc_live_YOUR_KEY" \
  "https://tryinciteful.com/api/v1/site-health?workspaceId=WORKSPACE_ID"
```

### Clusters

GET `/api/v1/clusters` Bearer key

List the account's saved clusters, newest first.

| Query | Type | Notes |
| --- | --- | --- |
| workspaceId | string, optional | Only clusters filed to this workspace. |

**Response 200** - `{"clusters":[{"id","workspaceId","niche","brand","pages","avgScore","citabilityScore","integrity","createdAt","updatedAt","publishedAt"}]}`. `avgScore` is the compatibility/readiness score; use `citabilityScore` and `integrity` for the separated customer-facing measures.

```
curl -H "Authorization: Bearer inc_live_YOUR_KEY" \
  https://tryinciteful.com/api/v1/clusters
```

GET `/api/v1/cluster` Bearer key

One saved cluster in full - pieces, scores, linking map - plus its loop state (publish date, first citation, days-to-citation, refresh-due). Deployment records and per-URL citation proof live on GET /api/deployments.

| Query | Type | Notes |
| --- | --- | --- |
| id | string, required | Cluster id from `/api/v1/clusters`. |

**Response 200** - `{"cluster":…}`. Unknown id: `404 {"error":"not found"}`.

```
curl -H "Authorization: Bearer inc_live_YOUR_KEY" \
  "https://tryinciteful.com/api/v1/cluster?id=CLUSTER_ID"
```

GET `/api/v1/cluster/pages` Bearer key

Per-page, ready-to-insert payloads for headless importers - each page is pre-rendered and branded, so your CMS never re-implements rendering. This is the endpoint the WordPress plugin consumes.

| Query | Type | Notes |
| --- | --- | --- |
| id | string, required | Cluster id. |
| workspaceId | string, optional | Brand override when the cluster is not filed to a workspace. |

**Response 200** - a cluster summary plus `pages`, one entry per page:

```
{
  "cluster": { "id", "niche", "siteName", "workspaceId" },
  "pages": [{
    "slug", "title", "metaTitle", "metaDescription",
    "intent", "cluster", "schemaTypes",
    "gutenberg",   // WordPress block markup
    "html",        // body fragment (no doctype)
    "jsonld",      // schema, as a JSON string
    "related": [{ "question", "slug" }]
  }]
}
```

```
curl -H "Authorization: Bearer inc_live_YOUR_KEY" \
  "https://tryinciteful.com/api/v1/cluster/pages?id=CLUSTER_ID"
```

GET `/api/v1/cluster/export` Bearer key

Download a cluster export as a file (zip, or xml for `wordpress`).

| Query | Type | Notes |
| --- | --- | --- |
| id | string, required | Cluster id. |
| format | string, optional | `markdown`, `html`, `wordpress` or `full`. Default `full`. |

**Response 200** - the file, with a `content-disposition` filename.

```
curl -OJ -H "Authorization: Bearer inc_live_YOUR_KEY" \
  "https://tryinciteful.com/api/v1/cluster/export?id=CLUSTER_ID&format=markdown"
```

### Content generation

The channel-agnostic engine surface the Shopify app is built on - usable from any commerce stack. Generation endpoints are rate-limited (40/hour) and honour your BYOK key when one is set.

POST `/api/v1/content/product-questions` Bearer key

Buyer-facing Q&A for one product, grounded in the catalog facts you supply. The server verifies returned claims against that catalog evidence and withholds unsafe items before any metafield write.

| Body field | Type | Notes |
| --- | --- | --- |
| product | object, required | Catalog facts - `title` (required), and any of `description`, `price`, `currency`, `url`, `brand`, etc. |
| shop | object, optional | Shop context (e.g. `{"name":…}`). |
| count | number, optional | 3-10 pairs; default 6. |
| mode | string, optional | `auto` (default), `live` or `mock`. |

**Response 200** - `{"faqs":[{"question","answer"}], "mode"}`.

```
curl -X POST https://tryinciteful.com/api/v1/content/product-questions \
  -H "Authorization: Bearer inc_live_YOUR_KEY" -H "content-type: application/json" \
  -d '{"product":{"title":"Trail running shoe","price":"129","currency":"GBP"},"count":5}'
```

POST `/api/v1/content/collection-page` Bearer key

A "best X" / comparison content cluster for a product collection, grounded in the real products you pass. Counts toward the plan's monthly cluster quota; saved automatically unless `save:false`.

| Body field | Type | Notes |
| --- | --- | --- |
| productContext | object, required | `{"collection":{…}, "products":[…], "shop":{…}}` - `products` must be non-empty. |
| niche | string | Topic; defaults to `productContext.collection.title` - one of the two is required. |
| count | number, optional | 3-8 pages; default 4. |
| save | boolean, optional | Default true - the cluster is persisted and its id returned. |
| workspaceId | string, optional | Workspace to file the saved cluster under. |
| mode | string, optional | `auto` (default), `live` or `mock`. |

**Response 200** - `{"clusterId", "cluster"}` (`clusterId` is null with `save:false`). Over quota: `402` with `{"error","code","usage"}`.

### Product schema

Deterministic JSON-LD builders with the integrity gate built in: offers are omitted unless a real price and currency exist, ratings and reviews are withheld unless they carry real values and provenance - fabricated trust signals are structurally impossible. `issues` lists everything that was withheld or dropped, and why.

POST `/api/v1/schema/product` Bearer key

Body: `{"product":{…}}` - `title`, `url`, `description`, `price`/`currency`, `images`, `brand`, `sku`, `faqs`, `breadcrumbs`, and optionally real `aggregateRating`/`reviews` data.

**Response 200** - `{"jsonld":{"@context","@graph":[Product, FAQPage?, BreadcrumbList?]}, "issues":[…]}`.

```
curl -X POST https://tryinciteful.com/api/v1/schema/product \
  -H "Authorization: Bearer inc_live_YOUR_KEY" -H "content-type: application/json" \
  -d '{"product":{"title":"Trail running shoe","url":"https://shop.example/products/trail",
       "price":"129","currency":"GBP"}}'
```

POST `/api/v1/schema/collection` Bearer key

Body: `{"collection":{"title","url","description","products":[…],"faqs","breadcrumbs"}}`. Products need a title and an http(s) URL to be listed.

**Response 200** - `{"jsonld":{"@graph":[CollectionPage, ItemList, FAQPage?, BreadcrumbList?]}, "issues":[…]}`.

### Prospecting

POST `/api/v1/prospect/report` Bearer key

Publish an agency prospect report to a shareable public link. Send a prospect row (the shape from `inciteful prospect --json`); the server renders a branded, self-contained report and hosts it at `/p/ ` with a Download-PDF button. Used by `inciteful prospect --publish`.

| Body field | Type | Notes |
| --- | --- | --- |
| agency | object, required | A prospect row with `agencyDomain` and `clientAudits[]`. |
| brand | string, optional | White-label brand name. Defaults to the agency's detected logo alt text. |
| accent | string, optional | Brand accent colour (hex, e.g. `#004BA8`). |

**Response 200** - `{"slug","url"}`. The report is public at `url` until unpublished.

### WordPress

POST `/api/v1/wp/register` Bearer key

Registers a WordPress site as a push target. The Connector plugin calls this for you when its Connect settings are saved - you only need it when building your own receiver.

| Body field | Type | Notes |
| --- | --- | --- |
| siteUrl | string, required | Public https URL of the site - no credentials, no port, no internal hosts. |
| token | string, required | The site's receiver token, 32-128 visible ASCII characters. Stored encrypted; re-registering the same site rotates it. |
| name | string, optional | Display name. |

**Response 200** - `{"ok":true, "site":{"id","siteUrl","name"}}`. Validation failures are `400` with a readable error.

GET `/api/wp/sites` Bearer key

**Response 200** - `{"sites":[{"id","siteUrl","name","lastPushAt"}]}`. Receiver tokens are never returned.

POST `/api/wp/push` Bearer key - owner only

Push a saved cluster to a registered site: creates a `wordpress` deployment, nudges the site's Connector plugin to pull and publish the cluster (re-push updates the same posts by slug), records the candidate URLs it reports, then independently verifies the public pages.

| Body field | Type | Notes |
| --- | --- | --- |
| clusterId | string, required | A saved cluster id. |
| siteId | string, required | From `/api/wp/sites`. An unknown id returns 404 with the registered `sites` so a caller can self-correct. |

**Response 200** - `{"ok":true, "deploymentId", "urls":[…], "verification", "deploymentStatus"}`. If the receiver cannot be reached or reports no URLs, the response is `409` with `code` `wp_unreachable` or `wp_bad_response`; the deployment stays `deployment_started`. Receiver success with failed public verification remains `verification_failed`, not live. Team members get `403 owner_only`.

```
curl -X POST https://tryinciteful.com/api/wp/push \
  -H "Authorization: Bearer inc_live_YOUR_KEY" -H "content-type: application/json" \
  -d '{"clusterId":"CLUSTER_ID","siteId":"SITE_ID"}'
```

POST `/api/wp/retrofit` Bearer key - owner only

Apply a retrofit patch to an EXISTING page on a registered site: the Connector (v1.2.0+) appends the additive answer-first + FAQ blocks and injects the JSON-LD, keeping the prior version as a WordPress revision. A `retrofit` deployment is recorded so later tracking can show whether the page's result changes. Body: `{"url","siteId","workspaceId","patch"}` where `patch` is the reviewed patch object from a retrofit audit - what you reviewed is exactly what lands.

POST `/api/wp/retrofit/revert` Bearer key - owner only

Revert a previously applied retrofit on that page: `{"url","siteId"}`. The Connector restores the pre-retrofit revision and removes the injected JSON-LD.

### Deployments

POST `/api/deployments` Bearer key

Start an approved deployment attempt. The workspace is inherited from the cluster unless overridden. This records intent and an audit event; it is not evidence that a page is live.

| Body field | Type | Notes |
| --- | --- | --- |
| clusterId | string, required | A saved cluster id. |
| connector | string, required | One of `self`, `wordpress`, `shopify`, `cli`, `mcp`, `export`, `other`. |
| workspaceId | string, optional | Workspace override. |
| idempotencyKey | string, optional | Stable 8-200 character retry key. Reusing it for the same cluster and connector returns the original attempt instead of creating a duplicate. |

**Response 200** - `{"deployment":{"id","clusterId","workspaceId","connector","status":"deployment_started","urls":[],"createdAt","approvedAt","updatedAt"}}`. A cluster not filed to a client with a website returns `422` with `code` `no_client_domain`.

POST `/api/deployments/urls` Bearer key

Report candidate public page URLs. By default Inciteful immediately performs read-only independent verification against the confirmed client domain.

| Body field | Type | Notes |
| --- | --- | --- |
| id | string, required | Deployment id. |
| urls | array, required | Candidate public http(s) URLs - plain strings or `{"slug","url"}` pairs (slug = the exported file the URL is expected to serve). Up to 100. |
| replace | boolean, optional | Overwrite the prior set instead of appending. Default false. |
| verify | boolean, optional | Set false only for an asynchronous connector workflow. The state remains `urls_recorded`, never live. |

Calls append and dedupe by host+path (www and trailing slashes normalized). The verifier checks host ownership, HTTP status, redirects, canonical and expected generated content. Only at least one intended-content match can produce `verified_live` and start automatic tracking.

**Response 200** - `{"deployment":…, "verification":{"status","verified","failed","contentVerified"}}` plus `autoPublished: {"publishedAt","linked"}` only when intended content was independently verified and passed the integrity gate.

POST `/api/deployments/verify` Bearer key

Retry independent verification after a DNS, page, redirect, canonical or content fix. Body: `{"id":"DEPLOYMENT_ID"}`. Verification is read-only and appends a new audit event; the prior evidence remains visible.

POST `/api/deployments/urls/remove` Bearer key

Remove one recorded URL from a deployment (a mistyped paste should not sit as "not cited yet" forever). Body: `{"id","url"}` - the URL is matched by normalized host+path. Unknown deployment or URL: `404`.

GET `/api/deployments` Bearer key

List deployment attempts with their append-only audit events and per-URL verification, crawler and citation evidence.

| Query | Type | Notes |
| --- | --- | --- |
| workspaceId | string, optional | Filter to one workspace. |

**Response 200** - `{"deployments":[…]}`. Each URL can carry `verification`, `crawler` and `cited/citedAt/citedBy/question` independently. Deployment summaries expose `verifiedUrls`, `crawlerSeenUrls`, `citedUrls`, the derived `stage`, and `events`.

```
curl -H "Authorization: Bearer inc_live_YOUR_KEY" \
  "https://tryinciteful.com/api/deployments?workspaceId=WORKSPACE_ID"
```

### Errors

Errors are JSON with a readable `error` message and, where a caller can act on it, a stable `code`:

| Status | Shape | When |
| --- | --- | --- |
| 400 | {"error": "…"} | Validation - the message says which field. A malformed JSON body is `"Invalid JSON body."` |
| 401 | {"error":"Not signed in","code":"unauthenticated"} | Missing or invalid key/session. On `/api/mcp` the 401 body is JSON-RPC instead - see MCP. |
| 402 | {"error","code","usage"} | Plan quota reached (e.g. monthly clusters on `collection-page`). |
| 403 | {"error","code":"owner_only"} | A team member called an owner-only action (API keys, WordPress push, billing). |
| 404 | {"error":"not found"} | Unknown or not-yours id - cross-tenant reads are 404, never 403. `/api/wp/push` adds the registered `sites` to an unknown-site 404. |
| 409 | {"error","code","deploymentId"?} | WordPress receiver failures: `wp_unreachable` / `wp_bad_response`. The deployment stays `deployment_started`. A pre-push failure (stored site token unreadable) returns 409 before any deployment exists, so `deploymentId` is absent. |
| 413 | {"error":"Request body too large."} | Body over 16 MB. |
| 422 | {"error","code":"integrity_block","blocked":[…]} | Starting or recording a deployment while pages carry placeholder, dead-cited or unsupported evidence. |
| 429 | {"error","retryAfter"} | Rate limited - honour the `retry-after` header. On `/api/mcp` the body is a JSON-RPC error (code `-32002`) - see the rate-limits note above. |
| 5xx | {"error":"Something went wrong on our side. Please try again."} | Our fault. Details are logged server-side and never leak into responses. |

## MCP server

Inciteful is an MCP (Model Context Protocol) server: AI agents - Claude Code, Claude Desktop, claude.ai custom connectors, any MCP client - can manage the GEO workflow directly. An agent can list a client's workspaces and clusters, pull a cluster as markdown, write it into a site repo, record where it went live, push to WordPress, and read subsequent citation evidence.

POST `/api/mcp` Bearer key only

A single stateless Streamable-HTTP endpoint speaking JSON-RPC 2.0 - no SSE stream, no session id. Auth is the same `inc_live_…` key as the REST API, but *key-only*: a browser session cookie is deliberately not accepted, so a logged-in browser can never be driven into this endpoint cross-site. A missing or invalid key returns HTTP 401 with a JSON-RPC error body (code `-32001`), not the REST error shape - agents parse it:

```
{"jsonrpc":"2.0","id":null,"error":{"code":-32001,
  "message":"unauthorized - send Authorization: Bearer inc_live_... (create an API key in Account)."}}
```

The 401 also carries a standard `WWW-Authenticate: Bearer` challenge (RFC 6750), so a
connector client gets a machine-readable reason rather than an opaque internal error id.

### Adding Inciteful as a Claude connector

**Inciteful does not run an OAuth authorization server.** It does not implement
dynamic client registration (RFC 7591) or a PKCE authorize/token pair, so Claude's
“Add custom connector” *Sign in* button has nothing to talk to and
will fail. That is a deliberate current limitation, not a misconfiguration — we would rather
refuse honestly than publish discovery metadata that starts a login flow which cannot finish.

Use the API key instead. It is the supported path and gives the same access:

1. In Inciteful, open **Account &rarr; API keys** and create a key (`inc_live_…`). Copy it — it is shown once.

2. In your MCP client, add `https://tryinciteful.com/api/mcp` as a Streamable-HTTP server.

3. Set the header `Authorization: Bearer inc_live_…`.

For Claude Code:

```
claude mcp add --transport http Inciteful https://tryinciteful.com/api/mcp \
  --header "Authorization: Bearer inc_live_YOUR_KEY"
```

The key is account-scoped and owner-only: a team member's key cannot reach another account's
clusters, and a browser session cookie is never accepted here.

### Protocol

| Method | Behaviour |
| --- | --- |
| initialize | Echoes protocol version `2025-06-18` or `2025-03-26` when requested, otherwise negotiates to `2025-06-18`; returns `capabilities.tools` and `serverInfo.name "Inciteful"`. |
| notifications/* | Accepted, `202` with no body (per JSON-RPC, notifications get no response). |
| ping | `{}` |
| tools/list | Every tool below, each with a JSON schema. |
| tools/call | Runs a tool. Every result is one text content block carrying a JSON string; failures set `isError: true` with the exact REST error message. |

Malformed JSON is `-32700`, a structurally invalid request (wrong `jsonrpc`, missing `method`, batch arrays) is `-32600`, an unknown method is `-32601`, an unknown tool name is `-32602`. Internal tool faults return an `isError` result with a generic message - stack traces never leave the box.

### Tools

| Tool | Args | Does |
| --- | --- | --- |
| inciteful_list_workspaces | - | List the client workspaces on the account. |
| inciteful_list_questions | workspaceId | The tracked buyer-intent questions for a workspace. |
| inciteful_tracking_summary | workspaceId | Latest live run: Presence, per-assistant breakdown, share of voice, top cited sources, verdict confidence. |
| inciteful_list_clusters | workspaceId? | Saved clusters - id, niche, page count, average citability, integrity state and dates. |
| inciteful_export_cluster | clusterId | The cluster as a markdown file bundle (`{path, content}` entries: index, llms.txt, linking map, one.md per page) ready to write into a repo. |
| inciteful_start_deployment | clusterId, connector?, workspaceId?, idempotencyKey? | Start an approved attempt (status `deployment_started`). Connector defaults to `mcp`. |
| inciteful_set_deployment_urls | deploymentId, urls | Report candidate URLs and run independent verification. A report alone remains `urls_recorded`. |
| inciteful_verify_deployment | deploymentId | Retry read-only public verification and append the evidence event. |
| inciteful_push_wordpress | clusterId, siteId | Push to a registered WordPress site, report its candidate URLs and independently verify them. |
| inciteful_list_deployments | workspaceId? | Attempts with separate URL verification, verified crawler-fetch and AI-citation evidence. |
| inciteful_retrofit_page | url, workspaceId | Audit an existing, already-ranking page and propose an *additive-first* fix for AI citation without touching its Google rankings: runs the AI-crawler-access, JS-render-visibility, structured-data, crawlability, sitemap, llms.txt and answerability gates, ties every gap to the tracked buyer questions this page should win (and who is cited instead), and returns a Tier-0 patch (answer-first block + FAQ block + JSON-LD) grounded only in on-page content + Brand Intelligence, integrity-gated, routed to the safest rollback-capable channel. |
| inciteful_apply_retrofit | url, workspaceId, siteId? | Apply the retrofit. On WordPress (with `siteId`) it lands as a reversible post-meta layer; for a headless/repo stack it returns the diff to apply. Records a retrofit deployment so later tracking can show whether the result changes. |
| inciteful_revert_retrofit | url, siteId | Remove a previously applied WordPress retrofit - deletes the layered post meta, leaving the original post untouched. Instant rollback. |

The intended agent flow: export the cluster, write it into the client's repo, start the deployment, ship, then report the candidate public URLs. Inciteful independently verifies the pages before tracking starts. `inciteful_list_deployments` keeps public-page, crawler and citation evidence separate. On WordPress, `inciteful_push_wordpress` performs the connector and verification flow in one call.

The deployment tools do not re-implement the REST logic - they dispatch to the same handlers as the endpoints above, so the two surfaces cannot drift.

### Add it to Claude

Create an API key in [Account](https://tryinciteful.com/account), then:

```
claude mcp add --transport http Inciteful https://tryinciteful.com/api/mcp \
  --header "Authorization: Bearer inc_live_YOUR_KEY"
```

Any MCP client that can send an `Authorization` header works the same way: URL `https://tryinciteful.com/api/mcp`, header `Authorization: Bearer inc_live_YOUR_KEY`. **Claude Desktop and claude.ai custom connectors** currently accept only OAuth-based remote servers (no custom headers), and Inciteful does not expose OAuth yet - use Claude Code or a header-capable client for now.

Smoke test:

```
curl -s https://tryinciteful.com/api/mcp \
  -H "authorization: Bearer inc_live_YOUR_KEY" -H "content-type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
```

[Back to the app](https://tryinciteful.com/app) · [hello@tryinciteful.com](https://tryinciteful.com/mailto:hello@tryinciteful.com)