Skip to main content

Error Code Reference

This comprehensive guide documents all error codes returned by the Lightning Enable API, organized by domain. Use this reference to implement robust error handling in your integration.

Error Response Format

All API errors return a consistent JSON structure:

{
"error": "Error Type",
"message": "Human-readable description of the error",
"code": "MACHINE_READABLE_CODE",
"details": {
"additional": "context"
}
}
FieldTypeDescription
errorstringHTTP status text (e.g., "Unauthorized", "Bad Request")
messagestringHuman-readable error description
codestringMachine-readable error code for programmatic handling
detailsobjectAdditional context (optional, varies by error)

Every error response also includes an X-Correlation-Id response header that you can use when contacting support. See Request Headers for details.

Unhandled Exceptions

Unhandled server errors return a correlation ID for support inquiries:

{
"error": "An error occurred processing your request.",
"correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"timestamp": "2026-01-09T12:00:00Z"
}

The correlationId field in the JSON body matches the X-Correlation-Id response header. Include this value in any support requests to help us locate your request in our logs.

Error Sanitization (Production vs. Development)

In production, error responses for unhandled exceptions are sanitized to prevent leaking internal details. You will only see a generic error message, a correlation ID, and a timestamp.

In development, additional debugging fields are included:

{
"error": "An error occurred processing your request.",
"correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"timestamp": "2026-01-09T12:00:00Z",
"detail": "Specific exception message",
"exceptionType": "System.InvalidOperationException",
"stackTrace": "..."
}
warning

The detail, exceptionType, and stackTrace fields are never included in production responses. Do not write code that depends on these fields in production.

HTTP Status Codes

Success Codes

CodeMeaningWhen Used
200 OKRequest succeededGET, PUT, POST (when returning data)
201 CreatedResource createdPOST when creating payments, refunds, proxies
204 No ContentSuccess, no response bodyDELETE operations

Client Error Codes

CodeMeaningCommon Causes
400 Bad RequestInvalid requestMissing required fields, invalid format, validation errors
401 UnauthorizedAuthentication failedMissing/invalid API key, expired credentials
402 Payment RequiredL402 payment neededAccessing L402-protected endpoints without valid token
403 ForbiddenAccess deniedInactive account, subscription issues, feature not available
404 Not FoundResource not foundInvalid invoice ID, order ID, proxy ID
409 ConflictResource conflictDuplicate order ID, concurrent modification
422 Unprocessable EntitySemantic errorValid syntax but business logic violation
429 Too Many RequestsRate limit exceededToo many requests in time window

Server Error Codes

CodeMeaningWhen Used
500 Internal Server ErrorServer errorUnexpected errors, includes correlationId
502 Bad GatewayUpstream errorOpenNode/Stripe API failures, target API unreachable
503 Service UnavailableTemporary outageMaintenance, circuit breaker open
504 Gateway TimeoutUpstream timeoutOpenNode/target API timeout

Authentication Errors

Missing API Key

HTTP Status: 401 Unauthorized

{
"error": "API key required",
"message": "Please provide API key in X-API-Key header"
}

Cause: Request missing the X-API-Key header.

Solution: Include your API key in every request:

curl -H "X-API-Key: lgw_your_api_key_here" https://api.lightningenable.com/api/payments

Invalid API Key

HTTP Status: 401 Unauthorized

{
"error": "Invalid API key",
"message": "The provided API key is invalid or inactive"
}

Cause: API key doesn't match any active merchant account.

Solution:

  • Verify you're using the correct API key
  • Check if your account is active
  • Contact support if you've lost your API key

Invalid Admin API Key

HTTP Status: 401 Unauthorized

{
"error": "Unauthorized",
"message": "Invalid admin API key"
}

Cause: Admin endpoint accessed with incorrect admin credentials.

Solution: Use the correct admin API key for /api/admin/* endpoints.

Server Configuration Error

HTTP Status: 500 Internal Server Error

{
"error": "Server configuration error"
}

Cause: Admin API key not configured on server.

Solution: Contact system administrator.


Subscription Errors

Account Inactive

HTTP Status: 403 Forbidden

{
"error": "Account inactive",
"message": "Your account is inactive. Please contact support.",
"action_required": "contact_support"
}

Cause: Merchant account has been deactivated.

Solution: Contact support@lightningenable.com to reactivate.

Subscription Required

HTTP Status: 403 Forbidden

{
"error": "Subscription required",
"message": "Your plan tier requires an active subscription. Please subscribe to continue using the service.",
"current_plan": "standard",
"action_required": "subscribe"
}

Cause: Non-pilot tier account without valid Stripe subscription.

Solution: Subscribe at lightningenable.com.

Subscription Not Active

HTTP Status: 403 Forbidden

{
"error": "Subscription not active",
"message": "Your subscription payment is past due. Please update your payment method to continue using the service.",
"subscription_status": "past_due",
"action_required": "update_payment_method"
}

Possible Status Values:

StatusMessageAction Required
past_duePayment is past dueupdate_payment_method
canceledSubscription canceledrenew_subscription
unpaidSubscription unpaidupdate_payment_method
incompleteSetup incompleteComplete payment process
incomplete_expiredSetup expiredStart new subscription

Subscription Period Expired

HTTP Status: 403 Forbidden

{
"error": "Subscription period expired",
"message": "Your subscription billing period has expired. Please renew your subscription to continue using the service.",
"subscription_status": "active",
"current_period_end": "2026-01-15T00:00:00.0000000Z",
"action_required": "renew_subscription"
}

Cause: The subscription's CurrentPeriodEnd has passed even though the status may still show active. This typically occurs when a Stripe webhook is delayed. The middleware catches expired billing periods as a safety net.

Solution: Renew your subscription or wait for Stripe to process the renewal. If your payment method is valid, this should resolve automatically once the Stripe webhook updates the billing period.

Feature Not Available

HTTP Status: 403 Forbidden

{
"error": "Feature not available",
"message": "Refund processing is not enabled for your account. Please contact support.",
"feature": "refunds",
"current_plan": "pilot",
"required_plan": "standard",
"action_required": "upgrade_plan"
}

Feature-to-Plan Requirements:

FeatureRequired PlanEndpoint
refundsKentico Commerce+/api/refunds
multi_currencyKentico Commerce+/api/payments/convert
l402Agentic Commerce/api/proxy, /l402/proxy

See Subscription & Plan Enforcement for full details on plan tiers and feature gating.


Payment Errors

Payment Not Found

HTTP Status: 404 Not Found

{
"error": "Payment not found"
}

Cause: Invoice ID doesn't exist or doesn't belong to your merchant account.

Solution: Verify the invoice ID is correct and belongs to your account.

Invalid Payment Request

HTTP Status: 400 Bad Request

{
"error": "Invalid request"
}

Common Validation Errors:

  • Amount must be greater than 0
  • Currency must be supported (USD, EUR, GBP, BTC, sats)
  • Order ID is required
  • Invalid callback URL format

Duplicate Order

HTTP Status: 409 Conflict

{
"error": "Order already exists",
"details": {
"orderId": "ORDER-123",
"existingInvoiceId": "inv_abc123"
}
}

Cause: A payment with this order ID already exists.

Solution: Use unique order IDs for each payment request.


Refund Errors

Invalid Refund Request

HTTP Status: 400 Bad Request

{
"error": "Cannot refund: invoice status is 'pending'"
}

Refundable Statuses: Only invoices with status paid, underpaid, or processing can be refunded.

Refund Not Found

HTTP Status: 404 Not Found

{
"error": "Refund not found"
}

Invoice Not Found (for refund)

HTTP Status: 404 Not Found

{
"error": "Invoice not found"
}

L402 Protocol Errors

Payment Required (402)

HTTP Status: 402 Payment Required

Headers:

WWW-Authenticate: L402 macaroon="AgEB...", invoice="lnbc..."
X-L402-Error: No Authorization header provided

Body:

{
"error": "Payment Required",
"message": "Pay the Lightning invoice to access this API",
"proxy": {
"id": "my-api-1234",
"name": "My API",
"description": "AI services monetized with Lightning"
},
"l402": {
"macaroon": "AgEBYXBpLmxpZ2h0bmluZ2VuYWJsZS5jb20...",
"invoice": "lnbc100n1pj...",
"amount_sats": 100,
"payment_hash": "abc123...",
"expires_at": "2026-01-09T13:00:00Z"
},
"instructions": {
"step1": "Pay the Lightning invoice using any Lightning wallet",
"step2": "Copy the preimage (proof of payment) from your wallet",
"step3": "Include in request: Authorization: L402 <macaroon>:<preimage>"
}
}

Invalid L402 Credential

HTTP Status: 402 Payment Required

Header: X-L402-Error: Invalid L402 format. Expected: L402 <macaroon>:<preimage>

Common L402 Errors:

Error MessageCause
No Authorization header providedMissing Authorization header
Invalid authorization schemeUsing Basic/Bearer instead of L402
Invalid L402 formatMalformed macaroon:preimage format
Preimage does not match payment hashIncorrect preimage
L402 verification failedInvalid or expired macaroon

Proxy Not Found

HTTP Status: 404 Not Found

{
"error": "Proxy not found",
"message": "No active proxy configuration found for ID: invalid-proxy"
}

Proxy Unavailable

HTTP Status: 404 Not Found

{
"error": "Proxy unavailable",
"message": "This API proxy is currently unavailable"
}

Cause: The merchant account owning the proxy is inactive.

L402 Proxy Gateway Errors

Bad Gateway (502):

{
"error": "Bad Gateway",
"message": "Unable to connect to the target API",
"proxy_id": "my-api-1234",
"details": "Connection refused"
}

Gateway Timeout (504):

{
"error": "Gateway Timeout",
"message": "The target API did not respond in time",
"proxy_id": "my-api-1234"
}

Webhook Errors

Invalid Webhook Payload

HTTP Status: 400 Bad Request

{
"error": "Invalid JSON",
"details": "Unexpected character at position 42"
}

Invalid Payload Structure

HTTP Status: 400 Bad Request

{
"error": "Invalid payload"
}

Invoice Not Found (Webhook)

HTTP Status: 404 Not Found

{
"error": "Invoice not found"
}

Cause: Webhook received for unknown OpenNode charge ID.

Invalid Webhook Signature

HTTP Status: 401 Unauthorized

{
"error": "Invalid signature"
}

Cause: OpenNode webhook signature verification failed.

Solution: Ensure your OpenNode API key is correctly configured.

Webhook Signature Required (Production)

HTTP Status: 401 Unauthorized

{
"error": "Webhook signature verification required in production"
}

Cause: In production, all webhooks must include verifiable signatures.

Invalid Stripe Signature

HTTP Status: 400 Bad Request

{
"error": "Invalid signature"
}

Cause: Stripe webhook signature verification failed.


Rate Limiting Errors

Rate Limit Exceeded

HTTP Status: 429 Too Many Requests

Headers:

Retry-After: 45
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1704067200

Body:

{
"error": "Too Many Requests",
"message": "Rate limit exceeded",
"code": "RATE_LIMIT_EXCEEDED",
"details": {
"limit": 100,
"window": "1 minute",
"retryAfter": 45
}
}

Rate Limits by Policy:

PolicyLimitWindowEndpoints
Global1001 minAll authenticated requests
Read2001 minGET operations
Payment Create101 minPOST /api/payments, refunds
Checkout Create51 minStripe checkout
Admin301 min/api/admin/*

Solution: Wait for Retry-After seconds, then retry.


OpenNode Integration Errors

OpenNode API Error

HTTP Status: 502 Bad Gateway

{
"error": "OpenNode API error",
"details": "Invalid API key"
}

Common OpenNode Errors:

  • Invalid API key
  • Insufficient balance
  • Invalid charge request
  • Rate limited by OpenNode

OpenNode Timeout

HTTP Status: 504 Gateway Timeout

{
"error": "OpenNode request timed out"
}

Solution: Retry the request. OpenNode has a 30-second timeout.

OpenNode Circuit Breaker Open

When OpenNode experiences multiple consecutive failures, the circuit breaker opens:

HTTP Status: 503 Service Unavailable

The circuit breaker:

  • Opens after 5 consecutive failures
  • Stays open for 30 seconds
  • Automatically tests recovery in half-open state

Stripe Integration Errors

Checkout Session Errors

HTTP Status: 400 Bad Request

{
"error": "Failed to create checkout session. Please try again."
}

Common Causes:

  • Invalid email format
  • Missing required fields
  • Stripe API error

Subscription Result Errors

Missing Session ID:

{
"error": "session_id is required"
}

Session Not Found:

{
"error": "Checkout session not found"
}

Payment Not Completed:

{
"error": "Payment not completed",
"paymentStatus": "unpaid"
}

Customer Not Found:

{
"error": "Customer not found for this session"
}

Merchant Not Found:

{
"error": "Merchant account not found. Please wait a moment and try again."
}

Customer Portal Errors

HTTP Status: 401 Unauthorized

{
"error": "API key authentication required"
}

HTTP Status: 400 Bad Request

{
"error": "No Stripe customer ID associated with this account"
}

Proxy Management Errors

Invalid Target URL

HTTP Status: 400 Bad Request

{
"error": "Invalid target URL. Must be a valid HTTP or HTTPS URL."
}

Invalid Path Pattern

HTTP Status: 400 Bad Request

{
"error": "Invalid path pattern. Must start with '/' and be a valid glob pattern."
}

Proxy Not Found

HTTP Status: 404 Not Found

{
"error": "Proxy not found"
}

Endpoint Pricing Not Found

HTTP Status: 404 Not Found

{
"error": "Endpoint pricing not found"
}

Merchant Settings Errors

Authentication Required

HTTP Status: 401 Unauthorized

{
"error": "Authentication required"
}

Merchant Not Found

HTTP Status: 404 Not Found

{
"error": "Merchant not found"
}

Invalid OpenNode Key

HTTP Status: 400 Bad Request

{
"error": "OpenNode API key is required"
}

Invalid Webhook URL

HTTP Status: 400 Bad Request

{
"error": "Invalid webhook URL format"
}

Error Handling Best Practices

1. Always Check HTTP Status First

const response = await fetch(url, options);

if (!response.ok) {
const error = await response.json();
throw new ApiError(response.status, error);
}

return response.json();

2. Handle Errors by Code

class ApiError extends Error {
constructor(status, data) {
super(data.message);
this.status = status;
this.code = data.code;
this.details = data.details;
}
}

function handleError(error) {
switch (error.code) {
case 'RATE_LIMIT_EXCEEDED':
const retryAfter = error.details?.retryAfter || 60;
return scheduleRetry(retryAfter);

case 'INVALID_API_KEY':
return showConfigurationError('Check your API key');

case 'SUBSCRIPTION_REQUIRED':
return redirectToSubscription();

default:
return logAndAlert(error);
}
}

3. Implement Retry Logic

async function withRetry(fn, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
if (!isRetryable(error) || attempt === maxRetries) {
throw error;
}

const delay = Math.min(1000 * Math.pow(2, attempt), 30000);
await new Promise(r => setTimeout(r, delay));
}
}
}

function isRetryable(error) {
// Retry server errors and rate limits
if (error.status >= 500) return true;
if (error.status === 429) return true;
if (error.code === 'OPENNODE_TIMEOUT') return true;
return false;
}

4. Log Errors with Context

function logError(error, context) {
console.error({
timestamp: new Date().toISOString(),
status: error.status,
code: error.code,
message: error.message,
correlationId: error.correlationId,
context: {
endpoint: context.endpoint,
orderId: context.orderId,
merchantId: context.merchantId
}
});
}

5. User-Friendly Messages

const userMessages = {
'INVALID_API_KEY': 'Authentication failed. Please check your settings.',
'RATE_LIMIT_EXCEEDED': 'Too many requests. Please wait a moment.',
'PAYMENT_NOT_FOUND': 'Payment not found. It may have expired.',
'SUBSCRIPTION_REQUIRED': 'Please subscribe to continue.',
'OPENNODE_ERROR': 'Payment service temporarily unavailable.'
};

function getUserMessage(error) {
return userMessages[error.code] || 'An error occurred. Please try again.';
}

Retry Strategy Summary

Error TypeRetry?Strategy
400 Bad RequestNoFix request data
401 UnauthorizedNoFix credentials
402 Payment RequiredNoComplete payment
403 ForbiddenNoCheck subscription/features
404 Not FoundNoCheck resource ID
429 Rate LimitedYesWait for Retry-After
500 Server ErrorYesExponential backoff
502 Bad GatewayYesExponential backoff
503 Service UnavailableYesWait, then retry
504 Gateway TimeoutYesRetry immediately

Next Steps