Documentation Index
Fetch the complete documentation index at: https://docs.lux-core.io/llms.txt
Use this file to discover all available pages before exploring further.
Node.js Examples
Complete Node.js examples for integrating with the LuxCore API usingaxios.
Installation
npm install axios
LuxCore Client Class
const axios = require('axios');
const crypto = require('crypto');
class LuxCoreClient {
static BASE_URL = 'https://api.lux-core.io/api/v1';
constructor(apiKey = process.env.LUXCORE_API_KEY) {
if (!apiKey) {
throw new Error('API key is required');
}
this.client = axios.create({
baseURL: LuxCoreClient.BASE_URL,
headers: {
'X-API-Key': apiKey,
'Content-Type': 'application/json'
}
});
// Add response interceptor for error handling
this.client.interceptors.response.use(
(response) => response.data,
(error) => {
const err = new LuxCoreError(
error.response?.data?.message || error.message,
error.response?.status,
error.response?.data?.error
);
throw err;
}
);
}
// Payments
async createPayment(data) {
return this.client.post('/payments', data);
}
async getPayment(paymentId) {
return this.client.get(`/payments/${paymentId}`);
}
async listPayments(filters = {}) {
return this.client.get('/payments', { params: filters });
}
async cancelPayment(paymentId) {
return this.client.post(`/payments/${paymentId}/cancel`);
}
// Balance
async getBalance(currency) {
const params = currency ? { currency } : {};
return this.client.get('/balance', { params });
}
async getAllBalances() {
return this.client.get('/balance/all');
}
// Webhooks
async createWebhook(data) {
return this.client.post('/webhooks', data);
}
async listWebhooks() {
return this.client.get('/webhooks');
}
async deleteWebhook(webhookId) {
return this.client.delete(`/webhooks/${webhookId}`);
}
// Static method for webhook verification
// IMPORTANT: Pass the raw request body string, not a parsed/re-serialized object
static verifyWebhookSignature(rawBody, signature, timestamp, secret) {
// Check timestamp (reject if older than 5 minutes)
const currentTime = Math.floor(Date.now() / 1000);
if (Math.abs(currentTime - timestamp) > 300) {
throw new Error('Webhook timestamp too old');
}
// Calculate expected signature using raw body
const payloadToSign = `${timestamp}.${rawBody}`;
const expectedSignature = 'hmac_sha256=' + crypto
.createHmac('sha256', secret)
.update(payloadToSign)
.digest('hex');
// Compare signatures (timing-safe)
if (!crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
)) {
throw new Error('Invalid webhook signature');
}
return true;
}
}
class LuxCoreError extends Error {
constructor(message, statusCode, errorCode) {
super(message);
this.name = 'LuxCoreError';
this.statusCode = statusCode;
this.errorCode = errorCode;
}
}
module.exports = { LuxCoreClient, LuxCoreError };
Usage Examples
Create a Deposit Payment
const { LuxCoreClient, LuxCoreError } = require('./luxcore');
const client = new LuxCoreClient();
async function createDeposit() {
try {
const payment = await client.createPayment({
amount: 100000, // $1,000.00 MXN (in centavos)
currency: 'MXN',
method: 'spei',
type: 'deposit',
merchant_reference: `order_${Date.now()}`,
customer: {
name: 'Juan Perez',
email: 'juan@example.com',
phone: '+525551234567'
},
metadata: {
order_id: '12345',
source: 'web'
}
});
console.log('Payment created:', payment.transaction_id);
console.log('Status:', payment.status);
if (payment.bank_details) {
console.log('Bank:', payment.bank_details.bank_name);
console.log('Account:', payment.bank_details.account_number);
console.log('Holder:', payment.bank_details.account_holder);
}
return payment;
} catch (error) {
if (error instanceof LuxCoreError) {
console.error(`API Error (${error.statusCode}): ${error.message}`);
} else {
console.error('Unexpected error:', error);
}
}
}
createDeposit();
Create a Withdrawal (Payout)
async function createPayout() {
const payout = await client.createPayment({
amount: 50000,
currency: 'MXN',
method: 'spei',
type: 'withdrawal',
merchant_reference: `payout_${Date.now()}`,
customer: {
name: 'Finance Team',
email: 'finance@company.com'
},
payout: {
recipient_name: 'Maria Garcia',
bank_account: '012345678901234567',
bank_code: '002',
reference: 'PAYOUT-001'
}
});
console.log('Payout created:', payout.transaction_id);
return payout;
}
List Payments
async function listRecentPayments() {
const result = await client.listPayments({
status: 'completed',
limit: 20,
created_at_from: '2025-01-01T00:00:00Z'
});
console.log(`Found ${result.total} payments`);
console.log(`Pagination: page ${result.pagination?.offset || 0}, total pages: ${result.pagination?.total_pages}`);
for (const payment of result.data) {
console.log(`${payment.transaction_id}: ${payment.amount} ${payment.currency}`);
}
}
Webhook Handler (Express)
const express = require('express');
const { LuxCoreClient } = require('./luxcore');
const app = express();
// Capture raw body for signature verification
app.use(express.json({
verify: (req, res, buf) => { req.rawBody = buf.toString(); }
}));
const WEBHOOK_SECRET = process.env.LUXCORE_WEBHOOK_SECRET;
app.post('/webhooks/luxcore', (req, res) => {
const signature = req.headers['x-webhook-signature'];
const timestamp = parseInt(req.headers['x-webhook-timestamp']);
// Verify using raw body (not re-serialized JSON)
try {
LuxCoreClient.verifyWebhookSignature(
req.rawBody,
signature,
timestamp,
WEBHOOK_SECRET
);
} catch (error) {
console.error('Webhook verification failed:', error.message);
return res.status(400).json({ error: error.message });
}
// Process event — use envelope structure
const event = req.headers['x-webhook-event'];
const webhookId = req.headers['x-webhook-id'];
const payment = payload.data.payment;
console.log(`Received ${event} for payment ${payment.id} (webhook: ${webhookId})`);
switch (event) {
case 'payment.completed':
// Handle completed payment
console.log(`Payment ${payment.id} completed!`);
// Update database, send confirmation email, etc.
break;
case 'payment.failed':
// Handle failed payment
console.log(`Payment ${payment.id} failed: ${payment.failure_reason}`);
break;
case 'payment.cancelled':
// Handle cancelled payment
console.log(`Payment ${payment.id} cancelled`);
break;
default:
console.log(`Unhandled event: ${event}`);
}
res.status(200).json({ received: true });
});
app.listen(3000, () => {
console.log('Webhook server listening on port 3000');
});
TypeScript Version
import axios, { AxiosInstance } from 'axios';
import crypto from 'crypto';
interface PaymentRequest {
amount: number;
currency: string;
method: string;
type: 'deposit' | 'withdrawal' | 'deposit_pp' | 'withdrawal_pp';
merchant_reference: string;
customer: {
name: string;
email: string;
phone?: string;
external_id?: string;
};
payout?: {
recipient_name: string;
bank_account: string;
bank_code: string;
reference?: string;
account_type?: string;
beneficiary_tax_id?: string;
description?: string;
payid?: string;
payid_type?: 'email' | 'phone' | 'abn';
};
webhook_url?: string;
webhook_events?: string[];
customer_id?: number;
description?: string;
traffic_type?: 'primary' | 'secondary' | 'vip';
metadata?: Record<string, unknown>;
}
interface Payment {
transaction_id: string;
status: string;
amount: number;
currency: string;
method: string | null;
type: string;
fee_amount?: number;
net_amount?: number;
error_code?: string;
error_message?: string;
created_at: string;
bank_details?: {
amount: string;
purpose: string;
currency: string;
bank_name: string;
swift_code: string | null;
account_holder: string;
account_number: string;
};
}
class LuxCoreClient {
private client: AxiosInstance;
private static BASE_URL = 'https://api.lux-core.io/api/v1';
constructor(apiKey: string = process.env.LUXCORE_API_KEY!) {
this.client = axios.create({
baseURL: LuxCoreClient.BASE_URL,
headers: {
'X-API-Key': apiKey,
'Content-Type': 'application/json'
}
});
}
async createPayment(data: PaymentRequest): Promise<Payment> {
const response = await this.client.post<Payment>('/payments', data);
return response.data;
}
async getPayment(paymentId: string): Promise<Payment> {
const response = await this.client.get<Payment>(`/payments/${paymentId}`);
return response.data;
}
// IMPORTANT: Pass the raw request body string, not a parsed/re-serialized object
static verifyWebhookSignature(
rawBody: string,
signature: string,
timestamp: number,
secret: string
): boolean {
const currentTime = Math.floor(Date.now() / 1000);
if (Math.abs(currentTime - timestamp) > 300) {
throw new Error('Webhook timestamp too old');
}
const payloadToSign = `${timestamp}.${rawBody}`;
const expectedSignature = 'hmac_sha256=' + crypto
.createHmac('sha256', secret)
.update(payloadToSign)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
}
export { LuxCoreClient, PaymentRequest, Payment };
Error Handling
const { LuxCoreClient, LuxCoreError } = require('./luxcore');
async function safeCreatePayment(data, attempt = 0, maxRetries = 3) {
const client = new LuxCoreClient();
try {
return await client.createPayment(data);
} catch (error) {
if (error instanceof LuxCoreError) {
switch (error.statusCode) {
case 401:
console.error('Invalid API key');
break;
case 400:
console.error('Validation error:', error.message);
break;
case 429:
if (attempt >= maxRetries) throw error;
console.error('Rate limited - implementing backoff');
await sleep(60000 * Math.pow(2, attempt));
return safeCreatePayment(data, attempt + 1, maxRetries);
case 500:
case 503:
if (attempt >= maxRetries) throw error;
console.error('Server error - retrying');
await sleep(5000 * Math.pow(2, attempt));
return safeCreatePayment(data, attempt + 1, maxRetries);
default:
console.error(`API error (${error.statusCode}): ${error.message}`);
}
}
throw error;
}
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
