Payment Sessions
One budgeted token covers a burst of rapid requests, and the Facilitator settles the charges on-chain in batches. Arrives with general availability.
The problem sessions solve
Paying per request breaks down once request volume climbs, and holding a subscription does not fix it. Consider an LLM inference agent that issues 500 API calls every minute. Putting a transaction on-chain for each call would add hundreds of milliseconds of latency to every one of them, and the fees would soon be worth more than the requests themselves.
A session moves authorization off the request path. The agent locks in a budget once, the Facilitator collects the accumulated charges in batches, and the payment cost of any single request drops to almost nothing.
Session flow
1. Agent calls agent.openSession({ provider, budget, ttl })
2. Opus Protocol Facilitator verifies the agent has sufficient balance
3. Facilitator issues a short-lived Session Token (JWT, TTL: 5-60 min)
4. Agent attaches the Session Token to each request header
5. Service validates the token against the Facilitator (sub-millisecond)
6. Facilitator batches on-chain settlements periodically
7. On session expiry: final settlement executed, unused balance returned
On the service side, checking a token is cheap. There is no on-chain lookup for any individual request, so the payment step contributes essentially no latency.
Token lifecycle
| Phase | Description |
|---|---|
| Open | The agent pledges a budget. The Facilitator reserves those funds and hands back a token. |
| Active | Requests proceed while the Facilitator tracks spending against the pledged budget. |
| Expired | Either the TTL runs out or the agent closes the session, and the closing settlement is written on-chain. |
| Settled | Every charge is final on-chain, and whatever budget went unspent has returned to the agent’s wallet. |
Planned API
Agent side: opening a session
const session = await agent.openSession({
provider: "https://api.inference.com",
budget: 10_000_000, // 10 USDG session budget
ttl: 3600, // 1 hour
});
// Make high-frequency calls through the session
const response = await session.get("/v1/completions", {
body: { prompt: "..." },
});
// Closing early triggers settlement and returns the unused budget
await session.close();
Provider side: accepting sessions
app.use("/v1", opusprotocol.sessionGate({
facilitatorUrl: "https://facilitator.opusprotocol.org",
}));
On each incoming request, sessionGate pulls the X-OpusProtocol-Session header and checks it with the Facilitator. No individual request results in an on-chain call.
The on-chain record
Only the individual charges are batched; the record is not. Closing a session produces an ordinary on-chain transaction, and anyone can inspect it to confirm the total paid, how long the session lasted, and who took part. The session ID travels in the transaction’s memo field. The authoritative record is still the chain.
Good fits for sessions
Sessions pay off for:
- Inference agents firing completions calls back to back
- Consumers of real-time data feeds
- Agent workflows with many steps that send a burst of sub-calls to a single provider
- Anything where the latency of each request counts
If your request rate is modest, one-time payments and subscriptions are simpler, and both are available now.