PayGate API Documentation

Welcome to the PayGate API documentation. This guide provides everything you need to integrate payments, payouts, and wallet functionality into your application.

Quick Start: All API requests use signature-based authentication with HMAC-SHA256. Make sure you have your API credentials ready before getting started.

Base URLs

  • Sandbox: https://api.paygate.sbs
  • Production: https://api.paygate.sbs
Current Status: Both sandbox and production use the same endpoint. Your API key determines whether you're in test or live mode.
Important - Currency Units:
โ€ข Payments: Amount in paise (smallest currency unit)
โ€ข Payouts: Amount in rupees (full currency unit)
โ€ข Conversion: 1 rupee = 100 paise

๐Ÿ” Authentication

All API requests require signature-based authentication using HMAC-SHA256.

Required Headers

HTTP Headers
X-Signature: {signature}
X-Timestamp: {unix_timestamp}
X-Idempotency-Key: {unique_key}  // For POST requests
Content-Type: application/json

๐Ÿ” Signature Generation

IMPORTANT: The PayGate API uses a two-step signature process. You must first hash your API key, then use that hash as the HMAC secret.

Critical Security Notice Never use your raw API key directly as the HMAC secret. Always hash it first as shown below.
JavaScript (Node.js)
const crypto = require('crypto');

// Step 1: Hash your API key with SHA256
const apiKeyHash = crypto
  .createHash('sha256')
  .update(apiKey)
  .digest('hex');

// Step 2: Generate signature using the HASH as secret
function generateSignature(merchantId, timestamp, payload, apiKeyHash) {
  const stringToSign = merchantId + timestamp + payload;
  return crypto
    .createHmac('sha256', apiKeyHash)  // Use the HASH
    .update(stringToSign)
    .digest('hex');
}

// Complete example
const merchantId = 'your-merchant-id';
const apiKey = 'sk_live_xxxx';
const timestamp = Math.floor(Date.now() / 1000);
const payload = '{"amount":10000,"currency":"INR"}';

// Generate API key hash
const apiKeyHash = crypto
  .createHash('sha256')
  .update(apiKey)
  .digest('hex');

// Generate final signature
const signature = generateSignature(merchantId, timestamp, payload, apiKeyHash);

console.log('Signature:', signature);

Signature String Construction

The signature string format is:

merchantId + timestamp + payload

Parameter Descriptions

Parameter Description Example
merchantId Your merchant UUID your-merchant-id-here
timestamp Current Unix timestamp in seconds 1734567890
payload JSON request body (exact string) or empty string for GET/DELETE {"amount":10000,"currency":"INR","description":"Payment"}
apiKeyHash SHA256 hash of your API key (NOT the raw key) your-api-key-hash-here
Signature String Format
The signature string is constructed by concatenating: merchantId + timestamp + payload
No separators or additional characters should be added between these values.

๐Ÿ”‘ Idempotency Keys

Use idempotency keys to prevent duplicate payments and ensure safe retries.

Generation Methods

JavaScript
// Method 1: UUID v4 (Recommended)
function generateIdempotencyKey() {
  return crypto.randomUUID();
}

// Method 2: Order-based hash
function generateIdempotencyKey(orderReference) {
  return crypto
    .createHash('sha256')
    .update(`${orderReference}-${Date.now()}`)
    .digest('hex')
    .substring(0, 32);
}

// Method 3: Random hex string
function generateIdempotencyKey() {
  return crypto.randomBytes(16).toString('hex');
}
Important: Idempotency keys are valid for 24 hours. Using the same key within this period will return the existing payment instead of creating a new one.

๐Ÿ’ณ Payment Creation

Create a new payment and get a payment URL for customer checkout.

POST
/api/v1/payments

Request Example

Terminal
# Create a new payment
curl --location 'https://api.paygate.sbs/api/v1/payments' \
--header 'X-Signature: sha256=your-calculated-signature' \
--header 'X-Timestamp: your-unix-timestamp' \
--header 'Content-Type: application/json' \
--header 'X-Idempotency-Key: your-unique-idempotency-key' \
--data '{
  "amount": 10000,
  "currency": "INR",
  "description": "Test payment for order #12346",
  "reference": "ORDER_1893089768",
  "redirectUrl": "https://yoursite.com/success"
}'

Request Parameters

Field Type Required Description
amount number โœ… Amount in smallest currency unit (paisa)
currency string โœ… Currency code (default: "INR")
description string โŒ Payment description (max 500 chars)
reference string โŒ Your order reference (max 100 chars)
redirectUrl string โŒ Redirect URL after payment

Success Response

JSON
{
  "success": true,
  "data": {
    "id": "pay_123abc456def789",
    "amount": 10000,
    "currency": "INR",
    "status": "PENDING",
    "description": "Test payment for order #12346",
    "reference": "ORDER_1893089768",
    "paymentUrl": "https://checkout.paygate.com/pay/pay_123abc456def789",
    "expiresAt": "2024-10-15T19:05:16.000Z",
    "createdAt": "2024-10-15T18:05:16.000Z"
  },
  "message": "Payment created successfully"
}

๐Ÿ’ธ Payout Creation

Create a payout to transfer funds to beneficiary bank accounts.

POST
/api/v1/payouts/api/create

Request Example

Terminal
# Create a new payout
curl --location 'https://api.paygate.sbs/api/v1/payouts/api/create' \
--header 'X-Signature: sha256=your-calculated-signature' \
--header 'X-Timestamp: your-unix-timestamp' \
--header 'Content-Type: application/json' \
--data '{
  "amount": 100,
  "currency": "INR",
  "purpose": "API test payout",
  "mode": "IMPS",
  "reference": "API_TEST_012",
  "beneficiary": {
    "name": "John Doe",
    "accountNumber": "123456789000",
    "ifscCode": "AIRP0000001",
    "bankName": "Airtel Bank",
    "accountType": "BANK_ACCOUNT"
  }
}'

Request Parameters

Field Type Required Description
amount number โœ… Amount in rupees (โ‚น100 = 100)
currency string โœ… Currency code (default: "INR")
purpose string โœ… Payout purpose (max 200 chars)
mode string โœ… Transfer mode: "IMPS", "NEFT", "RTGS"
beneficiary.name string โœ… Account holder name
beneficiary.accountNumber string โœ… Bank account number (9-18 digits)
beneficiary.ifscCode string โœ… Bank IFSC code
beneficiary.accountType string โœ… "BANK_ACCOUNT", "UPI", "WALLET"

Success Response

JSON
{
  "success": true,
  "data": {
    "id": "payout_789xyz123abc456",
    "amount": 100,
    "currency": "INR",
    "status": "PENDING",
    "purpose": "API test payout",
    "mode": "IMPS",
    "beneficiary": {
      "name": "John Doe",
      "accountNumber": "123456789000",
      "ifscCode": "AIRP0000001",
      "bankName": "Airtel Bank"
    },
    "fees": 2.50,
    "totalAmount": 102.50,
    "estimatedTime": "15 minutes",
    "createdAt": "2024-10-15T18:05:16.000Z"
  },
  "message": "Payout created successfully"
}

๐Ÿ’ฐ Wallet Balance

Retrieve wallet balance and transaction information.

GET
/api/v1/wallets/api/balance/{walletId}

Request Example

Terminal
# Get wallet balance
curl --location 'https://api.paygate.sbs/api/v1/wallets/api/balance/{walletId}' \
--header 'X-Signature: sha256=your-calculated-signature' \
--header 'X-Timestamp: your-unix-timestamp'
Note: For GET requests, the payload is an empty string "" when generating the signature.

Success Response

JSON
{
  "success": true,
  "data": {
    "id": "your-wallet-id",
    "merchantId": "your-merchant-id",
    "walletType": "MERCHANT",
    "currency": "INR",
    "balance": 88.00,
    "reserved": 0.00,
    "availableBalance": 88.00,
    "isActive": true,
    "lastTransactionAt": "2024-10-15T13:51:34.545Z"
  },
  "message": "Wallet retrieved successfully"
}

โŒ Error Codes

All API errors follow a consistent response structure:

JSON Error Response
{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human readable error message",
    "timestamp": "2024-10-15T18:00:18.414Z",
    "requestId": "2ews3zmhsjk"
  }
}

Common Error Codes

Code Status Description
UNAUTHORIZED 401 Invalid signature or timestamp
FORBIDDEN 403 Insufficient permissions
VALIDATION_ERROR 400 Invalid request payload
NOT_FOUND 404 Resource not found
INSUFFICIENT_BALANCE 400 Wallet balance too low
INTERNAL_ERROR 500 Server error

๐Ÿ”ง Troubleshooting Guide

Before You Debug
90% of integration issues are related to incorrect signature generation. Please double-check that you're:
  1. Hashing your API key FIRST with SHA256
  2. Using that HASH as the HMAC secret (not the raw key)
  3. Concatenating values without separators: merchantId + timestamp + payload

Common Issues & Solutions

1. ๐Ÿšซ Invalid Signature Error

Response: {"success": false, "error": {"code": "UNAUTHORIZED", "message": "Invalid signature"}}
  • CHECK: Are you hashing your API key first? sha256(apiKey)
  • CHECK: Are you using the HASH as HMAC secret (not the raw key)?
  • CHECK: Is your payload string EXACTLY what you're sending in the body?
  • CHECK: For GET/DELETE requests, is payload an empty string ""?
  • CHECK: Is your timestamp in seconds (not milliseconds)?
  • DEBUG: Log your signature string: merchantId + timestamp + payload

2. โฐ Timestamp Too Old/New Error

  • Window: Timestamp must be within ยฑ5 minutes of server time
  • Format: Use Unix timestamp in SECONDS (e.g., Math.floor(Date.now()/1000))
  • Sync: Ensure your server clock is synchronized with NTP
  • Test: Verify timestamp at unixtimestamp.com

3. ๐Ÿ”’ API Key Not Found or Inactive

  • Verify: API key exists in your PayGate dashboard
  • Check: API key is active (not disabled)
  • Check: Merchant account is ACTIVE status
  • Check: API key hasn't expired (if expiration set)
  • Permissions: Ensure key has required scopes:
    • โœ… payments - for creating payments
    • โœ… payouts - for creating payouts
    • โœ… wallets - for checking balance
    • โœ… read - for GET requests

4. ๐Ÿ“ Validation Errors

  • Amount:
    • Payments: Use paise (โ‚น100 = 10000)
    • Payouts: Use rupees (โ‚น100 = 100)
  • Currency: Must be "INR" (uppercase)
  • Reference: Max 100 characters, unique per payment
  • Description: Max 500 characters
  • JSON: Ensure valid JSON with proper escaping

๐Ÿ› ๏ธ Debug Checklist

Before Submitting a Request:

  1. โœ… Hash API key: sha256(apiKey)
  2. โœ… Generate timestamp: Math.floor(Date.now()/1000)
  3. โœ… Create payload string: JSON.stringify(body)
  4. โœ… Build signature string: merchantId + timestamp + payload
  5. โœ… Generate HMAC: HMAC-SHA256(apiKeyHash, signatureString)
  6. โœ… Set headers: X-Signature, X-Timestamp, X-Idempotency-Key
  7. โœ… Verify payload in body EXACTLY matches signature payload

๐Ÿงช Test with Our Script

Use the provided test script to verify your integration:

Terminal
# Run the test script
cp test-payment-correct.js my-test.js
# Edit my-test.js with your credentials
node my-test.js

# Expected output:
"โœ… SUCCESS! Payment created successfully!"
"Payment URL: https://checkout.paygate.sbs/pay/..."
Need Help?
๐Ÿ“ง Email: [email protected]
๐Ÿ’ฌ Discord: discord.gg/paygate
๐Ÿ“– Docs: docs.paygate.sbs

When contacting support, please include:
  • Your merchant ID
  • The request ID from error response
  • The exact payload you're sending
  • The signature string you generated

๐Ÿ“Š Rate Limits

API Key Type Rate Limit Headers
pk_test_* 100 requests/minute X-RateLimit-Limit: 100
sk_live_* 500 requests/minute X-RateLimit-Limit: 500

Note: Rate limit headers are included in all responses. When rate limited, you'll receive HTTP 429 with Retry-After header.

๐Ÿ“ Complete Integration Examples

Here are complete examples showing how to integrate with PayGate API using the correct signature method:

JavaScript (Node.js) - Complete Payment
const crypto = require('crypto');
const fetch = require('node-fetch'); // or use built-in fetch in Node 18+

// Your credentials (get these from PayGate dashboard)
const merchantId = 'your-merchant-id-here';
const apiKey = 'your-api-key-here';
const API_BASE = 'https://api.paygate.sbs';

// Step 1: Hash your API key (do this once and store the hash)
const apiKeyHash = crypto
  .createHash('sha256')
  .update(apiKey)
  .digest('hex');

console.log('API Key Hash:', apiKeyHash);

// Step 2: Generate signature function
function generateSignature(merchantId, timestamp, payload, apiSecretHash) {
  const stringToSign = merchantId + timestamp + payload;
  return crypto
    .createHmac('sha256', apiSecretHash)  // Use the HASH as secret
    .update(stringToSign)
    .digest('hex');
}

// Step 3: Create payment function
async function createPayment(orderData) {
  const timestamp = Math.floor(Date.now() / 1000);
  const idempotencyKey = crypto.randomUUID();
  
  // Prepare payload
  const payload = {
    amount: orderData.amount,
    currency: "INR",
    description: `Payment for order ${orderData.orderId}`,
    reference: orderData.orderId,
    redirectUrl: orderData.returnUrl
  };
  
  // Convert to exact string (maintain order and spacing)
  const payloadString = JSON.stringify(payload);
  
  // Generate signature using the correct method
  const signature = generateSignature(
    merchantId, 
    timestamp, 
    payloadString, 
    apiKeyHash  // Use the pre-computed hash
  );
  
  console.log('Debug:', {
    merchantId,
    timestamp,
    payload: payloadString,
    signature
  });
  
  const response = await fetch(`${API_BASE}/api/v1/payments`, {
    method: 'POST',
    headers: {
      'X-Signature': signature,  // NO 'sha256=' prefix
      'X-Timestamp': timestamp.toString(),
      'X-Idempotency-Key': idempotencyKey,
      'Content-Type': 'application/json'
    },
    body: payloadString
  });
  
  const result = await response.json();
  
  if (!response.ok) {
    throw new Error(`API Error: ${result.error?.message || result.message}`);
  }
  
  return result;
}

// Usage example
async function main() {
  try {
    const payment = await createPayment({
      amount: 10000, // โ‚น100.00 in paisa
      orderId: 'ORDER_' + Date.now(),
      returnUrl: 'https://yoursite.com/payment/success'
    });
    
    console.log('โœ… Payment created successfully!');
    console.log('Payment URL:', payment.data?.paymentUrl);
    console.log('Payment ID:', payment.data?.id);
    
  } catch (error) {
    console.error('โŒ Payment failed:', error.message);
  }
}

// Run the example
main();
Python Example
import hashlib
import hmac
import json
import time
import uuid
import requests

# Your credentials
MERCHANT_ID = 'your-merchant-id-here'
API_KEY = 'your-api-key-here'
API_BASE = 'https://api.paygate.sbs'

# Step 1: Hash your API key
api_key_hash = hashlib.sha256(API_KEY.encode()).hexdigest()
print(f"API Key Hash: {api_key_hash}")

# Step 2: Generate signature function
def generate_signature(merchant_id, timestamp, payload, api_secret_hash):
    string_to_sign = f"{merchant_id}{timestamp}{payload}"
    return hmac.new(
        api_secret_hash.encode(),
        string_to_sign.encode(),
        hashlib.sha256
    ).hexdigest()

# Step 3: Create payment function
def create_payment(order_data):
    timestamp = int(time.time())
    idempotency_key = str(uuid.uuid4())
    
    payload = {
        "amount": order_data["amount"],
        "currency": "INR",
        "description": f"Payment for order {order_data['orderId']}",
        "reference": order_data["orderId"],
        "redirectUrl": order_data["returnUrl"]
    }
    
    payload_string = json.dumps(payload, separators=(',', ':'))
    signature = generate_signature(MERCHANT_ID, timestamp, payload_string, api_key_hash)
    
    headers = {
        'X-Signature': signature,
        'X-Timestamp': str(timestamp),
        'X-Idempotency-Key': idempotency_key,
        'Content-Type': 'application/json'
    }
    
    response = requests.post(
        f"{API_BASE}/api/v1/payments",
        headers=headers,
        data=payload_string
    )
    
    result = response.json()
    
    if response.status_code != 200:
        raise Exception(f"API Error: {result.get('error', {}).get('message', result.get('message'))}")
    
    return result

# Usage exampleif __name__ == "__main__":
    try:
        payment = create_payment({
            "amount": 10000,  # โ‚น100.00 in paisa
            "orderId": f"ORDER_{int(time.time())}",
            "returnUrl": "https://yoursite.com/payment/success"
        })
        
        print("โœ… Payment created successfully!")
        print(f"Payment URL: {payment['data']['paymentUrl']}")
        print(f"Payment ID: {payment['data']['id']}")
        
    except Exception as e:
        print(f"โŒ Payment failed: {str(e)}")
PHP Example

// Your credentials
define('MERCHANT_ID', 'your-merchant-id-here');
define('API_KEY', 'your-api-key-here');
define('API_BASE', 'https://api.paygate.sbs');

// Step 1: Hash your API key
$api_key_hash = hash('sha256', API_KEY);
echo "API Key Hash: " . $api_key_hash . "\n";

// Step 2: Generate signature function
function generateSignature($merchant_id, $timestamp, $payload, $api_secret_hash) {
    $string_to_sign = $merchant_id . $timestamp . $payload;
    return hash_hmac('sha256', $string_to_sign, $api_secret_hash);
}

// Step 3: Create payment function
function createPayment($order_data) {
    $timestamp = time();
    $idempotency_key = uniqid();
    
    $payload = [
        'amount' => $order_data['amount'],
        'currency' => 'INR',
        'description' => "Payment for order {$order_data['orderId']}",
        'reference' => $order_data['orderId'],
        'redirectUrl' => $order_data['returnUrl']
    ];
    
    $payload_string = json_encode($payload);
    $signature = generateSignature(MERCHANT_ID, $timestamp, $payload_string, $GLOBALS['api_key_hash']);
    
    $headers = [
        'X-Signature: ' . $signature,
        'X-Timestamp: ' . $timestamp,
        'X-Idempotency-Key: ' . $idempotency_key,
        'Content-Type: application/json'
    ];
    
    $ch = curl_init(API_BASE . '/api/v1/payments');
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $payload_string);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    
    $response = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    $result = json_decode($response, true);
    
    if ($http_code !== 200) {
        throw new Exception($result['error']['message'] ?? $result['message'] ?? 'API Error');
    }
    
    return $result;
}

// Usage example
try {
    $payment = createPayment([
        'amount' => 10000,  // โ‚น100.00 in paisa
        'orderId' => 'ORDER_' . time(),
        'returnUrl' => 'https://yoursite.com/payment/success'
    ]);
    
    echo "โœ… Payment created successfully!\n";
    echo "Payment URL: " . $payment['data']['paymentUrl'] . "\n";
    echo "Payment ID: " . $payment['data']['id'] . "\n";
    
} catch (Exception $e) {
    echo "โŒ Payment failed: " . $e->getMessage() . "\n";
}

?>