# Agents

> List, limit and revoke the AI agents your users connected to their documents.

An agent is an MCP client, such as Claude Code or Codex, that one of your users approved to work in their documents. It connects to your platform's MCP address at `https://mcp.proof.exalto.ai/acme` (`/acme/test` in test mode), and Proof issues its tokens; your server never holds them. These endpoints are for your settings screens: show people their agents, choose which documents each reaches, and revoke them. Agents are created by approving an [agent request](/reference/api/agent-requests/). See [Agents](/concepts/agents/).

An agent's access is either:

- **`all`**: every document its person can open, editing at most.
- **`chosen`**: only the documents you give it a role in.

Either way, what it may do in a document is the lower of that and its person's current role there, checked on every call. It never owns a document.

## The agent object

| Attribute | Type | Description |
| --- | --- | --- |
| `id` | string | Proof's id for the agent, starting `agt_`. |
| `user` | string | The Proof id of the person it acts for. |
| `name` | string | The name the client registered with, which its person saw when approving it. Its edits are credited as this name and its person's: "Claude Code (Ada's agent)". |
| `host` | string | The domain the client is published from, checked by Proof. Two agents can share a name; the host tells them apart. |
| `access` | string | `all` or `chosen`. |
| `connected_at` | timestamp | When its person approved it. |
| `last_used_at` | timestamp or null | When it last called a tool, or `null` if it hasn't yet. |
| `expires_at` | timestamp or null | Until when it can renew its access unused: its newest refresh token lapses then, 90 days after it last renewed. Past it, or at `null`, its person approves it again. |

```json
{
  "id": "agt_3Vn8Qx2K",
  "user": "usr_5Kq2Lm8R",
  "name": "Claude Code",
  "host": "claude.ai",
  "access": "all",
  "connected_at": "2026-10-13T21:30:02Z",
  "last_used_at": "2026-10-13T22:58:41Z",
  "expires_at": "2027-01-11T22:58:41Z"
}
```

## List a user's agents

`GET /v1/users/{user_id}/agents`

The agents a user has connected, newest first.

| Parameter | Type | Description |
| --- | --- | --- |
| `user_id` | string, path, required | The user's Proof id. |
| `document` | string | A document id: each agent then has one more field, `document_role`, the role you gave it there, or `null`. For a document's sharing screen. |
| `limit` | integer | 1 to 100. Default 50. |
| `after` | string | The `next` cursor from the previous page. |

<Tabs syncKey="lang">
<TabItem label="curl">

```bash
curl https://api.proof.exalto.ai/v1/users/usr_5Kq2Lm8R/agents \
  -H "Authorization: Bearer $PROOF_SECRET_KEY"
```

</TabItem>
<TabItem label="Node">

```ts
const page = await proof.users.listAgents("usr_5Kq2Lm8R");
```

</TabItem>
</Tabs>

```json
{
  "data": [
    {
      "id": "agt_6Bw4Ys7J",
      "user": "usr_5Kq2Lm8R",
      "name": "Codex",
      "host": "openai.com",
      "access": "chosen",
      "connected_at": "2026-10-13T22:31:15Z",
      "last_used_at": "2026-10-13T22:38:09Z"
    },
    {
      "id": "agt_3Vn8Qx2K",
      "user": "usr_5Kq2Lm8R",
      "name": "Claude Code",
      "host": "claude.ai",
      "access": "all",
      "connected_at": "2026-10-13T21:30:02Z",
      "last_used_at": "2026-10-13T22:58:41Z"
    }
  ],
  "next": null
}
```

## Retrieve an agent

`GET /v1/agents/{agent_id}`

| Parameter | Type | Description |
| --- | --- | --- |
| `agent_id` | string, path, required | The agent's id. |

<Tabs syncKey="lang">
<TabItem label="curl">

```bash
curl https://api.proof.exalto.ai/v1/agents/agt_3Vn8Qx2K \
  -H "Authorization: Bearer $PROOF_SECRET_KEY"
```

</TabItem>
<TabItem label="Node">

```ts
const agent = await proof.agents.retrieve("agt_3Vn8Qx2K");
```

</TabItem>
</Tabs>

Returns the [agent](#the-agent-object), or `404 agent_not_found` once it has been revoked.

## Update an agent

`PATCH /v1/agents/{agent_id}`

Switches an agent between reaching all its person's documents and only the ones you choose. The change applies to its next tool call.

Switching to `chosen` keeps any roles you set before. An agent switched to `chosen` with no roles reaches nothing until you [give it a document](#set-an-agents-role-in-a-document).

| Parameter | Type | Description |
| --- | --- | --- |
| `agent_id` | string, path, required | The agent's id. |
| `access` | string, required | `all` or `chosen`. |

<Tabs syncKey="lang">
<TabItem label="curl">

```bash
curl https://api.proof.exalto.ai/v1/agents/agt_3Vn8Qx2K \
  -X PATCH \
  -H "Authorization: Bearer $PROOF_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"access": "chosen"}'
```

</TabItem>
<TabItem label="Node">

```ts
const agent = await proof.agents.update("agt_3Vn8Qx2K", { access: "chosen" });
```

</TabItem>
</Tabs>

Returns the updated [agent](#the-agent-object).

## List an agent's documents

`GET /v1/agents/{agent_id}/documents`

The documents you've given an agent a role in, most recently edited first. These roles apply while its access is `chosen`; with `all`, it reaches every document its person can open and this list is kept for when you switch.

| Parameter | Type | Description |
| --- | --- | --- |
| `agent_id` | string, path, required | The agent's id. |
| `limit` | integer | 1 to 100. Default 50. |
| `after` | string | The `next` cursor from the previous page. |

<Tabs syncKey="lang">
<TabItem label="curl">

```bash
curl https://api.proof.exalto.ai/v1/agents/agt_6Bw4Ys7J/documents \
  -H "Authorization: Bearer $PROOF_SECRET_KEY"
```

</TabItem>
<TabItem label="Node">

```ts
const page = await proof.agents.listDocuments("agt_6Bw4Ys7J");
```

</TabItem>
</Tabs>

```json
{
  "data": [
    {
      "agent": "agt_6Bw4Ys7J",
      "document": "doc_8Hq2Lm4R",
      "title": "On the Analytical Engine",
      "role": "suggester",
      "effective_role": "suggester"
    },
    {
      "agent": "agt_6Bw4Ys7J",
      "document": "doc_3Wp7Zc1V",
      "title": "Notes for Thursday",
      "role": "editor",
      "effective_role": "suggester"
    }
  ],
  "next": null
}
```

| Attribute | Type | Description |
| --- | --- | --- |
| `role` | string | The role you gave the agent: `editor`, `suggester` or `viewer`. |
| `effective_role` | string or null | What it can do now: the lower of `role` and its person's current role. `null` when its person can no longer open the document. |

## Set an agent's role in a document

`PUT /v1/agents/{agent_id}/documents/{document_id}`

Gives an agent a role in one document, or changes it.

| Parameter | Type | Description |
| --- | --- | --- |
| `agent_id` | string, path, required | The agent's id. |
| `document_id` | string, path, required | The document's id. |
| `role` | string, required | `editor`, `suggester` or `viewer`. An agent is never an owner. |

<Tabs syncKey="lang">
<TabItem label="curl">

```bash
curl https://api.proof.exalto.ai/v1/agents/agt_6Bw4Ys7J/documents/doc_8Hq2Lm4R \
  -X PUT \
  -H "Authorization: Bearer $PROOF_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"role": "suggester"}'
```

</TabItem>
<TabItem label="Node">

```ts
await proof.agents.putDocument("agt_6Bw4Ys7J", "doc_8Hq2Lm4R", { role: "suggester" });
```

</TabItem>
</Tabs>

```json
{
  "agent": "agt_6Bw4Ys7J",
  "document": "doc_8Hq2Lm4R",
  "title": "On the Analytical Engine",
  "role": "suggester",
  "effective_role": "suggester"
}
```

| Error | When |
| --- | --- |
| `400 invalid_parameter` on `role` | `role` is `owner`, or not a role. |
| `404 document_not_found` | The document doesn't exist. |

## Remove an agent's role in a document

`DELETE /v1/agents/{agent_id}/documents/{document_id}`

Takes a document off an agent's list. With `chosen` access, it can no longer reach the document.

| Parameter | Type | Description |
| --- | --- | --- |
| `agent_id` | string, path, required | The agent's id. |
| `document_id` | string, path, required | The document's id. |

<Tabs syncKey="lang">
<TabItem label="curl">

```bash
curl https://api.proof.exalto.ai/v1/agents/agt_6Bw4Ys7J/documents/doc_8Hq2Lm4R \
  -X DELETE \
  -H "Authorization: Bearer $PROOF_SECRET_KEY"
```

</TabItem>
<TabItem label="Node">

```ts
await proof.agents.deleteDocument("agt_6Bw4Ys7J", "doc_8Hq2Lm4R");
```

</TabItem>
</Tabs>

```json
{
  "agent": "agt_6Bw4Ys7J",
  "document": "doc_8Hq2Lm4R",
  "removed": true
}
```

## Revoke an agent

`DELETE /v1/agents/{agent_id}`

Disconnects an agent for good. Its tokens stop working at once, mid-call included, and Proof sends `agent.revoked`. What it already wrote stays in documents, credited to it. To connect it again, its person approves it again.

| Parameter | Type | Description |
| --- | --- | --- |
| `agent_id` | string, path, required | The agent's id. |

<Tabs syncKey="lang">
<TabItem label="curl">

```bash
curl https://api.proof.exalto.ai/v1/agents/agt_3Vn8Qx2K \
  -X DELETE \
  -H "Authorization: Bearer $PROOF_SECRET_KEY"
```

</TabItem>
<TabItem label="Node">

```ts
await proof.agents.revoke("agt_3Vn8Qx2K");
```

</TabItem>
</Tabs>

```json
{
  "id": "agt_3Vn8Qx2K",
  "revoked": true
}
```