> ## Documentation Index
> Fetch the complete documentation index at: https://docs.querying.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Source Influence

> Which cited content actually shaped an AI answer — claim by claim, with exact evidence, page location, and the gaps nobody filled

Compare a completed AI answer with its cited sources. The result says, for every
sentence, list item, and table cell of the answer, **which source supports it and
with what content** — and, just as important, which claims no source supports and
which inline citations are decorative. This is post-hoc evidence analysis, not
proof that a source caused the model to generate a sentence.

```bash theme={null}
curl -X POST https://api.querying.ai/v1/source-influence \
  -H "Authorization: Bearer $QUERYING_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "answer": "…the AI answer, as raw markdown…",
    "prompt": "best password manager for a small team",
    "engine": "CHATGPT",
    "brand": "1Password",
    "competitors": ["Bitwarden"],
    "citations": [
      { "url": "https://example.com/best-password-managers", "body": "…the page markdown…" },
      { "url": "https://another.example.com/pricing" }
    ]
  }'
```

Poll `GET /v1/async/task/:id`, or supply `webhook.url` when submitting; the task
reports `taskType: "SOURCE_INFLUENCE"`. Do not submit this analysis through
`POST /v1/async/task`; use the dedicated endpoint. `POST /v1/research` and the
`CITATION_ATTRIBUTION` task type are the pre-September-2026 names and still work
as deprecated aliases.

## Payload

| Field              | Required | Notes                                                                                                                |
| ------------------ | -------- | -------------------------------------------------------------------------------------------------------------------- |
| `answer`           | yes      | Original answer Markdown, 1–200,000 characters. Keep it unchanged; every range is a UTF-16 offset into it.           |
| `citations[]`      | yes      | 1–25 sources (0–25 with `analysis.version: 1`), at most 10 discussion-thread URLs.                                   |
| `citations[].url`  | yes      | HTTP(S) URL, at most 2,048 characters.                                                                               |
| `citations[].body` | no       | Source Markdown, at most 300,000 characters. Otherwise we fetch the page; a failed fetch is reported as `unfetched`. |
| `citations[].kind` | no       | `inline` or `panel`; detected from answer links when omitted.                                                        |
| `prompt`           | no       | Original question. Context, never evidence. Echoed in `context`.                                                     |
| `engine`           | no       | Which AI engine produced the answer. Echoed in `context` for aggregation.                                            |
| `brand`            | no       | Your brand name. Drives `claims[].entities` and `page.brandRelation`.                                                |
| `competitors[]`    | no       | Up to 25 competitor names, same use.                                                                                 |
| `country`          | no       | Source-fetch country, defaults to `US`.                                                                              |

## Result

```jsonc theme={null}
{
  "version": 2,
  "context": { "engine": "CHATGPT", "country": "US", "prompt": "…" },
  "brand": "1Password", "competitors": ["Bitwarden"],
  "claims": [
    {
      "id": "c2",
      "range": { "start": 76, "end": 131 },
      "text": "Teams plan starts at $19.95/month for up to 10 users.",
      "section": ["Top picks"],
      "entities": ["1Password"],
      "inlineCitations": [],
      "support": [{ "source": 1, "evidence": "e3", "verbatim": true, "scope": "full", "overclaim": false }],
      "status": "exclusive",
      "kind": "specific_fact",
      "origin": null
    }
  ],
  "sources": [
    {
      "url": "https://1password.com/teams/pricing",
      "kind": "panel",
      "outcome": "passage",
      "page": { "brandRelation": "own", "publishedAt": null, "chars": 3900, "tags": ["official pricing page"] },
      "evidence": [
        {
          "id": "e3",
          "range": { "start": 812, "end": 861 },
          "text": "Teams Starter Pack · $19.95 / month · up to 10 users",
          "location": { "block": "table_cell", "headingPath": ["Plans"], "depth": 0.21 },
          "tags": ["price", "seat cap"],
          "claims": ["c2"]
        }
      ],
      "usage": { "influence": 0.13, "rank": 1, "exclusiveClaims": 1, "usedRatio": 0.013 }
    }
  ],
  "summary": {
    "coverage": 0.49,
    "ranking": [1, 0],
    "claims": { "exclusive": 1, "corroborated": 1, "uncited": 1, "washed": 1 },
    "uncitedKinds": { "specific_fact": 1, "generic": 0, "transition": 0 }
  },
  "debug": { "ms": 91200, "judgeCalls": 5, "cacheHits": 2, "unfetched": 0, "sourceErrors": 1, "droppedMatches": 1, "reconcile": "ok", "llmTokens": { "input": 61200, "output": 8400 }, "sourceFetches": 3 }
}
```

### `claims[]` — one per answer unit

The answer is split into sentences, list items, table cells, and headings. Each
carries its exact `range`, the heading path it sits under (`section`), the brand or
competitor names it mentions (`entities`, only when you passed them), the citation
URLs linked inline at that claim, and every `support` entry linking it to a
source's evidence.

`status` is computed from those links:

| Status         | Meaning                                                                                                                                                |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `exclusive`    | Exactly one publisher (hostname) supports it, whatever the number of its pages. Within the inspected set; this does not establish original authorship. |
| `corroborated` | Two or more publishers support it.                                                                                                                     |
| `uncited`      | No source supports it and nothing is linked inline. No support found in the inspected set; unread sources remain uncertain.                            |
| `washed`       | A citation is linked inline, but no source — including that one — supports the claim.                                                                  |

`support[].scope` is `full` when the whole claim is supported and `partial` when
only a substring is; a partial entry carries `range`, the supported substring in
answer offsets (the claim's own `range` stays the whole unit).
`support[].verbatim` is true when the normalized claim and evidence contain each
other — the strongest signal that the answer copied the source.

Three fields come from a final reconcile pass that sees the whole verified ledger
at once (never the source bodies) and can only annotate, never add support:

* `kind`: `specific_fact` (a checkable fact a source could carry), `derived` (a
  number the answer computed from cited facts — a total, price × seats — not a
  gap), `generic` (common knowledge or framing), `transition` (structure,
  greeting, restated question). `uncited` × `specific_fact` is your
  content-opportunity list; `summary.uncitedKinds` counts them.
* `origin`: for `corroborated` claims, the supporting source whose wording the
  claim follows most closely; `null` when indistinguishable.
* `support[].overclaim`: a `full` support whose excerpt does not actually cover a
  number, condition or qualifier in the claim.

If that pass fails, `debug.reconcile` is `failed`; `kind` and `origin` remain
`null`. Legacy `overclaim: false` is not a verified negative in this case. The
rest of the result is unaffected.

### `sources[]` — one per citation, same order

* `outcome`: `passage` / `post` / `comment` when evidence was found, `none` when the
  source was read and nothing supports the answer, `unfetched` when the page could not
  be fetched (bot-challenge interstitials count as unfetched), `error` when analysing
  that source failed (the rest of the task still completes; `error` names the code),
  `duplicate` when the page repeats an earlier citation (`duplicateOf` gives its index;
  the page is judged once and never corroborates itself).
* `page`: `brandRelation` (`own`, `competitor`, `none`, or `null` without a brand),
  `publishedAt` (discussion threads only), `chars`, and free-form `tags` describing
  what kind of page it is.
* `evidence[]`: exact source excerpts. `range` addresses the supplied or fetched
  Markdown (for discussion threads, the post + comment snapshot). `location` says where
  on the page the content was: `block` (`heading`, `paragraph`, `list_item`,
  `table_cell`, `blockquote`, `post`, `comment`), `headingPath`, `depth` (0 = top of
  page, 1 = bottom), and `permalink` / `score` for comments. `tags` describe what kind
  of content it is; `claims` lists the answer claims it supports.
* `usage`: `influence` (share of answer characters this source supports), `rank`
  (exclusive claims first, then verbatim matches, then influence), `exclusiveClaims`,
  and `usedRatio` (share of the page that was actually used — a low value on a cited
  page means most of it was ignored).

### `summary`

`coverage` is the union of all supported answer ranges divided by answer length.
`ranking` lists source indices, best first, for sources with influence above zero.
`claims` counts each status. Filter `claims[]` by `status` for the gap list and sort
`sources[]` by `usage.usedRatio` for under-used pages.

Tags are free text on purpose: what kinds of content win is the question you are
asking the data, so the taxonomy comes from your aggregate, not from a fixed enum.

## Execution and limits

* One full comparison per readable citation, all in parallel.
* A single invalid match is dropped (`debug.droppedMatches`); a failed source is
  reported as `error` without failing the task. In legacy mode, the task fails when every source
  fails, on timeout, or on a configuration error. Opt-in mode preserves answer interpretation alongside source failures.
* Repeated source fetches use caches. Unavailable pages remain `unfetched`.
* Error codes: `MISSING_CONFIG`, `ANALYSIS_FAILED`, `ANALYSIS_TIMEOUT`.
* `debug.llmTokens` and `debug.sourceFetches` feed the metered credit policy
  (`1 + ⌈input tokens / 500⌉ + ⌈output tokens / 100⌉ + 2 per uncached fetch`), capped
  by the submission hold (`5 + 40 per citation + 6 per 1k answer characters`).

## Optional question and brand analysis

Set `analysis.version` to `1` on the same endpoint. The response remains version 2,
with an additional `analysis` object. Omitting `analysis` preserves the existing
result contract. The `/v1/research` alias accepts the same extension.

```json theme={null}
{
  "answer": "Atlas is suitable for small teams.",
  "prompt": "Which tool is suitable for small teams?",
  "citations": [],
  "analysis": {
    "version": 1,
    "entities": [
      { "id": "atlas", "name": "Atlas", "role": "competitor", "aliases": ["Atlas CRM"], "domains": ["atlas.example"] }
    ]
  }
}
```

With the extension, `citations` accepts 0–25 entries. A missing question produces
`stages.requirements: "insufficient_context"`; the answer is still analyzed.
There is no separate answer-analysis API.

### Trace a judgment to its evidence

`analysis.requirements` contains only the question's explicit goals, mandatory
conditions and preferences. Its evidence uses **prompt** offsets. A comparison
criterion introduced by the answer is not a question requirement.

`analysis.decisions` identifies a subject and a role: `mention`, `recommendation`,
`primary_recommendation`, or `against`. `evidence`, `subjectEvidence`, `conditions`
and `reasons` contain exact **answer** ranges. Conditional and conflicting
judgments remain separate. List position does not establish a ranking.
`entityId: null` means the subject could not be resolved. Unregistered entities
have answer-derived identity and unknown ownership role; products retain their
own ID and can reference a caller-provided `brandId`.

Follow `decision.claimIds` → `claims[].support` → `sources[].evidence` for the
verified source relationship. `analysis.summary.links` is a convenience index
of those same references. It labels each link `supported`, `partial`, `overclaim`,
or `unverified`, and distinguishes judgment evidence from `scope: "reason"`.
A price-only passage does not establish the entire “best choice” conclusion.
The summary counts unique judgment records, including neutral `mention` records;
neutral facts for the same identified entity and identical conditions share one
record, with separate evidence anchors and claim links. Facts already used as a
recommendation reason are not counted again as neutral mentions. It does not assign
causal contribution percentages. It gives no explanation for a brand's absence.

### Ownership and production are separate

Provide entity `domains` as hostnames, without schemes or paths. Matching uses
hostname boundaries: `docs.atlas.example` matches `atlas.example`, while
`notatlas.example` and `atlas.example.evil.test` do not. Unknown sites remain
unknown; a third-party domain is not automatically independent or earned.
Entity names and aliases must unambiguously identify one entity.

A citation can independently carry:

```json theme={null}
{
  "url": "https://blog.example/our-comparison",
  "body": "An exact source snapshot...",
  "fetchedAt": "2026-09-08T00:00:00Z",
  "relationship": {
    "ownership": "third_party",
    "production": "commissioned",
    "producerEntityId": "our-brand"
  }
}
```

`our-brand` must be an input entity ID. Ownership is `own`, `competitor`,
`third_party` or `unknown`; production is `direct`, `commissioned`, `independent`
or `unknown`. Explicit page metadata takes precedence over domain matching and
is labeled `caller`; domain matching is labeled `caller_domain`. Neither is
represented as independently verified. Page content types remain in existing
`page.tags` and evidence tags. Legacy `page.brandRelation` keeps its old heuristic
meaning; consumers of this extension should use `analysis.sourceRelationships`.

### Completion, original texts and cost

Check `analysis.status` and `analysis.stages`, even when the task is `COMPLETED`.
A failed interpretation is not an empty successful recommendation list. Source
failures, no source targets, insufficient question context and incomplete
reconciliation are separate states. Valid source results survive interpretation
failure. Independently validated question requirements also survive a failed decision
section. Decisions can survive failed requirements only when they do not reference
those requirements. Such results are `partial`; failed sections remain empty.
Links are `unverified` when reconciliation cannot certify them.

All ranges are exact UTF-16 offsets. `analysis.documents` hashes the actual
answer, question and source representation using SHA-256 over UTF-16LE bytes;
it also identifies caller bodies separately. A supplied body, including an empty
snapshot, is never silently replaced by a current page. `fetchedAt` is null when
unknown, and `historicalMatch` remains `unknown`: a current fetch does not recreate
the page at the answer's historical time. Optional `analysis.answeredAt` records
that answer time. `analysisKey` includes original data, entity/relationship inputs,
source identities, model configuration and analysis version. It is an identity
for downstream reanalysis, not a server-side analysis cache or an idempotency key.

The extension uses higher reasoning effort than the legacy default, with higher
token use and latency. Costs vary with input. The extension shares the
final reconcile call and the existing concurrency,
cancellation and timeout controls. An invalid structured result may receive one
corrective model call within the same budget and deadline. Source calls are not
repeated. The HIGH/max output cap is 32,768 tokens, including reasoning. Oversized interpretation fails explicitly with
`ANALYSIS_INPUT_TOO_LARGE`; text is not silently truncated. The temporary credit
hold adds a payload-sized input/output budget. The runtime enforces that same
budget across source windows and final interpretation. Calls wait for in-flight
usage to settle; exhausted budgets fail explicitly before another model call.
URL-only citations reserve a 16k-character window estimate; supplied bodies use
their actual length. Longer fetched pages can exhaust the allocation and produce
explicit partial/failure states. Existing token and source-fetch
**prices are unchanged**; only actual
metered usage is charged. `debug.modelCalls` counts all attempted model calls in
opt-in mode; `debug.judgeCalls` still counts source-window calls. `llmTokens`
includes reconciliation and known failed-call usage. Unknown provider usage after
an interrupted call cannot be reconstructed.

`uncited` means no support was found in the inspected source set. Unread sources
leave uncertainty; this is neither a claim about the whole web nor a prediction
that new content will succeed. Existing influence, publisher exclusivity and
wording-origin metrics do not measure causal generation effects.
