React components for integrating Bitcoin Lightning payments with NakaPay.
NEXT_PUBLIC_ prefix, or frontend applications.
npm install nakapay-react
# or
yarn add nakapay-reactCRITICAL: API keys must only be used server-side. Set up backend endpoints to handle payments securely:
// Backend example (Express.js) - SERVER SIDE ONLY
const express = require('express');
const { NakaPay } = require('nakapay-sdk');
const app = express();
// SECURE: API key from server environment variable only
const nakaPay = new NakaPay(process.env.NAKAPAY_API_KEY); // NOT NEXT_PUBLIC_
app.post('/api/create-payment', async (req, res) => {
try {
// Add input validation
const { amount, description, metadata } = req.body;
if (!amount || amount <= 0) {
return res.status(400).json({ error: 'Invalid amount' });
}
if (!description || description.trim().length === 0) {
return res.status(400).json({ error: 'Description required' });
}
const payment = await nakaPay.createPaymentRequest(req.body);
res.json(payment);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.get('/api/payment-status/:id', async (req, res) => {
try {
const { id } = req.params;
if (!id || id.trim().length === 0) {
return res.status(400).json({ error: 'Payment ID required' });
}
const status = await nakaPay.getPaymentStatus(id);
res.json(status);
} catch (error) {
res.status(500).json({ error: error.message });
}
});import React from 'react';
import { NakaPayButton } from 'nakapay-react';
function CheckoutPage() {
return (
<div>
<h2>Complete Your Purchase</h2>
<NakaPayButton
amount={50000} // Amount in satoshis
description="Product purchase"
onPaymentSuccess={(payment) => {
console.log('Payment successful!', payment);
// Redirect to success page or update UI
}}
onPaymentError={(error) => {
console.error('Payment failed:', error);
// Handle error
}}
/>
</div>
);
}A complete payment button that handles the entire payment flow.
Props:
amount(number, required): Payment amount in satoshisdescription(string, required): Payment descriptionmetadata?(object): Additional metadata for the paymenttext?(string): Custom button text (defaults to "Pay {amount} sats")className?(string): Additional CSS classesstyle?(CSSProperties): Custom stylesdisabled?(boolean): Disable the buttonapiEndpoint?(string): Backend endpoint for creating payments (default: '/api/create-payment')onPaymentCreated?(function): Called when payment is createdonPaymentSuccess?(function): Called when payment is successfulonPaymentError?(function): Called when payment fails
Real-time Payment Notifications:
useAbly?(boolean): Use Ably for real-time updates (recommended)ablyApiKey?(string): Ably API key for real-time connectionuseWebhooks?(boolean): Use WebSocket connection for real-time updateswebhookUrl?(string): WebSocket server URL for webhook-based updatesuseSSE?(boolean): Use Server-Sent Events for real-time updatespollInterval?(number): Polling interval in ms when real-time methods unavailable (default: 2000)statusEndpoint?(string): Backend endpoint for status polling (default: '/api/payment-status')
A payment modal component for custom implementations.
Props:
payment(Payment, required): Payment object from your backendonClose(function, required): Called when modal is closedonPaymentSuccess?(function): Called when payment is successfulonPaymentError?(function): Called when payment failsuseAbly?(boolean): Use Ably for real-time updatesablyApiKey?(string): Ably API key for real-time connectionuseWebhooks?(boolean): Use WebSocket connection for updateswebhookUrl?(string): WebSocket server URLuseSSE?(boolean): Use Server-Sent Events for updatespollInterval?(number): Status polling interval in ms (default: 2000)statusEndpoint?(string): Backend endpoint for checking status (default: '/api/payment-status')
NakaPay React components support multiple methods for real-time payment status updates, with automatic fallbacks:
Ably provides the most reliable real-time updates using cloud infrastructure:
<NakaPayButton
amount={50000}
description="Product purchase"
useAbly={true}
ablyApiKey="your-ably-api-key"
onPaymentSuccess={(payment) => console.log('Success!', payment)}
/>Setup:
- Sign up for Ably
- Get your API key
- Configure webhooks in your NakaPay dashboard to publish to Ably
Direct WebSocket connection to your webhook server:
<NakaPayButton
amount={50000}
description="Product purchase"
useWebhooks={true}
webhookUrl="ws://localhost:3002"
onPaymentSuccess={(payment) => console.log('Success!', payment)}
/>Setup:
- Run a WebSocket server (e.g., using Socket.IO)
- Configure NakaPay webhooks to notify your server
- Have your server emit WebSocket events to connected clients
HTTP streaming for real-time updates:
<NakaPayButton
amount={50000}
description="Product purchase"
useSSE={true}
onPaymentSuccess={(payment) => console.log('Success!', payment)}
/>Setup:
- Implement
/api/payments/streamendpoint that streams SSE - Configure NakaPay webhooks to trigger SSE updates
If no real-time method is configured, components automatically fall back to polling:
<NakaPayButton
amount={50000}
description="Product purchase"
pollInterval={3000} // Check every 3 seconds
statusEndpoint="/api/payment-status"
onPaymentSuccess={(payment) => console.log('Success!', payment)}
/>The components try real-time methods in this order:
- Ably (if
useAbly={true}) - WebSocket (if
useWebhooks={true}) - Server-Sent Events (if
useSSE={true}) - Polling (automatic fallback)
import React, { useState } from 'react';
import { NakaPayModal, Payment } from 'nakapay-react';
function CustomCheckout() {
const [showModal, setShowModal] = useState(false);
const [payment, setPayment] = useState<Payment | null>(null);
const handleCustomPayment = async () => {
try {
const response = await fetch('/api/create-payment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
amount: 25000,
description: 'Custom payment',
metadata: { orderId: '12345' }
})
});
const paymentData = await response.json();
setPayment(paymentData);
setShowModal(true);
} catch (error) {
console.error('Failed to create payment:', error);
}
};
return (
<div>
<button onClick={handleCustomPayment}>
Custom Pay Button
</button>
{showModal && payment && (
<NakaPayModal
payment={payment}
onClose={() => setShowModal(false)}
onPaymentSuccess={(payment) => {
console.log('Success!', payment);
setShowModal(false);
}}
/>
)}
</div>
);
}Import the default styles:
import 'nakapay-react/dist/styles.css';Or provide your own custom styles using the provided CSS classes:
.nakapay-button- Button component.nakapay-modal-overlay- Modal overlay.nakapay-modal- Modal content
This package includes TypeScript definitions. All components are fully typed.
MIT