Documentation

Introduction

BitcoinPayLinks is a service that lets you create simple Bitcoin lightning invoice links, so you can accept payments in seconds.

To create a payment link, construct a URL with your specific parameters:

https://bitcoinpaylinks.com?address=<your-lightning-address>&product=Coffee&amount=1000

Users who visit this link will be presented with a Bitcoin lightning invoice, showing your product name, amount & lightning invoice QR code. You can create them at: BitcoinPayLinks.

URL Parameters

Parameter Description Example Required
address The "lightning email address" or LNURL where you'd like to receive payments at name@domain.comor LNURL1... Yes
product Product or service name Coffee Yes
amount Amount in satoshis 1000 Yes
Optional Parameters
email Whether to collect customer email yes or no (default: no) No
success Webhook URL for payment notifications https://yoursite.com/webhook No

Webhooks

Webhook Payload

When a payment is successful, our system updates the payment page with the success message. If you've included a webhook URL, we'll send a POST request to that URL with this JSON payload:

{
  "event": "payment_success",
  "orderID": "3f54d5e2-8d27-4801-b724-d3e6fa331599",
  "productID": "6C8A778E-19E1-42B5-AE6F-6300C922D941",
  "productName": "Coffee",
  "btc_total": 0.00000010, 
  "timestamp": "2025-03-24T01:14:16.918Z",
  "transactionId": "D0F0106C-8379-438A-9D1D-6917AAE185C2",
  "status": "Complete"
}

Security Considerations

  1. Always verify payments in your Bitcoin wallet before fulfilling orders. Use webhooks as notifications only, not as authoritative proof of payment.
  2. Implement IP filtering when possible. All BitcoinPayLinks webhooks come from our server IP address.
Important: Webhooks should be treated as convenient notifications, not as authoritative proof of payment. Always verify the payment in your Bitcoin wallet before fulfilling orders.

Implementation Examples

app.post('/your-webhook-endpoint', (req, res) => {
  // Log the webhook
  console.log('==========================================');
  console.log(`WEBHOOK RECEIVED at ${new Date().toISOString()}`);
  console.log(`FROM IP ADDRESS: ${req.headers['x-forwarded-for'] || req.connection.remoteAddress}`);
  console.log('==========================================');
  console.log('Headers:', JSON.stringify(req.headers, null, 2));
  console.log('Body:', JSON.stringify(req.body, null, 2));
  console.log('==========================================');
  
  // Always respond with success to acknowledge receipt
  res.status(200).json({
    success: true,
    message: 'Webhook received'
  });
  
  // Process the order after verifying the payment in your wallet
  const { orderID, productName, price } = req.body;
  
  // Your order processing logic here...
});
<?php
// Get the raw POST data
$rawData = file_get_contents('php://input');
$headers = getallheaders();
$data = json_decode($rawData, true);

// Log the webhook
$logFile = fopen('webhook_log.txt', 'a');
fwrite($logFile, "===========================================\n");
fwrite($logFile, "WEBHOOK RECEIVED at " . date('Y-m-d H:i:s') . "\n");
fwrite($logFile, "FROM IP: " . $_SERVER['REMOTE_ADDR'] . "\n");
fwrite($logFile, "===========================================\n");
fwrite($logFile, "Headers: " . print_r($headers, true) . "\n");
fwrite($logFile, "Body: " . print_r($data, true) . "\n");
fwrite($logFile, "===========================================\n\n");
fclose($logFile);

// Respond with success
header('Content-Type: application/json');
echo json_encode(['success' => true, 'message' => 'Webhook received']);

// Process the order
$orderID = $data['orderID'];
$productName = $data['productName'];
$price = $data['price'];

// Your order processing logic here...
?>
from flask import Flask, request, jsonify
import logging
from datetime import datetime

app = Flask(__name__)
logging.basicConfig(filename='webhook_log.txt', level=logging.INFO)

@app.route('/your-webhook-endpoint', methods=['POST'])
def handle_webhook():
    # Log the webhook
    client_ip = request.headers.get('X-Forwarded-For', request.remote_addr)
    logging.info(f"==========================================")
    logging.info(f"WEBHOOK RECEIVED at {datetime.now().isoformat()}")
    logging.info(f"FROM IP ADDRESS: {client_ip}")
    logging.info(f"==========================================")
    logging.info(f"Headers: {request.headers}")
    logging.info(f"Body: {request.json}")
    logging.info(f"==========================================")
    
    # Process the webhook data
    data = request.json
    order_id = data.get('orderID')
    product_name = data.get('productName')
    price = data.get('price')
    
    # Your order processing logic here...
    
    # Always respond with success
    return jsonify({'success': True, 'message': 'Webhook received'})

if __name__ == '__main__':
    app.run(port=5000)

Testing Your Webhook

To test your webhook implementation:

  1. Set up your webhook endpoint
  2. Create a BitcoinPayLinks URL with your test endpoint as the success parameter
  3. Complete a small test payment (minimum amount)
  4. Verify that your endpoint receives the webhook