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.comor 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
successparameter - Complete a small test payment (minimum amount)
- Verify that your endpoint receives the webhook