Skip to main content

Node.js Examples

Complete Node.js example client for integrating with the Multihub API using the built-in crypto module and native fetch.
This is a reference implementation, not an official SDK package. It uses only Node.js built-in modules (no external dependencies required). Requires Node.js 18+ for native fetch.

Configuration

Store your credentials in environment variables:
export MULTIHUB_APP_ID="1"
export MULTIHUB_SECRET_KEY="your_secret_key"

MultihubClient Class (JavaScript)

const crypto = require('crypto');

class MultihubClient {
  constructor({
    appId = process.env.MULTIHUB_APP_ID,
    secretKey = process.env.MULTIHUB_SECRET_KEY,
    baseUrl = 'https://api.123hub.pro/public/api/multihub/v1',
  } = {}) {
    if (!appId || !secretKey) {
      throw new Error('appId and secretKey are required');
    }
    this.appId = appId;
    this.secretKey = secretKey;
    this.baseUrl = baseUrl;
  }

  async _send(body) {
    const bodyStr = JSON.stringify(body);
    const hash = crypto
      .createHash('sha512')
      .update(bodyStr + this.secretKey)
      .digest('hex');

    const response = await fetch(this.baseUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Data-Application-Id': this.appId,
        'X-Data-Hash': hash,
      },
      body: bodyStr,
    });

    return response.json();
  }

  async ping() {
    return this._send({ method: 'gateway.ping', params: {} });
  }

  async createDeposit(serviceId, amount, currency, cId, extra = {}) {
    return this._send({
      method: 'payment.in',
      service_id: serviceId,
      params: {
        payment: {
          identifiers: { c_id: cId },
          amount: { value: amount, currency },
          ...extra,
        },
      },
    });
  }

  async createWithdrawal(serviceId, amount, currency, cId, receiver, extra = {}) {
    return this._send({
      method: 'payment.out',
      service_id: serviceId,
      params: {
        payment: {
          identifiers: { c_id: cId },
          amount: { value: amount, currency },
          receiver,
          ...extra,
        },
      },
    });
  }

  async getStatus({ cId, hId } = {}) {
    const identifiers = {};
    if (cId) identifiers.c_id = cId;
    if (hId) identifiers.h_id = hId;
    return this._send({
      method: 'payment.status',
      params: { payment: { identifiers } },
    });
  }

  async getBalance() {
    return this._send({ method: 'balance.get', params: {} });
  }
}

module.exports = { MultihubClient };

MultihubClient Class (TypeScript)

import crypto from 'crypto';

interface MultihubResponse {
  success: boolean;
  result?: Record<string, any>;
  error?: { code: string; message: string };
  next: any;
  request_id: string;
  processing_time: number;
}

interface MultihubClientOptions {
  appId?: string;
  secretKey?: string;
  baseUrl?: string;
}

interface Receiver {
  bank_account?: string;
  ifsc_code?: string;
  person?: { first_name: string; last_name: string };
  [key: string]: any;
}

class MultihubClient {
  private appId: string;
  private secretKey: string;
  private baseUrl: string;

  constructor(options: MultihubClientOptions = {}) {
    this.appId = options.appId || process.env.MULTIHUB_APP_ID || '';
    this.secretKey = options.secretKey || process.env.MULTIHUB_SECRET_KEY || '';
    this.baseUrl = options.baseUrl || 'https://api.123hub.pro/public/api/multihub/v1';

    if (!this.appId || !this.secretKey) {
      throw new Error('appId and secretKey are required');
    }
  }

  private async send(body: Record<string, any>): Promise<MultihubResponse> {
    const bodyStr = JSON.stringify(body);
    const hash = crypto
      .createHash('sha512')
      .update(bodyStr + this.secretKey)
      .digest('hex');

    const response = await fetch(this.baseUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Data-Application-Id': this.appId,
        'X-Data-Hash': hash,
      },
      body: bodyStr,
    });

    return response.json() as Promise<MultihubResponse>;
  }

  async ping(): Promise<MultihubResponse> {
    return this.send({ method: 'gateway.ping', params: {} });
  }

  async createDeposit(
    serviceId: number,
    amount: number,
    currency: string,
    cId: number,
    extra: Record<string, any> = {},
  ): Promise<MultihubResponse> {
    return this.send({
      method: 'payment.in',
      service_id: serviceId,
      params: {
        payment: {
          identifiers: { c_id: cId },
          amount: { value: amount, currency },
          ...extra,
        },
      },
    });
  }

  async createWithdrawal(
    serviceId: number,
    amount: number,
    currency: string,
    cId: number,
    receiver: Receiver,
    extra: Record<string, any> = {},
  ): Promise<MultihubResponse> {
    return this.send({
      method: 'payment.out',
      service_id: serviceId,
      params: {
        payment: {
          identifiers: { c_id: cId },
          amount: { value: amount, currency },
          receiver,
          ...extra,
        },
      },
    });
  }

  async getStatus(options: { cId?: number; hId?: number } = {}): Promise<MultihubResponse> {
    const identifiers: Record<string, number> = {};
    if (options.cId) identifiers.c_id = options.cId;
    if (options.hId) identifiers.h_id = options.hId;
    return this.send({
      method: 'payment.status',
      params: { payment: { identifiers } },
    });
  }

  async getBalance(): Promise<MultihubResponse> {
    return this.send({ method: 'balance.get', params: {} });
  }
}

export { MultihubClient, MultihubResponse, MultihubClientOptions };

Usage Examples

Ping (Health Check)

const { MultihubClient } = require('./multihub');

const client = new MultihubClient({
  appId: '1',
  secretKey: 'your_secret_key',
});

async function main() {
  const result = await client.ping();
  console.log(result);
  // { success: true, result: { status: "ok", ... }, ... }
}

main();

Create a Deposit Payment

const result = await client.createDeposit(
  14701,   // service_id
  10000,   // amount
  'INR',   // currency
  12345,   // c_id (your client-side identifier)
  {
    description: 'Order #12345',
    payer: {
      email: '[email protected]',
      person: { first_name: 'John', last_name: 'Doe' },
    },
  },
);

if (result.success) {
  console.log('Payment created successfully');
  console.log('Request ID:', result.request_id);
} else {
  console.error(`Error: ${result.error.code} - ${result.error.message}`);
}

Create a Withdrawal (Payout)

const result = await client.createWithdrawal(
  14701,   // service_id
  5000,    // amount
  'INR',   // currency
  67890,   // c_id
  {        // receiver
    bank_account: '1234567890',
    ifsc_code: 'SBIN0001234',
    person: { first_name: 'Jane', last_name: 'Doe' },
  },
  {
    description: 'Payout #67890',
  },
);

if (result.success) {
  console.log('Withdrawal created successfully');
} else {
  console.error(`Error: ${result.error.code} - ${result.error.message}`);
}

Check Payment Status

// Look up by client-side ID
const result = await client.getStatus({ cId: 12345 });

if (result.success) {
  const status = result.result.payment.status.status;
  console.log(`Payment status: ${status}`);
} else {
  console.error(`Error: ${result.error.code} - ${result.error.message}`);
}

// Look up by hub-side ID
const result2 = await client.getStatus({ hId: 999001 });

Get Balance

const result = await client.getBalance();

if (result.success) {
  for (const balance of result.result.balances) {
    console.log(`${balance.currency}: ${balance.available}`);
  }
} else {
  console.error(`Error: ${result.error.code} - ${result.error.message}`);
}

Error Handling

Successful responses return HTTP 200, errors return HTTP 400. Always use the success field to determine the outcome:
const result = await client.createDeposit(14701, 10000, 'INR', 12345);

if (result.success) {
  // Operation succeeded
  console.log(`Request ID: ${result.request_id}`);
  console.log(`Processing time: ${result.processing_time}s`);
} else {
  // Operation failed
  const { code, message } = result.error;
  console.error(`Error code: ${code}`);
  console.error(`Error message: ${message}`);

  switch (code) {
    case 'INVALID_HASH':
      console.error('Authentication failed - check your secret key');
      break;
    case 'INVALID_PARAMS':
      console.error('Invalid parameters - check request body');
      break;
    case 'SERVICE_UNAVAILABLE':
      console.error('Service temporarily unavailable - retry later');
      break;
    default:
      console.error(`Unhandled error code: ${code}`);
  }
}

Handling Network Errors

Network-level errors can still occur independently of API responses:
const { MultihubClient } = require('./multihub');

const client = new MultihubClient({
  appId: '1',
  secretKey: 'your_secret_key',
});

async function safePing() {
  try {
    const result = await client.ping();
    if (result.success) {
      console.log('API is reachable');
    } else {
      console.error(`API error: ${result.error.message}`);
    }
  } catch (error) {
    if (error.cause?.code === 'ECONNREFUSED') {
      console.error('Cannot reach the API - check network connectivity');
    } else if (error.name === 'AbortError') {
      console.error('Request timed out - try again');
    } else {
      console.error(`Request failed: ${error.message}`);
    }
  }
}

Complete Example

const crypto = require('crypto');

class MultihubClient {
  constructor({ appId, secretKey, baseUrl = 'https://api.123hub.pro/public/api/multihub/v1' }) {
    this.appId = appId;
    this.secretKey = secretKey;
    this.baseUrl = baseUrl;
  }

  async _send(body) {
    const bodyStr = JSON.stringify(body);
    const hash = crypto.createHash('sha512').update(bodyStr + this.secretKey).digest('hex');
    const response = await fetch(this.baseUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Data-Application-Id': this.appId,
        'X-Data-Hash': hash,
      },
      body: bodyStr,
    });
    return response.json();
  }

  async ping() { return this._send({ method: 'gateway.ping', params: {} }); }
  async getBalance() { return this._send({ method: 'balance.get', params: {} }); }

  async createDeposit(serviceId, amount, currency, cId, extra = {}) {
    return this._send({
      method: 'payment.in',
      service_id: serviceId,
      params: { payment: { identifiers: { c_id: cId }, amount: { value: amount, currency }, ...extra } },
    });
  }

  async getStatus({ cId, hId } = {}) {
    const identifiers = {};
    if (cId) identifiers.c_id = cId;
    if (hId) identifiers.h_id = hId;
    return this._send({ method: 'payment.status', params: { payment: { identifiers } } });
  }
}

async function main() {
  const client = new MultihubClient({
    appId: process.env.MULTIHUB_APP_ID || '1',
    secretKey: process.env.MULTIHUB_SECRET_KEY || 'your_secret_key',
  });

  // 1. Ping the gateway
  const pingResult = await client.ping();
  if (!pingResult.success) {
    console.error(`Gateway unreachable: ${pingResult.error.message}`);
    return;
  }
  console.log('Gateway is up');

  // 2. Check balance
  const balanceResult = await client.getBalance();
  if (balanceResult.success) {
    for (const b of balanceResult.result.balances) {
      console.log(`  ${b.currency}: ${b.available}`);
    }
  } else {
    console.error(`Balance check failed: ${balanceResult.error.message}`);
  }

  // 3. Create a deposit
  const orderId = Date.now();
  const depositResult = await client.createDeposit(14701, 10000, 'INR', orderId, {
    description: `Order #${orderId}`,
    payer: {
      email: '[email protected]',
      person: { first_name: 'John', last_name: 'Doe' },
    },
  });

  if (depositResult.success) {
    console.log(`Deposit created (request_id=${depositResult.request_id})`);
  } else {
    console.error(`Deposit failed: ${depositResult.error.message}`);
    return;
  }

  // 4. Poll for status
  for (let i = 0; i < 5; i++) {
    await new Promise((r) => setTimeout(r, 3000));
    const statusResult = await client.getStatus({ cId: orderId });
    if (statusResult.success) {
      const status = statusResult.result.payment.status.status;
      console.log(`Payment status: ${status}`);
      if (['completed', 'failed', 'cancelled'].includes(status)) break;
    } else {
      console.error(`Status check failed: ${statusResult.error.message}`);
      break;
    }
  }
}

main().catch(console.error);