# Auto Extract

> Extract brand mentions from captured answer text and pin targets so presence and absence are both reported explicitly.

Auto Extract derives brand mentions from the **answer text only**. It can report
brands the answer happens to mention and pin specific brands or domains so an
absent target is returned explicitly rather than omitted. It never fabricates
an extraction.

Auto Extract is **BETA** and costs `0` credits today
(`EXTRACTION_CREDIT_COST = 0`). Requesting it does not change
`creditsToCharge` or `creditsCharged`. Pricing will change at GA.

## Request extraction

Add `extract` to `POST /v1/search`, `POST /v1/search/:surface`, or any item in
`POST /v1/search/batch`.

<ParamField body="extract" type="boolean | object">
  `true` is identical to `{}`: extract brands the answer mentions, with no
  pinned targets. `false`, or omitting the field, disables extraction and leaves
  `evidence.mentions` as `null`.

  <Expandable title="extract object">
    <ParamField body="targets" type="string[]">
      Brand names or bare domains to report whether present or absent. At most
      **10** entries; each must be non-empty and at most **100 characters**.
    </ParamField>
  </Expandable>
</ParamField>

Passing a string, number, array, empty target, target longer than 100
characters, or more than 10 targets returns `400 VALIDATION_FAILED`. Unknown
top-level fields are also rejected; send only documented fields.

## Mention fields

When extraction succeeds, `evidence.mentions` contains `confidence` (`0`–`1`)
and an `items` array.

<ResponseField name="brand" type="string">
  Canonical brand or product name as the surface displayed it.
</ResponseField>

<ResponseField name="domain" type="string | null">
  Primary domain when inferable; otherwise `null`.
</ResponseField>

<ResponseField name="mentioned" type="boolean">
  `false` only for a requested target that is absent from the answer.
</ResponseField>

<ResponseField name="position" type="integer | null">
  One-based order of first mention; `null` when `mentioned` is `false`.
</ResponseField>

<ResponseField name="sentiment" type="string | null">
  `positive`, `neutral`, or `negative`, derived from answer context only; `null`
  when `mentioned` is `false`.
</ResponseField>

<ResponseField name="linked" type="boolean">
  `true` when a cited source URL's registrable domain matches the brand's
  domain.
</ResponseField>

<ResponseField name="target" type="boolean">
  `true` when the row exists because the brand or domain was pinned through
  `extract.targets`.
</ResponseField>

<ResponseField name="sourceIds" type="number[]">
  Real `evidence.sources[].id` values backing the mention.
</ResponseField>

<ResponseField name="snippet" type="string | null">
  Verbatim first-mention context, at most 240 characters; `null` when
  `mentioned` is `false`.
</ResponseField>

## Honesty behavior

Pinned-target absence is data. A target that never appears still gets a row:

```json
{
  "brand": "Salesforce",
  "domain": null,
  "mentioned": false,
  "position": null,
  "sentiment": null,
  "linked": false,
  "target": true,
  "sourceIds": [],
  "snippet": null
}
```

- Brands are deduplicated case-insensitively.
- `linked` uses registrable-domain matching, not substring matching.
  `hubspot.com` matches `www.hubspot.com` and its subdomains, but not
  `nothubspot.com`.
- `sourceIds` contains only ids that exist in `evidence.sources[]`. A
  hallucinated citation id is dropped, never invented.

## Warnings

Extraction can degrade without failing the capture. In both cases below, the
job completes normally and `evidence.mentions` is `null`:

<ResponseField name="extraction_failed" type="warning">
  Extraction was requested, but its lane failed, was unavailable, or exhausted
  its time budget. No extraction is fabricated.
</ResponseField>

<ResponseField name="extraction_skipped" type="warning">
  Extraction was requested, but an empty answer or `surface_absent` left nothing
  to extract.
</ResponseField>

## Example

<CodeGroup>

```bash cURL
curl -X POST https://api.aisearchapi.dev/v1/search \
  -H "Authorization: Bearer $AISEARCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "best crm for startups",
    "surfaces": ["chatgpt"],
    "extract": { "targets": ["HubSpot", "attio.com"] }
  }'
```

```javascript Node
const res = await fetch('https://api.aisearchapi.dev/v1/search', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.AISEARCH_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    query: 'best crm for startups',
    surfaces: ['chatgpt'],
    extract: { targets: ['HubSpot', 'attio.com'] },
  }),
});

const result = await res.json();
console.log(result.children[0].evidence.mentions);
```

```python Python
import os
import requests

res = requests.post(
    "https://api.aisearchapi.dev/v1/search",
    headers={
        "Authorization": f"Bearer {os.environ['AISEARCH_API_KEY']}",
        "Content-Type": "application/json",
    },
    json={
        "query": "best crm for startups",
        "surfaces": ["chatgpt"],
        "extract": {"targets": ["HubSpot", "attio.com"]},
    },
)

mentions = res.json()["children"][0]["evidence"]["mentions"]
print(mentions)
```

</CodeGroup>

```json Response excerpt
{
  "evidence": {
    "sources": [
      {
        "id": 1,
        "url": "https://hubspot.com/startups",
        "title": "HubSpot for Startups",
        "role": "cited",
        "cited": true,
        "charRanges": [[34, 41]]
      },
      {
        "id": 2,
        "url": "https://attio.com",
        "title": "Attio — CRM for the modern team",
        "role": "cited",
        "cited": true,
        "charRanges": [[43, 48]]
      }
    ],
    "mentions": {
      "confidence": 0.82,
      "items": [
        {
          "brand": "HubSpot",
          "domain": "hubspot.com",
          "mentioned": true,
          "position": 1,
          "sentiment": "positive",
          "linked": true,
          "target": true,
          "sourceIds": [1],
          "snippet": "For startups, the top CRMs are HubSpot, Attio and Pipedrive..."
        },
        {
          "brand": "Attio",
          "domain": "attio.com",
          "mentioned": true,
          "position": 2,
          "sentiment": "neutral",
          "linked": true,
          "target": true,
          "sourceIds": [2],
          "snippet": "Attio is a newer entrant with a flexible, Notion-like data model."
        },
        {
          "brand": "Pipedrive",
          "domain": "pipedrive.com",
          "mentioned": true,
          "position": 3,
          "sentiment": "neutral",
          "linked": false,
          "target": false,
          "sourceIds": [],
          "snippet": "For startups, the top CRMs are HubSpot, Attio and Pipedrive..."
        }
      ]
    }
  }
}
```

If a pinned target is absent, its row uses `mentioned: false`, `position: null`,
`sentiment: null`, `linked: false`, `sourceIds: []`, and `snippet: null`.

<Note>
  [Watches](/guides/watches) carry the same `extract` configuration and reapply
  it on every scheduled run.
</Note>

## Related

<CardGroup cols={2}>
  <Card
    title="Create a search"
    icon="magnifying-glass"
    href="/api-reference/search"
  >
    Request Auto Extract on a search.
  </Card>
  <Card title="The Envelope" icon="box-open" href="/guides/output-formats">
    Read the full `evidence.mentions` response shape.
  </Card>
  <Card title="Watches" icon="satellite-dish" href="/guides/watches">
    Reapply extraction on every scheduled run.
  </Card>
  <Card title="Errors" icon="triangle-exclamation" href="/guides/errors">
    Handle validation errors and warning degradation.
  </Card>
</CardGroup>
