An Allowance lets a service (the grantee) draw funds out of an agent’s wallet (the granter), never exceeding a fixed total cap. Unlike a subscription, it has no billing cycle. The grantee deducts whenever usage calls for it, and the only constraint is the cap.

Allowance record

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. USDG)
  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

With a subscription, the same amount is collected on a regular schedule. An allowance gives up that predictability in exchange for flexibility. The agent decides the total cap a single time, then the grantee makes as many deductions as it needs, at whatever pace, until the cap runs out or the allowance expires.

Three billing patterns fit this model:

  • Metered billing. A service that bills by API call, by token, or by unit of compute. The agent limits its total exposure up front, and the service draws down the allowance as usage builds.
  • One-time purchases. The agent approves a maximum spend for one operation, without any subscription lifecycle.
  • Overage billing. If a plan bills for usage beyond its included quota, that overage is paid through an allowance that sits next to the subscription.

Granting an allowance

const allowance = await agent.createAllowance({
  grantee: "0x4298e8aa4048cf8d437f9a90266a7e8c436a7bba", // provider wallet
  token: "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168", // USDG
  maxAmount: 10_000_000,   // 10 USDG 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

Deducting from an allowance

A provider pulls funds from an allowance by calling deductAllowance:

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

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

If a deduction would push total spend above maxAmount, it fails with an AllowanceExhausted error. The contract on the chain enforces this cap directly, and there is nothing in Opus Protocol that can let a service spend beyond it.

Reading an allowance’s status

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

Expiration

Once the expiresAt timestamp passes, no further deductions are accepted. There is no unspent balance to recover, because the funds were never removed from the agent’s wallet. An allowance is not an escrow. It is only a permission to spend, and tokens leave the wallet at the moment of each individual deduction.

Revocation

Before an allowance expires, the agent may revoke it at any time:

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

The revocation is recorded on the chain and takes effect right away. Deductions that were signed and already in flight will still settle, but any deduction attempted afterward is rejected.

Using an allowance alongside a subscription

When a plan carries metered overage, a single agent.subscribe() transaction writes both the subscription record and a paired allowance record. The subscription handles the base fee, while the allowance handles usage past the quota. The Dashboard and webhook events show both.

At subscribe time, the agent chooses its overage ceiling through maxOveragePerCycle:

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