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

# Custom Data overview

> Give your agents a table of your own data — plans, stores, codes, eligibility rules — that they can look up mid-conversation.

**Custom Data** is a table you define and fill with your own rows, which your agents can read while they're talking to someone. A store list, a price book, a table of discount codes, eligibility rules — anything an agent needs to look up by name or filter by value.

You define the columns. The platform builds the agent's tools from that definition, so you don't write a tool per table.

## When to use one

Use Custom Data when:

* The agent needs to look something up **during** the conversation — "what's the price of the Pro plan in the EU?", "where's my nearest store?"
* The answer is **structured**: rows and columns, not prose
* You want **exact** answers, not the closest-sounding passage

Don't use it for:

* **Prose your agent should paraphrase** — policies, FAQs, manuals. Use a [knowledge base](/knowledge-bases/overview); it's built for meaning-based search, and Custom Data is not.
* **Live data owned by another system** — today's order status, a live inventory count. Call that system with an [HTTP step](/workflows/steps/http) in a workflow.
* **Per-call state** — the caller's name, what they said two turns ago. That's conversation context.

<Note>
  The line between Custom Data and a knowledge base is *shape*, not size. "What are your opening hours?" answered from a paragraph is a knowledge base. "What are the opening hours of store 4?" answered from a row is Custom Data.
</Note>

## How it works

<Steps>
  <Step title="Define the table">
    Name it and declare its columns — the name, the type, and which one identifies a row. See [Defining a table](/custom-data/defining-a-table).
  </Step>

  <Step title="Load rows">
    Paste or drop a CSV, or point a [workflow](/custom-data/keeping-data-fresh) at your source system to keep it current. See [Loading rows](/custom-data/loading-rows).
  </Step>

  <Step title="Give an agent the tools">
    The platform generates the lookup and search tools from your column definitions. Copy them into the agent. See [Agent tools](/custom-data/agent-tools).
  </Step>
</Steps>

Two optional extras, once the basics are working:

* **[Stored queries](/custom-data/stored-queries)** — write SQL when filters aren't enough. Distance calculations, bucketed totals, anything with arithmetic.
* **[Claiming rows](/custom-data/claiming-rows)** — hand out one-time values like discount codes, with a guarantee that two simultaneous conversations never get the same one.

## An example

A table called `plans`:

| plan\_id | name   | monthly\_price | region | available |
| -------- | ------ | -------------- | ------ | --------- |
| pro-eu   | Pro    | 49             | EU     | true      |
| pro-us   | Pro    | 55             | US     | true      |
| legacy   | Legacy | 29             | EU     | false     |

`plan_id` is the **row key** — the column that identifies a row. From that definition the platform generates two tools:

* `lookup_plans` — fetch one row by its `plan_id`
* `search_plans` — filter by any column, sort, and return several rows

An agent asked *"what does Pro cost in Europe?"* calls `search_plans` with `name = Pro` and `region = EU`, and gets the row back. You wrote no code.

## What it is not

Custom Data is deliberately narrow, and it's worth knowing the edges:

* **One table at a time.** There are no joins. If you need a store's country name and the country's tax rate together, put both on the store row.
* **Flat columns.** Text, numbers, yes/no, dates. No nested objects or lists.
* **Agents read; they don't write.** The one exception is [claiming a row](/custom-data/claiming-rows), which is narrow by design.
* **Not a database you connect to.** It's reached through agents, workflows, and the API — there's no connection string.

## Limits

|                       |                                                                   |
| --------------------- | ----------------------------------------------------------------- |
| Columns per table     | No hard limit; keep it to what an agent needs                     |
| Rows per table        | No hard limit; imports through the UI cap at 10 MB                |
| Rows a search returns | 500 max, 20 by default                                            |
| Table name            | Lowercase letters, digits and underscores, starting with a letter |
| Column name           | Letters, digits and underscores                                   |

## Permissions

| You can                              | With                 |
| ------------------------------------ | -------------------- |
| View tables and rows                 | `agents:read`        |
| Create, edit, delete tables and rows | `agents:manage`      |
| Claim a row                          | `agents:manage`      |
| Write and enable stored queries      | `custom_data:manage` |

Stored queries have their own permission because writing SQL that runs during a live call is a different act from editing reference data — the people who may do one aren't automatically the people who may do the other.

## Next

<CardGroup cols={2}>
  <Card title="Defining a table" icon="table" href="/custom-data/defining-a-table">
    Columns, types, and choosing a row key.
  </Card>

  <Card title="Loading rows" icon="upload" href="/custom-data/loading-rows">
    CSV, JSON, and what replace vs add really do.
  </Card>

  <Card title="Agent tools" icon="wrench" href="/custom-data/agent-tools">
    The tools generated from your table.
  </Card>

  <Card title="Stored queries" icon="code" href="/custom-data/stored-queries">
    SQL, for when filters aren't enough.
  </Card>
</CardGroup>
