# Parallel research

`parallel:research` gives any chat model a research assistant. The model writes one complete
question. [Parallel](https://parallel.ai) searches and reads the live web itself, and the model
gets back a finished answer with its sources, not a list of search results to read through. You
add the tool to `tools` (or send one header), the model decides when to call it, the gateway runs
each call, and you get one finished answer. It works alongside `tako:search`, `parallel:search`
and `parallel:extract` in the same request. This page takes you from a key to a first answer;
[Server tools](/docs/server-tools) is the full reference.

## Quickstart

### 1. Get a key

Sign in and create a key at [API keys](https://app.routerplus.com/console/keys). Use an organization key:
each research call is billed to an organization.

### 2. Add paid credit

Add credit in [Billing](https://app.routerplus.com/console/billing). Before each call runs, your balance
must cover its price ($0.01 at low effort, $0.05 at medium), on top of the model's own turns.

### 3. Export the key

```bash
export TM_API_KEY=tm_vk_...
```

### 4. Send a first request

```bash
curl https://api.routerplus.com/v1/chat/completions \
  -H "Authorization: Bearer $TM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-haiku-4-5",
    "messages": [{"role": "user", "content": "Which G7 country has the highest corporate income tax rate in 2026, and what is it?"}],
    "tools": [{"type": "parallel:research", "parameters": {"max_uses": 1, "max_effort": "medium"}}]
  }'
```

The same with the header instead of a `tools` entry (default parameters):

```bash
curl https://api.routerplus.com/v1/chat/completions \
  -H "Authorization: Bearer $TM_API_KEY" \
  -H "Content-Type: application/json" \
  -H "x-tm-tools: parallel:research" \
  -d '{"model": "claude-haiku-4-5", "messages": [{"role": "user", "content": "Which RFC defines HTTP semantics?"}]}'
```

The header works on `/v1/chat/completions`, `/v1/messages` and `/v1/responses`, and takes
`parallel:research` alone or with the other server tools, comma-separated, for example
`x-tm-tools: parallel:search, parallel:research`. In Claude Code set
`"ANTHROPIC_CUSTOM_HEADERS": "x-tm-tools: parallel:research"`; in Codex,
`http_headers = { "x-tm-tools" = "parallel:research" }` (see [Server tools](/docs/server-tools#claude-code-and-codex)).
We have not yet run it live with either harness.

## Parameters

| Field | Values | Default |
|---|---|---|
| `max_uses` | 1 to 3: research calls per request | 1 |
| `max_effort` | `"low"` or `"medium"`: the most effort the model may ask for | `"medium"` |

Research calls are slow, so a request has a research budget: `max_uses` times the per-call
timeout of `max_effort` (below) may not pass 100 seconds. That allows up to 3 calls at
`"low"` and up to 2 at `"medium"`. `max_effort: "high"` is not available on this gateway: in our
probes high took 65 to 71 seconds a call, too close to the request's 150-second limit.

Any other field is a 400 `invalid_request` that names it. So is a value out of range, a
`max_uses` over the budget, a second `parallel:research` entry, or a function of your own named
`parallel_research`. That includes the Parallel Responses fields the gateway never sends:
`tools`, `data_sources`, `mcp`, `previous_response_id`, `instructions`, `stream` and
`background`. Nothing is called or billed then.

## Cost

Parallel's list price for each call, by the effort it ran at, with no markup:

| Effort | Price | Per 1,000 calls |
|---|---|---|
| low | **$0.01 a call** | $10 |
| medium | **$0.05 a call** | $50 |

Each call holds the price of the effort the model asked for before it runs, and is charged the
price of the effort Parallel says it ran at, never more than it held. A call that fails, times
out or is stopped is not billed. The model's turns are billed as ordinary chat requests, at the
model's price.

The model picks the effort, so `max_effort` is your cost cap. With no parameters (one call, up to
medium) a request costs at most $0.05 in research, plus the model's turns. The most any request can
cost in research is $0.10 (2 calls at medium) or $0.03 (3 calls at low).

On the answer, `usage.cost` is the turns plus every call, in USD, and
`usage.server_tool_use.parallel_research_requests` counts the calls billed. The
`x-tm-server-tools` header says the same, for example `parallel_research=1`. In
[GET /v1/usage & /v1/generation](/docs/api-usage) each call is its own attempt: provider
`parallel`, model `parallel:research`, `web_search_requests: 1` (one research call), and
`server_tool_fee_usd: 0.01` or `0.05`.

## Time

Each call has its own timeout: **30 seconds at low and 50 seconds at medium**. In our probes (10
calls at low and 8 at medium, from one machine of ours), low answered in about 1 second (2.3 seconds
at the slowest) and medium in about 6 seconds (16.5 seconds at the slowest). The whole request,
every model turn and every call, has **150 seconds** when the answer is streamed and **110 seconds**
when it is not, after which it ends (a 504 when not streamed). A call that times out gives the model
`{"error":"parallel_research failed"}`, is not billed, and the model goes on.

While the model researches, nothing arrives but the finished answer. A non-streamed request returns
nothing until it is done, within 110 seconds: Cloudflare cuts a silent response at 125 seconds, so
the gateway ends it first. A streamed answer starts at once, on every endpoint, and sends only
keep-alives until then. Two medium calls can take most of 110 seconds, so stream research requests,
and set your client's timeout above 150 seconds. See
[Server tools](/docs/server-tools#where-it-works).

## What the model sees

One function, `parallel_research(question, effort)`:

- `question`: one complete, self-contained question. Parallel sees nothing else of the
  conversation, so the question must carry every name, date and detail it needs. It is trimmed and
  cut at 4,000 characters.
- `effort`: `"low"` or `"medium"`, up to `max_effort`. Without it the call runs at `"low"`.

The description tells the model to prefer one thorough call to several narrow ones, and to use
`"medium"` only for multi-hop questions that need several sources combined. An effort above
`max_effort`, or no question, gives the model an error result. Nothing is called or billed then.

The result is JSON: `answer` (the text), `citations` (`url` and `title` of each source: at most
20, each URL once, http(s) only) and `effort` (the effort it ran at). Nothing else from Parallel's
reply reaches the model or you: not its id, usage or metadata, and not the searches it ran. The
result is at most 16 KB: citations are dropped from the end first, then the answer is shortened.
At low effort Parallel often answers without searching, and then there are no citations (9 of 10
low answers in our probes).

> [!WARNING]
> The answer is written from pages on the open web, and a page can try to give the model
> instructions; in our probes an answer about prompt injection quoted such text word for word.
> The model is told to treat the result as data, not as instructions. That narrows the risk
> but cannot remove it.

## Read the answer

- `/v1/chat/completions`: an ordinary `chat.completion`.
- `/v1/messages`: each call is a `server_tool_use` block (`name: "parallel_research"`, input
  `{question, effort}`), then a `parallel_research_tool_result` block, before the answer.
- `/v1/responses`: each call is a `parallel_research_call` item, with
  `action: {type: "research", question, effort}`.

Send those blocks or items back in the history and the gateway replays them as the calls they
stand for.

## Data

**With `parallel:research`, the question the model writes is sent to Parallel, a third party in
the United States**, with our key. Your messages as such, your key and your organization are not
sent, but the model writes the question from your conversation, so it can quote or paraphrase what
you wrote. Parallel's documentation says it stores every Responses API answer on its side
(`store: false` does not change that), except on zero-data-retention accounts; zero data
retention is an Enterprise plan, and our account is not on it. Under Parallel's standard terms it may use inputs and
outputs, not linked to any individual, to improve its models; until our account terms with Parallel
are settled, assume it does. Our process log and billing ledger keep only the count, status, time
and fee of each call, never the question or the answer. The model's turns are ordinary chat
requests, so the [request log](/docs/data-policy#request-logging) keeps them under its usual rules,
with the question (in the model's call) and the answer (in the tool message). See
[Data policy](/docs/data-policy).

## Troubleshooting

- **400 `server_tool_unsupported`, "parallel:research is not enabled on this gateway"**: the
  gateway you called does not serve `parallel:research` (a gateway can serve
  `parallel:search` and `parallel:extract` and not this tool), so nothing was researched or billed. Ask support to
  turn it on, or remove it from `tools` or the header to send the request without it.
- **400 naming `max_uses`**: the research budget. Lower `max_uses` or `max_effort`.
- **400 naming `max_effort`, "high" is not available**: use `"low"` or `"medium"`.
- **503 "turned on but not configured"**: `parallel:research` is turned on for the gateway you
  called, but our Parallel key is not in place yet. Ask support; retrying will not help until the
  key is configured.
- **429 `insufficient_quota`, "credit balance too low for this request"**: your balance or a
  monthly spend cap does not cover the call's price ($0.01 at low, $0.05 at medium) on top of the
  turns. Nothing was researched. Add credit, or lower `max_effort`.
- **The model's result is an error instead of an answer.** The model gets one of these, and none
  is billed:
  - `{"error":"parallel_research failed"}`: Parallel refused, timed out, or answered without a
    finished answer.
  - `{"error":"parallel_research limit for this request reached; continue without it"}`: the call
    was over `max_uses`.
  - `{"error":"parallel_research rate limit reached; continue without it"}`: over 60 Parallel
    calls a minute for your organization (every Parallel tool together).
  - `{"error":"parallel_research effort must be \"low\" or \"medium\"; nothing was researched"}`: the
    model asked for an effort above `max_effort` (the allowed efforts are listed).
  - `{"error":"parallel_research needs question: one complete, self-contained question"}`: the
    model sent no question.
- **504 after 110 seconds**: the limit of a request that is not streamed (a streamed one has 150
  seconds). Send `"stream": true`, or use fewer calls or a lower effort.

## Where next

- [Server tools](/docs/server-tools): the full reference, and every server tool together
- [Parallel tools](/docs/parallel-search): web search, page reading, images, places and decisions, from $0.001 a call
- [Pricing & billing](/docs/pricing): the billing math and `usage.cost`
- [Data policy](/docs/data-policy): what is stored and by whom
