Skip to main content

L402 Producer API: Agents That Earn

The Key Differentiator

Until now, AI agents could only spend money. With the L402 Producer API, your agents can earn money too. This is true agentic commerce — agents that both buy and sell services autonomously.

The L402 Producer API lets Agentic Commerce subscribers turn their AI agents into service providers. Instead of just consuming paid APIs, your agent can create L402 payment challenges and verify payments before granting access to its own capabilities.

The Two Sides of Agentic Commerce

SideWhat It DoesWho PaysMCP Tools
Consumer (existing)Agent accesses paid APIsYour agent paysaccess_l402_resource, pay_l402_challenge
Producer (new)Agent charges for its servicesOther agents pay youcreate_l402_challenge, verify_l402_payment

Both sides use the same L402 protocol. The difference is direction: consumers pay invoices, producers create them.

Prerequisites

  • Agentic Commerce subscription — Individual ($99/mo) or Business ($299/mo)
  • LIGHTNING_ENABLE_API_KEY environment variable set to your merchant API key
  • A configured payment provider (Strike or OpenNode) on your Lightning Enable account
{
"mcpServers": {
"lightning-enable": {
"command": "dotnet",
"args": ["tool", "run", "lightning-enable-mcp"],
"env": {
"STRIKE_API_KEY": "your-strike-api-key",
"LIGHTNING_ENABLE_API_KEY": "your-merchant-api-key"
}
}
}
}
Consumer Tools Work Out of the Box

The 15 consumer tools (access_l402_resource, pay_l402_challenge, pay_invoice, etc.) require no API key — just a wallet. The 2 producer tools (create_l402_challenge, verify_l402_payment) and 6 ASA (Agent Service Agreement) tools require a Lightning Enable API key via LIGHTNING_ENABLE_API_KEY.

How It Works

The full agent-to-agent commerce flow:

┌──────────────────┐                    ┌──────────────────┐
│ Requesting Agent │ │ Producer Agent │
│ (Consumer) │ │ (Your Agent) │
└────────┬─────────┘ └────────┬─────────┘
│ │
│ 1. "I need weather data" │
│──────────────────────────────────────> │
│ │
│ │ 2. create_l402_challenge(
│ │ resource="/api/weather",
│ │ priceSats=50,
│ │ description="7-day forecast"
│ │ )
│ │
│ 3. HTTP 402 Payment Required │
│ + Lightning invoice + macaroon │
│ <──────────────────────────────────────│
│ │
│ 4. pay_l402_challenge(invoice, mac) │
│ ─ ─ ─ ─ ─ ─ ─ (pays invoice) ─ ─ ─ >│
│ │
│ 5. "Here's my L402 token: │
│ macaroon:preimage" │
│──────────────────────────────────────> │
│ │
│ │ 6. verify_l402_payment(
│ │ macaroon, preimage
│ │ )
│ │
│ 7. Access granted + response data │
│ <──────────────────────────────────────│

MCP Tools

create_l402_challenge

Create an L402 payment challenge to charge another agent or user for accessing a resource.

Parameters:

ParameterTypeRequiredDescription
resourcestringYesResource identifier — URL, service name, or description of what you're charging for
priceSatslongYesPrice in satoshis to charge
descriptionstringNoDescription shown on the Lightning invoice

Example:

User: When another agent asks for weather data, charge them 50 sats.

Claude: [Uses create_l402_challenge with resource="/api/weather/forecast",
priceSats=50, description="7-day weather forecast"]

L402 challenge created!
- Invoice: lnbc500n1p3xyza...
- Price: 50 sats
- Resource: /api/weather/forecast

Share the invoice and macaroon with the requesting agent.
After they pay, they'll send you an L402 token (macaroon:preimage).
Use verify_l402_payment to confirm payment before granting access.

Response:

{
"success": true,
"challenge": {
"invoice": "lnbc500n1p3xyza...",
"macaroon": "AgELbGlnaHRuaW5n...",
"paymentHash": "abc123def456...",
"expiresAt": "2026-03-13T14:30:00Z"
},
"resource": "/api/weather/forecast",
"priceSats": 50,
"instructions": {
"forPayer": "Pay the Lightning invoice, then present the L402 token...",
"tokenFormat": "L402 {macaroon}:{preimage}",
"verifyWith": "After receiving the L402 token from the payer, use verify_l402_payment to confirm payment before granting access."
},
"message": "L402 challenge created for 50 sats. Share the invoice with the payer."
}

verify_l402_payment

Verify an L402 token (macaroon + preimage) to confirm payment was made. Use this after a payer presents an L402 token, before granting access to the resource.

Parameters:

ParameterTypeRequiredDescription
macaroonstringYesBase64-encoded macaroon from the L402 token
preimagestringYesHex-encoded preimage (proof of payment)
Compare the returned resource yourself

This tool sends only the macaroon and preimage to the verify endpoint. The API always enforces merchant binding and expiry, but it enforces the resource caveat only when the verify request includes a resource value — which this tool does not send. valid: true therefore means "a real payment for some resource of yours" — check that the resource field in the result matches the resource the payer is asking for before granting access. See Token Binding below.

Example:

User: The requesting agent sent this L402 token. Verify it.

Claude: [Uses verify_l402_payment with macaroon="AgEL...", preimage="7f8a9b..."]

Payment verified! The agent has paid 50 sats for /api/weather/forecast.
Granting access now.

Response (valid):

{
"success": true,
"valid": true,
"resource": "/api/weather/forecast",
"message": "Payment verified. The payer has paid — you can now grant access to the resource."
}

Response (invalid):

{
"success": true,
"valid": false,
"message": "Payment verification failed. The token is invalid or the invoice has not been paid. Do NOT grant access."
}

Challenge Idempotency

When the same resource and price are requested from the same client while the original invoice is still live, the API returns the same invoice and macaroon instead of creating a new one. The idempotency window is the invoice expiry window — 10 minutes (600 seconds) by default, set server-side by L402Options.InvoiceExpirySeconds. This prevents duplicate invoices when agents retry requests or when network issues cause repeated calls.

Idempotency is determined by:

  • Client identifier — the X-Idempotency-Key request header, or the client's IP address if no header is provided
  • Resource — the resource identifier passed in the request
  • Price — the satoshi amount

If you need a fresh challenge for the same resource before the invoice expires, use a different X-Idempotency-Key. Once the invoice expires, the next call mints a fresh challenge automatically.

REST API Quick Start

The MCP tools call two REST endpoints under the hood. You can call them directly from any language.

Single source of truth

The Producer API Reference is the authoritative page for these endpoints — full request/response contracts (including the mppChallenge field), error tables, idempotency semantics, and the caveat-enforcement rules. The two calls below are just the quick start.

Create a challenge:

curl -X POST https://api.lightningenable.com/api/l402/challenges \
-H "X-API-Key: YOUR_MERCHANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"resource": "/api/weather/forecast",
"priceSats": 50,
"description": "7-day weather forecast"
}'

Verify a token — pass resource so the API enforces the macaroon's path caveat server-side (omit it and the bound resource is only reported back, not compared):

curl -X POST https://api.lightningenable.com/api/l402/challenges/verify \
-H "X-API-Key: YOUR_MERCHANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"macaroon": "AgELbGlnaHRuaW5n...",
"preimage": "7f8a9b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a",
"resource": "/api/weather/forecast"
}'

The verify endpoint returns 200 OK for both valid and invalid tokens — read the valid field, not the status code.

End-to-End Example: Weather Data Agent

Here is a complete example of a producer agent that charges for weather data.

Producer Agent Setup

{
"mcpServers": {
"lightning-enable": {
"command": "dotnet",
"args": ["tool", "run", "lightning-enable-mcp"],
"env": {
"STRIKE_API_KEY": "your-strike-key",
"LIGHTNING_ENABLE_API_KEY": "your-merchant-api-key"
}
}
}
}

Producer Agent Behavior

Requesting Agent: "I need the 7-day forecast for New York City."

Producer Agent (Claude):
1. [Uses create_l402_challenge(
resource="/api/weather/forecast/nyc",
priceSats=25,
description="7-day NYC weather forecast"
)]

2. Returns to requesting agent:
"Access to this forecast costs 25 sats.
Pay this invoice: lnbc250n1p3...
Then send me: L402 AgEL...:your_preimage"

Requesting Agent:
3. [Uses pay_l402_challenge(invoice="lnbc250n1p3...", macaroon="AgEL...")]
4. "Here's my token: L402 AgEL...:7f8a9b2c..."

Producer Agent (Claude):
5. [Uses verify_l402_payment(macaroon="AgEL...", preimage="7f8a9b2c...")]
6. Payment verified! Now fetching the forecast...
7. "NYC 7-Day Forecast:
Monday: Sunny, 72F
Tuesday: Partly cloudy, 68F
..."

Consumer Agent Setup

The consumer agent only needs a wallet — no subscription required:

{
"mcpServers": {
"lightning-enable": {
"command": "dotnet",
"args": ["tool", "run", "lightning-enable-mcp"],
"env": {
"STRIKE_API_KEY": "consumer-strike-key"
}
}
}
}

Use Cases

AI Research Agent

Charge other agents for access to your curated research database:

create_l402_challenge(
resource="/research/market-analysis",
priceSats=100,
description="Q1 2026 market analysis report"
)

Code Review Agent

Offer automated code review as a paid service:

create_l402_challenge(
resource="/services/code-review",
priceSats=500,
description="Automated code review with security analysis"
)

Data Aggregation Agent

Sell aggregated data from multiple sources:

create_l402_challenge(
resource="/data/crypto-sentiment",
priceSats=50,
description="Real-time crypto sentiment score from 10 sources"
)

Translation Agent

Charge per translation request:

create_l402_challenge(
resource="/translate/en-to-ja",
priceSats=10,
description="English to Japanese translation"
)

Security Considerations

Always Verify Before Granting Access

Never grant access based on a payer claiming they paid. Always call verify_l402_payment to cryptographically confirm:

  • The preimage matches the payment hash (SHA256(preimage) == payment_hash)
  • The macaroon signature is valid (not tampered with)
  • The macaroon was issued under your merchant account (always enforced server-side)
  • The token has not expired (always enforced server-side)

Token Binding

Each L402 token carries caveats binding it to the merchant who issued it, an expiry, the resource it was issued for, and the amount charged. What the verify endpoint enforces server-side depends on what you send:

  • Merchant bindingalways enforced. Verifying with your API key a token that was issued under a different merchant returns valid: false. No opt-out.
  • Expiryalways enforced. A token past its validity window (60 minutes by default) returns valid: false.
  • Resource (path caveat) — enforced only when your verify request includes resource. If you omit it, the bound resource is returned in the response but not compared — the comparison is your responsibility.
  • Amount — enforced only when your verify request includes amountSats; otherwise returned but not compared.

The MCP verify_l402_payment tool sends only the macaroon and preimage, so path/amount enforcement does not apply on that route — always compare the resource in the tool result against the resource you're about to grant before serving it. When calling the REST endpoint directly, pass resource (and amountSats if you gate multiple price tiers) to get server-side enforcement. See caveat enforcement rules in the Producer API Reference for the full contract.

Idempotency Keys

Use the X-Idempotency-Key header to prevent duplicate invoices in retry scenarios. Without it, the client's IP address is used for idempotency, which works but is less precise.

Next Steps