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

# Agents

> REST endpoints for managing agent identities.

The agents endpoints let you register, list, and retrieve the identities Tally attaches to payments and analytics. See [Agents (concept)](/agents) for the model and [SDK agents](/sdk/agents) for the TypeScript wrapper.

## The agent object

```json theme={null}
{
  "id": "research-bot",
  "status": "no_permissions",
  "mode": "test",
  "created_at": "2026-05-18T12:00:00Z",
  "active_signers": 0,
  "pending_signers": 0
}
```

| Field             | Type                             | Description                                                        |
| ----------------- | -------------------------------- | ------------------------------------------------------------------ |
| `id`              | string                           | Stable user-provided identifier. Unique within (account, mode).    |
| `status`          | `"no_permissions"` \| `"active"` | `active` once at least one wallet has authorized this agent.       |
| `mode`            | `"test"` \| `"live"`             | Derived from the API key; can't be changed after creation.         |
| `created_at`      | ISO 8601 string                  | When the agent was first registered.                               |
| `active_signers`  | number                           | Non-revoked, activated signers across all wallets.                 |
| `pending_signers` | number                           | Non-revoked signers awaiting the wallet owner's passkey signature. |

***

## `POST /v1/agents`

Create an agent if it doesn't exist; no-op if it does. Idempotent — safe to call on every deploy.

### Request

```bash theme={null}
curl https://api.tally.example.com/v1/agents \
  -X POST \
  -H "Authorization: Bearer $TALLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "id": "research-bot" }'
```

| Body field | Type   | Required | Description                                                           |
| ---------- | ------ | -------- | --------------------------------------------------------------------- |
| `id`       | string | Yes      | Stable identifier, 1–64 chars. Must be unique within (account, mode). |

### Response

`201 Created`:

```json theme={null}
{
  "agent": {
    "id": "research-bot",
    "status": "no_permissions",
    "mode": "test",
    "created_at": "2026-05-18T12:00:00Z",
    "active_signers": 0,
    "pending_signers": 0
  }
}
```

Returns 201 even on idempotent no-op (the agent already existed). The response always reflects the current state — including signer counts if grants already exist.

### Errors

| Status | `type`              | When                                                              |
| ------ | ------------------- | ----------------------------------------------------------------- |
| 400    | `validation_failed` | `id` is missing, empty, or fails server-side format checks.       |
| 401    | `unauthenticated`   | API key is missing, invalid, or out of its rotation grace window. |
| 429    | `rate_limited`      | Default bucket: 60 req/min per key exceeded.                      |

***

## `GET /v1/agents`

List every agent in this (account, mode).

### Request

```bash theme={null}
curl https://api.tally.example.com/v1/agents \
  -H "Authorization: Bearer $TALLY_API_KEY"
```

No query parameters today. Pagination is on the roadmap; until it lands, accounts with hundreds of agents get the full list in one response.

### Response

`200 OK`:

```json theme={null}
{
  "agents": [
    { "id": "research-bot", "status": "active", "mode": "test", ... },
    { "id": "summarizer", "status": "no_permissions", "mode": "test", ... }
  ]
}
```

Ordering is by `created_at` ascending. Stable across calls.

### Errors

| Status | `type`            | When                     |
| ------ | ----------------- | ------------------------ |
| 401    | `unauthenticated` | API key invalid.         |
| 429    | `rate_limited`    | Default bucket exceeded. |

***

## `GET /v1/agents/{id}`

Retrieve a single agent by its public id.

### Request

```bash theme={null}
curl https://api.tally.example.com/v1/agents/research-bot \
  -H "Authorization: Bearer $TALLY_API_KEY"
```

| Path param | Description                                                                      |
| ---------- | -------------------------------------------------------------------------------- |
| `id`       | The agent's public identifier. URL-encode it (handled automatically by the SDK). |

### Response

`200 OK`:

```json theme={null}
{ "agent": { "id": "research-bot", "status": "active", "mode": "test", ... } }
```

### Errors

| Status | `type`            | When                                           |
| ------ | ----------------- | ---------------------------------------------- |
| 401    | `unauthenticated` | API key invalid.                               |
| 404    | `not_found`       | No agent with that id in this (account, mode). |
| 429    | `rate_limited`    | Default bucket exceeded.                       |

***

## Patterns

### Register required agents at boot

Because `POST /v1/agents` is idempotent, the cleanest pattern is to declare the agents your service needs at startup:

```ts theme={null}
const REQUIRED = ["research-bot", "summarizer", "publisher"];
for (const id of REQUIRED) {
  await fetch(`${baseUrl}/v1/agents`, {
    method: "POST",
    headers: authHeaders,
    body: JSON.stringify({ id }),
  });
}
```

Adding a new agent later is a one-line change; existing entries are unchanged.

### Gate spend on `status`

`agent.status === "active"` means at least one wallet has authorized this agent. Use it as a gate before submitting payments:

```ts theme={null}
const { agent } = await get(`/v1/agents/research-bot`);
if (agent.status === "no_permissions") {
  // Surface to user: they need to grant a permission via the dashboard.
  return;
}
// Safe to call POST /v1/payments.
```

This won't tell you which wallets the agent can spend from — for that, attempt a payment and branch on the error code, or check the dashboard. SDK methods for listing grants are on the roadmap.

## Not yet exposed

* `DELETE /v1/agents/{id}` — soft-delete an agent.
* `GET /v1/agents` with cursor pagination — for accounts with hundreds of agents.
* `GET /v1/agents/{id}/permissions` — list active grants for an agent, with policy summary.

Tracked in [BUILD\_LOG.md](https://github.com/pkohler95/tally-v2/blob/main/BUILD_LOG.md).
