# Agent requests

> Approve or deny an agent from your consent page, so Proof can issue it tokens.

An agent request is one agent asking to act for one of your users. When someone adds your MCP address to their agent, the agent registers with Proof and opens the person's browser at Proof's authorize page. Proof has no sign-in, so it sends the browser on to the consent URL you set in the [console](https://developer.proof.exalto.ai/console) or with [`PATCH /v1/platform`](/reference/api/platform/), with the request's id:

```
https://acme.com/proof/connect?request=areq_7Tc1Pz9M
```

Your page signs the person in if they aren't already, shows them which agent is asking, and on Allow or Deny calls one of the endpoints below from your server. Each returns a `redirect_url`; send the browser there, and Proof finishes the OAuth flow with the agent directly. You approve; Proof issues the agent's tokens; you never see them. See [Connect agents](/guides/connect-agents/) for the whole flow.

A request lasts 10 minutes and can be answered once.

## The agent request object

| Attribute | Type | Description |
| --- | --- | --- |
| `id` | string | The request's id, starting `areq_`. |
| `status` | string | `pending`, `approved`, `denied` or `expired`. |
| `client` | object | The agent asking. `name`: the name it registered with. `host`: the domain its registration is published from, checked by Proof, so it can't claim someone else's. `logo_url`: its logo, or `null`. |
| `expires_at` | timestamp | When the request lapses if it isn't answered. |

```json
{
  "id": "areq_7Tc1Pz9M",
  "status": "pending",
  "client": {
    "name": "Claude Code",
    "host": "claude.ai",
    "logo_url": "https://claude.ai/images/claude-code-icon.png"
  },
  "expires_at": "2026-10-30T18:30:00Z"
}
```

Show `client.name` and `client.host` together on your consent page. The name is whatever the client chose; the host is the part people can trust.

## Retrieve an agent request

`GET /v1/agent-requests/{request_id}`

| Parameter | Type | Description |
| --- | --- | --- |
| `request_id` | string, path, required | The `request` value from your consent URL. |

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

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

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

```ts
const request = await proof.agentRequests.retrieve("areq_7Tc1Pz9M");
```

</TabItem>
</Tabs>

Returns the [agent request](#the-agent-request-object), or `404 request_not_found` for an id that isn't one of yours.

## Approve an agent request

`POST /v1/agent-requests/{request_id}/approve`

Approves the agent for one of your users and creates the [agent](/reference/api/agents/). Call it only after your own sign-in has confirmed who the person is, and only from a deliberate action such as a form post, never from a page load.

If the user has already connected this same client, Proof keeps the existing agent and replaces its access with what you pass here.

| Parameter | Type | Description |
| --- | --- | --- |
| `request_id` | string, path, required | The request's id. |
| `user` | string, required | The Proof id of the person approving: the one signed in to your product, never a value from the form. |
| `access` | string, required | `all` for every document they can open, editing at most, or `chosen` for only the documents in `documents`. |
| `documents` | object | With `chosen`: a map from document id to role, `editor`, `suggester` or `viewer`. |

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

```bash
curl https://api.proof.exalto.ai/v1/agent-requests/areq_7Tc1Pz9M/approve \
  -H "Authorization: Bearer $PROOF_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "user": "usr_5Kq2Lm8R",
    "access": "chosen",
    "documents": { "doc_8Hq2Lm4R": "suggester" }
  }'
```

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

```ts
const { redirect_url } = await proof.agentRequests.approve("areq_7Tc1Pz9M", {
  user: "usr_5Kq2Lm8R",
  access: "chosen",
  documents: { doc_8Hq2Lm4R: "suggester" },
});
// then redirect the browser to redirect_url
```

</TabItem>
</Tabs>

```json
{
  "redirect_url": "https://mcp.proof.exalto.ai/acme/authorize/continue?state=pz9Kq2Vn8Lr4",
  "agent": {
    "id": "agt_6Bw4Ys7J",
    "user": "usr_5Kq2Lm8R",
    "name": "Codex",
    "host": "openai.com",
    "access": "chosen",
    "connected_at": "2026-10-30T18:21:40Z",
    "last_used_at": null
  }
}
```

For an agent that's new, Proof also sends `agent.connected` to your [webhook endpoints](/reference/webhooks/).

| Error | When |
| --- | --- |
| `400 missing_parameter` on `documents` | `access` is `chosen` and `documents` is empty or missing. |
| `400 invalid_parameter` on `documents` | A role is `owner` or not a role. |
| `404 user_not_found` | The user doesn't exist. |
| `404 document_not_found` | A document in `documents` doesn't exist. |
| `409 request_expired` | More than 10 minutes have passed. The person starts again from their agent. |
| `409 request_already_answered` | The request was approved or denied already. |

## Deny an agent request

`POST /v1/agent-requests/{request_id}/deny`

Turns the agent away. Send the browser to `redirect_url` so the agent hears the answer instead of waiting.

| Parameter | Type | Description |
| --- | --- | --- |
| `request_id` | string, path, required | The request's id. |

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

```bash
curl https://api.proof.exalto.ai/v1/agent-requests/areq_7Tc1Pz9M/deny \
  -X POST \
  -H "Authorization: Bearer $PROOF_SECRET_KEY"
```

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

```ts
const { redirect_url } = await proof.agentRequests.deny("areq_7Tc1Pz9M");
```

</TabItem>
</Tabs>

```json
{
  "redirect_url": "https://mcp.proof.exalto.ai/acme/authorize/continue?state=pz9Kq2Vn8Lr4"
}
```

| Error | When |
| --- | --- |
| `409 request_expired` | More than 10 minutes have passed. |
| `409 request_already_answered` | The request was approved or denied already. |