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:

  1. Through a 402 response. A service that replies with 402 Payment Required includes the plan ID and its terms in the response body. The agent inspects them and chooses whether to pay.
  2. 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.