Documentation
Introduction
BitcoinPayLinks is a service that lets you create simple Bitcoin lightning invoice links, so you can accept payments in seconds.
Creating Payment Links
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.com or LNURL1... |
Yes |
product | Product or service name | Coffee |
Yes |
amount | Amount in satoshis | 1000 |
Yes |
Optional Parameters
|
|||
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
- Always verify payments in your Bitcoin wallet before fulfilling orders. Use webhooks as notifications only, not as authoritative proof of payment.
- 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:
- Set up your webhook endpoint
- Create a BitcoinPayLinks URL with your test endpoint as the
success
parameter - Complete a small test payment (minimum amount)
- Verify that your endpoint receives the webhook