XoomPe Client Payments API

Client endpoints for authentication, wallet balance, payout creation, and transaction tracking.

Base URL

https://xoompe.com/XoomPeAPI
All requests must be made over HTTPS. Protected endpoints require Authorization: Bearer <accessToken>.
Examples use placeholders: {{base_url}}, {{access_token}}, {{refresh_token}}, {{txnId}}.

Authentication

Generate access tokens using ClientId and ClientSecret, then call payout endpoints with Bearer JWT.

Authorization Header

Header
Authorization: Bearer {{access_token}}

Generate Access Token

Generate tokens using ClientId + ClientSecret (recommended) or Email + Password.

POST
/token

Request

curl --location '{{base_url}}/token' \
  --header 'Content-Type: application/json' \
  --data '{
    "clientId": "{{client_id}}",
    "clientSecret": "{{client_secret}}"
  }'
const response = await fetch('{{base_url}}/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    clientId: '{{client_id}}',
    clientSecret: '{{client_secret}}'
  })
});
const data = await response.json();
import requests
response = requests.post('{{base_url}}/token', json={
  'clientId': '{{client_id}}',
  'clientSecret': '{{client_secret}}'
})
data = response.json()
$ch = curl_init('{{base_url}}/token');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
  'clientId' => '{{client_id}}',
  'clientSecret' => '{{client_secret}}'
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);

Response

{
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refreshToken": "def50200...",
  "expiresIn": 600,
  "tokenType": "Bearer"
}

Refresh Token

Use refresh token to get a new access token.

POST
/refresh

Request

curl --location '{{base_url}}/refresh' \
  --header 'Content-Type: application/json' \
  --data '{
    "refreshToken": "{{refresh_token}}"
  }'
const response = await fetch('{{base_url}}/refresh', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ refreshToken: '{{refresh_token}}' })
});
const data = await response.json();
import requests
response = requests.post('{{base_url}}/refresh', json={'refreshToken': '{{refresh_token}}'})
data = response.json()
$ch = curl_init('{{base_url}}/refresh');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['refreshToken' => '{{refresh_token}}']));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);

Response

{
  "accessToken": "...new...",
  "refreshToken": "...new...",
  "expiresIn": 600,
  "tokenType": "Bearer"
}

Get Wallet Balance

Retrieve current available wallet balance.

GET
/Payout/getWalletBalance

Request

curl --location '{{base_url}}/Payout/getWalletBalance' \
  --header 'Authorization: Bearer {{access_token}}'
const response = await fetch('{{base_url}}/Payout/getWalletBalance', {
  headers: { 'Authorization': 'Bearer {{access_token}}' }
});
const data = await response.json();
import requests
response = requests.get('{{base_url}}/Payout/getWalletBalance',
  headers={'Authorization': 'Bearer {{access_token}}'}
)
data = response.json()
$ch = curl_init('{{base_url}}/Payout/getWalletBalance');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer {{access_token}}']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);

Response

{
  "statusCode": 200,
  "status": true,
  "message": "Balance fetched successfully",
  "availableBalance": 12345.67
}

Initiate Payout

Create a payout transaction from client wallet to beneficiary bank account.

POST
/Payout/CreateTransaction

Request Body

FieldTypeRequiredDescription
beneficiaryNamestringYesOnly letters and spaces; 3–200 chars
beneficiaryAccountNumberstringYes8–20 chars
ifscstringYes^[A-Z]{4}0[A-Z0-9]{6}$
amountnumberYes5000–10000000
clientTransactionRefNostringNoOptional idempotency reference

Request

curl --location '{{base_url}}/Payout/CreateTransaction' \
  --header 'Authorization: Bearer {{access_token}}' \
  --header 'Content-Type: application/json' \
  --data '{
    "beneficiaryName": "John Doe",
    "beneficiaryAccountNumber": "123456789012",
    "ifsc": "ABCD0123456",
    "amount": 5000,
    "clientTransactionRefNo": "INV-1001"
  }'
const response = await fetch('{{base_url}}/Payout/CreateTransaction', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer {{access_token}}',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    beneficiaryName: 'John Doe',
    beneficiaryAccountNumber: '123456789012',
    ifsc: 'ABCD0123456',
    amount: 5000,
    clientTransactionRefNo: 'INV-1001'
  })
});
const data = await response.json();
import requests

response = requests.post(
  '{{base_url}}/Payout/CreateTransaction',
  headers={'Authorization': 'Bearer {{access_token}}'},
  json={
    'beneficiaryName': 'John Doe',
    'beneficiaryAccountNumber': '123456789012',
    'ifsc': 'ABCD0123456',
    'amount': 5000,
    'clientTransactionRefNo': 'INV-1001'
  }
)
data = response.json()
$ch = curl_init('{{base_url}}/Payout/CreateTransaction');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
  'beneficiaryName' => 'John Doe',
  'beneficiaryAccountNumber' => '123456789012',
  'ifsc' => 'ABCD0123456',
  'amount' => 5000,
  'clientTransactionRefNo' => 'INV-1001'
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
  'Authorization: Bearer {{access_token}}',
  'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);

Response (success)

{
  "statusCode": 201,
  "responseCode": 1,
  "status": true,
  "message": "Transaction created successfully",
  "transactionNumber": "TX26010300001",
  "transaction": {
    "transactionNumber": "TX26010300001",
    "clientTransactionRefNo": "INV-1001",
    "beneficiaryName": "John Doe",
    "beneficiaryAccountNumber": "123456789012",
    "ifsc": "ABCD0123456",
    "amount": 5000,
    "status": "Pending",
    "utr": null,
    "remarks": null,
    "createdAt": "2026-01-09T17:21:00",
    "updatedAt": null
  }
}

Response (idempotent duplicate reference)

{
  "statusCode": 200,
  "responseCode": 1,
  "status": true,
  "message": "Transaction already exists (idempotent)",
  "transactionNumber": "TX26010300001",
  "transaction": {
    "transactionNumber": "TX26010300001",
    "clientTransactionRefNo": "INV-1001",
    "beneficiaryName": "John Doe",
    "beneficiaryAccountNumber": "123456789012",
    "ifsc": "ABCD0123456",
    "amount": 5000,
    "status": "Pending"
  }
}

Create Bulk Payouts

Submit multiple payout transactions in a single API call (1–500 items).

POST
/Payout/CreateBulkTransactions

Request

curl --location '{{base_url}}/Payout/CreateBulkTransactions' \
  --header 'Authorization: Bearer {{access_token}}' \
  --header 'Content-Type: application/json' \
  --data '{
    "transactions": [
      {
        "beneficiaryName": "A Person",
        "beneficiaryAccountNumber": "1234567890",
        "ifsc": "ABCD0123456",
        "amount": 5000,
        "clientTransactionRefNo": "BULK-1"
      },
      {
        "beneficiaryName": "B Person",
        "beneficiaryAccountNumber": "9876543210",
        "ifsc": "WXYZ0123456",
        "amount": 7500,
        "clientTransactionRefNo": "BULK-2"
      }
    ]
  }'
const response = await fetch('{{base_url}}/Payout/CreateBulkTransactions', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer {{access_token}}',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    transactions: [
      { beneficiaryName:'A Person', beneficiaryAccountNumber:'1234567890', ifsc:'ABCD0123456', amount:5000, clientTransactionRefNo:'BULK-1' },
      { beneficiaryName:'B Person', beneficiaryAccountNumber:'9876543210', ifsc:'WXYZ0123456', amount:7500, clientTransactionRefNo:'BULK-2' }
    ]
  })
});
const data = await response.json();
import requests

response = requests.post(
  '{{base_url}}/Payout/CreateBulkTransactions',
  headers={'Authorization': 'Bearer {{access_token}}'},
  json={
    'transactions': [
      {'beneficiaryName':'A Person','beneficiaryAccountNumber':'1234567890','ifsc':'ABCD0123456','amount':5000,'clientTransactionRefNo':'BULK-1'},
      {'beneficiaryName':'B Person','beneficiaryAccountNumber':'9876543210','ifsc':'WXYZ0123456','amount':7500,'clientTransactionRefNo':'BULK-2'}
    ]
  }
)
data = response.json()
$ch = curl_init('{{base_url}}/Payout/CreateBulkTransactions');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
  'transactions' => [
    ['beneficiaryName'=>'A Person','beneficiaryAccountNumber'=>'1234567890','ifsc'=>'ABCD0123456','amount'=>5000,'clientTransactionRefNo'=>'BULK-1'],
    ['beneficiaryName'=>'B Person','beneficiaryAccountNumber'=>'9876543210','ifsc'=>'WXYZ0123456','amount'=>7500,'clientTransactionRefNo'=>'BULK-2']
  ]
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
  'Authorization: Bearer {{access_token}}',
  'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);

Response

{
  "statusCode": 200,
  "status": true,
  "message": "Success: 2, Failed: 0",
  "successCount": 2,
  "failedCount": 0,
  "totalProcessed": 2,
  "successTransactions": [
    { "transactionNumber": "TX26010300001", "clientTransactionRefNo": "BULK-1", "beneficiaryName": "A Person", "amount": 5000 }
  ],
  "failedTransactions": []
}

Get Transactions (Client Filters)

Retrieve your transactions with pagination, search, and a wide set of column-level filters. All parameters are optional — combine any number of them to narrow down results.

GET
/Payout/GetClientTransactionsWithFilters

Query Parameters

ParameterTypeDefaultDescription
pageinteger1Page number for pagination
pageSizeinteger50Number of records per page
statusstring Filter by transaction status. Values: Pending, Success, Failed, Cancelled
searchstringGlobal keyword search across transaction number, beneficiary name, account number, client ref no, and UTR
transactionNumberstringFilter by transaction number (partial match)
beneficiaryNamestringFilter by beneficiary name (partial match)
accountNumberstringFilter by beneficiary account number (partial match)
ifscstringFilter by IFSC code (partial match)
utrstringFilter by UTR number (partial match)
remarksstringFilter by remarks (partial match)
batchStatusstring Filter by batch assignment. Values: batched, unbatched
amountdecimalExact amount match. Takes priority over minAmount/maxAmount
minAmountdecimalMinimum transaction amount (used only if amount is not set)
maxAmountdecimalMaximum transaction amount (used only if amount is not set)
datestringExact date filter — returns all transactions from that calendar day. Format: YYYY-MM-DD. Takes priority over date range.
startDatestringStart of date range. Format: YYYY-MM-DD
endDatestringEnd of date range (inclusive). Format: YYYY-MM-DD
Filter priority rules: When amount is provided, minAmount and maxAmount are ignored. When date is provided, it takes precedence over startDate/endDate.

Request

curl --location '{{base_url}}/Payout/GetClientTransactionsWithFilters?page=1&pageSize=50&status=Success&startDate=2026-01-01&endDate=2026-01-31' \
  --header 'Authorization: Bearer {{access_token}}'
const url = new URL('{{base_url}}/Payout/GetClientTransactionsWithFilters');
url.searchParams.set('page', '1');
url.searchParams.set('pageSize', '50');
url.searchParams.set('status', 'Success');
url.searchParams.set('startDate', '2026-01-01');
url.searchParams.set('endDate', '2026-01-31');

// Optional: add more filters as needed
// url.searchParams.set('beneficiaryName', 'John');
// url.searchParams.set('minAmount', '5000');
// url.searchParams.set('maxAmount', '100000');
// url.searchParams.set('utr', 'UTR123');
// url.searchParams.set('batchStatus', 'unbatched');

const response = await fetch(url, {
  headers: { 'Authorization': 'Bearer {{access_token}}' }
});
const data = await response.json();
import requests

response = requests.get(
  '{{base_url}}/Payout/GetClientTransactionsWithFilters',
  headers={'Authorization': 'Bearer {{access_token}}'},
  params={
    'page': 1,
    'pageSize': 50,
    'status': 'Success',
    'startDate': '2026-01-01',
    'endDate': '2026-01-31',
    # Optional filters:
    # 'beneficiaryName': 'John',
    # 'minAmount': 5000,
    # 'maxAmount': 100000,
    # 'utr': 'UTR123',
    # 'batchStatus': 'unbatched',
  }
)
data = response.json()
$params = http_build_query([
  'page'      => 1,
  'pageSize'  => 50,
  'status'    => 'Success',
  'startDate' => '2026-01-01',
  'endDate'   => '2026-01-31',
  // Optional filters:
  // 'beneficiaryName' => 'John',
  // 'minAmount' => 5000,
  // 'maxAmount' => 100000,
  // 'utr' => 'UTR123',
  // 'batchStatus' => 'unbatched',
]);
$ch = curl_init("{{base_url}}/Payout/GetClientTransactionsWithFilters?{$params}");
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer {{access_token}}']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);

Response

{
  "status": true,
  "message": "Transactions fetched successfully",
  "data": [
    {
      "transactionNumber": "TX26010300001",
      "clientTransactionRefNo": "INV-1001",
      "beneficiaryName": "John Doe",
      "beneficiaryAccountNumber": "123456789012",
      "ifsc": "ABCD0123456",
      "amount": 5000,
      "status": "Success",
      "utr": "UTR123456789",
      "remarks": null,
      "createdAt": "2026-01-09T17:21:00",
      "updatedAt": "2026-01-09T17:25:00"
    }
  ],
  "pagination": {
    "currentPage": 1,
    "pageSize": 50,
    "totalCount": 1,
    "totalPages": 1,
    "hasNextPage": false,
    "hasPreviousPage": false
  },
  "totalUnbatchedCount": 1
}

Get Transaction by ID

Retrieve complete details using transaction number (txnId).

GET
/Payout/GetTransactionByTxnId/{txnId}

Request

curl --location '{{base_url}}/Payout/GetTransactionByTxnId/TX26010300001' \
  --header 'Authorization: Bearer {{access_token}}'
const response = await fetch('{{base_url}}/Payout/GetTransactionByTxnId/TX26010300001', {
  headers: { 'Authorization': 'Bearer {{access_token}}' }
});
const data = await response.json();
import requests
response = requests.get(
  '{{base_url}}/Payout/GetTransactionByTxnId/TX26010300001',
  headers={'Authorization': 'Bearer {{access_token}}'}
)
data = response.json()
$ch = curl_init('{{base_url}}/Payout/GetTransactionByTxnId/TX26010300001');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer {{access_token}}']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);

Response

{
  "status": true,
  "message": "Transaction fetched successfully",
  "transaction": {
    "transactionNumber": "TX26010300001",
    "clientTransactionRefNo": "INV-1001",
    "beneficiaryName": "John Doe",
    "beneficiaryAccountNumber": "123456789012",
    "ifsc": "ABCD0123456",
    "amount": 5000,
    "status": "Success",
    "utr": "UTR123456789",
    "remarks": null,
    "createdAt": "2026-01-09T17:21:00",
    "updatedAt": "2026-01-09T17:25:00"
  }
}

Get Transaction by Client Reference

Retrieve transaction details using your own reference number (clientTransactionRefNo) that was supplied when creating the transaction.

GET
/Payout/GetTransactionByClientRef/{clientRefNo}

Path Parameter

ParameterTypeRequiredDescription
clientRefNostringYesThe client-supplied reference number used when creating the transaction (e.g. INV-1001)

Request

curl --location '{{base_url}}/Payout/GetTransactionByClientRef/INV-1001' \
  --header 'Authorization: Bearer {{access_token}}'
const clientRefNo = 'INV-1001';
const response = await fetch(`{{base_url}}/Payout/GetTransactionByClientRef/${clientRefNo}`, {
  headers: { 'Authorization': 'Bearer {{access_token}}' }
});
const data = await response.json();
import requests

client_ref_no = 'INV-1001'
response = requests.get(
  f'{{base_url}}/Payout/GetTransactionByClientRef/{client_ref_no}',
  headers={'Authorization': 'Bearer {{access_token}}'}
)
data = response.json()
$clientRefNo = 'INV-1001';
$ch = curl_init("{{base_url}}/Payout/GetTransactionByClientRef/{$clientRefNo}");
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer {{access_token}}']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);

Response (success)

{
  "status": true,
  "message": "Transaction fetched successfully",
  "transaction": {
    "transactionNumber": "TX26010300001",
    "clientTransactionRefNo": "INV-1001",
    "beneficiaryName": "John Doe",
    "beneficiaryAccountNumber": "123456789012",
    "ifsc": "ABCD0123456",
    "amount": 5000,
    "status": "Success",
    "utr": "UTR123456789",
    "remarks": null,
    "createdAt": "2026-01-09T17:21:00",
    "updatedAt": "2026-01-09T17:25:00"
  }
}

Response (not found)

{
  "status": false,
  "message": "Transaction not found"
}
This endpoint only returns transactions belonging to your account. Use this to look up a specific transaction using the same reference number you passed in clientTransactionRefNo during creation — useful for idempotency checks.

Webhooks

Receive real-time HTTP POST notifications to your configured webhook URL whenever a transaction status is updated by the admin.

Webhook Payload

The request body is a flat JSON object sent directly to your endpoint:

{
  "transactionNumber": "TXN26021700002",
  "clientTransactionRefNo": null,
  "status": "Success",
  "previousStatus": "Pending",
  "utr": "CMS260217147206",
  "amount": 6000,
  "beneficiaryName": "John Doe",
  "beneficiaryAccountNumber": "2345678866",
  "ifsc": "SBIN0001234",
  "remarks": "Processed",
  "updatedAt": "2026-02-17T14:49:55.6725005+05:30",
  "timestamp": 1771319995
}

Payload Fields

FieldTypeDescription
transactionNumberstringUnique system-generated transaction ID
clientTransactionRefNostring | nullYour reference number supplied at creation. null if not provided.
statusstringNew (current) status — Success, Failed, or Cancelled
previousStatusstringStatus before this update (e.g. Pending)
utrstring | nullUTR reference number. Populated when status is Success.
amountnumberTransaction amount in INR
beneficiaryNamestringName of the beneficiary
beneficiaryAccountNumberstringBeneficiary bank account number
ifscstringBeneficiary bank IFSC code
remarksstring | nullAdmin remarks, if any
updatedAtstring (ISO 8601)Timestamp of the status change (IST, with offset)
timestampintegerUnix epoch seconds (UTC) — use this to detect and reject replayed webhooks

Security Headers

Every webhook request includes two custom headers. HTTP delivers them in lowercase — use the exact names below:

Header (exact, lowercase)Example valueDescription
x-webhook-signature55d01f91372a768f6d0c89f5c75871...HMAC-SHA256 lowercase hex digest of the raw JSON body, keyed with your webhook secret
x-webhook-timestamp1771319995Unix epoch seconds (UTC) at the moment the webhook was dispatched
How the signature is generated (server side):
HMAC-SHA256(key=webhookSecret, message=rawJsonBody) → lowercase hex string.
The JSON body uses camelCase keys, no whitespace, and UTF-8 encoding — exactly as received in the request body. To verify, recompute the same HMAC over the raw bytes of the request body before any JSON parsing.

Verifying the Signature

const crypto = require('crypto');

// Call with the raw Buffer body (do NOT parse JSON first)
function verifyWebhook(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)           // raw UTF-8 Buffer or string
    .digest('hex');            // lowercase hex — matches server output
  return crypto.timingSafeEqual(
    Buffer.from(expected, 'hex'),
    Buffer.from(signature,  'hex')
  );
}

// Express example — use express.raw() so req.body is a Buffer
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const sig       = req.headers['x-webhook-signature'];
  const timestamp = req.headers['x-webhook-timestamp'];

  // Reject stale webhooks (older than 5 minutes)
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
    return res.status(400).send('Stale webhook');
  }

  if (!sig || !verifyWebhook(req.body, sig, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  const payload = JSON.parse(req.body);
  // payload.status     → "Success" | "Failed" | "Cancelled"
  // payload.utr        → UTR string (null if not Success)
  // payload.timestamp  → Unix epoch — use for your own dedup logic
  console.log('Status:', payload.status, '| UTR:', payload.utr);
  res.status(200).send('OK');
});
import hmac
import hashlib
import time
from flask import Flask, request, abort

app = Flask(__name__)
WEBHOOK_SECRET = 'your-webhook-secret'

@app.route('/webhook', methods=['POST'])
def webhook():
    # Flask normalises headers — both forms work, but lowercase matches actual delivery
    sig       = request.headers.get('x-webhook-signature', '')
    timestamp = request.headers.get('x-webhook-timestamp', '0')

    # Reject stale webhooks (older than 5 minutes)
    if abs(time.time() - int(timestamp)) > 300:
        abort(400, 'Stale webhook')

    raw_body = request.get_data()          # raw bytes — do NOT decode/parse first
    expected = hmac.new(
        WEBHOOK_SECRET.encode('utf-8'),
        raw_body,
        hashlib.sha256
    ).hexdigest()                          # lowercase hex — matches server output

    if not hmac.compare_digest(expected, sig):
        abort(401, 'Invalid signature')

    payload = request.get_json()
    # payload['status']    → "Success" | "Failed" | "Cancelled"
    # payload['utr']       → UTR string or None
    # payload['timestamp'] → Unix epoch int
    print('Status:', payload['status'], '| UTR:', payload.get('utr'))
    return 'OK', 200
<?php
$secret    = 'your-webhook-secret';
$sig       = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? 0;

// Reject stale webhooks (older than 5 minutes)
if (abs(time() - (int)$timestamp) > 300) {
    http_response_code(400);
    exit('Stale webhook');
}

$rawBody  = file_get_contents('php://input');
$expected = hash_hmac('sha256', $rawBody, $secret);

if (!hash_equals($expected, $sig)) {
    http_response_code(401);
    exit('Invalid signature');
}

$payload = json_decode($rawBody, true);
error_log('Status: ' . $payload['status'] . ' UTR: ' . ($payload['utr'] ?? 'N/A'));
http_response_code(200);
echo 'OK';
Responding to webhooks: Your endpoint must return an HTTP 2xx response. Webhooks are fire-and-forget — no automatic retries are performed. Configure your webhook URL and secret in the Client Dashboard.
Default secret: If no webhook secret is configured for your account, the signature is computed using the string default-secret. Always set a strong, unique secret in your dashboard before going to production.

Replay attack prevention: Always validate the X-Webhook-Timestamp header and reject requests older than 5 minutes.

Transaction Statuses

StatusDescription
PendingTransaction created and queued for processing
ProcessingTransaction is being processed by the payment gateway
SuccessTransaction completed successfully
FailedTransaction failed (insufficient balance, invalid account, etc.)
CancelledTransaction was reversed/refunded

Error Handling

API uses standard HTTP status codes and returns error details in JSON format.

Error Response Format

{
"statusCode": 400,
"responseCode": 0,
"status": false,
"message": "Invalid beneficiary name format. Only letters and spaces are allowed."
}

Common HTTP Status Codes

CodeDescription
200Success
201Created
400Bad Request - Validation error
401Unauthorized - Invalid or expired token
403Forbidden - Insufficient permissions
404Not Found
429Too Many Requests - Rate limit exceeded
500Internal Server Error

Validation Rules

Beneficiary Name

Account Number

IFSC Code

Amount

Security Best Practices