Skip to content

User Guide

Welcome to the ElenPAY User Guide. This guide will help you integrate and use our payment system, covering deposits, withdrawals, webhooks, and best practices for a smooth experience.

API Documentation

You can find the full API reference here: ElenPAY API

Before You Start

Note: Store setup, API authentication, and webhook registration are handled by our operations team. Merchants do not need to configure these themselves. If you need to add a new store, change your store currency, or update webhook endpoints, please contact our support or ops team.

Error Handling

For details on API error responses, error codes, and troubleshooting failed requests, please refer to the API Documentation. The API docs include example error payloads and guidance on interpreting error messages.

Currency Support

Each store is configured to accept either BTC or a single fiat currency (e.g., USD, EUR). If you wish to accept payments in multiple currencies, you must request a separate store for each currency through our ops team. You do not need to provide the team with a different callback url.

Invoice Expiry

  • Lightning (Bolt11) invoices expire after 15 minutes by default.
  • You can set a custom expiration by including the checkout.expirationMinutes field (in minutes) in your invoice creation request (see API docs for details).
  • Payments cannot be made after expiry; the Lightning Network enforces this restriction.

Staging Environment

  • All integration and testing should be performed against our staging environment, referenced as api-staging.elenpay.tech in this guide.
  • The staging environment mirrors production but is safe for test transactions.

Deposits (Receiving Payments)

A deposit is the process of receiving a payment from an end user using the ElenPAY payment widget.

Flow:

  • The end user clicks "Checkout with Lightning" on your website.
  • Your backend creates an invoice by calling the ElenPAY API.
  • ElenPAY returns the invoice details, including a checkoutLink.
  • You display the checkout link to the user, which opens the ElenPAY payment widget.
  • The user pays through the widget using their preferred Lightning wallet.
  • ElenPAY notifies you of the payment status via webhook (settled or expired).

Sequence Diagram:

sequenceDiagram
  EndUser->>Merchant: Click on "Checkout with Lightning"
  Merchant->>ElenPAY: Create invoice
  ElenPAY-->>Merchant: Return invoice details (with checkoutLink)
  Merchant->>EndUser: Show checkout widget
  EndUser-->>ElenPAY: Pay with Lightning wallet
  ElenPAY->>Merchant: Webhook notification (settled, expired)

Deposit Widget

Redirecting to the Widget

When initiating a deposit, you can configure the redirectURL and redirectAutomatically fields. This will allow the widget to redirect to your website after a deposit is completed:

  • redirectURL: Specifies the URL where the customer will be redirected after payment completion. Make sure your url starts with https://
  • redirectAutomatically: If set to true, the widget will automatically redirect the customer to the redirectURL after payment completion. Otherwise, we will expose a button that the user can click for going back to your website.

Without Widget (Direct Bolt11)

A deposit can also be processed without the widget, by directly presenting the user with a Bolt11 invoice.

Flow:

  • The end user initiates a payment on your site.
  • Your backend creates an invoice by calling the ElenPAY API.
  • You obtain the Bolt11 invoice from the payment methods endpoint.
  • You display the Bolt11 invoice (QR code or string) to the user for payment.
  • ElenPAY notifies you of the payment status via webhook (settled or expired).

Sequence Diagram:

sequenceDiagram
  EndUser->>Merchant: Initiate payment
  Merchant->>ElenPAY: Create invoice
  ElenPAY-->>Merchant: Return invoice details
  Merchant->>ElenPAY: Get payment methods (Bolt11)
  Merchant->>EndUser: Show Bolt11 invoice (QR or string)
  EndUser-->>ElenPAY: Pay with Lightning wallet
  ElenPAY->>Merchant: Webhook notification (settled, expired)

Creating an Invoice

Endpoint: POST /api/v1/stores/{storeId}/invoices

Description: Creates a new invoice for a deposit. Use this to request payment from a user via Lightning or the widget.

Required fields:

  • checkout.paymentMethods: ["BTC-LightningNetwork"]
  • currency: BTC or a fiat currency (e.g., USD, EUR). Fiat rates are always based on BTC.
  • amount: Use two decimals for fiat, eight for BTC (e.g., 5.00 for USD, 0.00100000 for BTC).
  • metadata: JSON object with required fields:
  • OrderId (required): Unique order identifier for your system
  • CustomerId (required): Unique customer identifier for your system
  • MerchantId (optional): Your merchant identifier if you use multiple merchant accounts

Example metadata:

{
  "OrderId": "12345678",
  "CustomerId": "401329b6-dd4e-4b4e-a866-730d4bc116c4",
  "MerchantId": "5GtvTUFXtJGrqGV5kqMbadtKr4aL2Z63Muk2rAQkYzyT" // Optional
}

Example CURL:

export STORE_ID="XXXXXXXXXXXXXX"
export API_TOKEN="XXXXXXXXXXXXX"
export URL="https://api-staging.elenpay.tech"
curl -X POST "${URL}/api/v1/stores/${STORE_ID}/invoices" \
  -H "accept: application/json" \
  -H "Content-Type: application/json" \
  -H "Authorization: Token ${API_TOKEN}" \
  -d '{
    "metadata": {
      "OrderId": "12345678",
      "MerchantId": "5GtvTUFXtJGrqGV5kqMbadtKr4aL2Z63Muk2rAQkYzyT",
      "CustomerId": "401329b6-dd4e-4b4e-a866-730d4bc116c4"
    },
    "checkout": {"paymentMethods": ["BTC-LightningNetwork"]},
    "amount": "5.00",
    "currency": "USD"
  }'

Response:

  • The response contains the invoice id. Store this in your database for future reference.

Payment links allow you to direct users to complete payments using either the ElenPAY widget or a direct Lightning invoice. Below are the two options:

Use the checkoutLink field from the invoice creation response to direct users to the ElenPAY widget. This widget provides a seamless payment experience.

Example:

https://<ElenPAY_domain>/i/<invoiceId>

2. Lightning Invoice (No Widget)

If you want to use your own widget or make the user pay from your own website, retrieve the Lightning invoice using the payment methods endpoint. The payments[0].destination field in the response contains the Bolt11 invoice, which you can display as a QR code or a clickable link for wallets.

Endpoint: GET /api/v1/stores/{storeId}/invoices/{invoiceId}/payment-methods

Example:

lnbc1...

Withdrawals (Pull Payments)

With Widget

A withdrawal (pull payment) can be processed using the ElenPAY withdrawal widget, allowing the user to choose how to receive their funds.

Endpoint: POST /api/v1/stores/{storeId}/withdrawal/request

Description: Initiates a withdrawal and returns a checkoutLink for the user to complete the process via the widget.

Flow:

  • You request a withdrawal by calling the endpoint above.
  • ElenPAY returns a checkoutLink for the withdrawal.
  • You present the checkout link to the user, which opens the ElenPAY withdrawal widget.
  • The user chooses how to receive the funds (e.g., by providing a Lightning invoice or using LNURL) through the widget.
  • ElenPAY processes the withdrawal and notifies you via webhook.

Sequence Diagram:

sequenceDiagram
  Merchant->>ElenPAY: Request withdrawal
  ElenPAY-->>Merchant: Return withdrawal details (with checkoutLink)
  Merchant->>EndUser: Show withdrawal widget
  EndUser-->>ElenPAY: Choose payout method (e.g., Lightning invoice, LNURL)
  ElenPAY->>Merchant: Webhook notification (settled, cancelled)

Widget Screenshots:

  • Type Selection: Withdrawal Type Selection

  • LNURL Option: Withdrawal LNURL

  • Invoice Option: Withdrawal Invoice

Redirecting to your website

When initiating a withdrawal, you can configure the redirectURL and redirectAutomatically fields. This will allow the widget to redirect to your website after a withdrawal is completed:

  • redirectURL: Specifies the URL where the customer will be redirected after withdrawal completion. Make sure your url starts with https://
  • redirectAutomatically: If set to true, the widget will automatically redirect the customer to the redirectURL after withdrawal completion. Otherwise, we will expose a button that the user can click for going back to your website.

Without Widget

A withdrawal can also be processed directly, by providing the payout details up front (e.g., a Lightning invoice).

Flow:

  • You request a withdrawal by calling the appropriate endpoint for the withdrawal type (see below).
  • ElenPAY processes the withdrawal asynchronously and pays the user directly.
  • You receive webhook notifications about the withdrawal status (settled or cancelled).

Sequence Diagram:

sequenceDiagram
  Merchant->>ElenPAY: Request withdrawal (with payout details)
  ElenPAY-->>Merchant: Return withdrawal details
  ElenPAY->>EndUser: Pay user directly (e.g., Lightning invoice, LNURL)
  ElenPAY->>Merchant: Webhook notification (settled, cancelled)

a) Withdraw to a Lightning Invoice

Endpoint: POST /api/v1/stores/{storeId}/invoice-withdrawal

Description: Pays the given amount to a provided Bolt11 invoice. Payment is processed asynchronously and retried if it fails. To withdraw directly to a Lightning invoice, include the paymentRequest field in your request.

Required fields:

  • amount: Amount to withdraw (BTC, up to 8 decimals)
  • currency: Must be BTC
  • metadata: JSON object with required fields:
  • OrderId (required): Unique order identifier for your system
  • CustomerId (required): Unique customer identifier for your system
  • MerchantId (optional): Your merchant identifier if you use multiple merchant accounts
  • paymentRequest: The Bolt11 invoice to pay

Request Example:

{
  "amount": "0.001",
  "currency": "BTC",
  "metadata": {
    "OrderId": "12345678",
    "CustomerId": "401329b6-dd4e-4b4e-a866-730d4bc116c4"
  },
  "paymentRequest": "lnbc1..."
}

b) Withdraw via LNURL

Endpoint: POST /api/v1/stores/{storeId}/withdrawal/request

Description: Initiates a withdrawal and returns a link (LNURL) for the user to complete the process via their wallet.

Required fields:

  • amount: Amount to withdraw (BTC, up to 8 decimals)
  • currency: Must be BTC
  • metadata: JSON object with required fields:
  • OrderId (required): Unique order identifier for your system
  • CustomerId (required): Unique customer identifier for your system
  • MerchantId (optional): Your merchant identifier if you use multiple merchant accounts

Request Example:

{
  "amount": "0.001",
  "currency": "BTC",
  "metadata": {
    "OrderId": "12345678",
    "CustomerId": "401329b6-dd4e-4b4e-a866-730d4bc116c4"
  },
}

How to use the LNURL:

  • You will receive a link field in the response, which is an LNURL (bech32-encoded URL).
  • Display this LNURL to the user as a QR code or provide it as a string for them to paste into their Lightning wallet.
  • The user scans the QR code or pastes the LNURL in their wallet. Their wallet will then negotiate the withdrawal details directly with our backend.
  • Once the user completes the withdrawal in their wallet, we will process the payment and notify you via webhook when it is settled or cancelled.

Note: For security reasons, a LNURL link can be used once. If at any point the process fails, the merchant must request a different LNURL from ElenPAY

Withdrawal Retry Policy

If a withdrawal (pull payment) fails due to network, routing, or liquidity issues, our system will automatically retry the withdrawal multiple times over a period of time. You do not need to manually retry failed withdrawals; the system handles retries for you.

If all attempts fail, the withdrawal will be marked as cancelled and you will receive a PullPaymentCancelled webhook event. After this webhook is received, it is safe to to ask for another withdrawal for the same order.

Webhooks

Webhooks notify you about important events:

  • InvoiceSettled: Payment received
  • InvoiceExpired: Invoice expired
  • PullPaymentSettled: Withdrawal completed
  • PullPaymentCancelled: Withdrawal failed/cancelled

Webhook Security

Webhooks are a critical integration point and must be handled securely to prevent spoofing or unauthorized actions. Follow these best practices:

1. Signature Verification

  • Every webhook request from ElenPAY includes a BTCPay-Sig header.
  • This header contains a HMAC SHA256 signature of the raw request body, using your webhook secret as the key.
  • Always verify this signature before processing the webhook. If the signature does not match, reject the request (e.g., respond with HTTP 401 Unauthorized).

2. Webhook Secret

  • Your webhook secret is provided by our ops team during store setup.
  • Store this secret securely and never expose it publicly or in client-side code.
  • If you believe your secret has been compromised, contact support immediately to rotate it.

3. Secure Endpoint

  • Your webhook endpoint must be accessible from the public internet.
  • Use HTTPS to encrypt traffic and prevent interception or tampering.
  • Do not expose sensitive business logic or data at the webhook endpoint.

4. Idempotency and Replay Protection

  • Webhooks will be retried if your server returns an HTTP status code of 400 or higher.
  • Ensure your webhook handler is idempotent (processing the same event multiple times has no adverse effect).
  • Use unique event IDs (e.g., deliveryId in the payload) to detect and ignore duplicate events.

5. Logging and Monitoring

  • Log webhook deliveries and verification failures for auditing and troubleshooting.
  • Monitor for unexpected or failed webhook attempts.

6. Example: Signature Verification

See examples.md for a C# code sample. You can implement similar logic in any backend language.

Example webhook payloads and more details: See Webhook Types below.

7. Metadata in Webhooks

For the merchant's convenience, every webhook includes the metadata provided during the initiation of the transaction. This allows you to easily match webhook events to your internal records, such as orders or customer details.

Example: If you provided OrderId, CustomerId, and MerchantId in the metadata when creating an invoice or withdrawal, these fields will be included in the webhook payload.

See the Webhook Types section for example payloads and field descriptions.

Best Practices

  • Always store invoice and pull payment IDs for future reference.
  • Validate webhook signatures to prevent spoofing.
  • Handle API errors and rate limits gracefully (implement retries with backoff).
  • Keep your API keys and webhook secrets secure.

Webhook Types

Event Name Description
InvoiceExpired Invoice (deposit) has expired
InvoiceSettled Invoice (deposit) has been settled
PullPaymentSettled Pull payment (withdrawal) has been settled
PullPaymentCancelled Pull payment (withdrawal) has been cancelled (e.g., Lightning errors, node offline, retry time exhausted)

Example: Deposit Webhook

{
  "manuallyMarked": false,
  "currency": "BTC",
  "cryptoAmount": 0.001,
  "fiatAmount": 350.00,
  "deliveryId": "KcaTiTbW3wizMoRy4LY2qY",
  "webhookId": "Ery8f2rjP3iLzbF2pVqkuF",
  "originalDeliveryId": "CPbfRrDc6RDUigbim8V4fd",
  "isRedelivery": false,
  "type": "InvoiceSettled",
  "timestamp": 1717000000,
  "storeId": "5GtvTUFXtJGrqGV5kqMbadtKr4aL2Z63Muk2rAQkYzyT",
  "invoiceId": "3J2zjjKBkY3Bt2yDk91mHy",
  "metadata": {
    "OrderId": "12345678",
    "CustomerId": "401329b6-dd4e-4b4e-a866-730d4bc116c4"
  }
}

Example: Withdrawal Webhook

{
  "currency": "BTC",
  "cryptoAmount": 0.001,
  "fiatAmount": 350.00,
  "deliveryId": "Cs49yfQw5mWAJu1ZrYzQDj",
  "webhookId": "S6Y7qomhBe4yCKATRFm1nN",
  "originalDeliveryId": "A1DMdwVYMKf6DWgm1X9YEU",
  "isRedelivery": false,
  "type": "PullPaymentSettled",
  "timestamp": 1717000000,
  "storeId": "5GtvTUFXtJGrqGV5kqMbadtKr4aL2Z63Muk2rAQkYzyT",
  "pullPaymentId": "6HUy85LvPuHCY6Gvpn8ZRP",
  "invoiceId": null,
  "reason": null,
  "metadata": {
    "OrderId": "12345678",
    "CustomerId": "401329b6-dd4e-4b4e-a866-730d4bc116c4"
  }
}

Troubleshooting

  • If you miss a webhook, you can poll the invoice or withdrawal status via the API or redeliver it from the ElenPAY backoffice.
  • Webhooks are retried automatically if your server is temporarily unavailable.
  • For any questions, contact our support team.

For additional questions, see our FAQ.

This guide is designed to be clear and actionable. If you have suggestions or need more examples, let us know!