---
title: Delegate authority
description: Give a sub-agent a bounded slice of what the parent holds, and nothing more.
---

A supervisor agent fans work out to workers. Each worker should be able to do
its piece and nothing else. That is a delegation.

## Create one

```bash
curl -X POST https://veefore.example.com/v1/delegations \
  -H "Authorization: Bearer $VEEFORE_API_KEY" \
  -H 'content-type: application/json' \
  -H 'Idempotency-Key: delegate-refunds-to-worker-3' \
  -d '{
    "from_agent_id": "agt_supervisor",
    "to_agent_id": "agt_worker_3",
    "capabilities": ["refund.create"],
    "max_amount": 50000,
    "currency": "INR",
    "expires_at": "2026-10-10T00:00:00.000Z",
    "max_depth": 0,
    "reason": "Batch refund processing for the 2026-10 damage claims queue"
  }'
```

:::params

:::param from_agent_id | string | required
The parent. Must itself hold everything being delegated.
:::

:::param to_agent_id | string | required
The child.
:::

:::param capabilities | string[] | required
A **subset** of the parent's. Never an addition.
:::

:::param max_amount | number | optional
Minor units. At most the parent's ceiling.
:::

:::param expires_at | ISO-8601 | required
At or before the parent's expiry. Set it to when the work ends.
:::

:::param max_depth | number | optional
Further hops permitted. `0` means the child cannot sub-delegate.
:::

:::param reason | string | optional
Recorded in the audit trail. Worth filling in — in three months this is the only
thing that explains why the grant exists.
:::

:::

## Check first

```bash
curl -X POST https://veefore.example.com/v1/delegations/simulate \
  -H "Authorization: Bearer $VEEFORE_API_KEY" \
  -H 'content-type: application/json' \
  -d '{
    "from_agent_id": "agt_supervisor",
    "to_agent_id": "agt_worker_3",
    "capabilities": ["refund.create", "payout.initiate"],
    "max_amount": 200000
  }'
```

Tells you whether it would be permitted and which bound it violates. Cheaper
than discovering it from a `403`, and it is what the console calls as you fill
in the form.

:::security A child can never exceed its parent
Asking for a capability the parent does not hold, an amount above its ceiling,
or an expiry past its expiry is **refused** with `DELEGATION_ESCALATION` —
refused, not silently clamped.

Silent clamping means the caller believes it has authority it does not have and
finds out at the worst possible moment. An explicit failure at grant time is
strictly better than a surprise at use time.
:::

## See what a worker can actually do

```bash
curl -s https://veefore.example.com/v1/agents/agt_worker_3/authority \
  -H "Authorization: Bearer $VEEFORE_API_KEY"
```

Returns the **resolved** effective authority after intersecting every hop.

:::warning Narrowing anywhere narrows everything below
If the root grants ₹100,000 and an intermediate hop narrowed it to ₹50,000, the
leaf's ceiling is ₹50,000 — even if the leaf's own grant says ₹100,000. The
effective value at each dimension is the **narrowest** in the chain, not the
nearest.

This is the usual cause of "the delegation says 100000 but we get
`AUTHORITY_EXCEEDED` at 60000". Read the resolved authority, not the individual
grant.
:::

## Handle it in the agent

A delegation is not something the child agent passes as a parameter. It is
resolved server-side from the agent's identity, at stage 6 of every pipeline
run. The worker just acts:

```ts
const worker = protect(workerAgent, { name: 'refund-worker-3' });

try {
  await worker.act({
    tool: 'refund_customer',
    capability: 'refund.create',
    amount: 60_000,
    currency: 'INR',
    parameters: { orderId: 'ord_8812' },
  });
} catch (error) {
  if (error instanceof VeeforeBlockedError) {
    // AUTHORITY_EXCEEDED arrives here. The details carry the ceiling and the
    // requested amount, so the worker can report something useful.
    return { status: 'over_ceiling', reason: error.message };
  }
  throw error;
}
```

The error `details` include the capability, the ceiling and what was requested,
so a worker can report "requested 60000, ceiling is 50000" rather than
"forbidden".

## Shape the topology

**Depth 0 at the leaf.** A worker that can sub-delegate is a worker whose
authority you no longer fully know. Set `max_depth: 0` unless you have a
specific reason.

**Short expiries.** A delegation for a batch job should expire when the batch
does. An open-ended grant is a standing permission with extra steps.

**One delegation per purpose.** Two delegations with clear reasons beat one
broad grant that covers both, because revoking one does not affect the other.

**Narrow the ceiling to the work.** If the batch's largest claim is ₹400, do not
grant ₹50,000 because it was a round number.

## Revoke

```bash
curl -X POST https://veefore.example.com/v1/delegations/del_01ABC/revoke \
  -H "Authorization: Bearer $VEEFORE_API_KEY" \
  -H 'content-type: application/json' \
  -d '{ "reason": "Batch complete" }'
```

Cascades to everything derived from the grant, at every depth, immediately. No
grace period and no draining — a cascade that waits is a cascade that does not
work when you need it.

Narrowing is also allowed and takes effect immediately:

```http
PATCH /v1/delegations/{delegationId}
```

Widening is refused. To grant more, create a new delegation from a parent that
actually holds that authority.

## See the graph

```bash
curl -s https://veefore.example.com/v1/delegations/graph \
  -H "Authorization: Bearer $VEEFORE_API_KEY"
```

Nodes and edges for the whole graph. The console renders it on the Delegations
page, and it is the fastest way to answer "what can this agent reach, and
through whom" — a question that is hard from a list and obvious from a graph.

## Policy on delegation shape

```json
{
  "id": "rule-deep-chain-dangerous",
  "name": "Dangerous tools need direct authority",
  "priority": 850,
  "enabled": true,
  "when": {
    "kind": "group",
    "id": "g-deep-dangerous",
    "operator": "and",
    "children": [
      { "kind": "condition", "id": "c-dangerous", "field": "tool.dangerous", "operator": "is_true" },
      {
        "kind": "condition",
        "id": "c-chain",
        "field": "delegation.chain_length",
        "operator": "gt",
        "value": 2
      }
    ]
  },
  "then": { "decision": "BLOCK", "reason": "Dangerous tools require direct authority." }
}
```

Available fields: `authority.max_amount`, `authority.capabilities`,
`authority.depth`, `delegation.depth`, `delegation.chain_length`,
`delegation.valid`.

## Related

:::cards

:::card Delegated authority | /concepts/delegation
The model, the invariant and resolution.
:::

:::card Delegation API | /reference/api/delegation
Create, simulate, graph, narrow, revoke.
:::

:::card Delegation semantics | /architecture/adr/0004-delegation-semantics
Why refusal beats clamping.
:::

:::card Policy fields | /reference/policy-fields
Every authority and delegation field.
:::

:::
