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.
Base URLs
- Sandbox:
https://api.paygate.sbs - Production:
https://api.paygate.sbs
โข 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
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.
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 |
The signature string is constructed by concatenating:
merchantId + timestamp + payloadNo 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
// 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');
}
๐ณ Payment Creation
Create a new payment and get a payment URL for customer checkout.
/api/v1/payments
Request Example
# 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
{
"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.
/api/v1/payouts/api/create
Request Example
# 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
{
"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.
/api/v1/wallets/api/balance/{walletId}
Request Example
# 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'
"" when generating the signature.
Success Response
{
"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:
{
"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
90% of integration issues are related to incorrect signature generation. Please double-check that you're:
- Hashing your API key FIRST with SHA256
- Using that HASH as the HMAC secret (not the raw key)
- 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:
- โ
Hash API key:
sha256(apiKey) - โ
Generate timestamp:
Math.floor(Date.now()/1000) - โ
Create payload string:
JSON.stringify(body) - โ
Build signature string:
merchantId + timestamp + payload - โ
Generate HMAC:
HMAC-SHA256(apiKeyHash, signatureString) - โ
Set headers:
X-Signature,X-Timestamp,X-Idempotency-Key - โ Verify payload in body EXACTLY matches signature payload
๐งช Test with Our Script
Use the provided test script to verify your integration:
# 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/..."
๐ง Email:
[email protected]๐ฌ Discord:
discord.gg/paygate๐ Docs:
docs.paygate.sbsWhen 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:
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();
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)}")
// 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";
}
?>