# Tako search guide

`tako:search` gives a chat model live, sourced data from [Tako](https://tako.com):
financial, economic, sports, weather and company series as charted "cards", plus
web results. You add it to `tools`, the model decides when to search, the
gateway runs each search, and you get one finished answer with the cards it
used. This page takes you from a key to your first cards, and through the
things that go wrong. [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: `tako:search` is billed per search to an organization.

### 2. Add paid credit

Add credit in [Billing](https://app.routerplus.com/console/billing). Each search needs its
$0.007 in credit before it runs, on top of the model's own turns.

### 3. Export the key

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

### 4. Send a first search

The same request three ways. It asks a question that needs data newer than the
model's training, allows at most 3 searches, and asks the model to search first.

```bash
curl -i 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": "How did US CPI inflation change each month from January to September 2026?"}],
    "tools": [{"type": "tako:search", "parameters": {"max_uses": 3}}],
    "tool_choice": {"type": "tako:search"}
  }'
```

Python — the official `openai` SDK, with the tool in `extra_body`:

```python
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.routerplus.com/v1", api_key=os.environ["TM_API_KEY"])

completion = client.chat.completions.create(
    model="claude-haiku-4-5",
    messages=[{"role": "user", "content": "How did US CPI inflation change each month from January to September 2026?"}],
    extra_body={
        "tools": [{"type": "tako:search", "parameters": {"max_uses": 3}}],
        "tool_choice": {"type": "tako:search"},
    },
    timeout=180,  # a whole answer comes when the request is done, within 110 s
)

message = completion.choices[0].message
print(message.content)
tako = getattr(message, "tako", None) or {}  # absent when no search succeeded
for card in tako.get("cards", []):
    print(card["title"], card["embed_url"], card["coverage_end"])
usage = completion.usage
print(usage.server_tool_use["tako_search_requests"], "searches, cost $", usage.cost)
```

TypeScript — the official `openai` SDK, with a cast:

```typescript
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.routerplus.com/v1",
  apiKey: process.env.TM_API_KEY,
  timeout: 180_000, // a whole answer comes when the request is done, within 110 s
});

type TakoCard = {
  title: string; webpage_url: string; embed_url: string;
  image_url: string; source_names: string[]; coverage_end: string;
};

// The SDK's types know only function and custom tools, so the body is cast; it is sent as is.
const completion = await client.chat.completions.create({
  model: "claude-haiku-4-5",
  messages: [{ role: "user", content: "How did US CPI inflation change each month from January to September 2026?" }],
  tools: [{ type: "tako:search", parameters: { max_uses: 3 } }],
  tool_choice: { type: "tako:search" },
} as unknown as OpenAI.Chat.ChatCompletionCreateParamsNonStreaming);

const message = completion.choices[0].message as OpenAI.Chat.ChatCompletionMessage & { tako?: { cards: TakoCard[] } };
const usage = completion.usage as OpenAI.CompletionUsage & { cost: number; server_tool_use?: { tako_search_requests: number } };
console.log(message.content);
for (const card of message.tako?.cards ?? []) console.log(card.title, card.embed_url, card.coverage_end); // absent when no search succeeded
console.log(usage.server_tool_use?.tako_search_requests ?? 0, "searches, cost $", usage.cost);
```

The SDKs do not know the `tako:search` tool type. In Python, `tools` and
`tool_choice` go in `extra_body`, which the SDK merges into the request body
unchanged, and the answer's extra fields read as plain dicts
(`message.tako["cards"]`, `usage.server_tool_use["tako_search_requests"]`). In
TypeScript, the request is cast to `ChatCompletionCreateParamsNonStreaming`
(the SDK sends the body as written) and the answer is cast to add `tako` and
`server_tool_use`.

## Make the model search

Adding the tool lets the model search; it does not make it search. Whether a
model calls `tako_search` is the model's own choice, and any model can answer
from what it already knows instead. In the playground, a receipt that says
"0 Tako searches" means the model chose not to search, not that Tako failed.

Two things help:

- **Ask for the first search.** `tool_choice: {"type": "tako:search"}` asks the
  model to search on its first turn. It applies to the first turn only; later
  turns are `"auto"`, so the model decides whether to search again.
- **Ask for data the model cannot know.** Name a series and a recent period,
  newer than the model's training. For example:
  - "How did US CPI inflation change each month from January to September 2026?"
  - "What was Nvidia's quarterly revenue in each of the last four quarters, through 2026?"
  - "How did the US unemployment rate move over the last 12 months?"
  - "What was the 10-year US Treasury yield at the end of each week in October 2026?"

The playground has no `tool_choice` control: there you get a search by the
prompt alone. To force one, open **Code** in the composer
("This request as code"), copy the request, and add `"tool_choice": {"type": "tako:search"}` to it.

## Read the answer

The answer is an ordinary `chat.completion` with two additions:

- `choices[0].message.tako.cards`: the cards the searches found, at most 20, one
  per title. Each has `title`, `webpage_url`, `embed_url`, `image_url`,
  `source_names` and `coverage_end` (where the card's data ends, such as
  `"2026-09"`). Use `embed_url` to show Tako's chart in your app, and
  `webpage_url` to link to it. When no search succeeded, `tako` is absent.
- `usage.server_tool_use.tako_search_requests`: the number of searches billed.
  The header `x-tm-server-tools: tako_search=<n>` says the same. On a streamed
  answer it comes as an HTTP trailer, after the body: read
  `usage.server_tool_use` there instead.

`usage.cost` is in USD: the model's turns plus the searches. `usage.prompt_tokens`
is the last turn's prompt (the context after the request), `completion_tokens`
adds up every turn's output, and `usage.server_tool_turns` lists each turn's own
usage ([Server tools](/docs/server-tools#the-answer)). To see the header
with curl on a whole (non-streamed) answer, add `-i` (as above) or `-D -`:

```bash
curl -s -D - -o /dev/null 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": "How did the US unemployment rate move over the last 12 months?"}], "tools": [{"type": "tako:search"}], "tool_choice": {"type": "tako:search"}}' \
  | grep -i x-tm-server-tools
```

With `"stream": true` the response starts at once and sends a keep-alive every
10 seconds; the whole answer still comes at the end. See
[Server tools](/docs/server-tools#the-answer) for the stream's events.

## Parameters

| Field | Values | Default |
|---|---|---|
| `max_uses` | a whole number from 1 to 10: searches per request, across all turns | 5 |
| `count` | a whole number from 1 to 5: results of each source per search | 3 |
| `effort` | `"instant"` or `"fast"` | `"fast"` |
| `sources` | a non-empty list of `"data"` (cards) and `"web"` (web results) | both |

`max_tokens` and the rest of your request are sent with each model turn, so
`max_tokens` limits each turn, not the whole request.

## Playground

To try it without code, open the [Playground](/docs/playground):

1. Pick a chat model, open **Parameters** in the composer, and turn on **Tako
   search**. The switch is off in every new chat, so turn it on in each one.
2. Set the options if you like:
   - **Effort**: fast or instant. Instant answers from Tako's cached cards and
     is quicker; fast fetches fresh data. Same price.
   - **Most searches per request (1–10)**: `max_uses`, 5 by default.
   - **Results per source (1–5)**: `count`, 3 by default.
   - **Sources**: data cards, web results, or both (at least one).
3. Send a prompt that needs live data (see [Make the model search](#make-the-model-search)).
   While the gateway searches, the pending reply says it is searching Tako, and
   nothing appears until the answer is ready.
4. The cards appear under the reply, and the receipt shows "N Tako searches ($x)",
   such as "1 Tako search ($0.007)" or "3 Tako searches ($0.021)".

## Cost

A search costs **$0.007 ($7 per 1,000 searches)**, Tako's list price, with no
markup. A search that fails is not billed. The model's turns are billed as
ordinary chat requests, at the model's price. A request has at most
`max_uses + 1` model turns.

| Searches | Search fees |
|---|---|
| 1 | $0.007 |
| 3 | $0.021 |
| at most 5 (the default `max_uses`) | at most $0.035 |
| at most 10 (`max_uses` 10) | at most $0.070 |

The sample answer in [Server tools](/docs/server-tools#the-answer) made one
search: its `usage.cost` of 0.009324 is $0.007 for the search plus $0.002324 for
the model's turns. See [Pricing & billing](/docs/pricing) for the billing math.

## Troubleshooting

**0 searches.** The model chose not to search and answered from what it knows.
Tako did not fail. Send `tool_choice: {"type": "tako:search"}`, or ask for a
named series over a recent period (see [Make the model search](#make-the-model-search)).

**400 `server_tool_unsupported` "not enabled on this gateway".** The gateway you
called does not serve `tako:search`, so nothing was searched or billed. Ask
support to turn it on, or remove `tako:search` from `tools` (or the `x-tm-tools`
header) to send the request without it.

**503 "turned on but not configured".** `tako:search` is turned on for the
gateway you called, but our Tako key is not in place yet. Ask support; retrying
will not help until the key is configured.

**Nothing arrives for a long time.** This is expected: a whole (non-streamed)
answer arrives when the request is done, within 110 seconds. A streamed answer
starts at once, on every endpoint, and sends a keep-alive every 10 seconds; the
request can take up to 150 seconds. Set your client's read timeout above 150
seconds.

**Claude Code or Codex.** Send the header `x-tm-tools: tako:search`: see
[Claude Code and Codex](/docs/server-tools#claude-code-and-codex).

**504 after 110 seconds.** A request that is not streamed has 110 seconds (a
streamed one has 150), and each search has 15. Searches that finished are
billed. Retry with `"stream": true`, or use `effort: "instant"` or a lower
`max_uses`.

**400 that names a field or the endpoint.** A parameter out of range, an
unknown parameter, an `effort` other than `"instant"` or `"fast"`, a second
`tako:search` entry, or a tool of your own named `tako_search`. The tool is a
400 `server_tool_unsupported` on a composite model (`tm/...`) and on a
dedicated endpoint, on `POST /v1/messages` beside another server tool (with a
`tools` entry; with the header alone such a request is served without Tako),
`mcp_servers` or `container`, and on `POST /v1/responses` beside
`previous_response_id`, `background` or a hosted tool other than web search. Use
a catalog model on `POST https://api.routerplus.com/v1/chat/completions`,
`/v1/messages` or `/v1/responses`. Nothing is searched or billed.

**429 `insufficient_quota`.** Your balance, or a monthly spend cap, does not
cover the next search's $0.007. Add credit in [Billing](https://app.routerplus.com/console/billing)
or raise the cap.

**The model says a search failed or a limit was reached.** The model saw a tool
result of `{"error":"tako_search failed"}` (Tako refused, timed out after 15
seconds, or answered in a form we cannot read; not billed) or
`{"error":"tako_search limit for this request reached; continue without it"}` (it asked for
more than `max_uses` searches). At most 60 searches a minute run per
organization; a search over that rate is not sent or billed, and the model gets
an error result and goes on. Raise `max_uses`, or ask a narrower question.

## Data

Only the query the model writes goes to Tako, a third party, never your messages,
your key or your organization. The model's turns are kept like any chat request.
See [Data policy](/docs/data-policy) and [Server tools](/docs/server-tools#data).

## Where next

- [Server tools](/docs/server-tools) — the full `tako:search` reference
- [Playground](/docs/playground) — try it without code
- [Pricing & billing](/docs/pricing) — the billing math and `usage.cost`
