# Exa Contents' Python client against SpecStream

Date: 2026-11-10. Client: exa-py 2.28.0.

## The one line a user changes

Before:

```
Exa(api_key="...")
```

After:

```
Exa(api_key=KEY, base_url="https://api.specstream.ai/exa")
```

The same address serves Exa's search. One call reads up to 20 pages; a call with more is answered with Exa's 400 error body.

## Request parameters

Honoured means the check in the Measured column passed on the reply. Accepted, not applied means status 200 and the reply has the form of the same call without the parameter. Refused means the vendor's error body and status.

Counts: 5 honoured, 11 accepted, not applied, 3 refused.

| Parameter | Sent | Verdict | Measured |
|---|---|---|---|
| `urls (one string)` | `https://en.wikipedia.org/wiki/Web_scraping` | honoured | status 200; results[0] is the page with its text (exa-py sends text.maxCharacters by default) |
| `urls (a list)` | 3 URLs, one host that does not resolve | honoured | status 200; results 2, statuses 3 |
| `text` | `true` | honoured | status 200; results[0].text holds the page |
| `text.maxCharacters` | `200` | honoured | status 200; text has 200 characters |
| `ids` | `["https://en.wikipedia.org/wiki/Web_scraping"]` | honoured | status 200; results[0] is the page |
| `text.includeHtmlTags` | `true` | accepted, not applied | status 200; reply has the baseline's form |
| `text.verbosity` | `full` | accepted, not applied | status 200; reply has the baseline's form |
| `highlights` | `true` | accepted, not applied | status 200; reply has the baseline's form |
| `summary` | `{query}` | accepted, not applied | status 200; reply has the baseline's form |
| `extras.links` | `5` | accepted, not applied | status 200; reply has the baseline's form |
| `subpages` | `2` | accepted, not applied | status 200; reply has the baseline's form |
| `subpage_target` | `history` | accepted, not applied | status 200; reply has the baseline's form |
| `livecrawl` | `always` | accepted, not applied | status 200; reply has the baseline's form |
| `livecrawl_timeout` | `5000` | accepted, not applied | status 200; reply has the baseline's form |
| `max_age_hours` | `0` | accepted, not applied | status 200; reply has the baseline's form |
| `user_identifier` | `proof-1` | accepted, not applied | status 200; reply has the baseline's form |
| `urls (21 URLs)` | 21 URLs | refused | status 400; 400, Exa's error body |
| `urls with ids` | both | refused | status 400; 400, Exa's error body |
| `api key (wrong key)` | a key that is not one | refused | status 401; 401, Exa's error body |

## Response fields

Present means the field holds a value in the replies to the calls above. Empty means it is there with no value. Absent means it is not in the reply.

Counts: 14 present, 0 empty, 11 absent.

| Field | State | Measured |
|---|---|---|
| `requestId` | present | the JSON body of a two URL call |
| `results` | present | the JSON body of a two URL call |
| `statuses` | present | the JSON body of a two URL call |
| `costDollars.total` | present | the JSON body of a two URL call |
| `searchTime` | present | the JSON body of a two URL call |
| `context` | absent | the JSON body of a two URL call |
| `results[].title` | present | every result |
| `results[].url` | present | every result |
| `results[].id` | present | every result |
| `results[].publishedDate` | present | every result |
| `results[].author` | absent | every result |
| `results[].text` | present | every result |
| `results[].highlights` | absent | every result |
| `results[].highlightScores` | absent | every result |
| `results[].summary` | absent | every result |
| `results[].image` | absent | every result |
| `results[].favicon` | absent | every result |
| `results[].subpages` | absent | every result |
| `results[].extras` | absent | every result |
| `results[].entities` | absent | every result |
| `statuses[].id` | present | every status |
| `statuses[].status` | present | every status |
| `statuses[].source` | present | every status |
| `statuses[].error.tag` | present | every status |
| `statuses[].error.httpStatusCode` | absent | every status |
