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
paidstatus - 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
| Header | Required | Description |
|---|---|---|
X-API-Key | Yes | Your merchant API key |
Content-Type | Yes | application/json |
Request Body
{
"invoiceId": "inv_abc123def456",
"amount": 49.99,
"currency": "USD",
"lightningInvoice": "lnbc499900n1pnxyz...",
"reason": "Customer requested refund"
}
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
invoiceId | string | Yes | Original invoice ID to refund |
amount | decimal | Yes | Refund amount |
currency | string | Yes | Currency (must match original) |
lightningInvoice | string | Yes | Customer's Lightning invoice |
reason | string | No | Reason 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
| Parameter | Type | Description |
|---|---|---|
refundId | string | Refund 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
| Parameter | Type | Default | Description |
|---|---|---|---|
page | int | 1 | Page number |
pageSize | int | 20 | Items per page (max 100) |
status | string | all | Filter 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
| Parameter | Type | Description |
|---|---|---|
invoiceId | string | Original 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
| Status | Description |
|---|---|
pending | Refund initiated, processing |
completed | Refund sent successfully |
failed | Refund 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
- Payments API - Create payments
- Webhooks - Refund notifications
- Errors - Error handling