> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tako.com/llms.txt
> Use this file to discover all available pages before exploring further.

# For Your Coding Agent

> The build reference for coding agents integrating Tako's Data Graph. Self-contained and copy-paste-ready — Graph Search, Graph Related, and Graph Node endpoints, every parameter, real response shapes, and the full agentic workflow for grounding /v3/search queries in resolved graph nodes.

export const AgentPromptCard = ({title, description, children}) => <div className="relative mt-4 rounded-xl border border-zinc-950/10 dark:border-white/10 bg-zinc-50/60 dark:bg-white/[0.03] px-4 pt-3 pb-1">
    <div className="absolute top-3.5 right-4 flex items-center gap-2 text-zinc-900 dark:text-zinc-100">
      <svg role="img" aria-label="Claude" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="#D97757" className="h-5 w-5"><path d="m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z" /></svg>
      <svg role="img" aria-label="Cursor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="currentColor" fillRule="evenodd" className="h-5 w-5"><path d="M22.106 5.68L12.5.135a.998.998 0 00-.998 0L1.893 5.68a.84.84 0 00-.419.726v11.186c0 .3.16.577.42.727l9.607 5.547a.999.999 0 00.998 0l9.608-5.547a.84.84 0 00.42-.727V6.407a.84.84 0 00-.42-.726zm-.603 1.176L12.228 22.92c-.063.108-.228.064-.228-.061V12.34a.59.59 0 00-.295-.51l-9.11-5.26c-.107-.062-.063-.228.062-.228h18.55c.264 0 .428.286.296.514z" /></svg>
      <svg role="img" aria-label="ChatGPT" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="currentColor" fillRule="evenodd" className="h-5 w-5"><path d="M9.205 8.658v-2.26c0-.19.072-.333.238-.428l4.543-2.616c.619-.357 1.356-.523 2.117-.523 2.854 0 4.662 2.212 4.662 4.566 0 .167 0 .357-.024.547l-4.71-2.759a.797.797 0 00-.856 0l-5.97 3.473zm10.609 8.8V12.06c0-.333-.143-.57-.429-.737l-5.97-3.473 1.95-1.118a.433.433 0 01.476 0l4.543 2.617c1.309.76 2.189 2.378 2.189 3.948 0 1.808-1.07 3.473-2.76 4.163zM7.802 12.703l-1.95-1.142c-.167-.095-.239-.238-.239-.428V5.899c0-2.545 1.95-4.472 4.591-4.472 1 0 1.927.333 2.712.928L8.23 5.067c-.285.166-.428.404-.428.737v6.898zM12 15.128l-2.795-1.57v-3.33L12 8.658l2.795 1.57v3.33L12 15.128zm1.796 7.23c-1 0-1.927-.332-2.712-.927l4.686-2.712c.285-.166.428-.404.428-.737v-6.898l1.974 1.142c.167.095.238.238.238.428v5.233c0 2.545-1.974 4.472-4.614 4.472zm-5.637-5.303l-4.544-2.617c-1.308-.761-2.188-2.378-2.188-3.948A4.482 4.482 0 014.21 6.327v5.423c0 .333.143.571.428.738l5.947 3.449-1.95 1.118a.432.432 0 01-.476 0zm-.262 3.9c-2.688 0-4.662-2.021-4.662-4.519 0-.19.024-.38.047-.57l4.686 2.71c.286.167.571.167.856 0l5.97-3.448v2.26c0 .19-.07.333-.237.428l-4.543 2.616c-.619.357-1.356.523-2.117.523zm5.899 2.83a5.947 5.947 0 005.827-4.756C22.287 18.339 24 15.84 24 13.296c0-1.665-.713-3.282-1.998-4.448.119-.5.19-.999.19-1.498 0-3.401-2.759-5.947-5.946-5.947-.642 0-1.26.095-1.88.31A5.962 5.962 0 0010.205 0a5.947 5.947 0 00-5.827 4.757C1.713 5.447 0 7.945 0 10.49c0 1.666.713 3.283 1.998 4.448-.119.5-.19 1-.19 1.499 0 3.401 2.759 5.946 5.946 5.946.642 0 1.26-.095 1.88-.309a5.96 5.96 0 004.162 1.713z" /></svg>
    </div>
    <div className="text-sm font-semibold text-zinc-900 dark:text-zinc-100" style={{
  paddingRight: '6rem'
}}>{title}</div>
    <div className="mt-1 text-sm text-zinc-600 dark:text-zinc-400" style={{
  paddingRight: '6rem'
}}>{description}</div>
    <div style={{
  marginTop: '-2px',
  marginBottom: '-14px'
}}>
      {children}
    </div>
  </div>;

This page is a complete, self-contained reference for building against **Tako's Data Graph** — and for the agentic pattern it enables: discover what data Tako has, ground your searches on it, and report what's missing. It is written for coding agents (and developers in a hurry): every example runs after you supply an API key, every parameter is grounded in the live API, and the common mistakes are called out explicitly. For the auto-generated schemas, see the API reference ([Graph Search](/api-reference/graph-search), [Graph Related](/api-reference/graph-related), [Graph Node](/api-reference/graph-node)); for a narrative introduction, see the [Overview](/documentation/integrating-tako/data-graph/overview).

<AgentPromptCard title={<>Give your coding agent the <code>tako-graph-agent</code> skill</>} description={<>Teaches your agent the graph-grounded workflow — resolve names to nodes, read what data exists, compose pinned searches, report gaps honestly. Its main use is <strong>building agentic applications that integrate Tako Search</strong>; it's equally handy for checking what Tako covers or debugging searches that return vague cards. One command installs it:</>}>
  ````bash theme={null}
  mkdir -p .claude/skills/tako-graph-agent && \
    curl -fsSL https://docs.tako.com/skills/tako-graph-agent.md \
      | sed -n '/^```/,/^```/p' | sed '1d;$d' \
      > .claude/skills/tako-graph-agent/SKILL.md && \
    curl -fsSL https://docs.tako.com/skills/tako-graph-agent/resolve-example.md \
      | sed -n '/^```/,/^```/p' | sed '1d;$d' \
      > .claude/skills/tako-graph-agent/resolve-example.ts
  ````
</AgentPromptCard>

## What the Data Graph does

Tako serves live financial, macroeconomic, and company data as embeddable knowledge-card charts through [`POST /v3/search`](/documentation/integrating-tako/search/for-coding-agent). The graph endpoints tell you **what data Tako actually has before you search** — so you compose queries that hit, pin the exact nodes you resolved, and honestly report gaps.

* **Base URL:** `https://tako.com/api/`
* **Auth:** every endpoint on this page — including the graph endpoints — takes your API key in the **`X-API-Key`** request header. Create a key in the [Tako console](https://tako.com/console/api-keys).
* **Cost:** graph calls consume **no credits**. They are bounded by rate limits only: **180/minute and 10,000/day** per account. Back off on `429` with jittered exponential retry.
* **Endpoints:** `GET /beta/graph/search` (resolve a name to nodes), `GET /beta/graph/related` (explore what a node connects to), `GET /beta/graph/node/{id}` (confirm what an id refers to — occasional use).

<Note>
  The graph endpoints are **beta**. A returned node is a guide, not a guarantee — see [Knowing what you don't know](#knowing-what-you-dont-know) for how to report coverage honestly.
</Note>

## Minimal working example

Resolve an entity, read its metrics, then run a search pinned to the resolved node. Complete after you set `TAKO_API_KEY` — no SDK required, the graph is plain HTTP.

<CodeGroup>
  ```bash cURL theme={null}
  # 1. Resolve the entity
  curl "https://tako.com/api/beta/graph/search?q=nvidia&types=entity" \
    -H "X-API-Key: $TAKO_API_KEY"

  # 2. What revenue-like metrics exist for it? (use the id from step 1)
  curl "https://tako.com/api/beta/graph/related?node_id=NODE_ID&relation=metrics&q=revenue" \
    -H "X-API-Key: $TAKO_API_KEY"

  # 3. Search, pinned to the resolved node
  curl -X POST https://tako.com/api/v3/search \
    -H "X-API-Key: $TAKO_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"query": "Nvidia quarterly revenue", "sources": {"data": {"node_ids": ["NODE_ID"]}}}'
  ```

  ```python Python theme={null}
  import os, requests

  BASE = "https://tako.com/api"
  HEADERS = {"X-API-Key": os.environ["TAKO_API_KEY"]}

  # 1. Resolve the entity
  nodes = requests.get(f"{BASE}/beta/graph/search",
                       params={"q": "nvidia", "types": "entity"},
                       headers=HEADERS).json()["results"]
  node = nodes[0]

  # 2. What revenue-like metrics exist for it?
  page = requests.get(f"{BASE}/beta/graph/related",
                      params={"node_id": node["id"], "relation": "metrics", "q": "revenue"},
                      headers=HEADERS).json()
  metrics = page["relation"]["items"]  # items live in relation.items, NOT results

  # 3. Search, pinned to the resolved node
  results = requests.post(f"{BASE}/v3/search", headers=HEADERS, json={
      "query": f"{node['name']} quarterly revenue",
      "sources": {"data": {"node_ids": [node["id"]]}},
  }).json()
  for card in results.get("cards", []):
      print(card["title"], card["embed_url"])
  ```

  ```typescript TypeScript theme={null}
  const BASE = "https://tako.com/api";
  const HEADERS = { "X-API-Key": process.env.TAKO_API_KEY! };

  // 1. Resolve the entity
  const search = await fetch(`${BASE}/beta/graph/search?q=nvidia&types=entity`, { headers: HEADERS });
  const node = (await search.json()).results[0];

  // 2. What revenue-like metrics exist for it?
  const rel = await fetch(
    `${BASE}/beta/graph/related?node_id=${node.id}&relation=metrics&q=revenue`,
    { headers: HEADERS },
  );
  const metrics = (await rel.json()).relation.items; // items live in relation.items, NOT results

  // 3. Search, pinned to the resolved node
  const results = await fetch(`${BASE}/v3/search`, {
    method: "POST",
    headers: { ...HEADERS, "Content-Type": "application/json" },
    body: JSON.stringify({
      query: `${node.name} quarterly revenue`,
      sources: { data: { node_ids: [node.id] } },
    }),
  });
  for (const card of (await results.json()).cards ?? []) {
    console.log(card.title, card.embed_url);
  }
  ```
</CodeGroup>

## Graph Search — resolve a name to nodes

`GET /beta/graph/search` resolves free text to entity and metric nodes. Decide up front whether you're resolving **a thing** (entity) or **a measure** (metric) and pass the matching `types` — don't mix them in one lookup.

| Parameter     | Type        | Default        | Description                                                                                               |
| ------------- | ----------- | -------------- | --------------------------------------------------------------------------------------------------------- |
| `q`           | string      | — *(required)* | Search text. Shorter than 2 characters returns an empty `results` list (200, not an error).               |
| `types`       | string      | both           | Comma-separated facets: `entity`, `metric`. Unknown value → 400.                                          |
| `label`       | string enum | none           | Ranking **boost** toward one NER label (see below). Unknown value → 400. Supplying it disables inference. |
| `infer_label` | boolean     | `true`         | Auto-detect the entities in `q` and apply the matching label boost. Disable with `false`/`0`/`no`/`off`.  |
| `limit`       | integer     | `20`           | Max results; values above 50 are clamped to 50 (below 1 → 400).                                           |

### Labels: disambiguating without filtering

Ambiguous names ("air china", "apple") resolve to a pile of nodes across types — a company can share its name with a country or a fruit. A **`label`** biases the ranking toward one entity category (`label=ORG` floats Air China the airline above China the country). It is a **boost, not a filter** — matching nodes rank higher, but off-label nodes still return. Use it to steer the top result, not to guarantee exclusivity.

* **Values:** `PERSON`, `ORG`, `GPE`, `LOC`, `PRODUCT`, `EVENT`, `LANGUAGE`, `MONEY`, `METRIC`, `STOCK_TICKER`, `WEBSITE`. Sports teams are `ORG`.
* **Auto-detection:** with no explicit `label`, Tako infers the entities in `q` and applies the matching boost; the labels it found come back in `inferred_labels` (empty list = inference ran, found nothing; absent = didn't run).

### Response

```json theme={null}
{
  "results": [
    {
      "id": "nvidia-3f8b2c",
      "type": "entity",
      "name": "NVIDIA",
      "aliases": ["Nvidia Corporation", "NVDA"],
      "description": "American technology company",
      "subtype": "Companies",
      "label": "ORG"
    }
  ],
  "inferred_labels": ["ORG"]
}
```

Results are ordered by a relevance + popularity blend. Fields that are null are omitted from the response, not sent as `null`.

## Graph Related — explore what a node connects to

`GET /beta/graph/related` takes a `node_id` from Graph Search and returns everything it connects to, grouped by relation.

| Parameter               | Type    | Default        | Description                                                                                                                                               |
| ----------------------- | ------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `node_id`               | string  | — *(required)* | The node's opaque public id. Unknown id → 404.                                                                                                            |
| `relation`              | string  | none           | A relation **key** to paginate: `metrics`, `entities`, `siblings`, `part_of`, `members`, or a named edge like `rel:competes_with`. Omit for the overview. |
| `q`                     | string  | none           | Case-insensitive substring filter on related nodes' names + aliases. Filters every group of the overview, or the one paginated group.                     |
| `label` / `infer_label` | —       | as above       | Same boost semantics as Graph Search; inference runs only when `q` is set.                                                                                |
| `cursor`                | string  | none           | Opaque pagination cursor from `next_cursor`. Malformed → 400.                                                                                             |
| `limit`                 | integer | `50`           | Page size; values above 100 are clamped.                                                                                                                  |

<Note>
  An unknown `relation` key returns **200 with empty items**, not an error — so a typo'd `rel:*` key reads as "no relation." Relation keys are per-node: read the overview to discover them, then drill.
</Note>

### Overview response (no `relation`)

An ordered `relations[]` list — named semantic edges first, then membership, data co-reference, and siblings. Empty groups are dropped.

```json theme={null}
{
  "node": { "id": "nvidia-3f8b2c", "type": "entity", "name": "NVIDIA", "subtype": "Companies" },
  "relations": [
    { "key": "rel:competes_with", "kind": "related", "label": "Competes With",
      "items": [{ "id": "amd-91c04d", "type": "entity", "name": "AMD", "subtype": "Companies" }],
      "total": 12, "total_capped": false },
    { "key": "part_of", "kind": "membership", "label": "Part Of",
      "items": [{ "id": "magnificent-seven-55aa01", "type": "entity", "name": "Magnificent Seven" }],
      "total": 3, "total_capped": false },
    { "key": "metrics", "kind": "data", "label": "Metrics",
      "items": [{ "id": "revenues-8d21aa", "type": "metric", "name": "Revenues" }],
      "total": 250, "total_capped": true },
    { "key": "siblings", "kind": "sibling", "label": "Other Companies",
      "items": [{ "id": "microsoft-7be913", "type": "entity", "name": "Microsoft" }],
      "total": 250, "total_capped": true }
  ]
}
```

Groups by `kind`:

| `kind`       | Keys                                                                                                      | Meaning                                                                                                       |
| ------------ | --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `related`    | `rel:<phrase>` — `rel:competes_with`, `rel:subsidiaries_of`, `rel:in_industry`, `rel:headquartered_in`, … | **Named semantic edges.** The richest signal for entities. Keys are per-node — read the overview, then drill. |
| `membership` | `part_of`, `members`                                                                                      | Cohort/geo membership (Apple `part_of` FAANG; a league's `members`).                                          |
| `data`       | `metrics`, `entities`                                                                                     | Table co-reference — the metrics/entities that share datasets with this node.                                 |
| `sibling`    | `siblings`                                                                                                | Same-type peers (the class namespace — "Other Companies" — not a curated cohort).                             |

### Drill response (`relation=<key>`)

```json theme={null}
{
  "node": { "id": "nvidia-3f8b2c", "type": "entity", "name": "NVIDIA", "subtype": "Companies" },
  "relation": {
    "key": "metrics", "kind": "data", "label": "Metrics",
    "items": [
      { "id": "revenues-8d21aa", "type": "metric", "name": "Revenues", "aliases": ["Total Revenue"] },
      { "id": "revenue-per-employee-1c9f70", "type": "metric", "name": "Revenue Per Employee" }
    ],
    "total": 14, "total_capped": false,
    "next_cursor": null
  }
}
```

Items are in `relation.items` — **not** `results`. A node with no relations returns 200 with empty groups, not a 404.

### Reading related results well

* **Always pass `q` on big entities.** Unfiltered, a big entity returns hundreds of items (`total` caps at **250** with `total_capped: true` — render as "250+"). `q=revenue` narrows and floats the right metrics ("Revenues", "Revenue Per Employee") to the top. Pagination ends at the cap — narrow with `q` to reach the tail.
* **Items are ranked by popularity, blended with match strength when `q` is set** — read the top few, not the tail.
* **Every item carries an `id`** — use it to hop (metric → its entities → their relations…) and to pin into search.
* **Enumerating a cohort** ("Nvidia's competitors", "all NBA teams", "the Magnificent Seven"): resolve the anchor entity → read its overview → pick the group by its `key` (a `rel:*` edge or `members`) → drill with `limit=100` if `total` exceeds the preview. Members arrive as **full nodes** — feed them straight into per-member searches, no re-resolution. This replaces LLM-recalled member lists — the usual source of hallucinated comparisons — with a database read. Don't treat a capped `siblings` group as a cohort: it's the class namespace, not curated peers.

## Graph Node — confirm what an id refers to

`GET /beta/graph/node/{id}` resolves a single id (from a search card, or from the other graph endpoints) to its full `name`, `aliases`, and `description`. 404 when the id doesn't resolve. You'll rarely need it — mostly to verify that a card was built from the entity you meant before you rely on it.

## Grounding `/v3/search` — two levers, use both

1. **Query text (wording drives retrieval).** Compose queries from the resolved node's **name, aliases, and description** — so a metric aliased "inflation" answers an inflation question even when the user said "CPI". Keep queries short and data-shaped (subject + measure + time). Analytical/causal phrasing ("how has X affected Y") retrieves nothing — collect the series, do the analysis in your synthesis step.
2. **Pinned node ids (deterministic candidacy).** Pass resolved ids in the request body:

```json theme={null}
{
  "query": "Nvidia quarterly revenue",
  "sources": {
    "data": {
      "node_ids": ["nvidia-3f8b2c", "revenues-8d21aa"],
      "strict": false
    }
  }
}
```

| Setting    | Behavior                                                                                                                                                                                                                            |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `node_ids` | Up to **20 distinct ids** (deduped before the cap is enforced). Pinned nodes get **guaranteed retrieval candidacy + a strong boost**; organic results are unaffected. Malformed id → 400; an id that no longer resolves is skipped. |
| `strict`   | When `true`, return **only** cards matching a pinned node — `node_ids` must then be non-empty (else 400).                                                                                                                           |

Use text alone when you resolved intent but not a specific node; add pinned ids whenever you *did* resolve the exact metric/entity and want to force it in.

**Enforce grounding in code, not just the prompt** — let your LLM write the wording, but guard what it emits:

```typescript theme={null}
if (!citesListedMetric(q, resolvedMetrics)) drop(q);  // must cite a resolved name/alias verbatim
if (namesMultipleEntities(q, resolved)) drop(q);      // one entity per query
if (kept.length === 0) queries = fallbackQueries(lookup); // mechanical "{entity} {fragment}" pairs
```

Don't deterministically concatenate `"{node} {metric}"` as the *primary* composer — it misses alias-named metrics and reads templated. Let the model compose from names + aliases; keep the concat as the fallback.

## The agentic loop

The full pattern for a data-question agent:

1. **Break** a multi-part question into a few entities and/or metrics.
2. **Resolve** each with Graph Search (`types=entity` OR `types=metric`; add `label` only to force disambiguation, else let inference run).
3. **Pick** the node(s) — read `subtype`, `label`, and `description`.
4. **Explore** their `q`-filtered relations, ranked by popularity and match strength; keep the top few. For cohorts, drill the named `rel:*` edge or `members`.
5. **Compose** grounded `/v3/search` queries from the resolved names and aliases, **and pin the resolved ids** in `sources.data.node_ids`.
6. **Fetch** concurrently; render each card's `embed_url` as an iframe (embeds post their height via a `tako::resize` message — see [Embedding Knowledge Cards](/documentation/integrating-tako/embedding-knowledge-cards)); **report gaps**.

Any stage can come up empty — a valid, visible outcome, not a failure. Give your planner a **validated output contract** so the graph phase runs deterministically:

```typescript theme={null}
const zLookup = z.object({
  entities: z.array(z.string().min(1)).min(1).max(3),      // 1-3 DIFFERENT names for ONE subject ("Google", "Alphabet")
  label: z.enum(NER_LABELS).nullable().optional(),          // optional boost; omit to let inference run
  metricFilters: z.array(z.string().min(1)).min(1).max(5),  // short metric-NAME fragments for related's substring q
});
```

* **Models:** question-breakdown and node-picking run fine on cheap/fast models; the **compose step is the one that matters** (wording drives hits) — give it your best model.
* **Latency/cost:** several graph round-trips + a couple of LLM calls fire before the data search, so the loop is slower than a single `/v3/search` — but graph calls cost no credits and the LLM calls are small. The payoff is grounded searches that hit more often, plus an honest gaps report.
* **Caps are yours:** a few entities, a few related metrics each, dedupe queries case-insensitively, bound total searches. Raise for research, lower for a chat sidebar.

<Tip>
  **Skip the wiring.** If you're building an agentic application that integrates Tako Search, the `tako-graph-agent` skill packages this whole loop — resolve, explore, compose, pin, report gaps — as one installable file. The one-command install is in the card at the top of this page.
</Tip>

## Knowing what you don't know

Report what the graph can't ground as explicit **gaps** — *"Tako has X and Y, but not Z."* An empty result is a valid, honest answer; never invent data to fill a gap. Saying what Tako knows **and doesn't** is the whole advantage over blind search. Two caveats keep the report honest:

* **"Related" is table-level, not entity-level.** A node's related metrics are the metrics in the datasets that *cover* that entity — strong evidence, not proof of that exact combination. `/v3/search` is the final validator.
* **The graph is not the whole index.** It indexes what's structured as metrics/entities — not everything search can return. **Stock/share-price and market-quote data especially** is usually not a graph metric, yet search almost always has it (same for rankings, screens, overviews). A thin graph result for an entity Tako obviously covers is a cue to run an entity-level `/v3/search`, **not** to declare a gap.

## When to use — and when to decline

Use the graph-grounded loop for data/chart questions where Tako plausibly has coverage (public companies, macro indicators, indices, commodities, sports). **Skip discovery** when you already know the exact chart — a named chart or fully-qualified metric + entity goes straight to `POST /v3/search`. **Decline** advice/opinion/prediction asks ("should I buy X", "will Y happen") — the pipeline fetches data, it doesn't forecast; serve the factual sub-question and decline the rest. Poor fit: purely qualitative/sentiment asks, coding, trivia.

## Common mistakes

<Warning>
  Avoid these — they are the patterns coding agents most often get wrong.
</Warning>

| Wrong                                            | Correct                                                                                                                                    |
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
| Calling the graph endpoints without a key        | Graph endpoints require the same `X-API-Key` as `/v3/search` (401 without). They cost no credits, but they are authenticated.              |
| Skipping `q` on `graph/related` for a big entity | Unfiltered returns hundreds of items. Pass `q=<topic>` and read the top of the ranking.                                                    |
| `types=entity,metric` in one lookup              | Decide "thing vs. measure" up front and pass one.                                                                                          |
| Treating `label` as a filter                     | It's a ranking **boost** — off-label nodes still return. Read `subtype`/`label` on each node to actually pick.                             |
| Only drilling `metrics`/`entities`               | The `rel:*` named relations and `part_of`/`members` are often the answer. Read the overview's keys first.                                  |
| Hardcoding a `rel:*` key from a past run         | Keys are per-node — fetch the overview, then drill. An unknown key returns 200 with empty items, so a typo reads as "no relation."         |
| Treating a capped `siblings` group as a cohort   | Siblings are the class namespace ("Other Companies"), not curated peers — use a named `rel:*` edge or `members` for a real comparison set. |
| Parsing related items from `results[]`           | Overview items are in `relations[].items`; drill items are in `relation.items`. The wrong key reads a 200 as zero results.                 |
| Composing text queries but never pinning ids     | You resolved the exact node — pin it via `sources.data.node_ids`. Text + ids beats text alone.                                             |
| Composing analytical/causal queries              | "How has X affected Y" retrieves nothing — query the series, analyze in synthesis.                                                         |
| Declaring a gap because the graph had no metric  | Price/market data especially lives outside the graph — run an entity-level `/v3/search` before declaring a gap.                            |
| Skipping the gaps output                         | Gaps are the point — otherwise you're back to blind search.                                                                                |

## Errors

Failures return `{ "error_message": "...", "error_type": "..." }`.

| Status | Meaning                                                                                             | Fix                                                                             |
| ------ | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| `400`  | Missing `q`/`node_id`, an unknown `types` or `label` value, a malformed cursor, or `limit` below 1. | Validate against the parameter tables above.                                    |
| `401`  | Missing or invalid API key.                                                                         | Send a valid key in the `X-API-Key` header.                                     |
| `404`  | `node_id` (or node path id) doesn't resolve.                                                        | Re-resolve the name with Graph Search — ids can go stale across graph rebuilds. |
| `429`  | Rate limit exceeded (180/min or 10,000/day).                                                        | Back off with jittered exponential retry.                                       |
| `503`  | A backing data store is temporarily unavailable.                                                    | Retry with backoff.                                                             |
