Node.js Examples
Complete Node.js example client for integrating with the Multihub API using the built-incrypto 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:Copy
export MULTIHUB_APP_ID="1"
export MULTIHUB_SECRET_KEY="your_secret_key"
MultihubClient Class (JavaScript)
Copy
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)
Copy
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)
Copy
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
Copy
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)
Copy
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
Copy
// 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
Copy
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 thesuccess field to determine the outcome:
Copy
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:Copy
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
Copy
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);
