Plans
The on-chain pricing record that agents look up in the on-chain Plan Registry.
A Plan is the on-chain record of what your service charges. When you publish one, it is written to the Plan Registry, a public catalog that Opus Protocol maintains on Robinhood Chain mainnet, where any agent or client can look it up. Once the terms are public, an agent can subscribe to them or authorize a payment against them.
Plan fields
interface Plan {
id: string; // On-chain plan id
provider: Address; // Service provider wallet
name: string; // Display name, e.g. "Pro API (10k calls/month)"
amount: number; // Price in token base units (e.g. 49_000_000 = 49 USDG)
token: Address; // Token contract address (USDG during beta)
interval: BillingInterval; // MONTHLY | WEEKLY | DAILY | PER_REQUEST
trialPeriodDays?: number; // Optional free trial length
meteredOverage?: {
unit: string; // e.g. "1000 tokens"
price: number; // Price per unit above the plan limit
};
}
Publishing a plan
const plan = await opusprotocol.createPlan({
name: "Inference Pro",
amount: 49_000_000, // 49 USDG
interval: "MONTHLY",
trialPeriodDays: 7,
});
console.log(plan.id); // store this as your plan id
Calling createPlan submits a transaction from your provider wallet that records the plan in the Plan Registry on Robinhood Chain mainnet. The plan goes live the moment that transaction confirms, and other parties can find it from then on.
Billing intervals
| Interval | Description |
|---|---|
MONTHLY |
Collects once every 30 days |
WEEKLY |
Collects once every 7 days |
DAILY |
Collects once every 24 hours |
PER_REQUEST |
No billing cycle; used for one-time or metered access |
Plans cannot be changed
Once published, a plan is frozen. The price, the billing interval, the token, and the trial length stay exactly as written for as long as the record exists.
Immutability is deliberate. When an agent subscribes, it agrees to a particular set of terms, and because those terms live on the chain they cannot drift afterward. A provider has no way to raise the price on subscribers who already accepted it, and anyone reviewing a subscription can rely on the record they see.
If you need different pricing, publish a second plan. Subscribers on the old plan continue under the terms they accepted until they cancel or until you move them over. How and when that migration happens is up to you.
Charging for overage
When a plan includes a quota and bills for usage beyond it, attach a meteredOverage block:
const plan = await opusprotocol.createPlan({
name: "Compute Standard",
amount: 20_000_000, // 20 USDG base fee
interval: "MONTHLY",
meteredOverage: {
unit: "1000 tokens",
price: 2_000, // 0.002 USDG per 1k tokens above quota
},
});
Overage charges are collected through an Allowance. At subscribe time the agent authorizes a spending limit, which caps what it can be charged, and the service deducts from that allowance as usage grows.
How agents find plans
There are two ways for an agent or client to arrive at a plan:
- Through a
402response. A service that replies with402 Payment Requiredincludes the plan ID and its terms in the response body. The agent inspects them and chooses whether to pay. - Directly from the registry. The Plan Registry is public, so any Robinhood Chain client can query it and list every plan a given provider has published.
Both paths are covered step by step in Payment Flows.
Retiring a plan
Because the record is permanent, a plan can never be deleted. It can, however, be deprecated, which stops anyone new from subscribing. Current subscriptions keep renewing until their subscribers cancel.
await opusprotocol.deprecatePlan({ planId: plan.id });
Once deprecated, the payment gate middleware stops including the plan in 402 responses. The record itself stays on the chain and anyone can still read it.