Skip to main content

Node.js Examples

Complete Node.js examples for integrating with the LuxCore API using axios.

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
  static verifyWebhookSignature(payload, 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
    const payloadString = JSON.stringify(payload);
    const payloadToSign = `${timestamp}.${payloadString}`;
    const expectedSignature = '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.instructions) {
      console.log('Bank:', payment.instructions.bank_name);
      console.log('CLABE:', payment.instructions.account_number);
      console.log('Reference:', payment.instructions.reference);
    }

    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`);
  
  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();
app.use(express.json());

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']);
  const payload = req.body;

  // Verify signature
  try {
    LuxCoreClient.verifyWebhookSignature(
      payload,
      signature,
      timestamp,
      WEBHOOK_SECRET
    );
  } catch (error) {
    console.error('Webhook verification failed:', error.message);
    return res.status(400).json({ error: error.message });
  }

  // Process event
  const { event, payment } = payload;
  console.log(`Received ${event} for payment ${payment.id}`);

  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 'payout.completed':
      // Handle completed payout
      console.log(`✅ Payout ${payment.id} completed!`);
      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;
  };
  payout?: {
    recipient_name: string;
    bank_account: string;
    bank_code: string;
    reference?: string;
  };
  metadata?: Record<string, unknown>;
}

interface Payment {
  transaction_id: string;
  status: string;
  amount: number;
  currency: string;
  method: string;
  type: string;
  created_at: string;
  instructions?: {
    bank_name: string;
    account_number: string;
    reference: string;
    beneficiary: 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;
  }

  static verifyWebhookSignature(
    payload: object,
    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}.${JSON.stringify(payload)}`;
    const expectedSignature = '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) {
  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:
          console.error('Rate limited - implementing backoff');
          await sleep(60000);
          return safeCreatePayment(data); // Retry
        case 500:
        case 503:
          console.error('Server error - retrying');
          await sleep(5000);
          return safeCreatePayment(data); // Retry
        default:
          console.error(`API error (${error.statusCode}): ${error.message}`);
      }
    }
    throw error;
  }
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}