Monetize Your API in 10 Minutes
Lightning Enable turns any HTTP API into a paid API. Every request either includes a valid payment token or gets back a 402 with a Lightning invoice. You pick how it sits in the request path.
Two integration modes — pick one
Lightning Enable supports two ways to put L402 in front of your API:
| Native mode (recommended for production APIs) | Proxy mode (no code changes) | |
|---|---|---|
| Where traffic lives | On your domain, your servers | Routed through api.lightningenable.com |
| Code changes | One install + one line of middleware | None |
| Existing auth, rate limiting, observability | Preserved — chain your own middleware around it | LE consumes Authorization, harder to pass through |
| Custom logic per route | Full control | Limited to what the proxy supports |
| Best for | Commercial APIs, anything with sensitive infrastructure | Public APIs, experiments, demos |
If your API is something you already run in production — and especially if it has its own auth — Native mode is the right answer. That's the path this Quick Start walks. If you want zero code changes and you're fine with traffic going through Lightning Enable, jump to Alternative: hosted proxy mode below.
Prerequisites
- A Lightning Enable account on Agentic Commerce — Individual ($99/mo) or Agentic Commerce — Business ($299/mo). Both include a 30-day free trial; card required, no charge until trial ends.
- A payment provider — Strike (recommended) or OpenNode. Strike supports preimage return for full L402 compatibility.
- An existing HTTP API on a supported stack (Node + Express or .NET + ASP.NET Core today; FastAPI and Go on the roadmap — see the Producer API Reference for raw HTTP integration in any language).
Check your setup state at any time
If you want to know exactly where you are in the 10-minute setup — what's done, what's still required, what example payload comes next — hit the quick-start endpoint:
curl https://api.lightningenable.com/api/merchant/quickstart \
-H "X-API-Key: YOUR_LE_API_KEY"
You get back a state machine with completedSteps, requiredStepsCompleted, isReadyForProduction, and a per-step breakdown. Useful both as a "did I miss something" sanity check and as a programmatic readiness probe.
Step 1: Configure your payment provider (minutes 1-3)
Lightning Enable supports Strike (recommended) and OpenNode. Strike is the default — it supports preimage return for full L402 compatibility and requires no additional environment setup.
Option A: Strike (recommended)
- Create an account at strike.me and get your API key from dashboard.strike.me
- Add it to Lightning Enable:
curl -X PUT https://api.lightningenable.com/api/merchant/strike-key \
-H "X-API-Key: YOUR_LE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"strikeApiKey": "your-strike-api-key"}'
Response:
{
"success": true,
"message": "Strike API key updated successfully. Webhook will re-register on the next L402 challenge."
}
Option B: OpenNode (alternative)
For testing (no KYB required): create a dev account at dev.opennode.com, generate an API key, and add it:
curl -X PUT https://api.lightningenable.com/api/merchant/opennode-key \
-H "X-API-Key: YOUR_LE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"openNodeApiKey": "your-opennode-dev-key"}'
For production: same flow at opennode.com. KYB verification takes 2-4 business days; use testnet in the meantime.
OpenNode environment (dev vs production) is set platform-wide in your Lightning Enable instance, not per-merchant. Hosted Lightning Enable runs against OpenNode production by default. If you need to switch your hosted account to dev, contact support.
Step 2: Install the middleware (minutes 4-5)
Pick your stack:
Node.js + Express
npm install l402-express l402-server
l402-server is the underlying SDK that l402-express calls; both are MIT-licensed and the middleware re-exports the SDK's types.
.NET + ASP.NET Core
dotnet add package L402Server.AspNetCore
The underlying L402Server SDK is pulled in transitively. Both are MIT-licensed.
Another stack?
The producer API is HTTP — you can integrate from any language. See the Producer API Reference for the two endpoints you'll call (POST /api/l402/challenges to mint, POST /api/l402/challenges/verify to validate).
Step 3: Add the middleware + set prices (minutes 6-7)
One line in your app. Anything mounted under it costs the configured number of sats per request.
Express
import express from "express";
import { l402 } from "l402-express";
const app = express();
// Anything below this costs 100 sats per request
app.use("/api/premium", l402({
apiKey: process.env.LIGHTNING_ENABLE_API_KEY,
priceSats: 100,
}));
app.get("/api/premium/weather", (_req, res) => {
res.json({ temp: 72 });
});
app.listen(3000);
Endpoints not mounted under l402(...) pass through untouched — mix paid and free routes freely.
For variable per-request pricing, pass a function instead of a number: priceSats: (req) => req.query.model === "premium" ? 500 : 100.
ASP.NET Core
using L402Server.AspNetCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddL402AspNetCore(opts =>
{
opts.ApiKey = builder.Configuration["LightningEnable:ApiKey"]!;
});
var app = builder.Build();
app.UseRouting();
app.UseL402();
app.MapControllers();
app.Run();
Then mark any action with [L402(PriceSats = N)]:
[ApiController]
[Route("api/premium")]
public class PremiumController : ControllerBase
{
[HttpGet("weather")]
[L402(PriceSats = 100)]
public IActionResult Weather() => Ok(new { temp = 72 });
}
That's the whole integration. For both stacks, the middleware:
- Reads
Authorization: L402 <macaroon>:<preimage>from each request - If absent → mints a fresh challenge and returns
402 Payment Requiredwith the invoice - If present → verifies it via Lightning Enable. Valid → call your handler; invalid → respond
401
Step 4: Test it (minutes 8-9)
Try an unpaid request
curl -i https://your-api.example/api/premium/weather
You'll get:
HTTP/1.1 402 Payment Required
Content-Type: application/json
WWW-Authenticate: L402 macaroon="AgEL...", invoice="lnbc..."
{
"error": "Payment Required",
"l402": {
"macaroon": "AgEL...",
"invoice": "lnbc1u1p3...",
"amount_sats": 100,
"payment_hash": "abc123...",
"expires_at": "<ISO-8601 timestamp, typically invoice-creation + 10 minutes>",
"resource": "/api/premium/weather"
}
}
Pay and access
# After paying the invoice and extracting the preimage:
curl https://your-api.example/api/premium/weather \
-H "Authorization: L402 AgEL...:deadbeef..."
# 200 OK — your API's response
Step 5: Ship it (minute 10)
Deploy your app. Your existing API is now a paid API. Give your callers (or their agents) the URL — they hit it, pay 402 invoices, get access.
How L402 interacts with your existing auth
The most common question: does L402 replace my auth, or sit next to it?
Two cases — both work:
- L402 is your only auth. The macaroon's caveats (path, amount, merchant ID, expiry) plus preimage verification are the authorization. Anyone who pays for that resource gets in. This is the right model for the ~90% case — paid APIs where "they paid" is the only fact you need to enforce. L402 is anonymous-payment by design, so this is what you get out of the box.
- L402 + your existing customer auth, side by side. They coexist because they live in different request fields. L402 owns
Authorization: L402 <macaroon>:<preimage>. Your existing auth uses a cookie,X-API-Key, a JWT in a separate header, an IP allowlist, mTLS — whatever you're already doing. Chain your own auth middleware aroundl402(...)(Express) or before/afterapp.UseL402()(ASP.NET Core); they don't fight.
After successful verification, the middleware exposes the verified credential to your handler:
- Express:
res.locals.l402→{ resource, amountSats, paymentHash } - ASP.NET Core:
HttpContextitems — same fields
Useful for usage logging, per-endpoint analytics, fraud detection. The payment hash gives you a stable per-payment identifier without revealing buyer identity.
Optional: list your API in the registry
If you want AI agents to discover your paid API (not just successfully call it once they know the URL), publish a manifest in the L402 registry. This step is independent of the middleware and uses the existing proxy management endpoints — see Setting Up Your Proxy for the manifest and registry portion (skip the upstream URL bits; in Native mode your manifest points at your own host).
Alternative: hosted proxy mode (no code changes)
If you'd rather not touch your application code, Lightning Enable can sit in front of your API as a hosted proxy. You give us your API URL, we give you a https://api.lightningenable.com/l402/proxy/{your-slug}/ URL that handles the 402 challenge dance and forwards paid requests to your origin.
- Pros: zero code changes, no deploy required, fastest path to a working paywall
- Cons: traffic flows through Lightning Enable, your existing
Authorization-header auth is hard to preserve, customer domain changes
Full walkthrough: Setting Up Your Proxy.
What Lightning Enable handles (both modes)
| Concern | Handled |
|---|---|
| Invoice creation | Via your configured payment provider (Strike or OpenNode) |
| Payment verification | Preimage validated against payment hash cryptographically |
| Token management | Macaroon mint with caveats (path, amount, merchant ID, expiry) |
| Tenant isolation | A token for Merchant A can never verify against Merchant B |
| Token reuse within validity window | Same payment hash re-verifiable for same resource until expiry (feature, not bug; see producer API reference) |
| SSRF protection (proxy mode) | Private IPs blocked, target URLs validated |
| Analytics | Tracks requests, revenue, endpoint usage |
Next steps
- Native Integration — Express — full reference for the Node middleware
- Native Integration — ASP.NET Core — full reference for the .NET middleware
- Producer API Reference — raw HTTP API if you're on a stack we don't have a middleware for yet
- Native Integration overview — deeper architectural rationale
- Setting Up Your Proxy — full proxy-mode walkthrough if you chose that path