Skip to main content
Delegations allow an agent owner to grant specific permissions to other wallets. A delegate can update metadata, submit feedback, spend tokens, or manage services on behalf of the agent — scoped by fine-grained permissions and constraints. Delegations also power x402 budget-based payments. By combining an on-chain delegation with an SPL Token approve, users can authorize autonomous spending without signing each transaction.

Delegation PDA

Seeds: [b"delegation", delegator.as_ref(), delegate.as_ref(), delegation_id.to_le_bytes()]

Permission flags

Seven boolean flags control what a delegate can do:

Constraints

Constraints limit what a delegate can do even when they have the right permission:
Zero values mean “no limit” for all constraint fields. Setting max_spend_per_tx = 0 means there is no per-transaction cap, not that the delegate cannot spend.

Delegation depth

Delegations support up to 3 levels of chaining: When creating a sub-delegation, the program enforces that the child’s constraints are a subset of the parent’s:
  • max_spend_total cannot exceed the parent’s remaining budget (parent.max_spend_total - parent.spent_total).
  • expires_at cannot be later than the parent’s expiry.
  • allowed_tokens must be a subset of the parent’s allowed tokens.
  • allowed_programs must be a subset of the parent’s allowed programs.
  • Permissions must be a subset of the parent’s permissions.
The maximum depth value is 2, meaning 3 total levels (owner, delegate, sub-delegate). Attempting to create a delegation at depth 3 or greater will fail with MaxDelegationDepthExceeded.

Cascading invalidation via owner_version

When an agent NFT is transferred and claim_agent is called, the owner_version on the AgentIdentity increments. Every delegation stores the owner_version at creation time. At use time, the program checks:
If the values do not match, the delegation is rejected. This provides instant, zero-cost invalidation of all delegations when an agent changes hands — no need to iterate and revoke each one individually. Sub-delegations are also invalidated because the parent delegation (which they verify at use time) fails the owner_version check.

DelegationBuilder fluent API

The SDK provides a builder pattern for constructing delegations:

Permission methods

Constraint methods

x402 budget integration

Delegations power budget-based x402 payments. Instead of signing every payment transaction, a user sets up a spending budget once and the x84 facilitator auto-debits within the budget constraints.
1

Create delegation and SPL approve in one transaction

The user signs a single transaction containing two instructions:
  1. spl_token::approve — authorizes the x84 facilitator wallet as delegate on the user’s token account (ATA), with an amount matching max_spend_total.
  2. x84::create_delegation — creates the on-chain delegation with can_transact = true and desired constraints.
2

Facilitator auto-debits on each request

When the user calls an x402-gated agent endpoint, the x402 gate reads the X-DELEGATION header, loads the Delegation PDA, verifies all constraints, and uses the SPL Token delegate authority to transfer tokens from the user’s ATA. No per-request signature is needed.
3

Spent tracking

Each delegated settlement updates delegation.spent_total on-chain, providing a full audit trail of cumulative spending per delegation.

Revocation

A single revocation transaction can invalidate both the on-chain delegation and the SPL Token approve. The delegator or the agent owner can revoke at any time. Sub-delegations that reference a revoked parent become invalid at use time — the program checks the parent’s active status during verification.
When a delegate attempts to use their delegation, the program runs these checks in order:
  1. delegation.active == true
  2. delegation.delegate == caller
  3. delegation.nft_mint == agent.nft_mint
  4. delegation.owner_version == agent.owner_version
  5. Expiry: delegation.expires_at == 0 or delegation.expires_at > now
  6. Uses: delegation.uses_remaining == 0 or delegation.uses_remaining > 0
  7. Required permission flag is set
  8. If spending: amount <= max_spend_per_tx and spent_total + amount <= max_spend_total
  9. If token specified: allowed_tokens is empty or contains the token mint
  10. If program specified: allowed_programs is empty or contains the program ID
  11. If parent_delegation is set: recursively verify the parent (max depth ensures termination)