Skip to main content

Environment Variables

Lightning Enable is a hosted SaaS. The API at api.lightningenable.com is deployed and operated by Lightning Enable — as a merchant you never run the server or set its server-side configuration. Your setup happens in the dashboard and via the merchant API.

This page covers two audiences:

  • For merchants — environment variables for the open-source MCP server that you run on your own machine so AI agents can pay over Lightning.
  • Platform operator reference — server-side settings used by Lightning Enable staff to operate the hosted platform. Documented for transparency; merchants never set these.

For merchants: MCP server configuration

The MCP (Model Context Protocol) server enables AI agents to use Lightning Enable tools. It runs locally (or wherever your agent runs) and is configured entirely through environment variables and a local config file — none of this touches the hosted platform.

Wallet Configuration

The MCP server is open-source (MIT) and free to install. Wallet, invoice, L402, budget, and API-discovery tools work out of the box with just a wallet configured below. Producer tools (sell access via L402) and Agent Service Agreement tools (agent-to-agent commerce over Nostr) unlock with a Lightning Enable API key. See the MCP Complete Guide for the full tool list.

Choose one wallet provider (listed in default priority order):

LND (Best for L402):

LND_REST_HOST=https://your-lnd-node:8080
LND_MACAROON_HEX=your-admin-macaroon-hex

Nostr Wallet Connect (NWC):

NWC_CONNECTION_STRING=nostr+walletconnect://pubkey?relay=wss://relay.example.com&secret=xxx

Strike (Recommended for USD users):

STRIKE_API_KEY=your-strike-api-key

OpenNode:

OPENNODE_API_KEY=your-opennode-api-key
OPENNODE_ENVIRONMENT=production # or "dev" for testnet
Wallet Priority

If multiple wallet credentials are configured, they are used in this order:

  1. LND (if LND_REST_HOST and LND_MACAROON_HEX are set)
  2. NWC (if NWC_CONNECTION_STRING is set)
  3. Strike (if STRIKE_API_KEY is set)
  4. OpenNode (if OPENNODE_API_KEY is set)

This order prioritizes wallets that return a preimage, which is required for L402. OpenNode does not return preimages, so L402 will not work with it. You can override the priority with the WALLET_PRIORITY environment variable (values: lnd, nwc, strike, opennode).

Only the first configured wallet is used.

Spending Limits Configuration

Budget limits are configured via ~/.lightning-enable/config.json:

{
"currency": "USD",
"tiers": {
"autoApprove": 0.10,
"logAndApprove": 1.00,
"formConfirm": 10.00,
"urlConfirm": 100.00
},
"limits": {
"maxPerPayment": 500.00,
"maxPerSession": 100.00
}
}

This file is created automatically on first run (or written by the setup_wallet tool). AI agents cannot modify this file through any MCP tool (an agent with direct shell or filesystem access to the host is outside this guarantee). At runtime, an agent can tighten its own caps via the budget tool's action="tighten" (formerly the standalone configure_budget tool), but it can never raise them above the limits in this file.

See AI Spending Security for detailed configuration.

MCP Configuration Summary

VariableRequiredDefaultDescription
LND_REST_HOSTIf using LND-LND REST API host
LND_MACAROON_HEXIf using LND-LND admin macaroon in hex
NWC_CONNECTION_STRINGIf using NWC-Nostr Wallet Connect URI
STRIKE_API_KEYIf using Strike-Strike API key (preferred for USD)
OPENNODE_API_KEYIf using OpenNode-OpenNode API key with withdrawal permissions
OPENNODE_ENVIRONMENTNoproductionproduction or dev
WALLET_PRIORITYNo-Override default wallet priority (lnd, nwc, strike, or opennode)
LIGHTNING_ENABLE_API_KEYNo-Merchant API key; required by every l402_producer action and the agent_services actions request/publish/unpublish/attest (discover/settle/reputation work without it)
LIGHTNING_ENABLE_TOOL_PROFILENostandardlite (pay and check the wallet only), standard (the full current surface), or full (standard plus every pre-consolidation tool name as a deprecated alias, removed in v3.0.0) — see the MCP Complete Guide
LIGHTNING_ENABLE_HOSTEDNounsetSet to 1 in a non-interactive/hosted deployment so out-of-band confirmation defaults to refusing (rather than printing to stderr) when the process isn't attached to a TTY — see AI Spending Security
Open-Source MCP Server

The MCP server is open-source (MIT) and free to install. Wallet, invoice, L402, budget, and API-discovery tools work out of the box with just a wallet — no account or API key required. Producer tools (sell access via L402) and the ASA request/publish/unpublish tools unlock with a Lightning Enable API key; ASA discovery, settlement, and reputation reads work with just a wallet. See the MCP Complete Guide for the full tool list.

Merchant payment provider keys are NOT environment variables

Your Strike or OpenNode API key for accepting payments through Lightning Enable is configured in the dashboard (Settings → Payment Provider) or via the merchant API (PUT /api/merchant/strike-key / PUT /api/merchant/opennode-key) — never through environment variables. The STRIKE_API_KEY / OPENNODE_API_KEY variables above configure the MCP server's outgoing wallet only.

Platform operator reference (Lightning Enable staff)

Merchants never set these

Lightning Enable is hosted SaaS — everything below configures the platform itself and is managed by Lightning Enable staff on the production deployment. It is documented here for transparency and for internal operations. If you are a merchant, nothing in this section applies to you.

Required Configuration

Database Encryption Key

DB_ENCRYPTION_KEY=your-base64-encoded-32-byte-key

Purpose: Encrypts sensitive fields (API keys, provider keys) at rest using AES-256-GCM.

Generate a secure key:

# Linux/Mac
openssl rand -base64 32

# PowerShell
[Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Maximum 256 }))
Critical
  • BACKUP THIS KEY - If lost, all encrypted merchant data is permanently unrecoverable
  • NEVER CHANGE after deployment - existing encrypted data becomes unreadable

Admin API Key

ADMIN_API_KEY=your-secure-admin-key

Purpose: Authenticates internal admin API requests and Hangfire dashboard access for platform operators. Not used by merchants.

Recommended: Generate using the same method as DB_ENCRYPTION_KEY.

Database Connection

ConnectionStrings__DefaultConnection="Server=your-server;Database=LightningEnable;..."

Purpose: SQL Server connection string for the application database.

For Azure SQL with Entra ID authentication:

Server=your-server.database.windows.net;Database=LightningEnable;Authentication=Active Directory Managed Identity;

Stripe Configuration

All Stripe settings are required for subscription management.

Secret Key

Stripe__SecretKey=sk_live_xxxxxxxxxxxxx

Purpose: Server-side Stripe API authentication.

  • Production: Use sk_live_... keys
  • Development: Use sk_test_... keys

Publishable Key

Stripe__PublishableKey=pk_live_xxxxxxxxxxxxx

Purpose: Client-side Stripe Checkout initialization.

Webhook Secret

Stripe__WebhookSecret=whsec_xxxxxxxxxxxxx

Purpose: Verifies webhook signatures from Stripe.

Get this from: Stripe Dashboard → Webhooks → Select endpoint → Signing secret

Base URL

Stripe__BaseUrl=https://api.lightningenable.com

Purpose: Base URL for success/cancel redirect URLs after checkout.

Pricing Plans

{
"Stripe": {
"PricingPlans": {
"individual": {
"Name": "Agentic Commerce",
"Description": "Full L402 access with settlement via Strike API",
"PriceId": "price_xxxxxxxxxxxxx",
"PriceCents": 4900,
"TrialEligible": true,
"Features": [
"Unlimited L402 endpoints",
"Strike as settlement provider",
"Per-endpoint pricing"
]
},
"l402": {
"Name": "Agentic Commerce — Business",
"Description": "Pay-per-request API monetization",
"PriceId": "price_xxxxxxxxxxxxx",
"PriceCents": 29900,
"TrialEligible": true,
"Features": ["Everything in Agentic Commerce", "White-glove onboarding", "Direct founder access"]
}
}
}
}

Purpose: Maps plans to Stripe pricing. Each key maps to an object — not a bare price-ID string — with Name, Description, PriceId, PriceCents, an optional TrialEligible, and a Features array. Since the September 2026 repricing, individual is the only plan a new self-serve checkout can select — the l402 key stays configured so GetTierFromStripePriceId can still resolve webhook and portal events for existing Business subscribers; it is not offered to new customers (Business is contact-only, see Subscription & Plan Enforcement).

Only PriceId is load-bearing. Name, Description, PriceCents, and Features are display values, and TrialEligible here is not read by anything — trial eligibility comes from the plan table in PlanTierService, so setting "TrialEligible": false on a block does not suppress the trial. Use Stripe:TrialPeriodDays for that.

Live keys: individual and l402. l402microtransactions is also accepted as a spelling of l402GetPriceId matches on tier identity in both directions, so a config keyed either way resolves the same price for either spelling of the request.

Free has no key here. It is not purchasable through Stripe, so it has no price ID.

Note — these keys are checkout-selection identifiers, not the stored Merchant.PlanTier value. The checkout flow looks up a PriceId by this key (StripeSettings.GetPriceId), and the Stripe webhook then derives the tier persisted to Merchant.PlanTier from the PriceId via PlanTierService.GetTierFromStripePriceIdnot from this key. A key therefore does not have to match the resulting tier ID.

Note — a retired key never prices a live checkout. Configurations written before September 2026 may still carry a standaloneapi or kenticocommerce block. Two things keep it inert. First, a request naming a retired tier never reaches the lookup: POST /api/stripe/create-checkout-session accepts only individuall402 and l402microtransactions are also rejected with a 400 since the September 2026 repricing made Business contact-only. Second, when GetPriceId falls back to matching config keys by tier identity, it considers only keys that name a tier still on offer — so a retired key is skipped rather than treated as a synonym for Individual. That is deliberate: the retired Kentico block carries its own price, distinct from either live plan, and matching it would charge the wrong amount. Delete retired blocks when convenient.

Payment Provider Configuration

Lightning Enable supports multiple payment providers. These settings control the platform-wide defaults; each merchant supplies their own provider API key via the dashboard or merchant API.

Default Provider

PaymentProvider__Default=Strike

Values: Strike (default) or OpenNode

This sets the default provider for merchants that don't have an explicit provider configured. Per-merchant provider selection is available via the merchant settings API.

Strike Configuration

PaymentProvider__Strike__BaseUrl=https://api.strike.me/v1
SettingDefaultDescription
PaymentProvider:Strike:BaseUrlhttps://api.strike.me/v1Strike API base URL. Use https://api.dev.strike.me/v1 for sandbox. Platform-wide — not selectable per merchant.

Merchants configure their Strike API key via the merchant settings API. The key is encrypted at rest using AES-256-GCM.

Strike vs OpenNode
FeatureStrikeOpenNode
Invoice creation2-step (create + quote)Single step
Preimage supportDirect from APIParsed from BOLT11
Native refundsNo (uses payment-quotes)Yes
Webhook formatThin (entityId only)Full payload
CurrenciesBTC, USD, EUR, GBPBTC, USD
Best forL402, general paymentsRefund-heavy workflows

OpenNode Environment

OpenNode__Environment=production

Values:

Platform-wide — the hosted platform runs against OpenNode production, so merchants use production OpenNode API keys.

Webhook URL (Optional)

PaymentProvider__WebhookUrl=https://api.lightningenable.com/api/webhooks/opennode

Purpose: Override auto-detected webhook URL. Used as the callback URL for all payment providers (OpenNode and Strike).

Auto-detection order:

  1. PaymentProvider:WebhookUrl from config (if set)
  2. WEBSITE_HOSTNAME environment variable (Azure App Service)
  3. APP_URL environment variable (custom deployment)
  4. localhost:5096 (local development fallback)

L402 Configuration

Root Key

L402_ROOT_KEY=your-secret-l402-root-key

Purpose: Secret key for macaroon signing. Required in production.

caution

In development, a default key is used. Always set this in production.

L402 Options (appsettings.json)

{
"L402": {
"Enabled": true,
"ServiceName": "lightning-enable",
"Location": "https://api.lightningenable.com",
"DefaultPriceSats": 100,
"InvoiceExpirySeconds": 600,
"DefaultTokenValiditySeconds": 3600,
"CacheVerifiedTokens": true,
"TokenCacheSeconds": 300,
"AllowLegacyLsatScheme": true,
"MaxProxyRequestBodyBytes": 1048576,
"MaxProxyResponseBodyBytes": 10485760,
"ProtectedPaths": ["/api/l402/*"],
"ExcludedPaths": ["/api/l402/pricing", "/api/l402/status"],
"EndpointPricing": [
{
"PathPattern": "/api/l402/demo",
"PriceSats": 1,
"ServiceName": "demo",
"TokenValiditySeconds": 3600
}
]
}
}
SettingDefaultDescription
EnabledtrueEnable L402 authentication middleware
ServiceNamelightning-enableService identifier in macaroons
Location-Base URL for the service
DefaultPriceSats100Default price in satoshis for unpriced endpoints
InvoiceExpirySeconds600Lightning invoice expiry (10 min)
DefaultTokenValiditySeconds3600Token validity period (1 hour)
CacheVerifiedTokenstrueCache verified tokens for performance
TokenCacheSeconds300Token cache duration (5 min)
AllowLegacyLsatSchemetrueAccept the legacy "LSAT" auth scheme in addition to "L402"
MaxProxyRequestBodyBytes1048576Max request body size through L402 proxy (1 MB). Set to 0 to disable
MaxProxyResponseBodyBytes10485760Max response body size through L402 proxy (10 MB). Set to 0 to disable
ProtectedPaths[]Glob patterns for protected endpoints
ExcludedPaths[]Glob patterns to exclude from L402
EndpointPricing[]Per-endpoint pricing rules (array of PathPattern, PriceSats, ServiceName, TokenValiditySeconds)

Email Configuration

Lightning Enable sends transactional email (magic links, trial reminders, payment confirmations) via SMTP or Microsoft Graph, configured under the Email section (Email__Provider, Email__SmtpHost, etc. — see EmailSettings).

Send Timeout

Email__SmtpTimeoutSeconds=15

Purpose: Bounds one email send — the whole SMTP connect + authenticate + send sequence, or the outbound Microsoft Graph API call — to a single budget. MailKit's own per-stage SMTP default is roughly 100 seconds, so a hung or unreachable mail server could otherwise hold a request thread for minutes across the three stages combined. Several sends happen inline on request paths (Stripe webhook handling, magic-link delivery), so a slow mail server could make an upstream caller like Stripe time out and retry.

Default: 15 seconds. Valid range: 1120, validated at startup — an out-of-range value fails host startup rather than degrading silently.

CORS Configuration

{
"AllowedOrigins": [
"https://yourapp.com",
"https://admin.yourapp.com"
]
}

Purpose: Restrict browser-based API access to specific domains.

  • Production: List all legitimate client domains
  • Development: Automatically allows common localhost ports
  • Empty array: API not accessible from browsers

Merchant-specific origins (e.g., Shopify storefronts) are additionally covered by the dynamic per-merchant origin registry — merchants don't need entries here.

Logging Configuration

{
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"WriteTo": [
{ "Name": "Console" },
{
"Name": "File",
"Args": {
"path": "logs/lightning-enable-.txt",
"rollingInterval": "Day"
}
}
]
}
}

Development Configuration

For local development, use appsettings.Development.json:

{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=LightningEnable;Trusted_Connection=True;"
},
"AdminApiKey": "DEV-ADMIN-KEY-FOR-LOCAL-TESTING",
"OpenNode": {
"Environment": "dev"
},
"Stripe": {
"SecretKey": "sk_test_xxxxx",
"PublishableKey": "pk_test_xxxxx",
"WebhookSecret": "whsec_xxxxx",
"BaseUrl": "http://localhost:5096"
}
}

Default encryption key in development:

DEV-ENCRYPTION-KEY-DO-NOT-USE-IN-PRODUCTION-12345678

Production Checklist

Before deploying to production, ensure:

  • DB_ENCRYPTION_KEY is set and backed up securely
  • ADMIN_API_KEY is set to a secure value
  • ASPNETCORE_ENVIRONMENT=Production
  • Database connection string configured for production SQL Server
  • PaymentProvider__Default set (Strike recommended)
  • OpenNode:Environment=production for mainnet (if any merchants use OpenNode)
  • Stripe live keys configured (sk_live_..., pk_live_...)
  • Stripe webhook endpoint created in Stripe Dashboard
  • AllowedOrigins restricted to legitimate domains
  • L402_ROOT_KEY set (if using L402)
  • SSL/TLS certificate configured
  • Database migrations applied

Azure App Service Configuration

When deploying to Azure App Service, set these application settings:

Setting NameValue
ASPNETCORE_ENVIRONMENTProduction
DB_ENCRYPTION_KEY(from Key Vault)
ADMIN_API_KEY(from Key Vault)
L402_ROOT_KEY(from Key Vault)
ConnectionStrings__DefaultConnection(Azure SQL connection)
Stripe__SecretKey(from Key Vault)
Stripe__PublishableKeypk_live_...
Stripe__WebhookSecret(from Key Vault)
Stripe__BaseUrlhttps://api.lightningenable.com
PaymentProvider__DefaultStrike
OpenNode__Environmentproduction (if any merchants use OpenNode)
Use Key Vault References

For sensitive values, use Azure Key Vault references:

@Microsoft.KeyVault(SecretUri=https://your-vault.vault.azure.net/secrets/DB-ENCRYPTION-KEY/)

Next Steps