# Payments

> Implement CEP-8 payments in ContextVM using the @contextvm/sdk payments middleware. Use when building paid servers/clients, configuring priced capabilities, integrating payment processors/handlers, or troubleshooting payment notification flows.

- Skill: `contextvm/payments` (Agent Skill, multi-file: 7 files)
- Install (CLI): `npx skillmds@latest add contextvm/payments`
- Raw SKILL.md: https://api.skillmd.com/api/skills/contextvm/payments/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: contextvm (https://skillmd.com/u/contextvm)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/contextvm/payments

---


# ContextVM Payments (CEP-8)

Use this skill when you want ContextVM servers to **charge for specific capabilities** and clients to **pay automatically** using the TypeScript SDK payments layer.

Payments are implemented as **middleware around transports**:

- **Server-side** middleware gates priced requests: it must not forward to the underlying MCP server until payment is verified.
- **Client-side** middleware listens for payment notifications, executes a handler, then continues the original request.

This skill documents _how to use_ the SDK payments layer. For transport setup (signers, relays, encryption), see:

- [`../typescript-sdk/SKILL.md`](../typescript-sdk/SKILL.md)
- [`../server-dev/SKILL.md`](../server-dev/SKILL.md)
- [`../client-dev/SKILL.md`](../client-dev/SKILL.md)

## Quick start: charge for one tool (server + client)

### Server: price a capability and attach payments

```ts
import type { PricedCapability } from '@contextvm/sdk/payments';
import { LnBolt11NwcPaymentProcessor, withServerPayments } from '@contextvm/sdk/payments';

const pricedCapabilities: PricedCapability[] = [
  {
    method: 'tools/call',
    name: 'my-tool',
    amount: 10,
    currencyUnit: 'sats',
    description: 'Example paid tool',
  },
];

const processor = new LnBolt11NwcPaymentProcessor({
  nwcConnectionString: process.env.NWC_SERVER_CONNECTION!,
});

const paidTransport = withServerPayments(baseTransport, {
  processors: [processor],
  pricedCapabilities,
});
```

### Client: attach a handler and pay automatically

```ts
import { LnBolt11NwcPaymentHandler, withClientPayments } from '@contextvm/sdk/payments';

const handler = new LnBolt11NwcPaymentHandler({
  nwcConnectionString: process.env.NWC_CLIENT_CONNECTION!,
});

const paidTransport = withClientPayments(baseTransport, {
  handlers: [handler],
});
```

## Core concepts (what to understand once)

### Notifications and correlation

CEP-8 payments are expressed as correlated JSON-RPC notifications:

- `notifications/payment_required`
- `notifications/payment_accepted`
- `notifications/payment_rejected` (reject without charging)

They are correlated to the original request via an `e` tag (request event id). Your app should treat these as **notifications**, not responses.

### PMI (Payment Method Identifier)

Each payment rail is identified by a **PMI** string (example: `bitcoin-lightning-bolt11`).

- Server processors advertise which PMIs they can accept.
- Client handlers advertise which PMIs they can pay.
- A payment only works if there is an intersection.

### Amounts: advertise vs settle

`pricedCapabilities[].amount` + `currencyUnit` are what you _advertise_ (discovery). The selected PMI determines how you _settle_.

If you use dynamic pricing via `resolvePrice`, the amount you return must match the unit expected by your chosen processor.

## Server patterns

- Fixed pricing via `pricedCapabilities`
- Dynamic pricing via `resolvePrice`
- Reject without charging via `resolvePrice → { reject: true, message? }`
- Waive payment (prepaid/subscription) via `resolvePrice → { waive: true }`

Read: [`references/server-setup.md`](references/server-setup.md)

## Client patterns

- Multiple handlers (multiple rails)
- Handling `payment_rejected` outcomes
- PMI advertisement via `pmi` tags (automatic when wrapping with `withClientPayments`)

Read: [`references/client-setup.md`](references/client-setup.md)

## Built-in rails (provided by the SDK)

The SDK currently ships multiple built-in payment rails under the same PMI:

- PMI: `bitcoin-lightning-bolt11`

Rails:

- **Lightning over NWC (NIP-47)**
  - Server: `LnBolt11NwcPaymentProcessor`
  - Client: `LnBolt11NwcPaymentHandler`
  - Read: [`references/lightning-nwc.md`](references/lightning-nwc.md)
- **Lightning via LNbits (REST API)**
  - Server: `LnBolt11LnbitsPaymentProcessor`
  - Client: `LnBolt11LnbitsPaymentHandler`
  - Read: [`references/lightning-lnbits.md`](references/lightning-lnbits.md)

More rails may be added over time (new PMIs and/or additional implementations under existing PMIs). Prefer selecting rails based on PMI compatibility and operational needs.

## Build your own rail (custom PMI)

Implement:

- a server-side `PaymentProcessor` (issue + verify)
- a client-side `PaymentHandler` (pay)

Read: [`references/custom-rails.md`](references/custom-rails.md)

## Troubleshooting pointers

- No `payment_required`: verify request matches `method` + `name` in `pricedCapabilities`.
- Payment succeeds but no `payment_accepted`: verify server relay connectivity and processor verification settings.
- Immediate rejection: handle `notifications/payment_rejected` and surface the optional `message`.

For general relay/encryption/connection issues, see [`../troubleshooting/SKILL.md`](../troubleshooting/SKILL.md).

## Reference index

- [`references/cep-8-overview.md`](references/cep-8-overview.md)
- [`references/server-setup.md`](references/server-setup.md)
- [`references/client-setup.md`](references/client-setup.md)
- [`references/lightning-nwc.md`](references/lightning-nwc.md)
- [`references/lightning-lnbits.md`](references/lightning-lnbits.md)
- [`references/custom-rails.md`](references/custom-rails.md)

