An Allowance is an on-chain authorization letting a service (the grantee) spend from an agent’s wallet (the granter), up to a capped total. There’s no fixed billing cycle here, unlike a subscription. The grantee draws against the cap as needed, until it hits the maximum.

Allowance structure

interface Allowance {
  id: string;            // On-chain allowance id
  granter: Address;      // Agent wallet authorizing the spend
  grantee: Address;      // Service or facilitator permitted to spend
  token: Address;        // Token contract address (e.g. USDC)
  maxAmount: number;     // Total spend cap, in token base units
  spent: number;         // Accumulated spend so far
  expiresAt?: number;    // Optional Unix timestamp
}

How allowances differ from subscriptions

A subscription pulls a fixed amount on a fixed schedule. An allowance is looser: the total spend cap gets set once, and after that the grantee can draw against it as many times as it wants, at whatever pace, until the cap runs out or the allowance expires.

That makes allowances the right fit for:

  • Metered billing: services that charge per API call, per token, or per unit of compute. The agent sets a total spend cap and the service draws down as usage builds up.
  • One-time purchases: an agent can authorize a specific maximum for a single operation without touching the full subscription lifecycle.
  • Overage billing: when a subscription plan bills metered overage beyond its included quota, that overage portion runs through an allowance sitting alongside the subscription.

Creating an allowance

const allowance = await agent.createAllowance({
  grantee: "0x4298e8aa4048cf8d437f9a90266a7e8c436a7bba", // provider wallet
  token: "0xecdda8f70c0880d915f746c861ace5dd58721a74", // USDC
  maxAmount: 10_000_000,   // 10 USDC total cap
  expiresAt: Date.now() / 1000 + 86400, // expires in 24 hours
});

console.log(allowance.id);        // on-chain allowance id
console.log(allowance.maxAmount); // 10_000_000
console.log(allowance.spent);     // 0

Spending against an allowance

On the provider side, drawing against an allowance goes through deductAllowance:

const result = await hoodlayer.deductAllowance({
  allowanceId: allowance.id,
  amount: 500_000, // 0.50 USDC for this request
});

console.log(result.remaining); // remaining balance

A deduction that would push past maxAmount fails with an AllowanceExhausted error. Enforcement lives in the on-chain contract, so there’s no way for HoodLayer to let a service overdraw.

Checking an allowance

const status = await agent.getAllowance({ allowanceId: allowance.id });

console.log(status.spent);     // amount spent so far
console.log(status.remaining); // maxAmount - spent
console.log(status.expired);   // boolean

Expiry

Once the expiresAt timestamp passes, the allowance can no longer be drawn against. Any unspent balance is automatically back under the agent’s control. There’s no “return funds” step because the funds never actually left the agent’s wallet. An allowance only authorizes spending; the real token transfers happen at draw time.

Revoking an allowance

An agent can revoke an allowance before its expiry:

await agent.revokeAllowance({ allowanceId: allowance.id });

Revocation happens on-chain and takes effect immediately. Deductions that were already signed and in flight will still land, but nothing new can be drawn after that.

Allowances and subscriptions together

When a plan carries metered overage, agent.subscribe() sets up both a subscription record and a companion allowance record in one transaction. The fixed monthly fee goes through the subscription; anything over quota goes through the allowance. Both appear in the Dashboard and in webhook events.

At subscribe time, the agent authorizes a maxOveragePerCycle:

const sub = await agent.subscribe({
  planId: plan.id,
  maxOveragePerCycle: 20_000_000, // authorize up to 20 USDC in overage per month
});