Skip to the page

Research reports

POST /v1/research answers a question with a written report from the live web. Each cited sentence links to the page it came from, with the time the page was read.

Start a report

Send your question as input and choose a depth. The call answers 202 at once with the report’s id and its price. Create a key under Agents & API in your workspace. Authentication

Terminal
curl https://api.specstream.ai/v1/research \
-H "Authorization: Bearer $SPECSTREAM_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: report-2026-11-13-001" \
-d '{"input": "Which countries have a retail central bank digital currency, and when did each launch?", "depth": "quick"}'
JSON
{
"data": {
"id": "rr_836a49eb6e934a1101427e77",
"status": "queued",
"depth": "quick",
"price_usd": 0.1,
"links": {
"self": "/v1/research/rr_836a49eb6e934a1101427e77",
"events": "/v1/research/rr_836a49eb6e934a1101427e77/events"
}
}
}

Read the report

Read GET /v1/research/{id} until status is completed. A quick report takes about a minute, a standard report about four minutes, and a deep report about five. To follow the work as it happens, open GET /v1/research/{id}/events: it is a server-sent event stream that names each stage and each page as it is read, and Last-Event-ID resumes it.

Terminal
curl https://api.specstream.ai/v1/research/rr_836a49eb6e934a1101427e77 \
-H "Authorization: Bearer $SPECSTREAM_API_KEY"

A completed report, cut short:

JSON
{
"data": {
"id": "rr_836a49eb6e934a1101427e77",
"status": "completed",
"stage": "done",
"depth": "quick",
"progress": {"searches": 5, "pages_read": 8, "sources": 7},
"report": {
"title": "...",
"format": "markdown",
"content": "... markdown with [1] markers ...",
"citations": [
{"n": 1, "url": "https://...", "title": "...", "read_at": "2026-11-12T23:16:31Z",
"excerpt": "the passage behind the sentence", "start": 812, "end": 977, "supported": true}
],
"sources": [{"n": 1, "url": "https://...", "title": "...", "read_at": "2026-11-12T23:16:31Z", "cited": true}]
},
"usage": {"searches": 5, "pages_read": 8, "charged_usd": 0.1}
}
}
FieldWhat it holds
statusqueued, running, completed, failed, cancelled, or payment_required.
stagequeued, planning, searching, reading, writing, checking, or done.
report.contentThe text, with a [1] marker after each cited sentence. For JSON output, report.structured holds the object.
report.citationsOne entry per cited sentence: the page, when it was read, the passage, and where the sentence sits in content (start and end).
report.sourcesEvery page read for the report, with its read time.
usageThe searches run, the pages read, and charged_usd, the price taken for this report.

The same two calls in Python:

Python
import os, time, requests
api = "https://api.specstream.ai"
auth = {"Authorization": "Bearer " + os.environ["SPECSTREAM_API_KEY"]}
run = requests.post(api + "/v1/research", headers=auth,
json={"input": "<your question>", "depth": "standard"}).json()["data"]
while run["status"] in ("queued", "running"):
time.sleep(5)
run = requests.get(api + "/v1/research/" + run["id"], headers=auth).json()["data"]
print(run["report"]["content"])
for citation in run["report"]["citations"]:
print(citation["n"], citation["url"], citation["read_at"])

POST /v1/research/{id}/cancel stops a report. GET /v1/research lists your account’s reports, newest first.

Price and retries

A report is $0.10 at quick depth, $0.30 at standard, and $1 at deep. The price comes out of your balance once, when the report is delivered. A canceled report is not charged. Send an Idempotency-Key header (at most 128 characters) to retry safely: the same key and body return the same report.

What you can send

FieldWhat it does
inputThe question, in plain words. Up to 15,000 characters.
depthquick, standard (the default), or deep. Each depth has one price and reads more of the web than the one before it.
output{"type": "text"} for markdown (the default), or {"type": "json", "schema": {...}} for JSON that matches your JSON Schema.
lengthshort, standard, or long. It sets how long the text is.
languageThe report’s language. By default it is the question’s language.
include_domains, exclude_domainsThe sites to read, or the sites to leave out.
webhook{"url": "https://..."}. SpecStream calls it when the report ends, signed with your account’s webhook secret.
metadataUp to 16 keys of your own. They come back on the report.

On MCP

research_price shows the price of each depth. start_research starts a report once the user approves that price as confirm_max_cents. get_research reads it until it is completed, cancel_research stops it, and list_research lists the account’s reports. Set up MCP

When a call stops

StatusWhat happened
401No key or token. Send Authorization: Bearer with your API key.
402insufficient_balance: the balance doesn’t hold the report’s price. Add balance under Settings, Usage and billing, then send it again.
404No report with this ID on your account.
409The Idempotency-Key was used with another body. Send a new key.
422A field is wrong. The reply names the field and the problem.
429The account used its calls for the minute. Wait the seconds in Retry-After and send it again.