Node.js SDK
Official Node.js SDK for Moneybag Payment API
Node.js SDK
Official Node.js SDK for Moneybag Payment Gateway with full TypeScript support. Integrate Moneybag payments into your Node.js applications with ease.
Installation
Using npm
npm install @moneybag/sdk
Using yarn
yarn add @moneybag/sdk
Requirements
- Node.js >= 14.0.0
- npm >= 6.0.0
Features
- ✅ Full TypeScript support with type definitions
- ✅ Automatic request retry with exponential backoff
- ✅ Comprehensive error handling
- ✅ Built-in request/response validation
- ✅ Redirect URL parsing utilities
- ✅ Promise-based API
Quick Start
Initialize the SDK
const { MoneybagSdk } = require('@moneybag/sdk');
// or
import { MoneybagSdk } from '@moneybag/sdk';
// Initialize the SDK
const moneybag = new MoneybagSdk({
apiKey: 'your-merchant-api-key',
baseUrl: 'https://sandbox.api.moneybag.com.bd/api/v2' // Use sandbox for testing
});
Configuration Options
apiKey
(required): Your merchant API keybaseUrl
(required): The API base URL- Sandbox:
https://sandbox.api.moneybag.com.bd/api/v2
- Production:
https://api.moneybag.com.bd/api/v2
- Sandbox:
timeout
(optional): Request timeout in milliseconds (default: 30000)retryAttempts
(optional): Number of retry attempts for failed requests (default: 3)
Usage Examples
Create a Payment Checkout
const checkoutRequest = {
order_id: 'order123',
currency: 'BDT',
order_amount: '100.00',
order_description: 'Purchase from my store',
success_url: 'https://yourdomain.com/payment/success',
cancel_url: 'https://yourdomain.com/payment/cancel',
fail_url: 'https://yourdomain.com/payment/fail',
ipn_url: 'https://yourdomain.com/payment/ipn', // Optional IPN URL
customer: {
name: 'John Doe',
email: 'john@example.com',
address: '123 Main Street',
city: 'Dhaka',
postcode: '1000',
country: 'Bangladesh',
phone: '+8801700000000'
},
// Optional fields
order_items: [
{
product_name: 'Product 1',
quantity: 1,
unit_price: '100.00'
}
],
shipping: {
name: 'John Doe',
address: '123 Main Street',
city: 'Dhaka',
postcode: '1000',
country: 'Bangladesh'
},
payment_info: {
allowed_payment_methods: ['card', 'mobile_banking'],
is_recurring: false,
requires_emi: false
}
};
try {
const response = await moneybag.checkout(checkoutRequest);
console.log('Checkout URL:', response.data.checkout_url);
// Redirect customer to response.data.checkout_url
} catch (error) {
console.error('Checkout failed:', error);
}
Verify Payment
try {
const response = await moneybag.verify('transaction_id_here');
if (response.data.verified && response.data.status === 'SUCCESS') {
console.log('Payment verified successfully');
// Update order status in your database
}
} catch (error) {
console.error('Verification failed:', error);
}
Handle Redirect URLs
import { RedirectHandler } from '@moneybag/sdk';
// In your success/fail/cancel callback handler
app.get('/payment/success', async (req, res) => {
try {
// Parse redirect parameters
const params = RedirectHandler.parseRedirectUrl(req.url);
// params = { transaction_id: 'txn123...', status: 'SUCCESS' }
// Verify the payment
const verification = await moneybag.verify(params.transaction_id);
if (verification.data.verified && params.status === 'SUCCESS') {
// Payment successful
}
} catch (error) {
console.error('Error handling redirect:', error);
}
});
Framework Integration
Express.js Integration
const express = require('express');
const { MoneybagSdk, RedirectHandler } = require('@moneybag/sdk');
const app = express();
app.use(express.json());
const moneybag = new MoneybagSdk({
apiKey: process.env.MONEYBAG_API_KEY,
baseUrl: process.env.MONEYBAG_BASE_URL || 'https://sandbox.api.moneybag.com.bd/api/v2'
});
// Create payment endpoint
app.post('/api/create-payment', async (req, res) => {
try {
const { amount, customer, products } = req.body;
const checkoutRequest = {
order_id: `ORDER_${Date.now()}`,
order_amount: amount.toString(),
currency: 'BDT',
order_description: 'Purchase from Express Shop',
success_url: `${req.protocol}://${req.get('host')}/payment/success`,
cancel_url: `${req.protocol}://${req.get('host')}/payment/cancel`,
fail_url: `${req.protocol}://${req.get('host')}/payment/fail`,
customer: customer,
order_items: products
};
const response = await moneybag.checkout(checkoutRequest);
res.json({
success: true,
checkout_url: response.data.checkout_url,
session_id: response.data.session_id
});
} catch (error) {
console.error('Payment error:', error);
res.status(error.status || 500).json({
success: false,
error: error.message
});
}
});
// Payment success callback
app.get('/payment/success', async (req, res) => {
try {
const params = RedirectHandler.parseRedirectUrl(req.url);
const verification = await moneybag.verify(params.transaction_id);
if (verification.data.verified && params.status === 'SUCCESS') {
// Update order status in database
// Send confirmation email
// Clear cart
res.render('payment-success', {
transaction: verification.data
});
} else {
res.render('payment-failed', {
message: 'Payment verification failed'
});
}
} catch (error) {
res.status(500).render('error', { error });
}
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
Next.js Integration
API Route (App Router)
// app/api/checkout/route.js
import { NextResponse } from 'next/server';
import MoneybagClient from '@/lib/moneybag';
const moneybag = new MoneybagClient(
process.env.MONEYBAG_API_KEY,
process.env.NODE_ENV === 'production' ? 'production' : 'sandbox'
);
export async function POST(request) {
try {
const body = await request.json();
const checkout = await moneybag.createCheckout({
order_id: `ORDER_${Date.now()}`,
order_amount: body.amount,
currency: 'BDT',
order_description: body.description,
success_url: `${process.env.NEXT_PUBLIC_URL}/payment/success`,
cancel_url: `${process.env.NEXT_PUBLIC_URL}/payment/cancel`,
fail_url: `${process.env.NEXT_PUBLIC_URL}/payment/fail`,
customer: body.customer
});
return NextResponse.json({
success: true,
payment_url: checkout.data.payment_url
});
} catch (error) {
return NextResponse.json(
{ success: false, error: error.message },
{ status: error.status || 500 }
);
}
}
Client Component
// app/checkout/page.js
'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
export default function CheckoutPage() {
const router = useRouter();
const [loading, setLoading] = useState(false);
const handlePayment = async () => {
setLoading(true);
try {
const response = await fetch('/api/checkout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
amount: 1000,
description: 'Product purchase',
customer: {
name: 'John Doe',
email: 'john@example.com',
phone: '+8801700000000'
}
})
});
const data = await response.json();
if (data.success) {
window.location.href = data.payment_url;
} else {
alert('Payment failed: ' + data.error);
}
} catch (error) {
alert('Error: ' + error.message);
} finally {
setLoading(false);
}
};
return (
<button onClick={handlePayment} disabled={loading}>
{loading ? 'Processing...' : 'Pay with Moneybag'}
</button>
);
}
NestJS Integration
// moneybag.service.ts
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import axios, { AxiosInstance } from 'axios';
@Injectable()
export class MoneybagService {
private client: AxiosInstance;
constructor(private configService: ConfigService) {
const apiKey = this.configService.get<string>('MONEYBAG_API_KEY');
const environment = this.configService.get<string>('NODE_ENV');
this.client = axios.create({
baseURL: environment === 'production'
? 'https://api.moneybag.com.bd/api/v2'
: 'https://sandbox.api.moneybag.com.bd/api/v2',
headers: {
'X-Merchant-API-Key': apiKey,
'Content-Type': 'application/json',
},
});
}
async createCheckout(data: any) {
const response = await this.client.post('/payments/checkout', data);
return response.data;
}
async verifyPayment(transactionId: string) {
const response = await this.client.get(`/payments/verify/${transactionId}`);
return response.data;
}
}
// payment.controller.ts
import { Controller, Post, Get, Body, Query } from '@nestjs/common';
import { MoneybagService } from './moneybag.service';
@Controller('payment')
export class PaymentController {
constructor(private moneybagService: MoneybagService) {}
@Post('checkout')
async createCheckout(@Body() body: any) {
return await this.moneybagService.createCheckout({
order_id: `ORDER_${Date.now()}`,
order_amount: body.amount,
currency: 'BDT',
customer: body.customer,
// ... other fields
});
}
@Get('verify')
async verifyPayment(@Query('transaction_id') transactionId: string) {
return await this.moneybagService.verifyPayment(transactionId);
}
}
Error Handling
The SDK throws typed exceptions for different error scenarios:
import {
ValidationException,
ApiException,
NetworkException
} from '@moneybag/sdk';
try {
await moneybag.checkout(request);
} catch (error) {
if (error instanceof ValidationException) {
// Handle validation errors
console.error('Invalid request:', error.message);
} else if (error instanceof ApiException) {
// Handle API errors
console.error('API error:', error.statusCode, error.message);
} else if (error instanceof NetworkException) {
// Handle network errors
console.error('Network error:', error.message);
}
}
Constants
The SDK exports useful constants:
import { PAYMENT_STATUS, PAYMENT_METHODS, CURRENCY_CODES } from '@moneybag/sdk';
// Payment statuses
PAYMENT_STATUS.SUCCESS // 'SUCCESS'
PAYMENT_STATUS.FAILED // 'FAILED'
PAYMENT_STATUS.PENDING // 'PENDING'
PAYMENT_STATUS.CANCELLED // 'CANCELLED'
// Payment methods
PAYMENT_METHODS.CARD // 'card'
PAYMENT_METHODS.MOBILE_BANKING // 'mobile_banking'
// Currency codes
CURRENCY_CODES.BDT // 'BDT'
CURRENCY_CODES.USD // 'USD'
Webhook Signature Verification
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return `sha256=${expectedSignature}` === signature;
}
// Express middleware for webhook verification
const webhookMiddleware = (req, res, next) => {
const signature = req.headers['x-webhook-signature'];
const payload = JSON.stringify(req.body);
if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
next();
};
Testing
// test/moneybag.test.js
const MoneybagClient = require('../lib/moneybag');
describe('Moneybag Payment Integration', () => {
let moneybag;
beforeAll(() => {
moneybag = new MoneybagClient(process.env.TEST_API_KEY, 'sandbox');
});
test('should create checkout successfully', async () => {
const checkout = await moneybag.createCheckout({
order_id: `TEST_${Date.now()}`,
order_amount: 100,
currency: 'BDT',
customer: {
name: 'Test User',
email: 'test@example.com',
phone: '+8801700000000'
}
});
expect(checkout.success).toBe(true);
expect(checkout.data.payment_url).toBeDefined();
});
test('should handle invalid API key', async () => {
const invalidClient = new MoneybagClient('invalid_key', 'sandbox');
await expect(
invalidClient.createCheckout({ /* data */ })
).rejects.toThrow('Invalid API key');
});
});
Environment Variables
# .env
MONEYBAG_API_KEY=sk_test_your_api_key_here
MONEYBAG_WEBHOOK_SECRET=whsec_your_webhook_secret
MONEYBAG_ENVIRONMENT=sandbox
NEXT_PUBLIC_URL=http://localhost:3000
TypeScript Support
// types/moneybag.d.ts
export interface Customer {
name: string;
email: string;
phone: string;
address?: string;
city?: string;
postcode?: string;
country?: string;
}
export interface CheckoutRequest {
order_id: string;
order_amount: number;
currency: string;
order_description?: string;
success_url: string;
cancel_url: string;
fail_url: string;
customer: Customer;
metadata?: Record<string, any>;
}
export interface CheckoutResponse {
success: boolean;
data: {
payment_url: string;
transaction_id: string;
expires_at: string;
};
}
export interface VerificationResponse {
success: boolean;
data: {
transaction_id: string;
order_id: string;
amount: number;
status: 'SUCCESS' | 'FAILED' | 'CANCELLED' | 'PROCESSING';
payment_method: string;
paid_at: string;
};
}
Resources
Support
- Email: support@moneybag.com.bd
- GitHub Issues: Report bugs or request features
- Status Page: status.moneybag.com.bd