Skip to main content

Payments API

Create Lightning invoices and manage payment status.

Create Payment

Create a new Lightning invoice for a customer payment.

POST /api/payments

Request Headers

HeaderRequiredDescription
X-API-KeyYesYour merchant API key
Content-TypeYesapplication/json

Request Body

{
"orderId": "ORDER-12345",
"amount": 49.99,
"currency": "USD",
"description": "Premium Subscription",
"customerEmail": "customer@example.com",
"metadata": {
"productId": "prod_123",
"userId": "user_456"
}
}

Parameters

FieldTypeRequiredDescription
orderIdstringYesYour unique order identifier (1–100 chars)
amountdecimalYesPayment amount in currency. 0 creates a demo invoice that auto-confirms without real payment
currencystringYesUppercase 3-letter code (USD, EUR, GBP, BTC) — anything else fails validation
descriptionstringNoPayment description (max 500 chars)
customerEmailstringNoCustomer email for receipt
customerNamestringNoCustomer name (max 200 chars)
successUrlstringNoURL to send the customer to after payment
metadataobjectNoCustom key-value data — string values only

Response

{
"invoiceId": "1042",
"status": "unpaid",
"amount": 49.99,
"currency": "USD",
"lightningInvoice": "lnbc1250000n1pnxyz...",
"paymentHash": "a1b2c3d4e5f6...",
"onchainAddress": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
"hostedCheckoutUrl": "https://checkout.opennode.com/abc123",
"providerChargeId": "charge_abc123",
"openNodeChargeId": "charge_abc123",
"createdAt": "2026-07-03T12:00:00Z",
"expiresAt": "2026-07-03T13:00:00Z"
}
FieldNotes
invoiceIdLightning Enable invoice ID — a numeric string (e.g. "1042"). Use it for status lookups
lightningInvoiceBOLT11 invoice to display / encode as a QR code
paymentHashThe invoice's payment hash — use this instead of parsing the BOLT11 yourself
onchainAddressOn-chain fallback address, when the provider supplies one
hostedCheckoutUrlProvider-hosted checkout page — OpenNode only; empty for Strike merchants
expiresAtWhen the invoice expires — always honor this field (see Invoice Expiration)
Provider Charge IDs

providerChargeId is the provider-agnostic charge identifier that works with both Strike and OpenNode. openNodeChargeId is retained for backward compatibility and will always be populated alongside providerChargeId.

Example

curl -X POST https://api.lightningenable.com/api/payments \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"orderId": "ORDER-12345",
"amount": 49.99,
"currency": "USD",
"description": "Premium Subscription"
}'

Get Payment by Invoice ID

Retrieve payment details by Lightning Enable invoice ID.

GET /api/payments/{invoiceId}

Parameters

ParameterTypeDescription
invoiceIdstringLightning Enable invoice ID

Response

{
"invoiceId": "1042",
"orderId": "ORDER-12345",
"providerChargeId": "charge_abc123",
"openNodeChargeId": "charge_abc123",
"status": "paid",
"amount": 49.99,
"currency": "USD",
"lightningInvoice": "lnbc1250000n1pnxyz...",
"onchainAddress": "bc1qxy2...",
"hostedCheckoutUrl": "https://checkout.opennode.com/abc123",
"createdAt": "2026-07-03T12:00:00Z",
"paidAt": "2026-07-03T12:05:00Z",
"expiresAt": "2026-07-03T13:00:00Z"
}

Example

curl https://api.lightningenable.com/api/payments/1042 \
-H "X-API-Key: YOUR_API_KEY"

Public Payment Status (browser polling)

GET /api/payments/{invoiceId}/status

No API key required. Returns only { "status": "..." }, so it is safe to call from client-side code — this is the endpoint your checkout page should poll instead of embedding your API key in the browser:

{ "status": "paid" }
// Browser-safe polling
const { status } = await (await fetch(
`https://api.lightningenable.com/api/payments/${invoiceId}/status`
)).json();

Fulfillment decisions belong on your server — use webhooks or the authenticated endpoints above for the authoritative record.

Get Payment by Order ID

Retrieve payment details by your order ID.

GET /api/payments/order/{orderId}

Parameters

ParameterTypeDescription
orderIdstringYour order identifier

Response

Same as Get Payment by Invoice ID.

Example

curl https://api.lightningenable.com/api/payments/order/ORDER-12345 \
-H "X-API-Key: YOUR_API_KEY"

Sync Payment Status

Force sync payment status from the payment provider. Useful if webhook was delayed.

POST /api/payments/{invoiceId}/sync

Parameters

ParameterTypeDescription
invoiceIdstringLightning Enable invoice ID

Response

Returns updated payment object with current status.

Example

curl -X POST https://api.lightningenable.com/api/payments/1042/sync \
-H "X-API-Key: YOUR_API_KEY"

Payment Statuses

StatusDescription
unpaidInvoice created, awaiting payment
processingPayment detected, confirming
paidPayment confirmed
expiredInvoice expired without payment
refundedPayment was refunded

Payment Flow

1. Create Payment
POST /api/payments
Returns: invoiceId, lightningInvoice

2. Display to Customer
Show QR code or invoice string
Customer pays with Lightning wallet

3. Payment Confirmed
Webhook notification sent
Or poll GET /api/payments/{invoiceId}

4. Fulfill Order
When status = "paid", deliver goods/services

Supported Currencies

CurrencyCodeNotes
US DollarUSDConverted to BTC at current rate
EuroEURConverted to BTC at current rate
British PoundGBPConverted to BTC at current rate
BitcoinBTCDirect amount as a decimal with up to 8 places — for satoshi precision, use BTC (e.g. 0.00062500 = 62,500 sats)

Currency codes must be uppercase 3-letter values — there is no sats currency code; lowercase or 4-letter values fail validation with a 400.

Invoice Expiration

Expiration is provider-dependent — always read the expiresAt field from the response instead of assuming a window:

  • Strike (recommended default): ~60 minutes
  • OpenNode: the provider's invoice TTL
  • Demo invoices (amount: 0): 10 minutes

After expiration an invoice cannot be paid — create a new payment.

Error Responses

Errors are plain JSON with an error field (and no machine-readable code field — dispatch on HTTP status):

// 400 — business validation (e.g. duplicate order)
{ "error": "Invoice already exists for OrderId ORDER-12345" }

// 404 — unknown invoice / wrong merchant
{ "error": "Invoice not found" }

Model-binding failures (missing orderId, malformed currency, negative amount) return the standard ASP.NET validation problem shape — a 400 with an errors dictionary keyed by field name. See Errors for the full contract.

Code Examples

JavaScript

async function createPayment(orderId, amount, currency) {
const response = await fetch('https://api.lightningenable.com/api/payments', {
method: 'POST',
headers: {
'X-API-Key': process.env.LIGHTNING_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({ orderId, amount, currency })
});

if (!response.ok) {
throw new Error(`Payment failed: ${response.statusText}`);
}

return response.json();
}

// Usage
const payment = await createPayment('ORDER-123', 49.99, 'USD');
console.log('Lightning Invoice:', payment.lightningInvoice);

C#

public async Task<PaymentResponse> CreatePaymentAsync(
string orderId,
decimal amount,
string currency)
{
var request = new
{
orderId,
amount,
currency
};

var response = await _httpClient.PostAsJsonAsync("/api/payments", request);
response.EnsureSuccessStatusCode();

return await response.Content.ReadFromJsonAsync<PaymentResponse>();
}

Python

import requests

def create_payment(order_id, amount, currency):
response = requests.post(
'https://api.lightningenable.com/api/payments',
headers={
'X-API-Key': os.environ['LIGHTNING_API_KEY'],
'Content-Type': 'application/json'
},
json={
'orderId': order_id,
'amount': amount,
'currency': currency
}
)
response.raise_for_status()
return response.json()

Next Steps