@powforge/langchain-l402-middleware
v0.1.0
Published
L402 Lightning payment middleware for LangChain.js tools — wrap any async tool function with a pay-per-call Lightning gate backed by LNBits. Works with DynamicTool, StructuredTool, or any plain async function.
Maintainers
Readme
@powforge/langchain-l402-middleware
L402 Lightning payment middleware for LangChain.js tools. Wrap any async
tool function with a pay-per-call Lightning gate backed by LNBits. Works
with DynamicTool, StructuredTool, or any plain async function.
Install
npm install @powforge/langchain-l402-middlewareRequires Node 18+ (for global fetch).
Use
Wrap an existing async function
const { wrapWithL402 } = require('@powforge/langchain-l402-middleware');
const summarize = async (text) => `summary of ${text}`;
const paidSummarize = wrapWithL402(summarize, {
lnbitsUrl: 'https://lnbits.example',
lnbitsApiKey: process.env.LNBITS_INVOICE_KEY,
satsAmount: 21,
});
// First call — no proof, returns a 402 envelope.
const challenge = await paidSummarize('hello world');
// {
// error: 'payment_required',
// invoice: 'lnbc...',
// payment_hash: 'abc123',
// sats: 21,
// next_step: 'Pay the invoice, then re-call with the payment_hash as paymentProof.'
// }
// Pay the invoice externally, then re-call with the payment_hash:
const result = await paidSummarize('hello world', 'abc123');
// "summary of hello world"Build a LangChain.js-compatible tool
const { createL402Tool } = require('@powforge/langchain-l402-middleware');
const { DynamicTool } = require('@langchain/core/tools');
const toolSpec = createL402Tool({
name: 'paid_summary',
description: 'Summarizes any text. Costs 21 sats per call.',
func: async (text) => `summary of ${text}`,
lnbitsUrl: 'https://lnbits.example',
lnbitsApiKey: process.env.LNBITS_INVOICE_KEY,
satsAmount: 21,
});
const tool = new DynamicTool(toolSpec);Because DynamicTool.func only receives one argument, callers smuggle
the payment proof through a JSON envelope:
await tool.func(JSON.stringify({
__payment_proof__: 'abc123',
__tool_input__: 'hello world',
}));
// "summary of hello world"Payment flow
- Caller invokes the wrapped tool with no proof.
- Wrapper mints a Lightning invoice via LNBits and returns a 402
envelope
{ error: 'payment_required', invoice, payment_hash, sats }. - Caller pays the invoice over Lightning.
- Caller re-invokes the tool with
payment_hashas the proof. - Wrapper checks LNBits for paid status (cached after first success)
and either executes the original function or returns
{ error: 'invoice_not_paid', payment_hash }.
Configuration
| Option | Required | Default | Description |
| --- | --- | --- | --- |
| lnbitsUrl | yes* | — | LNBits instance base URL |
| lnbitsApiKey | yes* | — | Invoice/read key (NOT admin) |
| satsAmount | no | 10 | Sats charged per call |
| memo | no | langchain-l402 | Invoice memo |
| fetchImpl | no | globalThis.fetch | Injectable fetch |
| createInvoiceFn | no | LNBits adapter | Override the invoice minter |
| checkPaidFn | no | LNBits adapter | Override the paid-check function |
| state | no | new in-memory | Shared payment cache |
* Required unless you inject createInvoiceFn + checkPaidFn directly
(useful for tests or non-LNBits backends).
Error envelopes
The wrapper never throws on the payment path — it returns a structured object so a LangChain agent can read the error from the tool output.
| error | Meaning |
| --- | --- |
| payment_required | No proof; pay the invoice and retry |
| invoice_not_paid | Proof points at an unpaid hash |
| payment_provider_unavailable | LNBits invoice mint failed |
| payment_verifier_unavailable | LNBits paid-check failed |
Why payment_hash, not preimage?
This package accepts the LNBits payment_hash as the "proof" rather
than the canonical L402 preimage. Trade-off:
- The hash is a hex string LangChain tools can carry through their single-argument interface without binary serialization.
- LNBits' read endpoint is the authoritative oracle — the wrapper consults it on every uncached request.
- For full preimage-based macaroon verification (the canonical L402
flow) use
@powforge/mcp-l402-gate.
License
MIT
