---
title: Delegated authority
description: Bounded, time-limited, revocable grants that can never exceed their parent — the one invariant the whole model rests on.
label: Delegation
---

A delegation is a grant of authority from one principal to another, narrowed and
bounded. A human delegates to an agent. An agent delegates to a sub-agent. The
sub-agent delegates to a worker. Each hop is recorded, each is constrained, and
each can be revoked.

The whole thing rests on one rule.

:::security A child can never exceed its parent
Not "should not". Cannot. A delegation that asks for a capability the parent does
not hold, an amount above the parent's ceiling, an expiry past the parent's
expiry, or a scope wider than the parent's scope is **refused** with
`DELEGATION_ESCALATION`.

It is refused rather than silently clamped, because 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.
:::

## What a delegation carries

| | What it bounds |
| --- | --- |
| Capabilities | A subset of the parent's. Never an addition. |
| Amount ceiling | Minor units. At most the parent's ceiling. |
| Scope | Organization, workspace, environment, agent or tool. Never broader than the parent's. |
| Expiry | At or before the parent's expiry. |
| Depth | How many further hops are permitted. |
| Constraints | Extra conditions: destinations, resources, time windows. |

```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' \
  -d '{
    "from_agent_id": "agt_supervisor",
    "to_agent_id": "agt_worker",
    "capabilities": ["refund.create"],
    "max_amount": 50000,
    "currency": "INR",
    "expires_at": "2026-10-10T00:00:00.000Z",
    "max_depth": 0
  }'
```

`max_depth: 0` means the worker cannot delegate onward. That is usually what you
want at the leaf: a worker that can sub-delegate is a worker whose authority you
no longer fully know.

## Check before you grant

```http
POST /v1/delegations/simulate
```

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

## Resolution at request time

Stage 6 of the pipeline resolves the chain:

1. Walk from the acting agent up to the root grant.
2. Check every hop is still valid — not revoked, not expired, issuer still operational.
3. Intersect the constraints of every hop. The effective authority is the *narrowest* value at each dimension, not the nearest.
4. Compare the request against the result.

Point 3 is the one that catches people. If the root grants a ₹100,000 ceiling 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. Narrowing anywhere in the chain narrows
everything below it, permanently, for as long as that hop exists.

:::diagram delegation | The narrowest value in the chain wins at every dimension, not the nearest.
The root grants ₹1,000,000, a supervisor narrows it to ₹100,000, and a team
agent narrows it again to ₹50,000. The worker's own grant says ₹100,000 and its
effective ceiling is still ₹50,000. This is the usual cause of "the delegation
says 100000 but we get `AUTHORITY_EXCEEDED` at 60000".
:::

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

returns the resolved effective authority — what the agent can actually do right
now, after every intersection. When an agent is refused and nobody can work out
why, this is the first thing to read.

## Refusals

| Code | Cause |
| --- | --- |
| `DELEGATION_ESCALATION` | The grant asked for more than the parent holds. Refused at creation. |
| `DELEGATION_INVALID` | The chain does not resolve: a hop was revoked, or an issuer is no longer operational. |
| `DELEGATION_EXPIRED` | A hop's expiry has passed. |
| `AUTHORITY_EXCEEDED` | The chain resolved and the request is outside it. |

`AUTHORITY_EXCEEDED` is the common one in normal operation, and the error
`details` carry the capability, the ceiling and what was requested, so the agent
can report something useful instead of "forbidden".

## Narrowing and revoking

Reducing a delegation is allowed and takes effect immediately:

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

Widening is refused — same invariant, same error. To grant more, create a new
delegation whose parent actually holds that authority.

Revocation cascades:

```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": "Supervisor agent decommissioned" }'
```

Everything derived from that grant dies with it, 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.

## Seeing the shape of it

```http
GET /v1/delegations/graph
```

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

## Depth is bounded on purpose

An unbounded chain is a reasoning problem and a performance problem. Every hop
is another set of constraints to intersect and another record to check for
revocation. More importantly, a human reviewing authority four hops deep cannot
realistically tell you what the leaf can do.

Set `max_depth` to the smallest number that works. Most useful topologies are
two or three deep.

## Policy fields

| Field | Use |
| --- | --- |
| `authority.max_amount` | The resolved ceiling |
| `authority.capabilities` | The resolved capability set |
| `authority.depth` | Depth backing the authority |
| `delegation.depth` | Depth of the delegation used |
| `delegation.chain_length` | Number of hops |
| `delegation.valid` | Whether resolution succeeded |

A useful rule: require approval whenever an agent acts near the top of its
ceiling.

```json
{
  "id": "rule-near-ceiling",
  "name": "Approval near the authority ceiling",
  "priority": 700,
  "enabled": true,
  "when": {
    "kind": "group",
    "id": "g-near-ceiling",
    "operator": "and",
    "children": [
      { "kind": "condition", "id": "c-amount", "field": "amount", "operator": "gt", "value": 40000 },
      {
        "kind": "condition",
        "id": "c-ceiling",
        "field": "authority.max_amount",
        "operator": "lte",
        "value": 50000
      }
    ]
  },
  "then": {
    "decision": "REQUIRE_APPROVAL",
    "reason": "Request is close to the delegated ceiling.",
    "approval": { "routingMode": "SINGLE", "requiredApprovals": 1, "ttlSeconds": 900 }
  }
}
```

Another: refuse deep chains for anything dangerous.

```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." }
}
```

## Related

:::cards

:::card Delegate authority | /build/delegate-authority
The working integration, with sub-agents.
:::

:::card Capabilities | /concepts/capabilities
The static grant a delegation narrows.
:::

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

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

:::
