Digital Lemonade Stands
- The core idea: paid, structured interactionâwithout permission
- PMIs are âuniversal settlement plug-insâ
- The CEP-8 lifecycle: small semantics, big consequences
- Why this matters: the economics of permissionless services
- Clear roles: processors mint, handlers pay
- The SDK: payments as middleware, not as a transport rewrite
- Amounts: discovery vs settlement
- Using CEP-8 in the SDK (compact examples)
- What to build now
Finally, payments are here! đ
You can publish software that other people (or agents) can call, but getting paid usually means stepping back into the old world: accounts, gatekeepers, geography, and payment rails that donât compose. L402/X402 are great standards, but are still tied to HTTP.
ContextVM set out to change the shape of collaboration: services addressed by public keys, routed over relays, all done in a permissionless way. Weâve written before about why that matters for censorship-resistance and sovereign infrastructure.
Now weâre adding the missing economic primitive.
CEP-8 (Capability Pricing and Payment Flow) makes âdigital lemonade standsâ real: paid, permissionless capabilities that can be run by anyone, discovered by anyone, and consumed by humans or agentsâwithout a centralized registry and without forcing a single payment system on the entire ecosystem.
âLemonade standâ doesnât mean âtoy.â It means sovereign commerce at the edge: the ability to expose anything from a single tool to a serious production service, and get paid per interaction, without asking anyone for permission.
This post is an announcement, not a full guide. The goal is to explain why CEP-8 looks the way it does, what it unlocks, and how the SDK integrates payments without bloating transports or breaking existing deployments.
The core idea: paid, structured interactionâwithout permission
When people hear âpayments,â they often imagine a monolith: one platform, one processor, one set of rules. That model doesnât survive contact with the real world.
Real networks are messy:
-
some calls are stateful, some are stateless
-
some providers want fixed prices, others want dynamic quotes
-
some payment methods are invoice-based, others are bearer assets
-
relays can duplicate or reorder messages
-
many different payment methods exist
CEP-8 embraces this chaos instead of hiding it.
It gives ContextVM a minimal, robust lifecycle for paid capability invocations, and it does so in a way that preserves the permissionless nature of the protocol.
The mechanism has three pillars:
-
Discovery pricing
captags): servers can advertise reference prices for capabilities. -
Compatibility negotiation
pmitags): clients and servers advertise which payment methods they can speak. -
A notification flow: the server requests payment, the client pays, the server verifies, then the request is fulfilled.
All of that is specified in CEP-8.
PMIs are âuniversal settlement plug-insâ
The most important design decision in CEP-8 is that the payment request itself is opaque.
The protocol doesnât standardize âLightning invoices,â âCashu proofs,â âcredit card sessions,â or whatever comes next. Instead, CEP-8 standardizes how to ask for payment, how to correlate it to the call, and how to agree on the language of settlement.
That language is the Payment Method Identifier (PMI), based on the W3C standard with the same name.
In CEP-8 terms:
-
pmiis the type tag. -
pay_reqis the payload. -
the meaning of
pay_reqis PMI-defined.
This is deliberately similar to the way the web uses content-types: you donât need to standardize every possible payload, you need a reliable way to say âinterpret this blob as X.â
Together with CEP-8 we added CEP-21, which provides recommended PMI naming conventions for the ContextVM ecosystem, but itâs explicitly non-normative: you can define your own PMIs when you need new semantics. See CEP-21.
Matching by intersection (how payment rails stay permissionless)
PMIs make payments composable because selection is just compatibility matching:
-
clients advertise what they can pay
-
servers advertise what they can accept
-
the payment rail is chosen from the intersection
Thatâs not âsupporting one payment method.â Itâs a matching mechanism that lets many payment methods coexist without fragmenting the protocol.
This matters for resilience: in a permissionless environment, you donât want a payment monopoly baked into the protocol.
The CEP-8 lifecycle: small semantics, big consequences
Once a capability is priced, CEP-8 defines a simple lifecycle:
-
client calls a capability
-
server responds with a payment required notification
-
client pays using a handler for the specified PMI
-
server verifies settlement and emits payment accepted or payment rejected notifications
-
server fulfills the request
This is how you get a payment flow that survives the real world.
Direct bearer payments (saving round trips)
Some payment methods are bearer assetsâCashu, for exampleâwhere value can be transferred by attaching a token directly in the request, saving round trips.
CEP-8 includes an optional optimization for this: the direct_payment tag. When a PMI supports it, the client can attach a PMI-scoped payload on the original request and skip the invoice round trip.
Why this matters: the economics of permissionless services
If you remove centralized identity, centralized discovery, and centralized hosting constraints, you get something powerfulâbut it still doesnât sustain itself without an economic loop.
CEP-8 closes that loop in a way that matches ContextVMâs philosophy:
-
no registry required to monetize a capability
-
no platform account required to pay or get paid
-
no single rail forced on everyone
-
no protocol fork required to add new settlement systems
This is how you get a world of âdigital lemonade standsâ: thousands of specialized capabilities, each easy to publish, easy to pay for, and easy to compose into larger workflows.
In an agent-to-agent world, this isnât a nice-to-have. Itâs the difference between a permissioned economy and an open one.
Clear roles: processors mint, handlers pay
CEP-8 is deliberately explicit about roles, because it keeps implementations honest and keeps the protocol surface small:
-
Server = payment processor: it mints a payment request
pay_req) for a quote, and later verifies that settlement happened. -
Client = payment handler: it interprets the
pay_req(based onpmi) and performs the wallet action.
Everything elseâhow an invoice is created, how settlement is proved, which third-party system is involvedâis PMI-scoped and intentionally outside the CEP.
The SDK: payments as middleware, not as a transport rewrite
We implemented CEP-8 in the TypeScript SDK with one strong constraint: payments must be optional and must not bloat transports.
Thatâs why the integration is middleware-first:
-
transports keep doing transport things (Nostr event conversion, routing, encryption, correlation)
-
payments wrap the message flow at the seam where requests are forwarded
This allowed us to add paid capabilities without introducing breaking changes. If you donât enable payments, you shouldnât pay a performance or complexity tax.
The SDK exposes this through two simple wrappers:
-
withServerPayments(...)to gate priced capabilities on the server side -
withClientPayments(...)to automatically handle payment requests on the client side
Built-in rails (same PMI, different âbackendâ)
The new version of the SDK ships with two real Lightning BOLT11 integrations, and they both implement the same PMI bitcoin-lightning-bolt11). More integrations can be added in the future. Or you can build your own to satisfy your own needs.
Thatâs the point: the PMI is the contract, not the vendor.
-
NWC (NIP-47) processor/handler (wallet-driven)
-
LNbits processor/handler (service-driven)
Both satisfy the same settlement surface. Both can be swapped without changing CEP-8 semantics.
This is a concrete example of the PMI idea: the protocol contract stays stable even as the backend changes.
Amounts: discovery vs settlement
CEP-8 deliberately separates price discovery from settlement.
When a server advertises pricing, it uses cap tags. Think of these as the menu: helpful for UX, browsing, and automation.
When the server requests payment, it sends notifications/payment_required with:
-
a final
amount -
a
pmi -
an opaque
pay_reqthat encodes the real settlement request for that PMI
The implication is subtle but powerful:
-
a server can advertise prices in
usdfor clarity -
and still settle in sats when the chosen PMI is Lightning, for example
The conversion and quoting logic lives in the serverâs dynamic pricing callback.
Using CEP-8 in the SDK (compact examples)
These snippets are intentionally lightweight and partially pseudo-code. The goal is to show the mechanics without turning this post into a tutorial.
1) Server: fixed pricing + payments gate
Configure which capabilities are priced, then wrap the transport.
import {
withServerPayments,
LnBolt11NwcPaymentProcessor,
type PricedCapability,
} from '@contextvm/sdk/payments';
import { NostrServerTransport } from '@contextvm/sdk/transport';
const pricedCapabilities: PricedCapability[] = [
{
method: 'tools/call',
name: 'your_tool',
amount: 10,
currencyUnit: 'sats',
description: 'Example paid capability',
},
];
const baseTransport = new NostrServerTransport({ signer, relayHandler });
const paidTransport = withServerPayments(baseTransport, {
processors: [
new LnBolt11NwcPaymentProcessor({
// ... NWC connection details
}),
// Or swap for LNbits without changing CEP-8 semantics.
],
pricedCapabilities,
});
What matters here isnât the wallet backend. Itâs that the server has a processor that can mint and verify a payment request for the chosen PMI, and the payments layer will fail closed: no paid capability gets forwarded before settlement.
2) Server: dynamic pricing + currency conversion with resolvePrice
Fixed prices are a demo. Real services need quoting.
The SDK supports a per-request quote callback.
import {
withServerPayments,
type ResolvePriceFn,
} from '@contextvm/sdk/payments';
const resolvePrice: ResolvePriceFn = async ({ capability, request }) => {
// Pseudo-logic: a real quote often depends on the request.
// Example: charge more for larger inputs, _and_ allow advertising in USD while settling in sats.
const inputSize = JSON.stringify(request.params ?? {}).length;
const units = Math.max(1, Math.ceil(inputSize / 1_000));
// Start from the advertised price.
const advertised = capability.amount * units;
// If you advertise in USD for UX, convert here before minting a sats-based invoice.
const amount =
capability.currencyUnit === 'usd'
? await convertUsdToSats(advertised)
: advertised;
return amount;
};
const paidTransport = withServerPayments(baseTransport, {
processors: [processor],
pricedCapabilities,
resolvePrice,
});
This is a subtle but important CEP-8 principle: cap tags are discovery*, while the payment required amount is the final quote. You can publish a âmenuâ in one unit and still settle in another.
3) Client: pay automatically when required
The client wraps its transport with withClientPayments() and provides one or more handlers.
import {
withClientPayments,
LnBolt11LnbitsPaymentHandler,
LnBolt11NwcPaymentHandler,
} from '@contextvm/sdk/payments';
import { NostrClientTransport } from '@contextvm/sdk/transport';
const baseTransport = new NostrClientTransport({ signer, relayHandler, serverPubkey });
const paidTransport = withClientPayments(baseTransport, {
handlers: [
new LnBolt11NwcPaymentHandler({
// ... NWC connection details
}),
// Other handlers can be added.
],
});
The important part: when payments are enabled, the client automatically advertises its supported PMIs to help the server pick a compatible method.
What to build now
CEP-8 isnât âpayments added.â Itâs a sustainable primitive for permissionless capability markets.
If youâre building on ContextVM, there are three obvious next steps:
-
Price one capability in an existing serverâmake it a real lemonade stand.
-
Build a client that can pay (or an agent that can pay) and start composing paid capabilities into workflows.
-
Implement a new PMI if your settlement method isnât covered yet. CEP-8 is designed for pluralism: new rails should not require new transports.
Specifications:
The frontier is open. Build a stand. Price a capability. Let value flow where computation happens.