Merchant API – Access & Security Specification

Overview

Bridg.Money Merchant APIs use HMAC-SHA256 authentication to ensure request authenticity, payload integrity, replay-attack prevention, and response integrity

End Points

EnvironmentBase URL
Productionhttps://api.bridg.money
Betahttps://api-beta.bridg.money

Beneficiaries

Add Beneficiary

Use this API to add a beneficiary to your Bridg.Money account by providing the beneficiary’s name, phone number, and bank account details. Only active beneficiaries can receive payouts.

POST /v1/beneficiaries

Body

application/json
namestringrequired

Beneficiary name. Max 100 characters; letters, numbers, spaces, and common special characters allowed.

sample - Ravi Traders Pvt Ltd

emailstring

Valid email address (optional).

sample - ravi@merchant.com

phoneNumberstringrequired

Beneficiary mobile number (valid Indian mobile number).

sample - 9876543210

accountNumberstringrequired

Bank account number (9–18 digits). Must be unique for active beneficiaries under the same business.

sample - 0002053000010425

ifscstringrequired

Bank IFSC (11 characters. Format: AAAA0XXXXXX).

sample - UTIB0000123

Response

application/json
201Beneficiary created successfully
{
  "success": true,
  "message": "Beneficiary created successfully",
  "data": {
    "beneficiaryId": "123e4567-e89b-12d3-a456-426614174000",
    "beneficiaryCode": "BEN000123"
  }
}
400Duplicate active beneficiary or invalid data
{
  "success": false,
  "message": "Duplicate active beneficiary account"
}
401Unauthorized
{
  "success": false,
  "message": "Unauthorized"
}
500Internal server error
{
  "success": false,
  "message": "Something went wrong"
}

Delete Beneficiary

This operation performs a soft delete by setting the beneficiary status to Inactive (0). Inactive beneficiaries cannot receive payouts, but historical payout records remain preserved.

DELETE /v1/beneficiaries/:beneficiaryId

Path Parameters

beneficiaryIdstringrequired

Unique ID of the beneficiary to deactivate

sample - 123e4567-e89b-12d3-a456-426614174000

Response

application/json
200Beneficiary deleted successfully
{
  "success": true,
  "message": "Beneficiary deleted successfully",
  "data": {
    "beneficiaryId": "123e4567-e89b-12d3-a456-426614174000",
    "status": 0
  }
}
404Beneficiary not found
{
  "success": false,
  "message": "Beneficiary not found"
}
500Internal server error
{
  "success": false,
  "message": "Internal server error"
}

Payouts

Initiate Payout Transaction

Initiates a payout transfer to a vendor. Wallet balance is validated and debited during processing.

Processing Flow:
• Step 1: Payout record created in database
• Step 2: Wallet validation and debit
• Step 3: Webhook triggered (if configured)
• Step 4: Bank transfer initiated
• Step 5: Final status persisted

⚠️ Final payout status should be verified using the Get Payout API.

POST /v1/payouts

Body

application/json
beneficiaryIdstringrequired

Beneficiary unique identifier (UUID). Beneficiary must exist, be active, and belong to the authenticated business.

sample - 123e4567-e89b-12d3-a456-426614174001

amountstringrequired

Payout amount as a string with exact decimal format (e.g., "1000.00"). Must match configured decimal precision and business limits.

sample - 1000.00

transactionTypestringrequired

Transaction mode. Allowed values: I (IMPS), N (NEFT), R (RTGS), S (SELF). Must match business configuration.

sample - N

Response

application/json
200Payout processed successfully or currently in progress
{
  "success": true,
  "message": "Payout initiated and is being processed",
  "data": {
    "payoutTransactionId": "e4df91c1-4180-43d7-8de4-6e0a20a86db9",
    "amount": "1000.00",
    "status": "InProgress",
    "commissionAmount": "10.00",
    "commissionGSTAmount": "1.80"
  }
}
500Payout failed
{
  "success": true,
  "message": "Payout failed",
  "data": {
    "payoutTransactionId": "e4df91c1-4180-43d7-8de4-6e0a20a86db9",
    "amount": "1000.00",
    "status": "Failed",
    "commissionAmount": "10.00",
    "commissionGSTAmount": "1.80"
  }
}
400Validation error, insufficient balance, limit exceeded, or configuration issue
{
  "success": false,
  "message": "Failed to initiate payout"
}
401Unauthorized
{
  "success": false,
  "message": "Unauthorized"
}

Transaction Types

  • I – IMPS
  • N – NEFT
  • R – RTGS
  • S – SELF

Payout Transaction

Fetches complete payout transaction details including vendor information, transaction reference, commission details, and current payout status.

GET /v1/payouts/:payoutTransactionId

Path Parameters

payoutTransactionIdstringrequired

Unique payout transaction identifier (UUID).

sample - 5f8f75b4-8bc6-4c08-b90c-f90a34df2ec9

Response

application/json
200Payout details retrieved successfully
{
  "success": true,
  "data": [
    {
      "payoutTransactionId": "5f8f75b4-8bc6-4c08-b90c-f90a34df2ec9",
      "businessId": "123e4567-e89b-12d3-a456-426614174000",
      "merchantId": "123e4567-e89b-12d3-a456-426614174999",
      "vendorId": "123e4567-e89b-12d3-a456-426614174001",
      "vendorCode": "VEND001",
      "name": "Ravi Traders",
      "ifsc": "HDFC0001234",
      "accountNumber": "123456789012",
      "transactionType": "N",
      "transactionTypeName": "NEFT",
      "amount": "1000.00",
      "commissionAmount": "10.00",
      "commissionGSTAmount": "1.80",
      "status": "Successful",
      "responseCode": "100",
      "responseMessage": "Transfer completed",
      "transactionReference": "BANKREF12345",
      "createdDate": "2025-01-10T10:30:00Z",
      "updatedDate": "2025-01-10T10:31:00Z"
    }
  ]
}
404Payout not found
{
  "success": false,
  "message": "Data does not exist"
}
400Server error
{
  "success": false,
  "message": "Server error"
}
⚠️ Note:
  • Response returns an array containing the payout record.
  • If no record is found, API may return an empty array unless 404 mode is explicitly enabled.

Postman Collection

Use the official Postman collection to quickly test and integrate Bridg.Money Payout APIs.

Postman Setup Instructions

  • Set base_url in environment Variables.
  • Set api_key in environment Variables.
  • Set api_secret in environment Variables.
  • All request URLs use {{base_url}}

Payout API Call with Signature

Important

  • Delimiter must be pipe (|)
  • Method must be uppercase
  • Timestamp must be in milliseconds
  • Sign the exact JSON string sent in the request
  • HMAC algorithm: SHA256 (hex output)
payout.ts
/**
 * Initiate Payout - Bridg.Money API
 * Canonical format:
 * METHOD | PATH | TIMESTAMP | BODY
 */

import axios from "axios";
import crypto from "crypto";

const API_KEY = "YOUR_API_KEY";
const API_SECRET = "YOUR_API_SECRET";

async function initiatePayout() {
  const method = "POST";
  const path = "/v1/payouts";
  const baseUrl = "https://api-beta.bridg.money";

  const body = {
    beneficiaryId: "f81d4fae-7dec-11d0-a765-00a0c91e6bf6",
    amount: "100.00",
    transactionType: "I"
  };

  const timestamp = Date.now().toString();
  const payload = JSON.stringify(body);

  const canonical = [
    method.toUpperCase(),
    path,
    timestamp,
    payload
  ].join("|");

  const signature = crypto
    .createHmac("sha256", API_SECRET)
    .update(canonical)
    .digest("hex");

  const response = await axios.post(
    baseUrl + path,
    body,
    {
      headers: {
        "Content-Type": "application/json",
        "x-api-key": API_KEY,
        "x-timestamp": timestamp,
        "x-signature": signature
      }
    }
  );

  console.log(response.data);
}

initiatePayout();

Payout Testing Accounts

SELF BANK TESTING

Beneficiary Account Number: 0002053000010425

Account Name: BEENA DENNY

NEFT / OTHER BANK TESTING

Beneficiary Account Number: 0574050000000449

Beneficiary IFSC: CSBK0000237

IMPS / OTHER BANK TESTING

Beneficiary Account Number: 123456041

Beneficiary IFSC: UTIB0000119

Authentication Headers

HeadersDescription
x-api-keyPublic API key
x-timestampUnix epoch milliseconds as string (Date.now().toString())
x-signatureHMAC-SHA256 signature

Timestamp Rules

  • Format: Unix epoch milliseconds string
  • Validity: ±5 minutes

Canonical Request Format

METHOD | PATH | TIMESTAMP | BODY

Signature Algorithm

HMAC-SHA256 with hex encoding

Generate Request Signature

Canonical Request Format

METHOD | PATH | TIMESTAMP | BODY

• Delimiter must be pipe (|) • Timestamp must be in milliseconds • GET/DELETE/HEAD/OPTIONS must have empty body • Signature algorithm: HMAC-SHA256 (hex)

generateSignature.typescript
/**
 * Generates HMAC-SHA256 signature for Bridg.Money API
 * Canonical format:
 * METHOD | PATH | TIMESTAMP | BODY
 */

import crypto from "crypto";

export function generateApiSignature({
  method,
  path,
  body,
  apiSecret,
}) {
  const timestamp = Date.now().toString();

  const canonicalBody =
    ["GET", "DELETE", "HEAD", "OPTIONS"].includes(method.toUpperCase())
      ? ""
      : body
        ? JSON.stringify(body)
        : "";

  const canonicalString = [
    method.toUpperCase(),
    path,
    timestamp,
    canonicalBody,
  ].join("|");

  const signature = crypto
    .createHmac("sha256", apiSecret)
    .update(canonicalString)
    .digest("hex");

  return { timestamp, signature };
}

Verify Response Signature

Response Signature Verification

TIMESTAMP | RAW_RESPONSE_STRING

• Delimiter must be pipe (|)
• Use the exact raw response body (do NOT re-stringify JSON)
• Signature algorithm: HMAC-SHA256 (hex)
• Use constant-time comparison

verifySignature.typescript

/**
 * Verifies response signature from Bridg.Money API
 * Canonical format:
 * TIMESTAMP | RAW_RESPONSE_STRING
 */

import crypto from "crypto";

export function verifyResponseSignature({
  timestamp,
  rawBody, // MUST be raw response string
  signature,
  apiSecret,
}) {
  const canonicalString = [
    timestamp,
    rawBody
  ].join("|");

  const expectedSignature = crypto
    .createHmac("sha256", apiSecret)
    .update(canonicalString)
    .digest("hex");

  const sigBuf = Buffer.from(signature, "hex");
  const expBuf = Buffer.from(expectedSignature, "hex");

  if (sigBuf.length !== expBuf.length) return false;

  return crypto.timingSafeEqual(sigBuf, expBuf);
}

IP Whitelisting

Follow the instructions below to configure IP whitelisting:

  • Log in to your dashboard using your credentials.
  • Navigate to Settings > IP Whitelist.
  • You will see the IP Whitelisting page with no IPs added.
IP whitelisting initial page
  • IP: Enter the IP address from which you want to allow API access.
  • Click Add IP to whitelist the entered IP address.
IP whitelisting setup

Once IP addresses are added to the whitelist, only requests originating from these IPs will be allowed to access your APIs. This helps ensure that only trusted systems can interact with your account, reducing the risk of unauthorized access. You can add or remove whitelisted IPs at any time, giving you full control over API access.

Response Signing

Responses include:

x-response-timestamp

x-response-signature

Canonical Response Format

STATUS | PATH | RESPONSE_TIMESTAMP | RESPONSE_BODY

Error Codes

CodeDescription
200Request successful
400Invalid request format or malformed signature
401Missing authentication headers or request expired
403Invalid API key, signature, or IP not whitelisted
500Internal server error

Webhook

Webhooks allow your application to receive real-time updates about payout status changes.

Webhook Payload

webhook_payload.json
{
  "payoutWebhookId": "1ee3be28-0330-48eb-b89c-8290413c81f8",
  "event": "Successful",
  "data": {
    "status": 11,
    "timestamp": "2026-03-04 17:05:15.000000",
    "businessId": "1b313206-049a-11f1-8a8e-0a0c26167b3f",
    "responseCode": "100",
    "transactionId": "BMPT2026030400007",
    "responseMessage": "Operation Success",
    "payoutTransactionId": "45e254c0-17ec-11f1-8a8e-0a0c26167b3f"
  }
}

Webhook Event Types

EventStatus CodeDescription
Initiated3The payout request has been created and submitted for processing.
Successful11The payout has been processed successfully and funds were transferred.
Failed12The payout failed during processing.

Webhook Headers

  • x-webhook-timestamp
  • x-webhook-signature
  • x-webhook-alg (sha256)

Canonical String

TIMESTAMP | RAW_REQUEST_BODY

Use the exact raw request body received by your server when verifying the webhook signature.

verifyWebhook.typescript

import crypto from "crypto";

export function verifyWebhookSignature({
  timestamp,
  rawBody,
  signature,
  webhookSecret,
}) {

  const tolerance = 5 * 60 * 1000;
  const diff = Math.abs(Date.now() - Number(timestamp));

  if (diff > tolerance) {
    throw new Error("Webhook timestamp expired");
  }

  const canonical = `${timestamp}|${rawBody}`;

  const expectedSignature = crypto
    .createHmac("sha256", webhookSecret)
    .update(canonical)
    .digest("hex");

  return expectedSignature === signature;
}

Version

  • API Security Spec: v1.1
  • Last Updated: Jan 2026