Skip to main content

Refunds API

Process refunds for completed Lightning payments.

Plan Requirement

Refunds are available on all paid plans. Contact support@lightningenable.com to enable refunds.

How Refunds Work

Lightning payments are instant and irreversible. Refunds are processed as new Lightning payments from your OpenNode account to the customer's wallet.

Original Payment:  Customer → OpenNode → Your Account
Refund: Your Account → OpenNode → Customer Wallet

Requirements:

  • Original payment must be in paid status
  • Customer provides a Lightning invoice for the refund amount
  • Sufficient balance in your OpenNode account

Create Refund

Initiate a refund for a paid invoice.

POST /api/refunds

Request Headers

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

Request Body

{
"invoiceId": "inv_abc123def456",
"amount": 49.99,
"currency": "USD",
"lightningInvoice": "lnbc499900n1pnxyz...",
"reason": "Customer requested refund"
}

Parameters

FieldTypeRequiredDescription
invoiceIdstringYesOriginal invoice ID to refund
amountdecimalYesRefund amount
currencystringYesCurrency (must match original)
lightningInvoicestringYesCustomer's Lightning invoice
reasonstringNoReason for refund

Response

{
"refundId": "ref_xyz789abc",
"invoiceId": "inv_abc123def456",
"status": "pending",
"amount": 49.99,
"currency": "USD",
"amountSats": 125000,
"reason": "Customer requested refund",
"createdAt": "2024-12-29T14:00:00Z"
}

Example

curl -X POST https://api.lightningenable.com/api/refunds \
-H "X-API-Key: le_merchant_abc123" \
-H "Content-Type: application/json" \
-d '{
"invoiceId": "inv_abc123def456",
"amount": 49.99,
"currency": "USD",
"lightningInvoice": "lnbc499900n1pnxyz..."
}'

Get Refund

Retrieve refund details by ID.

GET /api/refunds/{refundId}

Parameters

ParameterTypeDescription
refundIdstringRefund identifier

Response

{
"refundId": "ref_xyz789abc",
"invoiceId": "inv_abc123def456",
"status": "completed",
"amount": 49.99,
"currency": "USD",
"amountSats": 125000,
"reason": "Customer requested refund",
"completedAt": "2024-12-29T14:01:00Z",
"createdAt": "2024-12-29T14:00:00Z"
}

Example

curl https://api.lightningenable.com/api/refunds/ref_xyz789abc \
-H "X-API-Key: le_merchant_abc123"

List Refunds

List all refunds for your account.

GET /api/refunds

Query Parameters

ParameterTypeDefaultDescription
pageint1Page number
pageSizeint20Items per page (max 100)
statusstringallFilter by status

Response

{
"data": [
{
"refundId": "ref_xyz789abc",
"invoiceId": "inv_abc123def456",
"status": "completed",
"amount": 49.99,
"currency": "USD"
}
],
"pagination": {
"page": 1,
"pageSize": 20,
"totalPages": 1,
"totalItems": 1
}
}

Example

curl "https://api.lightningenable.com/api/refunds?page=1&pageSize=20" \
-H "X-API-Key: le_merchant_abc123"

Get Refunds for Invoice

List all refunds for a specific invoice.

GET /api/refunds/invoice/{invoiceId}

Parameters

ParameterTypeDescription
invoiceIdstringOriginal invoice ID

Response

Returns array of refunds for the invoice.

Example

curl https://api.lightningenable.com/api/refunds/invoice/inv_abc123def456 \
-H "X-API-Key: le_merchant_abc123"

Refund Statuses

StatusDescription
pendingRefund initiated, processing
completedRefund sent successfully
failedRefund failed (insufficient balance, invalid invoice)

Partial Refunds

You can issue partial refunds by specifying an amount less than the original payment:

{
"invoiceId": "inv_abc123def456",
"amount": 25.00,
"currency": "USD",
"lightningInvoice": "lnbc250000n1..."
}

Notes:

  • Multiple partial refunds allowed
  • Total refunds cannot exceed original payment amount
  • Each partial refund requires a new customer Lightning invoice

Error Responses

Invoice Not Found

{
"error": "Not Found",
"message": "Invoice not found",
"code": "INVOICE_NOT_FOUND"
}

Invoice Not Paid

{
"error": "Bad Request",
"message": "Cannot refund unpaid invoice",
"code": "INVOICE_NOT_PAID"
}

Refund Exceeds Payment

{
"error": "Bad Request",
"message": "Refund amount exceeds original payment",
"code": "REFUND_EXCEEDS_PAYMENT"
}

Invalid Lightning Invoice

{
"error": "Bad Request",
"message": "Invalid Lightning invoice",
"code": "INVALID_LIGHTNING_INVOICE"
}

Insufficient Balance

{
"error": "Payment Failed",
"message": "Insufficient balance in OpenNode account",
"code": "INSUFFICIENT_BALANCE"
}

Feature Not Available

{
"error": "Forbidden",
"message": "Refunds not available on your plan",
"code": "FEATURE_NOT_AVAILABLE"
}

Code Examples

JavaScript

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

if (!response.ok) {
const error = await response.json();
throw new Error(error.message);
}

return response.json();
}

C#

public async Task<RefundResponse> CreateRefundAsync(
string invoiceId,
decimal amount,
string currency,
string lightningInvoice)
{
var request = new
{
invoiceId,
amount,
currency,
lightningInvoice
};

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

if (!response.IsSuccessStatusCode)
{
var error = await response.Content.ReadFromJsonAsync<ErrorResponse>();
throw new RefundException(error.Message);
}

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

Python

def create_refund(invoice_id, amount, currency, lightning_invoice):
response = requests.post(
'https://api.lightningenable.com/api/refunds',
headers={
'X-API-Key': os.environ['LIGHTNING_API_KEY'],
'Content-Type': 'application/json'
},
json={
'invoiceId': invoice_id,
'amount': amount,
'currency': currency,
'lightningInvoice': lightning_invoice
}
)
response.raise_for_status()
return response.json()

Best Practices

Collect Customer Invoice

Before initiating a refund, collect a valid Lightning invoice from the customer:

// Example refund flow
app.post('/refund-request', async (req, res) => {
const { orderId, lightningInvoice } = req.body;

// Verify the invoice is for correct amount
const originalPayment = await getPayment(orderId);

// Create refund
const refund = await createRefund(
originalPayment.invoiceId,
originalPayment.amount,
originalPayment.currency,
lightningInvoice
);

res.json({ status: 'Refund initiated', refundId: refund.refundId });
});

Handle Failures

Refunds can fail for various reasons. Always handle errors:

try {
const refund = await createRefund(...);
// Success
} catch (error) {
if (error.code === 'INSUFFICIENT_BALANCE') {
// Fund your OpenNode account
} else if (error.code === 'INVALID_LIGHTNING_INVOICE') {
// Ask customer for new invoice
}
}

Next Steps