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

# Answer

> A question in, an answer out, with every sentence quoted from the page it cites.

`POST /api/answer` searches the web, reads the pages it finds, and answers by
quoting them.

Nothing is generated. Every sentence in `answer` is a span taken verbatim from
the source its marker points at, so a citation cannot point at something the
page never said. The quoted text and the citation are the same object.

```bash theme={"dark"}
curl https://api.truscan.co/api/answer \
  -H "Authorization: Bearer $TRUSCAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "why is TLS certificate pinning discouraged in mobile apps now"
  }'
```

```json theme={"dark"}
{
  "success": true,
  "message": "Answered from 3 sources.",
  "result": {
    "id": "ans_8d3ddecc038c10d9",
    "query": "why is TLS certificate pinning discouraged in mobile apps now",
    "answer": "Originally, certificate pinning was designed to prevent monster-in-the-middle (MITM) attacks by associating a hostname with a specific TLS certificate. [2]\n\nThe cost-benefit equation has changed: the risk of a rogue certificate is now quite low, whereas the risk of your own app breaking due to pinning is comparatively higher. [1]",
    "passages": [
      { "text": "Originally, certificate pinning was designed to prevent monster-in-the-middle (MITM) attacks by associating a hostname with a specific TLS certificate.", "source": 2, "score": 0.7412 },
      { "text": "The cost-benefit equation has changed: the risk of a rogue certificate is now quite low, whereas the risk of your own app breaking due to pinning is comparatively higher.", "source": 1, "score": 0.6903 }
    ],
    "sources": [
      {
        "n": 1,
        "url": "https://blog.cloudflare.com/why-certificate-pinning-is-outdated/",
        "title": "Avoiding downtime: modern alternatives to outdated certificate pinning practices",
        "domain": "blog.cloudflare.com",
        "score": 0.614
      },
      {
        "n": 2,
        "url": "https://www.sans.org/blog/tls-ssl-failures-and-some-thoughts-on-cert-pinning-part-1",
        "title": "TLS/SSL failures and some thoughts on cert pinning",
        "domain": "sans.org",
        "author": "Jake Williams",
        "score": 0.552
      }
    ],
    "format": "json",
    "usage": { "answers": 1, "search_requests": 1, "pages_read": 9 },
    "stats": {
      "took_ms": 13095,
      "search_ms": 12940,
      "sources_read": 9,
      "considered": 25,
      "cached": false
    }
  }
}
```

## Request

<ParamField body="query" type="string" required>
  The question, up to 512 characters. `q` is accepted as an alias.
</ParamField>

<ParamField body="tier" type="string" default="instant">
  Search depth behind the answer: `instant`, `deep` or `deep_reasoning`. A
  deeper tier reads more pages, so there is more to quote from. See
  [tiers](/search/tiers).
</ParamField>

<ParamField body="sources" type="integer" default="10">
  How many ranked results the answer may quote from. Clamped to 50.
</ParamField>

<ParamField body="passages" type="integer" default="5">
  How many quotes the answer carries. Clamped to 12. Past a dozen it stops
  reading as an answer and starts reading as the search results again.
</ParamField>

<ParamField body="format" type="string" default="json">
  `markdown` or `text` also fill `rendered` with the answer and its sources as
  one document, ready to paste into a note or a prompt.
</ParamField>

<ParamField body="site" type="string">
  Restrict to one domain, so the answer can only quote pages from it.
</ParamField>

<ParamField body="freshness" type="string">
  `day`, `week`, `month` or `year`. Excludes anything older before the answer
  is built.
</ParamField>

<ParamField body="lang" type="string" />

<ParamField body="category" type="string" default="general">
  `general`, `news`, `science`, `images`, `videos` or `it`.
</ParamField>

## How the answer is built

Four steps, and each one is visible in the response.

**Search.** The tier's budget decides how wide recall goes and how many pages
get read. Results arrive ranked, with matching passages already scored.

**Select.** Passages are scored on their own match weighted by how well search
ranked the page they came from, so a strong quote on a weak page does not
outrank a strong quote on the page search put first.

**Spread.** At most two passages come from any one document, so an answer is
corroborated rather than one page quoted four times. A question only one
document answers still gets a full answer: the cap lifts when nothing else has
anything to say.

**Assemble.** Quotes are joined in score order, each with a `[n]` marker, one
paragraph per statement. Sources nothing quoted are dropped and the rest are
renumbered, so the list is a citation list rather than the search results
again, and every marker resolves.

<Note>
  `considered` reports how many passages were available before selection, which
  is the number to tune `passages` against. A low `passages` against a high
  `considered` means you are leaving support on the table.
</Note>

## Reading the citations

`sources[].n` is the number used in `answer`. Markers are contiguous from 1, so
`[3]` always exists when it appears.

`passages[].source` points at the same number, and `passages[].text` is the
exact span that was quoted. That pairing is what makes an answer checkable:
take any marker, find its passage, and search the source for that text.

Ordering is by score rather than by source, so the best supported statement
comes first. The markers carry provenance, so reading order does not have to
match source order.

## What a page with no body contributes

A result Truscan could not read still appears as a source, and its engine
snippet can be quoted. Snippets score well below any extracted passage, so they
are only used when nothing better was read.

A page that failed to fetch does not appear in `pages_read`, and neither does
a client-rendered shell that yielded almost nothing.

## Cost

An answer is **one charge**. The search behind it and the pages it reads are
included in that price, so the same question at a deeper tier reads further and
costs the same.

That is deliberate. You asked one question. How wide the search goes and how
many pages get read to answer it is our retrieval strategy, not something you
ordered, and billing it back would make a better answer cost you more without
your having asked for one.

`usage` reports the work that price covered, not additional charges:

```json theme={"dark"}
"usage": { "answers": 1, "search_requests": 1, "pages_read": 9 }
```

`search_requests` and `pages_read` are `0` when the search behind the answer
was served from cache, because nothing was retrieved. `answers` is still `1`:
the answer was still assembled.

<Note>
  Units rather than dollars on purpose. Multiply `answers` by the
  [rate card](/billing/pricing), which is generated from the same constants
  that charge the request, so it cannot quote a rate that will not be honoured.
</Note>

## When there is nothing to quote

`answer` comes back empty, `sources` is empty, and `message` says so.

That is deliberate. An answer with no support is the one thing this endpoint
will not return, and inventing prose to fill the gap is exactly what every
other answer API does. Widen the filters or use a deeper tier so more pages get
read.
