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
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your merchant API key |
Content-Type | Yes | application/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
| Field | Type | Required | Description |
|---|---|---|---|
orderId | string | Yes | Your unique order identifier (1–100 chars) |
amount | decimal | Yes | Payment amount in currency. 0 creates a demo invoice that auto-confirms without real payment |
currency | string | Yes | Uppercase 3-letter code (USD, EUR, GBP, BTC) — anything else fails validation |
description | string | No | Payment description (max 500 chars) |
customerEmail | string | No | Customer email for receipt |
customerName | string | No | Customer name (max 200 chars) |
successUrl | string | No | URL to send the customer to after payment |
metadata | object | No | Custom 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"
}
| Field | Notes |
|---|---|
invoiceId | Lightning Enable invoice ID — a numeric string (e.g. "1042"). Use it for status lookups |
lightningInvoice | BOLT11 invoice to display / encode as a QR code |
paymentHash | The invoice's payment hash — use this instead of parsing the BOLT11 yourself |
onchainAddress | On-chain fallback address, when the provider supplies one |
hostedCheckoutUrl | Provider-hosted checkout page — OpenNode only; empty for Strike merchants |
expiresAt | When the invoice expires — always honor this field (see Invoice Expiration) |
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
| Parameter | Type | Description |
|---|---|---|
invoiceId | string | Lightning 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
| Parameter | Type | Description |
|---|---|---|
orderId | string | Your 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
| Parameter | Type | Description |
|---|---|---|
invoiceId | string | Lightning 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
| Status | Description |
|---|---|
unpaid | Invoice created, awaiting payment |
processing | Payment detected, confirming |
paid | Payment confirmed |
expired | Invoice expired without payment |
refunded | Payment 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
| Currency | Code | Notes |
|---|---|---|
| US Dollar | USD | Converted to BTC at current rate |
| Euro | EUR | Converted to BTC at current rate |
| British Pound | GBP | Converted to BTC at current rate |
| Bitcoin | BTC | Direct 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()