Refunds API
Process refunds for completed Lightning payments.
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 outgoing Lightning payments from your payment provider account to the customer's wallet.
Original Payment: Customer → Payment Provider → Your Account
Refund: Your Account → Payment Provider → Customer Wallet
Strike does not have a native refund API. Refunds via Strike are implemented as outgoing payments using Strike's payment-quotes flow — the mechanics are the same from the API perspective, but the underlying provider call differs.
OpenNode processes refunds as standard outgoing payments from your OpenNode account balance.
Requirements:
- Original payment must be in
paidstatus - Customer provides a Lightning invoice for the refund amount
- Sufficient balance in your payment provider 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 |
|---|---|---|---|
skip | int | 0 | Number of records to skip |
take | int | 50 | Items to return (max 100) |
status | string | all | Filter by status |
Response
{
"data": [
{
"refundId": "ref_xyz789abc",
"invoiceId": "inv_abc123def456",
"status": "completed",
"amount": 49.99,
"currency": "USD"
}
],
"total": 1,
"skip": 0,
"take": 50
}
Example
curl "https://api.lightningenable.com/api/refunds?skip=0&take=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 payment provider 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 payment provider 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