# The Crawl4AI server's documented calls against SpecStream

Date: 2026-11-10. Client: Crawl4AI's documented curl calls (self-hosting guide read 2026-11-10).

## The one line a user changes

Before:

```
http://localhost:11235
```

After:

```
https://api.specstream.ai/crawl4ai
```

Crawl4AI's Python client (`Crawl4aiDockerClient`, crawl4ai 0.9.5) works with `base_url="https://api.specstream.ai/crawl4ai"` and `await client.authenticate(KEY)`: its `/token` sign-in takes the SpecStream key in place of the email, and its `/health`, `/token` and `/crawl` calls are answered at the host root, where the client sends them. The calls here are the server's documented requests with the address and the token changed. A `/crawl` and an `/md` are each one Extract API call; a page with no text is not charged.

## 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, 8 accepted, not applied, 6 refused.

| Parameter | Sent | Verdict | Measured |
|---|---|---|---|
| `crawl urls` | `[https://en.wikipedia.org/wiki/Web_scraping]` | honoured | status 200; results[0] has html and markdown.raw_markdown (28045 characters) |
| `crawl urls (three, one missing)` | 3 URLs | honoured | status 200; successes [True, True, False] |
| `crawl url (a page the site answers 404)` | a missing page | honoured | status 200; status_code 404, error_message set |
| `crawl browser_config` | `{"type": "BrowserConfig", "params": {"headless": true}}` | accepted, not applied | status 200; the baseline's form |
| `crawl crawler_config` | `{"type": "CrawlerRunConfig", "params": {"stream": false, "cache_mode": "bypass"}}` | accepted, not applied | status 200; the baseline's form |
| `crawl crawler_configs` | `[]` | accepted, not applied | status 200; the baseline's form |
| `crawl hooks` | `{}` | accepted, not applied | status 200; the baseline's form |
| `crawl urls (empty)` | `[]` | refused | status 400; an error body |
| `crawl urls (101)` | 101 URLs | refused | status 400; an error body |
| `md url` | `https://en.wikipedia.org/wiki/Web_scraping` | honoured | status 200; markdown of 28045 characters |
| `md f` | `raw` | honoured | status 200; filter raw echoed, markdown present |
| `md f` | `{"f": "bm25", "q": "history"}` | accepted, not applied | status 200; the baseline's markdown |
| `md q` | `{"q": "history"}` | accepted, not applied | status 200; the baseline's markdown |
| `md c` | `{"c": "1"}` | accepted, not applied | status 200; the baseline's markdown |
| `md provider` | `{"provider": "openai/gpt-4o-mini"}` | accepted, not applied | status 200; the baseline's markdown |
| `md f (not a filter)` | `nope` | refused | status 400; an error body |
| `md url (no scheme)` | `example.com` | refused | status 400; an error body |
| `md url (a page with no text)` | a missing page | refused | status 500; an error body |
| `api token (wrong token)` | a token that is not one | refused | status 401; error body ['code', 'detail'] |

## 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: 21 present, 1 empty, 7 absent.

| Field | State | Measured |
|---|---|---|
| `crawl success` | present | every crawl |
| `crawl results` | present | every crawl |
| `crawl server_processing_time_s` | present | every crawl |
| `crawl server_memory_delta_mb` | absent | every crawl |
| `crawl server_peak_memory_mb` | absent | every crawl |
| `crawl results[].url` | present | every result |
| `crawl results[].html` | present | every result |
| `crawl results[].success` | present | every result |
| `crawl results[].cleaned_html` | absent | every result |
| `crawl results[].markdown` | present | every result |
| `crawl results[].markdown.raw_markdown` | present | every result |
| `crawl results[].markdown.markdown_with_citations` | present | every result |
| `crawl results[].markdown.references_markdown` | empty | every result |
| `crawl results[].markdown.fit_markdown` | absent | every result |
| `crawl results[].links` | present | every result |
| `crawl results[].links.internal` | present | every result |
| `crawl results[].links.external` | present | every result |
| `crawl results[].media` | absent | every result |
| `crawl results[].metadata` | present | every result |
| `crawl results[].status_code` | present | every result |
| `crawl results[].error_message` | present | every result |
| `crawl results[].screenshot` | absent | every result |
| `crawl results[].pdf` | absent | every result |
| `md url` | present | every md |
| `md filter` | present | every md |
| `md query` | present | every md |
| `md cache` | present | every md |
| `md markdown` | present | every md |
| `md success` | present | every md |
