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

# Agent authority

> Grant an agent specific allowed actions, a per-payment spend cap, and an expiry date. Revoke or narrow its authority at any time.

Set spend and action limits for an agent. A signed-in-profile agent can act after identity is on file. A separate spend account also needs this permission record.

The record shows who approved the agent, what it may do, how much it may spend, and when access expires.

**Verifier ID:** `agent-delegation`

**`controllerWallet`** is the approving account, the address that signs this step. See [Agent concepts](./concepts).

## Setup

<Steps>
  <Step title="Check">
    **`proofable_context`** → **`proofable_agent_link`**
  </Step>

  <Step title="Create">
    **`proofable_agent_create`**. Leave out **`controllerWallet`** when the signed-in profile account should approve.
  </Step>

  <Step title="Confirm">
    **`proofable_agent_link`** until **`linked: true`**
  </Step>
</Steps>

Or finish on Proofable via [hosted verify](../verification/hosted).

## SDK

```javascript theme={"system"}
await client.verify({
  verifier: 'agent-delegation',
  data: {
    controllerWallet: '0x...',
    controllerChainRef: 'eip155:8453',
    agentWallet: '0x...',
    agentChainRef: 'eip155:8453',
    allowedActions: ['read_proofs'],
  },
  walletAddress: '0x...',
});
```

Both accounts need a CAIP-2 network reference (`controllerChainRef`, `agentChainRef`) unless the request already includes `chain` or `chainId`.

## App link

One-time user approval lets your backend create proofs without asking for a signature on every request. This is different from creating a **listing** in your profile for hosted verification. See [Server integrations](../integrations/server).

1. User signs in on Proofable
2. User approves the delegation once
3. Your app stores the proof ID in **`qHash`**
4. Your backend calls verification with **`x-proofable-app`**. No per-request signature

```javascript theme={"system"}
await client.verify({
  verifier: 'agent-delegation',
  data: {
    controllerWallet: userWallet,
    agentWallet: userWallet,
    agentId: 'your-app-id',
    allowedActions: ['create_proof'],
    allowedOrigins: ['https://app.example.com'],
    expiresAt: Date.now() + 90 * 24 * 60 * 60 * 1000,
  },
  walletAddress: userWallet,
});
```

**`agentId`** matches your `x-proofable-app` header. **`allowedOrigins`** lists the exact web origins your app may act from; use `"*"` for server-to-server callers with no browser origin.

Send `x-proofable-app: your-app-id` and matching site origin on verification requests. On Node, set `appOrigin: 'https://app.example.com'` on `ProofableClient` (or pass `Origin` via `extraHeaders`).

## Payment limits

`maxSpend` is a whole-number string in token base units. For USDC (6 decimals), 25 USDC = `"25000000"`. Use `toAgentDelegationMaxSpend('25', 6)` from `@proofable/sdk`.

When `allowedActions` includes `make_payment`, `allowedPaymentTypes` and `maxSpend` are both required. The agent can then settle metered API calls via the allowed rails, such as x402, without a Proofable account. The calling application enforces the `maxSpend` cap client-side before signing each payment. The protocol does not decrement `maxSpend` server-side. When the cap is exhausted, the application stops signing payments and the agent is refused. See [Pay per call](../gates/pay-per-call) for the full settlement flow.

```javascript theme={"system"}
import { toAgentDelegationMaxSpend } from '@proofable/sdk';

await client.verify({
  verifier: 'agent-delegation',
  data: {
    controllerWallet: '0x...',
    agentWallet: '0x...',
    allowedActions: ['make_payment', 'read_proofs'],
    maxSpend: toAgentDelegationMaxSpend('100.50', 6),
    allowedPaymentTypes: ['x402'],
    receiptDisclosure: 'summary',
    expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000,
  },
  walletAddress: '0x...',
});
```

## Fields

| Field | Required | Description |
| - | - | - |
| `controllerWallet` | Yes | Approving account (must match signer) |
| `controllerChainRef` | Yes\* | CAIP-2 chain for the controller wallet. \*Optional if the request supplies `chain` or `chainId` |
| `agentWallet` | Yes | Agent address |
| `agentChainRef` | Yes\* | CAIP-2 chain for the agent wallet. \*Optional if the request supplies `chain` or `chainId` |
| `agentId` | No | Linked identity id |
| `allowedActions` | Yes | Explicit action allowlist. Must list at least one canonical action; an empty list grants nothing |
| `deniedActions` | No | Explicit action denylist. Always wins over `allowedActions` |
| `allowedOrigins` | No | Exact web origins an app agent may act from, or `"*"` for server callers |
| `maxSpend` | With `make_payment` | Spend cap in token base units |
| `allowedPaymentTypes` | With `make_payment` | Payment rails (e.g. `x402`) |
| `receiptDisclosure` | No | `summary`, `full`, or `none` |
| `expiresAt` | No | Expiration (Unix ms) |
| `instructions` | No | Policy text (16000 chars) |
| `skills` | No | Up to 48 skill objects |
| `runtimePolicy` | No | Provider/model limits and human-approval requirement |
| `approvalPolicy` | No | Approval requirements for new claims or content |

The protocol accepts canonical action strings only in **`allowedActions`** and **`deniedActions`**. `deniedActions` always wins over `allowedActions`, and an empty allow-list grants nothing.

## Human approval pattern

Your application enforces the limits recorded in the delegation proof:

```javascript theme={"system"}
const delegation = {
  controllerWallet,
  agentWallet,
  agentId: 'data-analyst',
  allowedActions: ['read_context', 'read_proofs', 'create_proof', 'execute_jobs'],
  deniedActions: ['send_message', 'make_payment'],
  runtimePolicy: {
    requiresHumanApproval: true,
  },
  approvalPolicy: {
    humanApprovalRequiredForNewClaims: true,
    preApprovedContentOnly: true,
  },
  maxSpend: '15000000',
  expiresAt: Date.now() + 30 * 24 * 60 * 60 * 1000,
};
```

At runtime:

1. Check the current delegation proof before the tool call.
2. Apply **`deniedActions`** first.
3. Pause when the policy requires human approval.
4. Continue only after approval is confirmed.

Schema: [`agent-delegation.json`](https://github.com/proofable/docs/blob/main/verifiers/schemas/agent-delegation.json).

## Result

A proof ID returned in **`qHash`**. Read that exact record with **`proofable_proofs_get`**. Use **`proofable_proofs_check`** only when you need a yes/no eligibility decision before an action.

## Revoke

```javascript theme={"system"}
await client.revokeOwnProof(qHash, walletAddress);
```

Set **`expiresAt`** and **`maxSpend`** when money or high-risk actions are in play.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.