RazCrypto Payment Gateway

Complete documentation for India's most reliable cryptocurrency payment gateway. Accept USDT, USDC, DAI payments ON BSC & ETH Chain with instant confirmations and easy integration.

Read this first:

  • SDK events vs Webhook events: razcrypto.payment.success/error (client-side) are not the same as payment.completed (server webhook).
  • Webhook signature: Always verify using HMAC-SHA256 of the raw body against header x-razcrypto-signature.
  • Status API: Returns pending/completed/expired/not_found with seconds_left.
  • Randomized amount: In v2, the system adds a small decimal fraction to original amount for unique blockchain matching.

Overview

RazCrypto is India's most reliable non-custodial cryptocurrency payment gateway that enables businesses to accept multi-chain stablecoin payments seamlessly.

Non-Custodial Security: Your funds go directly to your wallet. We never hold or control your cryptocurrency. 100% decentralized payment processing.

🚀 Mission & Vision

Mission: To provide businesses with a secure, non-custodial payment gateway that puts merchants in complete control of their funds while offering seamless cryptocurrency payment experiences.

Vision: To become the most trusted non-custodial payment infrastructure for the decentralized economy, enabling borderless financial freedom for businesses worldwide.

🎯 Key Features

  • Non-Custodial: Funds go directly to your wallet - we never hold your crypto
  • Multi-Chain Support: BSC, Ethereum, Polygon networks
  • Multi-Token Support: USDT, USDC, DAI stablecoins
  • Instant Confirmations: 2-5 second payment processing
  • 5-minute Integration: Simple API and SDK
  • No KYC Required: Start accepting payments immediately
  • 99.9% Uptime: Enterprise-grade reliability
  • Real-time Webhooks: Instant payment notifications
  • Custom Branding: White-label payment pages
  • Advanced Security: HMAC signatures, rate limiting

🔗 Supported Chains & Tokens

Blockchain Supported Tokens Status Network Speed Minimum Amount
BNB Smart Chain (BSC) USDT, USDC, DAI ✅ Live 2-3 seconds 0.01 USDT
Ethereum (ETH) USDT, USDC, DAI ✅ Live 3-5 seconds 0.01 USDT
Polygon (MATIC) USDT, USDC, DAI ✅ Live< 2-4 seconds 0.01 USDT

💡 How It Works

1. Setup Wallet

Add your wallet addresses for each chain and activate monitoring

2. Integrate API

Use our simple API or JavaScript SDK in your application

3. Accept Payments

Customers pay directly to your wallet with instant confirmations

Quick Start (5 Minutes)

Step 1: Create Account & Setup Wallet

  1. Sign Up: https://razcryptogateway.com/user/signup
  2. Verify Email: Check your inbox for verification link
  3. Setup Receiving Wallets:
    • Go to Receive Wallet section in dashboard
    • Add your wallet addresses for each chain:
      • BSC Address: For Binance Smart Chain payments
      • ETH Address: For Ethereum network payments
      • Polygon Address: For future Polygon support
    • Activate Each Chain:
      • Click "Activate" for BSC chain
      • Click "Activate" for ETH chain
      • Wait for activation confirmation (2-3 minutes per chain)
    • Note: Each chain must be activated separately before accepting payments
  4. Create Platform: Go to "Platforms" → "Add Platform"
  5. Get API Keys: Copy Public Key and Secret Key
Wallet Activation Required: You must activate each chain before accepting payments. Activation enables real-time transaction monitoring for your wallet addresses.
JavaScript
// Your API Keys will look like this:
const publicKey = "rz_pub_6d6c763aaa20498c773fb7f0fea8cf5b";
const secretKey = "rz_sec_abcd1234efgh5678ijkl90"; // Keep secure!

Integration Options

🎯 Choose Your Integration Style

Option 1: Checkout Page

Redirect to: checkout_page

Best for: Most businesses, e-commerce

Effort: 2 minutes

Option 2: Custom UI

Use: address + qr_code

Best for: Custom designs, mobile apps

Effort: 15-30 minutes

Option 3: Direct API

Use: Raw API responses

Best for: Advanced integrations

Effort: 30+ minutes

🚀 Quick Integration Code

JavaScript
// Simplest integration - 2 lines of code
const payment = await RazCrypto.createPayment({ amount: 10.00 });
window.location.href = payment.checkout_page; // You control the redirect
You Control the Redirect: Unlike some payment gateways, RazCrypto never auto-redirects. You decide when and where to send your customers based on your application flow.

Step 2: Basic Integration

HTML Example:

HTML
<!DOCTYPE html>
<html>
<head>
    <title>Accept USDT Payments</title>
    <script src="https://razcryptogateway.com/sdk/razcrypto-v2.js"></script>
</head>
<body>
    <button onclick="createPayment()">Pay with USDT</button>

    <script>
        // Initialize SDK
RazCrypto.init({
    public_key_id: "rz_pub_your_public_key_here"
});

async function createPayment() {
    try {
        const result = await RazCrypto.createPayment({
            amount: 10.00,
            email: "[email protected]",
            mobile: "9876543210",
            callback_url: "https://yourwebsite.com/success"
        });
        
        // Option 1: Redirect to checkout page (Recommended)
window.location.href = response.checkout_page;

// Option 2: Use hosted page
window.location.href = response.hosted_page;

// Option 3: Build custom UI
showCustomPaymentUI({
    address: response.address,
    amount: response.amount,
    qrCode: response.qr_code
});
        
    } catch (error) {
        console.error("Payment failed:", error);
        alert("Payment error: " + error.message);
    }
}
    </script>
</body>
</html>

Note:

  • SDK events: When you call RazCrypto.createPayment, the SDK dispatches browser events:
    • razcrypto.payment.success → Payment was created (JSON returned / redirect started)
    • razcrypto.payment.error → Some client/API error occurred
    Tip: These are different from payment.completed (webhook event). payment.completed is sent from the backend webhook.

Expected Response:

JSON
{
    "status": "success",
    "payment_id": "payid_abc123def456",
    "amount": 10.00,
    "currency": "USDT", 
    "chain": "BSC",
    "address": "0x123...",
    "checkout_page": "https://razcryptogateway.com/pay/checkout/payid_abc123def456",
    "hosted_page": "https://razcryptogateway.com/pay/payid_abc123def456",
    "payment_page": "https://razcryptogateway.com/pay/payid_abc123def456?m=30",
    "qr_code": "https://razcryptogateway.com/qr?address=0x...&amount=10.00",
    "expiry_minutes": 30
}

Authentication

Authentication Methods

Method Use Case Security
Public Key Frontend SDK ✅ Safe for browser
Secret Key Backend API 🔒 Server-side only

Getting Your API Keys

  1. Login to RazCrypto Dashboard
  2. Navigate to Platforms section
  3. Click Add Platform or select existing platform
  4. Copy your Public Key and Secret Key
Important: Never expose your secret key in client-side code. Always keep it secure on your server.

Environment Setup

Environment Variables
# .env file - NEVER commit this file
RAZ_PUBLIC_KEY=rz_pub_your_public_key_here
RAZ_SECRET_KEY=rz_sec_your_secret_key_here
RAZ_WEBHOOK_SECRET=same_your_secret_key_here

API Integration

Base URL

https://razcryptogateway.com/api/v2

Authentication

Professional Security: Always send authentication credentials in request headers for better security and industry-standard compliance.

Authentication Methods

HEADERS
X-Public-Key-Id: your_public_key_id_here

Use your Public Key ID from the dashboard for SDK integration.

HEADERS
X-Gateway-Id: your_gateway_id_here
X-Secret-Key: your_secret_key_here

Use both Gateway ID and Secret Key for server-to-server integration.

🔗 Chain & Token Configuration

Select your preferred blockchain and stablecoin for each payment:

JSON
{
    "chain": "BSC",           // BSC, ETH, POLYGON
    "currency": "USDT",       // USDT, USDC, DAI
    "amount": 10.50,
    "email": "[email protected]",
    "mobile": "9876543210", 
    "callback_url": "https://yourwebsite.com/webhook",
    "custom_data": {
        "order_id": "ORD_001",
        "user_id": "USER_123"
    },
    "return_json": "true"
}
Parameter Values Required Default Description
chain BSC, ETH, POLYGON No BSC Blockchain network for payment
currency USDT, USDC, DAI No USDT Stablecoin for payment
Chain Activation Required: Make sure you have activated the chain in your Receive Wallet settings before accepting payments on that network.

1. Create Payment Endpoint

Endpoint: POST /payments/create

Headers:

Content-Type: application/json
Accept: application/json
X-Public-Key-Id: your_public_key_id

Request Parameters:

Parameter Type Required Description Example
amount number Yes Payment amount (≥ 0.01) 10.50
email string No Customer email [email protected]
mobile string No Customer mobile 9876543210
callback_url string No Webhook URL https://yoursite.com/webhook
custom_data object No Custom metadata {"order_id": "ORD_001"}
chain string No Blockchain network BSC, ETH, POLYGON
currency string No Token currency USDT, USDC, DAI
return_json string No Force JSON response "true"
  • Authentication in Headers: Send credentials via X-Public-Key-Id header (SDK) or X-Gateway-Id and X-Secret-Key headers (Server-to-server).
  • Field aliases: For mobile you can use mobile or mobile_number, for email you can use email or email_id.
  • Backward Compatibility: Body authentication is deprecated but still supported for existing integrations.

Example Request (Multiple Languages):

curl -X POST "https://razcryptogateway.com/api/v2/payments/create" \
  -H "Content-Type: application/json" \
  -H "X-Public-Key-Id: rz_pub_6d6c763aaa20498c773fb7f0fea8cf5b" \
  -H "Accept: application/json" \
  -d '{
    "amount": 10.50,
    "email": "[email protected]",
    "mobile": "9876543210",
    "username": "john_doe",
    "callback_url": "https://yourstore.com/webhook",
    "subscription_id": "sub_id",
    "product_id": "PROD001",
    "chain": "BSC",
    "currency": "USDT",
    "return_json": "true"
  }'
// Using Fetch API
fetch('https://razcryptogateway.com/api/v2/payments/create', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'X-Public-Key-Id': 'rz_pub_6d6c763aaa20498c773fb7f0fea8cf5b'
    },
    body: JSON.stringify({
        amount: 10.50,
        email: "[email protected]",
        mobile: "9876543210",
        username: "john_doe",
        callback_url: "https://yourstore.com/webhook",
        subscription_id: "sub_id",
        product_id: "PROD001",
        chain: "BSC",
        currency: "USDT",
        return_json: "true"
    })
})
.then(response => response.json())
.then(data => console.log('Payment created:', data))
.catch(error => console.error('Error:', error));
<?php
// Using cURL with Header Authentication
$url = 'https://razcryptogateway.com/api/v2/payments/create';
$data = [
    'amount' => 10.50,
    'email' => '[email protected]',
    'mobile' => '9876543210',
    'username' => 'john_doe',
    'callback_url' => 'https://yourstore.com/webhook',
    'subscription_id' => 'sub_id',
    'product_id' => 'PROD001',
    'chain' => 'BSC',
    'currency' => 'USDT',
    'return_json' => 'true'
];

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Accept: application/json',
    'X-Public-Key-Id: rz_pub_6d6c763aaa20498c773fb7f0fea8cf5b'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($httpCode === 200) {
    $result = json_decode($response, true);
    echo "Payment ID: " . $result['payment_id'];
} else {
    echo "Error: " . $response;
}
?>
import requests
import json

url = "https://razcryptogateway.com/api/v2/payments/create"
headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
    "X-Public-Key-Id": "rz_pub_6d6c763aaa20498c773fb7f0fea8cf5b"
}

data = {
    "amount": 10.50,
    "email": "[email protected]",
    "mobile": "9876543210",
    "username": "john_doe",
    "callback_url": "https://yourstore.com/webhook",
    "subscription_id": "sub_id",
    "product_id": "PROD001",
    "chain": "BSC",
    "currency": "USDT",
    "return_json": "true"
}

try:
    response = requests.post(url, headers=headers, json=data)
    response.raise_for_status()
    result = response.json()
    print(f"Payment created successfully!")
    print(f"Payment ID: {result.get('payment_id')}")
    print(f"Payment URL: {result.get('payment_url')}")
except requests.exceptions.RequestException as e:
    print(f"Error creating payment: {e}")
// Using Node.js with axios
const axios = require('axios');

const headers = {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'X-Public-Key-Id': 'rz_pub_6d6c763aaa20498c773fb7f0fea8cf5b'
};

const data = {
    amount: 10.50,
    email: "[email protected]",
    mobile: "9876543210",
    username: "john_doe",
    callback_url: "https://yourstore.com/webhook",
    subscription_id: "sub_id",
    product_id: "PROD001",
    chain: "BSC",
    currency: "USDT",
    return_json: "true"
};

axios.post('https://razcryptogateway.com/api/v2/payments/create', data, { headers })
.then(response => {
    console.log('Payment created:', response.data);
    console.log('Payment ID:', response.data.payment_id);
    console.log('Payment URL:', response.data.payment_url);
})
.catch(error => {
    console.error('Error:', error.response?.data || error.message);
});
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.OutputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import org.json.JSONObject;

public class RazCryptoPayment {
    public static void createPayment() throws Exception {
        URL url = new URL("https://razcryptogateway.com/api/v2/payments/create");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/json");
        conn.setRequestProperty("Accept", "application/json");
        conn.setRequestProperty("X-Public-Key-Id", "rz_pub_6d6c763aaa20498c773fb7f0fea8cf5b");
        conn.setDoOutput(true);
        
        JSONObject json = new JSONObject();
        json.put("amount", 10.50);
        json.put("email", "[email protected]");
        json.put("mobile", "9876543210");
        json.put("username", "john_doe");
        json.put("callback_url", "https://yourstore.com/webhook");
        json.put("subscription_id", "sub_id");
        json.put("product_id", "PROD001");
        json.put("chain", "BSC");
        json.put("currency", "USDT");
        json.put("return_json", "true");
        
        try(OutputStream os = conn.getOutputStream()) {
            byte[] input = json.toString().getBytes("utf-8");
            os.write(input, 0, input.length);
        }
        
        try(BufferedReader br = new BufferedReader(
            new InputStreamReader(conn.getInputStream(), "utf-8"))) {
            StringBuilder response = new StringBuilder();
            String responseLine = null;
            while ((responseLine = br.readLine()) != null) {
                response.append(responseLine.trim());
            }
            
            JSONObject result = new JSONObject(response.toString());
            System.out.println("Payment ID: " + result.getString("payment_id"));
            System.out.println("Payment URL: " + result.getString("payment_url"));
        }
        
        conn.disconnect();
    }
}
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
)

func createPayment() error {
    url := "https://razcryptogateway.com/api/v2/payments/create"
    
    data := map[string]interface{}{
        "amount":         10.50,
        "email":          "[email protected]",
        "mobile":         "9876543210",
        "username":       "john_doe",
        "callback_url":   "https://yourstore.com/webhook",
        "subscription_id": "sub_id",
        "product_id":     "PROD001",
        "chain":          "BSC",
        "currency":       "USDT",
        "return_json":    "true",
    }
    
    jsonData, err := json.Marshal(data)
    if err != nil {
        return err
    }
    
    req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
    if err != nil {
        return err
    }
    
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Accept", "application/json")
    req.Header.Set("X-Public-Key-Id", "rz_pub_6d6c763aaa20498c773fb7f0fea8cf5b")
    
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return err
    }
    defer resp.Body.Close()
    
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return err
    }
    
    var result map[string]interface{}
    json.Unmarshal(body, &result)
    
    fmt.Printf("Payment created successfully!\n")
    fmt.Printf("Payment ID: %v\n", result["payment_id"])
    fmt.Printf("Payment URL: %v\n", result["payment_url"])
    
    return nil
}

Server-to-Server Integration Example

cURL
curl -X POST "https://razcryptogateway.com/api/v2/payments/create" \
  -H "Content-Type: application/json" \
  -H "X-Gateway-Id: YOUR_GATEWAY_ID" \
  -H "X-Secret-Key: YOUR_SECRET_KEY" \
  -H "Accept: application/json" \
  -d '{
    "amount": 25.00,
    "callback_url": "https://yourstore.com/webhook",
    "chain": "ETH",
    "currency": "USDC",
    "return_json": "true"
  }'

Multi-Chain Payment Examples

curl -X POST "https://razcryptogateway.com/api/v2/payments/create" \
  -H "Content-Type: application/json" \
  -H "X-Public-Key-Id: your_public_key" \
  -d '{
    "chain": "BSC",
    "currency": "USDT",
    "amount": 10.50,
    "return_json": "true"
  }'
curl -X POST "https://razcryptogateway.com/api/v2/payments/create" \
  -H "Content-Type: application/json" \
  -H "X-Public-Key-Id: your_public_key" \
  -d '{
    "chain": "ETH",
    "currency": "USDC",
    "amount": 25.00,
    "return_json": "true"
  }'
curl -X POST "https://razcryptogateway.com/api/v2/payments/create" \
  -H "Content-Type: application/json" \
  -H "X-Public-Key-Id: your_public_key" \
  -d '{
    "chain": "ETH",
    "currency": "DAI",
    "amount": 50.00,
    "return_json": "true"
  }'
curl -X POST "https://razcryptogateway.com/api/v2/payments/create" \
  -H "Content-Type: application/json" \
  -H "X-Public-Key-Id: your_public_key" \
  -d '{
    "chain": "POLYGON",
    "currency": "USDT",
    "amount": 15.00,
    "return_json": "true"
  }'

Note on Backward Compatibility:

While we recommend using header-based authentication for better security, the API still supports body authentication for existing integrations. However, new integrations should use headers as per industry standards.

{
    "status": "success",
    "payment_id": "payid_abc123def456",
    "amount": 10.50000646,
    "currency": "USDT",
    "chain": "BSC",
    "address": "0x1234567890abcdef1234567890abcdef12345678",
    "checkout_page": "https://razcryptogateway.com/pay/checkout/payid_abc123def456",
    "hosted_page": "https://razcryptogateway.com/pay/payid_abc123def456",
    "payment_page": "https://razcryptogateway.com/pay/payid_abc123def456?m=30",
    "qr_code": "https://razcryptogateway.com/qr/usdt.png?address=0x123...&amount=10.50000646",
    "email_id": "[email protected]",
    "mobile_number": "9876543210",
    "callback_url": "https://yourwebsite.com/your/webhook",
    "expiry_minutes": 30,
    "expires_at": "2024-01-15T11:00:00Z",
    "timestamp": "2024-01-15T10:30:00Z"
}
<?php
// Handling the response in PHP
$response = json_decode($apiResponse, true);

if ($response['status'] === 'success') {
    $paymentId = $response['payment_id'];
    $amount = $response['amount'];
    $paymentUrl = $response['payment_page'];
    $qrCode = $response['qr_code'];
    
    // Store in database
    $stmt = $pdo->prepare("INSERT INTO payments 
        (payment_id, amount, currency, chain, status) 
        VALUES (?, ?, ?, ?, 'pending')");
    $stmt->execute([$paymentId, $amount, 
        $response['currency'], $response['chain']]);
    
    // Redirect to payment page
    header("Location: " . $paymentUrl);
    exit;
} else {
    echo "Error: " . ($response['message'] ?? 'Unknown error');
}
?>
# Handling the response in Python
import json

# Assuming 'response' is the API response
data = response.json()

if data.get('status') == 'success':
    payment_id = data['payment_id']
    amount = data['amount']
    payment_url = data['payment_page']
    qr_code = data['qr_code']
    
    print(f"Payment created successfully!")
    print(f"Payment ID: {payment_id}")
    print(f"Amount: {amount} {data['currency']}")
    print(f"Payment URL: {payment_url}")
    print(f"QR Code: {qr_code}")
    
    # Store in database (example with SQLite)
    import sqlite3
    conn = sqlite3.connect('payments.db')
    cursor = conn.cursor()
    cursor.execute('''
        INSERT INTO payments 
        (payment_id, amount, currency, chain, status)
        VALUES (?, ?, ?, ?, 'pending')
    ''', (payment_id, amount, data['currency'], data['chain']))
    conn.commit()
    conn.close()
    
else:
    print(f"Error: {data.get('message', 'Unknown error')}")
// Handling the response in Node.js
// Using the response from axios/fetch
const response = await axios.post('https://razcryptogateway.com/api/v1/payments/create', data);

if (response.data.status === 'success') {
    const paymentId = response.data.payment_id;
    const amount = response.data.amount;
    const paymentUrl = response.data.payment_page;
    const qrCode = response.data.qr_code;
    
    console.log('Payment created successfully!');
    console.log(`Payment ID: ${paymentId}`);
    console.log(`Amount: ${amount} ${response.data.currency}`);
    console.log(`Payment URL: ${paymentUrl}`);
    console.log(`QR Code: ${qrCode}`);
    
    // Store in database (example with MongoDB)
    const Payment = require('./models/Payment');
    await Payment.create({
        paymentId: paymentId,
        amount: amount,
        currency: response.data.currency,
        chain: response.data.chain,
        status: 'pending',
        createdAt: new Date()
    });
    
    // Redirect or send response
    res.json({
        success: true,
        paymentUrl: paymentUrl,
        paymentId: paymentId
    });
} else {
    console.error('Error:', response.data.message);
    res.status(400).json({
        error: response.data.message || 'Payment creation failed'
    });
}

Note:

  • Randomized amount (v1 flow): The system adds a small random decimal (e.g. 10.50 → 10.50000646) so that blockchain transactions can be uniquely matched. Settlement and records are based on this final amount.

Example Request with Custom Metadata:

curl -X POST "https://razcryptogateway.com/api/v1/payments/create" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "public_key_id": "rz_pub_6d6c763aaa20498c773fb7f0fea8cf5b",
    "amount": 10.50,
    "email": "[email protected]",
    "mobile": "9876543210",
    "username": "john_doe",
    "callback_url": "https://yourstore.com/webhook",
    "subscription_id": "sub_id",
    "product_id": "PROD001",
    "return_json": "true",
    "custom_data": {
        "order_id": "ORD_2024_001",
        "user_id": "USER_123",
        "items": [
            {"name": "Product A", "price": 8.00, "quantity": 1},
            {"name": "Product B", "price": 2.50, "quantity": 1}
        ],
        "shipping": {
            "address": "123 Main Street",
            "city": "Mumbai",
            "pincode": "400001"
        },
        "metadata": {
            "source": "website",
            "campaign": "summer_sale_2024"
        }
    }
  }'
// JavaScript with custom metadata
const paymentData = {
    public_key_id: "rz_pub_6d6c763aaa20498c773fb7f0fea8cf5b",
    amount: 10.50,
    email: "[email protected]",
    mobile: "9876543210",
    username: "john_doe",
    callback_url: "https://yourstore.com/webhook",
    return_json: "true",
    custom_data: {
        order_id: "ORD_2024_001",
        user_id: "USER_123",
        items: [
            {name: "Product A", price: 8.00, quantity: 1},
            {name: "Product B", price: 2.50, quantity: 1}
        ],
        shipping: {
            address: "123 Main Street",
            city: "Mumbai",
            pincode: "400001"
        },
        metadata: {
            source: "website",
            campaign: "summer_sale_2024",
            affiliate_id: "AFF_12345"
        }
    }
};

// Using Fetch API
const response = await fetch('https://razcryptogateway.com/api/v1/payments/create', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    },
    body: JSON.stringify(paymentData)
});

const result = await response.json();
console.log('Payment created with custom data:', result);
<?php
// PHP with custom metadata
$customData = [
    'order_id' => 'ORD_2024_001',
    'user_id' => 'USER_123',
    'items' => [
        ['name' => 'Product A', 'price' => 8.00, 'quantity' => 1],
        ['name' => 'Product B', 'price' => 2.50, 'quantity' => 1]
    ],
    'shipping' => [
        'address' => '123 Main Street',
        'city' => 'Mumbai',
        'pincode' => '400001'
    ],
    'metadata' => [
        'source' => 'website',
        'campaign' => 'summer_sale_2024',
        'affiliate_id' => 'AFF_12345'
    ]
];

$paymentData = [
    'public_key_id' => 'rz_pub_6d6c763aaa20498c773fb7f0fea8cf5b',
    'amount' => 10.50,
    'email' => '[email protected]',
    'mobile' => '9876543210',
    'username' => 'john_doe',
    'callback_url' => 'https://yourstore.com/webhook',
    'return_json' => 'true',
    'custom_data' => $customData
];

$ch = curl_init('https://razcryptogateway.com/api/v1/payments/create');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'Accept: application/json'
    ],
    CURLOPT_POSTFIELDS => json_encode($paymentData)
]);

$response = curl_exec($ch);
$result = json_decode($response, true);

if ($result['status'] === 'success') {
    echo "Payment created with custom metadata!";
    echo "Payment ID: " . $result['payment_id'];
    echo "Custom data will be returned in webhooks.";
}
?>
{
    "status": "success",
    "payment_id": "payid_3d6b186277fce06d",
    "amount": 10.500071,
    "currency": "USDT",
    "chain": "BSC",
    "payment_url": "https://razcryptogateway.com/pay/payid_3d6b186277fce06d?m=30",
    "payment_view_url": "https://razcryptogateway.com/pay/payid_3d6b186277fce06d?m=30",
    "qr_url": "https://razcryptogateway.com/qr/usdt.png?address=0xc4E46228D741aE6a9FEE2e9F00b1303abe44eBDE&amount=10.500071",
    "email_id": "[email protected]",
    "mobile_number": "9876543210",
    "username": "john_doe",
    "callback_url": "https://yourstore.com/webhook",
    "expiry_minutes": 30,
    "subscription_id": "sub_id",
    "product_id": "PROD001",
    "custom_data": {
        "order_id": "ORD_2024_001",
        "user_id": "USER_123",
        "items": [
            {"name": "Product A", "price": 8.00, "quantity": 1},
            {"name": "Product B", "price": 2.50, "quantity": 1}
        ],
        "shipping": {
            "address": "123 Main Street",
            "city": "Mumbai",
            "pincode": "400001"
        },
        "metadata": {
            "source": "website",
            "campaign": "summer_sale_2024",
            "affiliate_id": "AFF_12345"
        }
    },
    "timestamp": "2024-01-15T14:30:00Z",
    "timestamp_iso": "2024-01-15T14:30:00Z"
}

Note:

  • custom_data passthrough: Any JSON you send in custom_data will be echoed back in both API responses and webhook payloads. Perfect for order mapping or tracking. Nested objects and arrays are supported.
  • Data Size Limit: Keep custom_data under 10KB for optimal performance.
  • Webhook Integration: The same custom_data will be sent in payment.completed webhook events.

2. Check Payment Status

Endpoint: GET /payments/status/{payment_id}

Example Request:

cURL
curl "https://razcryptogateway.com/api/v1/payments/status/payid_3d6b186277fce06d"

Response - Completed:

JSON
{
    "status": "completed",
    "payment_id": "payid_3d6b186277fce06d",
    "amount": 10.500071,
    "currency": "USDT",
    "chain": "BSC",
    "tx_hash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
    "sender": "0x9876543210fedcba9876543210fedcba98765432",
    "completed_at": "2024-01-15T14:30:00Z"
}

Response - if Pending:

JSON
{
    "status": "pending",
    "payment_id": "payid_a9b877fc9c3920c6",
    "seconds_left": 1610
}

JavaScript SDK

Installation

HTML
<!-- Include SDK in your HTML -->
<script src="https://razcryptogateway.com/sdk/razcrypto.js"></script>

Initialization

JavaScript
// Initialize with your public key
RazCrypto.init({
    public_key_id: "rz_pub_your_public_key_here",
    api_base: "https://razcryptogateway.com", // Optional
    auto_redirect: true,     // Auto redirect to payment page
    request_timeout: 15000,  // 15 seconds timeout
    show_messages: true      // Show alert messages
});

Note:

  • Quick checkout: Use auto_redirect: true → User is redirected to hosted payment page automatically.
  • Custom checkout: Use auto_redirect: false or API flag "return_json": "true" → You get raw JSON and can build your own UI.

Create Payment

JavaScript
// Basic payment
const result = await RazCrypto.createPayment({
    amount: 10.00,
    email: "[email protected]",
    mobile: "9876543210",
    callback_url: "https://yourwebsite.com/success"
});

// With custom metadata
const result = await RazCrypto.createPayment({
    amount: 25.00,
    email: "[email protected]",
    custom_data: {
        order_id: "GAME_ORD_001",
        user_id: "PLAYER_123",
        game_session: "SESSION_ABC"
    }
});

🎯 Two Integration Methods

Choose the method that best fits your application architecture:

Method A: Frontend Integration (No Backend Required)

Use this method if you want to accept payments directly from your frontend JavaScript code. Perfect for static websites, single-page applications, or when you don't want to manage a backend API.

Quick & Easy: Just 3 lines of code to start accepting payments!
JavaScript (Frontend)
// Step 1: Initialize SDK with your public key
RazCrypto.init({ 
    public_key_id: "rz_pub_your_public_key_here" 
});

// Step 2: Create payment (opens modal automatically)
RazCrypto.checkout({
    amount: 10.00,
    currency: "USDT",        // USDT, USDC, DAI
    chain: "BSC",            // BSC, ETH, POLYGON
    email: "[email protected]",
    mobile: "9876543210",
    callback_url: "https://yourwebsite.com/success",
    custom_data: {
        order_id: "ORD_001",
        product_name: "Premium Plan"
    },
    handler: function(response) {
        // Step 3: Handle success
        console.log("Payment successful!", response);
        console.log("Payment ID:", response.payment_id);
        console.log("Transaction Hash:", response.tx_hash);
        
        // Redirect to your success page
        window.location.href = "/thank-you?payment_id=" + response.payment_id;
    },
    onError: function(error) {
        // Handle error
        console.error("Payment failed:", error);
        alert("Payment failed: " + error.message);
    }
});
  • ✅ No Backend Required: Everything happens in the browser
  • ✅ Auto Modal: Payment modal opens automatically when you call checkout()
  • ✅ Instant Callback: Get payment confirmation in the handler function
  • ✅ Perfect for: Static websites, landing pages, simple e-commerce, freelancers

Method B: Backend Integration (Your API First)

Use this method if you already have a backend (PHP, Node.js, Python, etc.) and want to create payments server-side. You get full control over the payment creation process.

More Secure: Secret keys stay on your server. Perfect for existing applications.
JavaScript (Frontend) + Your Backend API
// Step 1: Call YOUR backend API to create payment
async function startPayment() {
    try {
        // Your backend creates payment and returns checkout_page URL
        const response = await fetch('/api/create-payment', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                amount: 10.00,
                currency: "USDT",
                chain: "BSC",
                email: "[email protected]",
                product_id: "PROD_001"
            })
        });
        
        const data = await response.json();
        // data should contain: { checkout_page: "https://razcryptogateway.com/pay/checkout/payid_xxx" }
        
        // Step 2: Open RazCrypto payment window with the URL
        RazCrypto.openPaymentWindow(data.checkout_page, function(result) {
            // Step 3: Handle payment completion
            console.log("Payment completed!", result);
            console.log("Payment ID:", result.payment_id);
            console.log("Transaction Hash:", result.tx_hash);
            
            // Redirect or show success message
            window.location.href = "/order-success?payment_id=" + result.payment_id;
        });
        
    } catch (error) {
        console.error("Error:", error);
        alert("Failed to create payment: " + error.message);
    }
}

// HTML button to trigger
// <button onclick="startPayment()">Pay Now</button>
PHP (Your Backend - /api/create-payment)
<?php
// api/create-payment.php
header('Content-Type: application/json');

$data = json_decode(file_get_contents('php://input'), true);

// Your secret key stays on server
$secretKey = "rz_sec_your_secret_key_here";
$publicKey = "rz_pub_your_public_key_here";

$ch = curl_init('https://razcryptogateway.com/api/v2/payments/create');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'X-Gateway-Id: ' . $publicKey,
    'X-Secret-Key: ' . $secretKey
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'amount' => $data['amount'],
    'currency' => $data['currency'],
    'chain' => $data['chain'],
    'email' => $data['email'],
    'product_id' => $data['product_id'],
    'callback_url' => 'https://yourwebsite.com/webhook'
]));

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response, true);

// Return checkout_page to frontend
echo json_encode([
    'checkout_page' => $result['checkout_page']
]);
?>
  • ✅ Secret Keys Safe: Your secret key never leaves your server
  • ✅ Full Control: You decide when and how to create payments
  • ✅ Custom Logic: Add your own validation, database updates, etc.
  • ✅ Perfect for: Existing applications, complex e-commerce, subscription systems

📊 Which Method Should You Choose?

Method A - Frontend Only

Best for:

  • ✅ Static websites
  • ✅ Landing pages
  • ✅ Simple product sales
  • ✅ Freelancers & creators
  • ✅ No backend experience

Time: 2 minutes

Method B - Backend First

Best for:

  • ✅ Existing applications
  • ✅ Complex e-commerce
  • ✅ Subscription systems
  • ✅ Maximum security
  • ✅ Custom business logic

Time: 15-30 minutes

Pro Tip: Start with Method A to test quickly, then migrate to Method B for production if you need backend integration. Both methods work perfectly with RazCrypto!

Event Listeners

JavaScript

// Payment created (API success) event
window.addEventListener('razcrypto.payment.success', function (e) {
  console.log('Payment created:', e.detail);
});

// Payment error event
window.addEventListener('razcrypto.payment.error', function (e) {
  console.error('Payment error:', e.detail);
  alert('Payment error: ' + (e.detail?.message || 'Unknown error'));
});

Webhook Integration

Webhook Setup

  1. Go to your RazCrypto Dashboard
  2. Navigate to Platform Settings
  3. Set your Webhook URL
  4. Save changes

Webhook Events

Note:

  • Currently live: Only payment.completed webhook is live today (triggered on blockchain confirmation). payment.pending and payment.failed are reserved for future use.
Event Description Trigger
payment.completed Payment completed successfully Payment confirmed on blockchain
payment.failed Payment failed or expired Payment expiry or failure
payment.pending Payment waiting confirmation Payment created but not confirmed

Webhook Payload

Note:

  • Signature header: Default is x-razcrypto-signature (case-insensitive). Dashboard/config allows customizing if needed.
  • Verify rule: Signature is generated on the raw JSON body string using HMAC-SHA256. Always verify against the raw request body — do not re-encode before checking.

Success Payload:

{
  "event": "payment.completed",
  "timestamp_iso": "2025-10-05T17:59:01+00:00",
  "status": "success",
  "amount": 0.20000448,
  "tx_hash": "0x4f3b0eedaad8ff3cf9d14b460ee98593d330899c5359b28fd77d40d0c204ad28",
  "gateway_id": "UID48440548",
  "payment_id": "payid_8b49b25fcf27bfd7",
  "timestamp": "2025-10-05T17:59:01+00:00",
  "invoice_url": "https://razcryptogateway.com/invoice/payid_8b49b25fcf27bfd7",
  "redirect_url": null,
  "mobile_number": "65682540822",
  "email_id": "[email protected]",
  "username": "Ram123",
  "product_id": "Pak123",
  "subscription_id": "Sub1",
  "custom_data": {
    "order_id": "ORD_2024_001",
    "user_id": "USER_123",
    "items": [
      {"name": "Product A", "price": 0.15, "quantity": 1},
      {"name": "Product B", "price": 0.05000448, "quantity": 1}
    ]
  }
}
// Webhook Payload Field Explanation
{
  "event": "payment.completed",           // Event type
  "timestamp_iso": "ISO-8601 timestamp",  // Recommended timestamp format
  "timestamp": "Legacy timestamp",        // Backward compatibility
  
  "status": "success",                    // Payment status
  "amount": 0.20000448,                   // Final amount (with random decimal)
  "tx_hash": "0x...",                     // Blockchain transaction hash
  "gateway_id": "UID...",                 // Internal gateway ID
  
  "payment_id": "payid_...",              // Your payment ID
  "invoice_url": "https://...",           // Invoice download URL
  
  // Customer Information
  "mobile_number": "91...",               // Customer mobile
  "email_id": "email@...",                // Customer email
  "username": "username",                 // Customer username (if provided)
  
  // Product Information
  "product_id": "product_id",             // Your product ID
  "subscription_id": "sub_id",            // Your subscription ID
  
  // Custom Data (echoed back from payment creation)
  "custom_data": {
    "order_id": "your_order_id",          // Your order tracking
    "user_id": "your_user_id",            // Your user ID
    // Any additional data you sent
  }
}
// Test Webhook Payload (for development)
{
  "event": "payment.completed",
  "timestamp_iso": "2024-01-15T14:30:00+05:30",
  "status": "success",
  "amount": 1.00012345,
  "tx_hash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
  "gateway_id": "UID12345678",
  "payment_id": "payid_test_123456",
  "timestamp": "2024-01-15T14:30:00+05:30",
  "invoice_url": "https://razcryptogateway.com/invoice/payid_test_123456",
  "redirect_url": "https://yourstore.com/thank-you",
  "mobile_number": "919876543210",
  "email_id": "[email protected]",
  "username": "test_user",
  "product_id": "TEST_PROD_001",
  "subscription_id": "TEST_SUB_001",
  "custom_data": {
    "order_id": "TEST_ORD_001",
    "user_id": "TEST_USER_001",
    "test_mode": true,
    "notes": "This is a test webhook payload"
  }
}

// Use this payload to test your webhook endpoint locally

🔐 How to Verify Webhook Signature

To ensure the webhook is genuinely from RazCrypto and not a hacker, you must verify the signature sent in the HTTP headers.

  1. Get Raw Payload: Read the raw HTTP request body (do not parse or format it as JSON yet).
  2. Get Header: Extract the x-razcrypto-signature from the request headers.
  3. Generate Hash: Create an HMAC-SHA256 hash of the raw payload using your Webhook Secret.
    (Where to find it: Go to Dashboard → Platforms and copy the key from the Webhook Secret column).
  4. Compare: Ensure your generated hash matches the signature received in the header.
Crucial Security Step: Always use the raw, unparsed string body for hashing. If your framework parses the JSON automatically, you must access the raw buffer/stream before parsing, otherwise the signature will mismatch.

Webhook Handler Examples

<?php
// webhook_handler.php - Complete PHP Webhook Handler
header('Content-Type: application/json');

class RazCryptoWebhook {
    private $webhookSecret;
    private $dbConnection;

    public function __construct($secret) {
        $this->webhookSecret = $secret;
        $this->connectDatabase();
    }

    private function connectDatabase() {
        // Database connection (adjust for your setup)
        $this->dbConnection = new PDO(
            'mysql:host=localhost;dbname=your_database',
            'username',
            'password'
        );
    }

    public function handle() {
        try {
            // 1) Get raw request body
            $rawPayload = file_get_contents('php://input');
            if (empty($rawPayload)) {
                throw new Exception('Empty request body');
            }

            // 2) Verify signature
            $signatureHeader = $_SERVER['HTTP_X_RAZCRYPTO_SIGNATURE'] ?? '';
            $expectedSignature = hash_hmac('sha256', $rawPayload, $this->webhookSecret);

            if (!hash_equals($expectedSignature, $signatureHeader)) {
                http_response_code(401);
                echo json_encode(['error' => 'Invalid signature']);
                return;
            }

            // 3) Parse JSON
            $payload = json_decode($rawPayload, true);
            if (json_last_error() !== JSON_ERROR_NONE) {
                throw new Exception('Invalid JSON: ' . json_last_error_msg());
            }

            // 4) Route by event type
            $event = $payload['event'] ?? '';
            switch ($event) {
                case 'payment.completed':
                    $this->handlePaymentCompleted($payload);
                    break;
                    
                case 'payment.failed':
                    $this->handlePaymentFailed($payload);
                    break;
                    
                case 'payment.pending':
                    $this->handlePaymentPending($payload);
                    break;
                    
                default:
                    throw new Exception("Unknown event type: {$event}");
            }

            // 5) Success response
            http_response_code(200);
            echo json_encode([
                'status' => 'success',
                'message' => 'Webhook processed successfully',
                'processed_at' => date('c')
            ]);

        } catch (Exception $e) {
            // Error handling
            http_response_code(400);
            echo json_encode([
                'error' => $e->getMessage(),
                'timestamp' => date('c')
            ]);
            error_log("Webhook Error: " . $e->getMessage());
        }
    }

    private function handlePaymentCompleted(array $data) {
        $paymentId = $data['payment_id'];
        $amount = $data['amount'];
        $txHash = $data['tx_hash'];
        $customData = $data['custom_data'] ?? [];

        // Update database
        $stmt = $this->dbConnection->prepare("
            UPDATE orders 
            SET status = 'paid', 
                payment_id = ?, 
                tx_hash = ?,
                paid_amount = ?,
                paid_at = NOW(),
                custom_data = ?
            WHERE order_id = ?
        ");

        $orderId = $customData['order_id'] ?? $paymentId;
        $stmt->execute([
            $paymentId,
            $txHash,
            $amount,
            json_encode($customData),
            $orderId
        ]);

        // Send email notification
        $this->sendPaymentEmail(
            $data['email_id'] ?? '',
            $paymentId,
            $amount,
            $orderId
        );

        // Log success
        error_log("Payment {$paymentId} completed for order {$orderId}");
    }

    private function handlePaymentFailed(array $data) {
        $paymentId = $data['payment_id'];
        $customData = $data['custom_data'] ?? [];
        
        // Update order status to failed
        $stmt = $this->dbConnection->prepare("
            UPDATE orders 
            SET status = 'failed', 
                failed_at = NOW()
            WHERE payment_id = ?
        ");
        $stmt->execute([$paymentId]);
        
        error_log("Payment {$paymentId} failed");
    }

    private function sendPaymentEmail($email, $paymentId, $amount, $orderId) {
        if (!empty($email)) {
            $subject = "Payment Confirmed - Order #{$orderId}";
            $message = "Your payment of {$amount} USDT has been confirmed.\n";
            $message .= "Payment ID: {$paymentId}\n";
            $message .= "Order ID: {$orderId}\n";
            $message .= "Thank you for your purchase!";
            
            mail($email, $subject, $message);
        }
    }
}

// Initialize and handle webhook
$secret = getenv('RAZ_WEBHOOK_SECRET') ?: 'your_webhook_secret_here';
$webhook = new RazCryptoWebhook($secret);
$webhook->handle();
?>
// webhook.js - Complete Node.js Webhook Handler
const express = require('express');
const crypto = require('crypto');
require('dotenv').config();

const app = express();
const PORT = process.env.PORT || 3000;

// Database connection (using mysql2 as example)
const mysql = require('mysql2/promise');
const pool = mysql.createPool({
    host: process.env.DB_HOST,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_NAME,
    waitForConnections: true,
    connectionLimit: 10,
    queueLimit: 0
});

// Use raw body for signature verification
app.post('/webhook/razcrypto',
    express.raw({ type: 'application/json' }),
    async (req, res) => {
        try {
            // 1) Get raw payload and signature
            const payload = req.body.toString('utf8');
            const signature = req.headers['x-razcrypto-signature'] || '';
            
            if (!payload || !signature) {
                return res.status(400).json({
                    error: 'Missing payload or signature'
                });
            }

            // 2) Verify signature
            const expected = crypto
                .createHmac('sha256', process.env.RAZ_WEBHOOK_SECRET)
                .update(payload)
                .digest('hex');

            if (!crypto.timingSafeEqual(
                Buffer.from(expected, 'utf8'),
                Buffer.from(signature, 'utf8')
            )) {
                return res.status(401).json({
                    error: 'Invalid signature',
                    received: signature,
                    expected: expected
                });
            }

            // 3) Parse JSON
            let data;
            try {
                data = JSON.parse(payload);
            } catch (parseError) {
                return res.status(400).json({
                    error: 'Invalid JSON',
                    details: parseError.message
                });
            }

            // 4) Process based on event
            const event = data.event;
            switch (event) {
                case 'payment.completed':
                    await handlePaymentCompleted(data);
                    break;
                    
                case 'payment.failed':
                    await handlePaymentFailed(data);
                    break;
                    
                case 'payment.pending':
                    await handlePaymentPending(data);
                    break;
                    
                default:
                    console.warn(`Unknown event received: ${event}`);
                    // Still return 200 to avoid retries
            }

            // 5) Success response
            res.status(200).json({
                status: 'success',
                message: 'Webhook processed',
                timestamp: new Date().toISOString()
            });

        } catch (error) {
            console.error('Webhook processing error:', error);
            res.status(500).json({
                error: 'Internal server error',
                message: error.message
            });
        }
    }
);

// Payment completed handler
async function handlePaymentCompleted(data) {
    const {
        payment_id,
        amount,
        tx_hash,
        email_id,
        custom_data = {}
    } = data;

    const orderId = custom_data.order_id || payment_id;
    
    try {
        // Update order in database
        const [result] = await pool.execute(`
            UPDATE orders 
            SET status = 'paid',
                payment_id = ?,
                tx_hash = ?,
                paid_amount = ?,
                paid_at = NOW(),
                custom_data = ?
            WHERE order_id = ? OR payment_id = ?
        `, [
            payment_id,
            tx_hash,
            amount,
            JSON.stringify(custom_data),
            orderId,
            payment_id
        ]);

        console.log(`Payment ${payment_id} completed for order ${orderId}`);

        // Send email notification
        if (email_id) {
            await sendPaymentEmail(
                email_id,
                payment_id,
                amount,
                orderId
            );
        }

        // Additional business logic
        await processOrderCompletion(orderId, custom_data);

    } catch (dbError) {
        console.error('Database error:', dbError);
        throw dbError;
    }
}

// Payment failed handler
async function handlePaymentFailed(data) {
    const { payment_id, custom_data = {} } = data;
    
    await pool.execute(`
        UPDATE orders 
        SET status = 'failed',
            failed_at = NOW()
        WHERE payment_id = ?
    `, [payment_id]);
    
    console.log(`Payment ${payment_id} marked as failed`);
}

// Payment pending handler
async function handlePaymentPending(data) {
    const { payment_id, amount } = data;
    console.log(`Payment ${payment_id} is pending: ${amount} USDT`);
    // You might want to update order status to 'pending_payment'
}

// Email sending function
async function sendPaymentEmail(email, paymentId, amount, orderId) {
    // Implement your email sending logic
    // Using nodemailer or your preferred service
    console.log(`Would send email to ${email} for payment ${paymentId}`);
}

// Additional order processing
async function processOrderCompletion(orderId, customData) {
    // Implement your business logic
    // e.g., generate download links, update inventory, etc.
    console.log(`Processing order completion for ${orderId}`);
}

// Start server
app.listen(PORT, () => {
    console.log(`Webhook server listening on port ${PORT}`);
    console.log(`Webhook endpoint: http://localhost:${PORT}/webhook/razcrypto`);
});

module.exports = app;
# webhook.py - Complete Python Webhook Handler
from flask import Flask, request, jsonify
import hmac
import hashlib
import json
import os
from datetime import datetime
import mysql.connector
from mysql.connector import Error
import logging

app = Flask(__name__)
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Load configuration
WEBHOOK_SECRET = os.getenv('RAZ_WEBHOOK_SECRET', '')
DB_CONFIG = {
    'host': os.getenv('DB_HOST', 'localhost'),
    'user': os.getenv('DB_USER', 'root'),
    'password': os.getenv('DB_PASSWORD', ''),
    'database': os.getenv('DB_NAME', 'your_database')
}

def get_db_connection():
    """Create database connection"""
    try:
        connection = mysql.connector.connect(**DB_CONFIG)
        return connection
    except Error as e:
        logger.error(f"Database connection error: {e}")
        return None

def verify_signature(payload, signature):
    """Verify HMAC-SHA256 signature"""
    if not WEBHOOK_SECRET:
        logger.error("WEBHOOK_SECRET not configured")
        return False
    
    expected = hmac.new(
        WEBHOOK_SECRET.encode('utf-8'),
        payload.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()
    
    return hmac.compare_digest(expected, signature)

@app.route('/webhook/razcrypto', methods=['POST'])
def handle_webhook():
    """Main webhook handler"""
    try:
        # Get raw payload
        payload = request.get_data(as_text=True)
        if not payload:
            return jsonify({'error': 'Empty payload'}), 400
        
        # Get signature header
        signature = request.headers.get('X-Razcrypto-Signature', '')
        if not signature:
            return jsonify({'error': 'Missing signature'}), 400
        
        # Verify signature
        if not verify_signature(payload, signature):
            return jsonify({'error': 'Invalid signature'}), 401
        
        # Parse JSON
        try:
            data = json.loads(payload)
        except json.JSONDecodeError as e:
            return jsonify({'error': f'Invalid JSON: {str(e)}'}), 400
        
        # Process event
        event = data.get('event', '')
        
        if event == 'payment.completed':
            handle_payment_completed(data)
        elif event == 'payment.failed':
            handle_payment_failed(data)
        elif event == 'payment.pending':
            handle_payment_pending(data)
        else:
            logger.warning(f"Unknown event received: {event}")
            # Still return 200 to prevent retries
        
        # Success response
        return jsonify({
            'status': 'success',
            'message': 'Webhook processed',
            'timestamp': datetime.utcnow().isoformat() + 'Z'
        }), 200
        
    except Exception as e:
        logger.error(f"Webhook processing error: {e}")
        return jsonify({
            'error': 'Internal server error',
            'message': str(e)
        }), 500

def handle_payment_completed(data):
    """Handle payment.completed event"""
    payment_id = data.get('payment_id', '')
    amount = data.get('amount', 0)
    tx_hash = data.get('tx_hash', '')
    email = data.get('email_id', '')
    custom_data = data.get('custom_data', {})
    
    order_id = custom_data.get('order_id', payment_id)
    
    logger.info(f"Payment {payment_id} completed for order {order_id}")
    
    # Update database
    connection = get_db_connection()
    if connection:
        try:
            cursor = connection.cursor()
            cursor.execute("""
                UPDATE orders 
                SET status = 'paid',
                    payment_id = %s,
                    tx_hash = %s,
                    paid_amount = %s,
                    paid_at = NOW(),
                    custom_data = %s
                WHERE order_id = %s OR payment_id = %s
            """, (
                payment_id,
                tx_hash,
                amount,
                json.dumps(custom_data),
                order_id,
                payment_id
            ))
            connection.commit()
            cursor.close()
            
            # Send email notification
            if email:
                send_payment_email(email, payment_id, amount, order_id)
                
            # Additional processing
            process_order_completion(order_id, custom_data)
            
        except Error as e:
            logger.error(f"Database error: {e}")
        finally:
            connection.close()

def handle_payment_failed(data):
    """Handle payment.failed event"""
    payment_id = data.get('payment_id', '')
    
    connection = get_db_connection()
    if connection:
        try:
            cursor = connection.cursor()
            cursor.execute("""
                UPDATE orders 
                SET status = 'failed',
                    failed_at = NOW()
                WHERE payment_id = %s
            """, (payment_id,))
            connection.commit()
            cursor.close()
            logger.info(f"Payment {payment_id} marked as failed")
        except Error as e:
            logger.error(f"Database error: {e}")
        finally:
            connection.close()

def handle_payment_pending(data):
    """Handle payment.pending event"""
    payment_id = data.get('payment_id', '')
    amount = data.get('amount', 0)
    logger.info(f"Payment {payment_id} pending: {amount} USDT")

def send_payment_email(email, payment_id, amount, order_id):
    """Send payment confirmation email"""
    # Implement email sending logic
    # Using smtplib or your preferred email service
    logger.info(f"Would send confirmation email to {email}")

def process_order_completion(order_id, custom_data):
    """Process order completion logic"""
    # Implement your business logic
    logger.info(f"Processing order completion for {order_id}")

if __name__ == '__main__':
    # Start Flask development server
    # In production, use gunicorn or uWSGI
    app.run(
        host='0.0.0.0',
        port=5000,
        debug=os.getenv('FLASK_DEBUG', 'False').lower() == 'true'
    )
// WebhookController.java - Complete Java Webhook Handler
package com.yourcompany.razcrypto;

import org.springframework.web.bind.annotation.*;
import org.springframework.http.*;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@RestController
@RequestMapping("/webhook")
public class WebhookController {
    
    private static final Logger logger = LoggerFactory.getLogger(WebhookController.class);
    
    @Value("${razcrypto.webhook.secret}")
    private String webhookSecret;
    
    @PostMapping("/razcrypto")
    public ResponseEntity> handleWebhook(
            @RequestHeader("X-Razcrypto-Signature") String signature,
            @RequestBody String rawBody) {
        
        try {
            // 1) Verify signature
            if (!verifySignature(rawBody, signature)) {
                logger.error("Invalid signature received");
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                    .body(Map.of("error", "Invalid signature"));
            }
            
            // 2) Parse JSON
            Map payload;
            try {
                payload = parseJson(rawBody);
            } catch (Exception e) {
                logger.error("Failed to parse JSON", e);
                return ResponseEntity.badRequest()
                    .body(Map.of("error", "Invalid JSON"));
            }
            
            // 3) Process event
            String event = (String) payload.get("event");
            switch (event) {
                case "payment.completed":
                    handlePaymentCompleted(payload);
                    break;
                case "payment.failed":
                    handlePaymentFailed(payload);
                    break;
                case "payment.pending":
                    handlePaymentPending(payload);
                    break;
                default:
                    logger.warn("Unknown event type: {}", event);
            }
            
            // 4) Return success response
            return ResponseEntity.ok(Map.of(
                "status", "success",
                "message", "Webhook processed",
                "timestamp", java.time.Instant.now().toString()
            ));
            
        } catch (Exception e) {
            logger.error("Webhook processing error", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(Map.of("error", "Internal server error"));
        }
    }
    
    private boolean verifySignature(String payload, String signature) 
            throws NoSuchAlgorithmException, InvalidKeyException {
        
        if (webhookSecret == null || webhookSecret.isEmpty()) {
            throw new IllegalArgumentException("Webhook secret not configured");
        }
        
        Mac sha256Hmac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKey = new SecretKeySpec(
            webhookSecret.getBytes(StandardCharsets.UTF_8), 
            "HmacSHA256"
        );
        sha256Hmac.init(secretKey);
        
        byte[] hash = sha256Hmac.doFinal(payload.getBytes(StandardCharsets.UTF_8));
        String expectedSignature = bytesToHex(hash);
        
        return constantTimeCompare(expectedSignature, signature);
    }
    
    private String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }
    
    private boolean constantTimeCompare(String a, String b) {
        if (a.length() != b.length()) {
            return false;
        }
        int result = 0;
        for (int i = 0; i < a.length(); i++) {
            result |= a.charAt(i) ^ b.charAt(i);
        }
        return result == 0;
    }
    
    @SuppressWarnings("unchecked")
    private Map parseJson(String json) throws Exception {
        // Use your preferred JSON library (Jackson, Gson, etc.)
        ObjectMapper mapper = new ObjectMapper();
        return mapper.readValue(json, Map.class);
    }
    
    private void handlePaymentCompleted(Map payload) {
        String paymentId = (String) payload.get("payment_id");
        Double amount = (Double) payload.get("amount");
        String txHash = (String) payload.get("tx_hash");
        
        @SuppressWarnings("unchecked")
        Map customData = (Map) payload.get("custom_data");
        String orderId = customData != null ? 
            (String) customData.get("order_id") : paymentId;
        
        // Update database
        updateOrderStatus(orderId, "paid", paymentId, txHash, amount, customData);
        
        // Send email
        String email = (String) payload.get("email_id");
        if (email != null && !email.isEmpty()) {
            sendPaymentEmail(email, paymentId, amount, orderId);
        }
        
        logger.info("Payment {} completed for order {}", paymentId, orderId);
    }
    
    private void handlePaymentFailed(Map payload) {
        String paymentId = (String) payload.get("payment_id");
        updateOrderStatus(paymentId, "failed", null, null, null, null);
        logger.info("Payment {} failed", paymentId);
    }
    
    private void handlePaymentPending(Map payload) {
        String paymentId = (String) payload.get("payment_id");
        Double amount = (Double) payload.get("amount");
        logger.info("Payment {} pending: {} USDT", paymentId, amount);
    }
    
    private void updateOrderStatus(String orderId, String status, 
                                   String paymentId, String txHash, 
                                   Double amount, Map customData) {
        // Implement your database update logic
        // Using JPA, JDBC, or your preferred ORM
        logger.info("Updating order {} to status {}", orderId, status);
    }
    
    private void sendPaymentEmail(String email, String paymentId, 
                                  Double amount, String orderId) {
        // Implement email sending logic
        logger.info("Sending payment email to {} for order {}", email, orderId);
    }
}
// webhook.go - Complete Go Webhook Handler
package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"
    "strings"
    "time"
    
    "github.com/gin-gonic/gin"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)

// WebhookSecret from environment
var webhookSecret = os.Getenv("RAZ_WEBHOOK_SECRET")

// Database connection
var db *gorm.DB

// WebhookPayload represents the incoming webhook data
type WebhookPayload struct {
    Event       string                 `json:"event"`
    PaymentID   string                 `json:"payment_id"`
    Amount      float64                `json:"amount"`
    TxHash      string                 `json:"tx_hash"`
    Email       string                 `json:"email_id"`
    Mobile      string                 `json:"mobile_number"`
    Timestamp   string                 `json:"timestamp_iso"`
    CustomData  map[string]interface{} `json:"custom_data"`
}

// Order represents your order table
type Order struct {
    gorm.Model
    OrderID     string                 `gorm:"uniqueIndex"`
    PaymentID   string                 `gorm:"index"`
    Status      string                 `gorm:"index"`
    Amount      float64
    TxHash      string
    PaidAt      *time.Time
    FailedAt    *time.Time
    CustomData  string                 `gorm:"type:JSON"`
}

func init() {
    // Initialize database
    dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
        os.Getenv("DB_USER"),
        os.Getenv("DB_PASSWORD"),
        os.Getenv("DB_HOST"),
        os.Getenv("DB_PORT"),
        os.Getenv("DB_NAME"),
    )
    
    var err error
    db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        log.Fatal("Failed to connect to database:", err)
    }
    
    // Auto migrate
    db.AutoMigrate(&Order{})
}

func main() {
    // Set Gin mode
    if os.Getenv("GIN_MODE") == "release" {
        gin.SetMode(gin.ReleaseMode)
    }
    
    router := gin.Default()
    
    // Webhook endpoint
    router.POST("/webhook/razcrypto", handleWebhook)
    
    // Health check
    router.GET("/health", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{
            "status": "healthy",
            "time":   time.Now().UTC(),
        })
    })
    
    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
    }
    
    log.Printf("Starting webhook server on port %s", port)
    if err := router.Run(":" + port); err != nil {
        log.Fatal("Failed to start server:", err)
    }
}

func handleWebhook(c *gin.Context) {
    // 1) Get signature header
    signature := c.GetHeader("X-Razcrypto-Signature")
    if signature == "" {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": "Missing signature header",
        })
        return
    }
    
    // 2) Read raw body
    body, err := ioutil.ReadAll(c.Request.Body)
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": "Failed to read request body",
        })
        return
    }
    
    // 3) Verify signature
    if !verifySignature(body, signature) {
        c.JSON(http.StatusUnauthorized, gin.H{
            "error": "Invalid signature",
        })
        return
    }
    
    // 4) Parse JSON
    var payload WebhookPayload
    if err := json.Unmarshal(body, &payload); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": "Invalid JSON format",
            "details": err.Error(),
        })
        return
    }
    
    // 5) Process based on event
    switch payload.Event {
    case "payment.completed":
        if err := handlePaymentCompleted(payload); err != nil {
            log.Printf("Error handling payment.completed: %v", err)
            c.JSON(http.StatusInternalServerError, gin.H{
                "error": "Failed to process payment",
            })
            return
        }
        
    case "payment.failed":
        if err := handlePaymentFailed(payload); err != nil {
            log.Printf("Error handling payment.failed: %v", err)
        }
        
    case "payment.pending":
        log.Printf("Payment pending: %s - %f", payload.PaymentID, payload.Amount)
        
    default:
        log.Printf("Unknown event received: %s", payload.Event)
    }
    
    // 6) Success response
    c.JSON(http.StatusOK, gin.H{
        "status":  "success",
        "message": "Webhook processed successfully",
        "time":    time.Now().UTC(),
    })
}

func verifySignature(body []byte, signature string) bool {
    if webhookSecret == "" {
        log.Println("Webhook secret not configured")
        return false
    }
    
    h := hmac.New(sha256.New, []byte(webhookSecret))
    h.Write(body)
    expected := hex.EncodeToString(h.Sum(nil))
    
    return hmac.Equal([]byte(expected), []byte(signature))
}

func handlePaymentCompleted(payload WebhookPayload) error {
    // Get order ID from custom data or use payment ID
    orderID := payload.PaymentID
    if payload.CustomData != nil {
        if id, ok := payload.CustomData["order_id"].(string); ok {
            orderID = id
        }
    }
    
    // Convert custom data to JSON string
    customDataJSON, _ := json.Marshal(payload.CustomData)
    
    // Update or create order
    var order Order
    result := db.Where("order_id = ?", orderID).First(&order)
    
    now := time.Now()
    if result.Error == gorm.ErrRecordNotFound {
        // Create new order
        order = Order{
            OrderID:    orderID,
            PaymentID:  payload.PaymentID,
            Status:     "paid",
            Amount:     payload.Amount,
            TxHash:     payload.TxHash,
            PaidAt:     &now,
            CustomData: string(customDataJSON),
        }
        if err := db.Create(&order).Error; err != nil {
            return fmt.Errorf("failed to create order: %v", err)
        }
    } else {
        // Update existing order
        order.Status = "paid"
        order.PaymentID = payload.PaymentID
        order.Amount = payload.Amount
        order.TxHash = payload.TxHash
        order.PaidAt = &now
        order.CustomData = string(customDataJSON)
        if err := db.Save(&order).Error; err != nil {
            return fmt.Errorf("failed to update order: %v", err)
        }
    }
    
    log.Printf("Payment %s completed for order %s", payload.PaymentID, orderID)
    
    // Send email notification
    if payload.Email != "" {
        go sendPaymentEmail(payload.Email, payload.PaymentID, payload.Amount, orderID)
    }
    
    return nil
}

func handlePaymentFailed(payload WebhookPayload) error {
    now := time.Now()
    result := db.Model(&Order{}).
        Where("payment_id = ?", payload.PaymentID).
        Updates(map[string]interface{}{
            "status":    "failed",
            "failed_at": &now,
        })
    
    if result.Error != nil {
        return fmt.Errorf("failed to update order: %v", result.Error)
    }
    
    log.Printf("Payment %s marked as failed", payload.PaymentID)
    return nil
}

func sendPaymentEmail(email, paymentID string, amount float64, orderID string) {
    // Implement email sending using your preferred service
    log.Printf("Sending payment confirmation to %s for order %s", email, orderID)
}
# webhook.rb - Complete Ruby Webhook Handler
require 'sinatra'
require 'json'
require 'openssl'
require 'mysql2'
require 'dotenv/load'

# Configuration
WEBHOOK_SECRET = ENV['RAZ_WEBHOOK_SECRET']
DB_CONFIG = {
  host: ENV['DB_HOST'] || 'localhost',
  username: ENV['DB_USER'],
  password: ENV['DB_PASSWORD'],
  database: ENV['DB_NAME']
}

# Database connection
def db_connection
  @db ||= Mysql2::Client.new(DB_CONFIG)
end

# Sinatra application
class WebhookApp < Sinatra::Base
  set :port, ENV['PORT'] || 4567
  set :environment, ENV['RACK_ENV'] || 'development'
  
  # Webhook endpoint
  post '/webhook/razcrypto' do
    content_type :json
    
    begin
      # 1) Get signature header
      signature = request.env['HTTP_X_RAZCRYPTO_SIGNATURE']
      unless signature
        status 400
        return { error: 'Missing signature header' }.to_json
      end
      
      # 2) Get raw request body
      request.body.rewind
      payload = request.body.read
      
      # 3) Verify signature
      unless verify_signature(payload, signature)
        status 401
        return { error: 'Invalid signature' }.to_json
      end
      
      # 4) Parse JSON
      begin
        data = JSON.parse(payload)
      rescue JSON::ParserError => e
        status 400
        return { error: 'Invalid JSON', details: e.message }.to_json
      end
      
      # 5) Process event
      event = data['event']
      case event
      when 'payment.completed'
        handle_payment_completed(data)
      when 'payment.failed'
        handle_payment_failed(data)
      when 'payment.pending'
        handle_payment_pending(data)
      else
        puts "Unknown event received: #{event}"
      end
      
      # 6) Success response
      status 200
      {
        status: 'success',
        message: 'Webhook processed',
        timestamp: Time.now.utc.iso8601
      }.to_json
      
    rescue => e
      puts "Webhook processing error: #{e.message}"
      puts e.backtrace
      
      status 500
      { error: 'Internal server error', message: e.message }.to_json
    end
  end
  
  # Health check endpoint
  get '/health' do
    content_type :json
    { status: 'healthy', time: Time.now.utc.iso8601 }.to_json
  end
  
  private
  
  def verify_signature(payload, signature)
    return false unless WEBHOOK_SECRET
    
    expected = OpenSSL::HMAC.hexdigest(
      'sha256',
      WEBHOOK_SECRET,
      payload
    )
    
    # Constant time comparison to prevent timing attacks
    OpenSSL.fixed_length_secure_compare(expected, signature)
  end
  
  def handle_payment_completed(data)
    payment_id = data['payment_id']
    amount = data['amount'].to_f
    tx_hash = data['tx_hash']
    email = data['email_id']
    custom_data = data['custom_data'] || {}
    
    order_id = custom_data['order_id'] || payment_id
    
    puts "Payment #{payment_id} completed for order #{order_id}"
    
    # Update database
    custom_data_json = custom_data.to_json
    
    db_connection.query("
      INSERT INTO orders (
        order_id, payment_id, status, amount, 
        tx_hash, paid_at, custom_data, created_at, updated_at
      ) VALUES (
        '#{db_connection.escape(order_id)}',
        '#{db_connection.escape(payment_id)}',
        'paid',
        #{amount},
        '#{db_connection.escape(tx_hash)}',
        NOW(),
        '#{db_connection.escape(custom_data_json)}',
        NOW(),
        NOW()
      ) ON DUPLICATE KEY UPDATE
        status = 'paid',
        payment_id = '#{db_connection.escape(payment_id)}',
        amount = #{amount},
        tx_hash = '#{db_connection.escape(tx_hash)}',
        paid_at = NOW(),
        custom_data = '#{db_connection.escape(custom_data_json)}',
        updated_at = NOW()
    ")
    
    # Send email notification
    send_payment_email(email, payment_id, amount, order_id) if email
    
    # Additional processing
    process_order_completion(order_id, custom_data)
  end
  
  def handle_payment_failed(data)
    payment_id = data['payment_id']
    
    puts "Payment #{payment_id} failed"
    
    db_connection.query("
      UPDATE orders 
      SET status = 'failed',
          failed_at = NOW(),
          updated_at = NOW()
      WHERE payment_id = '#{db_connection.escape(payment_id)}'
    ")
  end
  
  def handle_payment_pending(data)
    payment_id = data['payment_id']
    amount = data['amount'].to_f
    
    puts "Payment #{payment_id} pending: #{amount} USDT"
  end
  
  def send_payment_email(email, payment_id, amount, order_id)
    # Implement email sending using your preferred gem
    # Example with Mail gem:
    # mail = Mail.new do
    #   to email
    #   subject "Payment Confirmed - Order ##{order_id}"
    #   body "Your payment of #{amount} USDT has been confirmed."
    # end
    # mail.deliver!
    
    puts "Would send payment confirmation email to #{email}"
  end
  
  def process_order_completion(order_id, custom_data)
    # Implement your business logic
    puts "Processing order completion for #{order_id}"
  end
end

# Run the application
if __FILE__ == $0
  WebhookApp.run!
end

Note:

  • Timestamps: Webhook payloads contain both timestamp_iso (ISO-8601) and timestamp (legacy). ISO format is recommended for integration.
  • Retry Logic: If your webhook endpoint returns non-2xx status code, RazCrypto will retry the webhook delivery up to 3 times with exponential backoff.
  • Security: Always verify the HMAC signature before processing webhook data. Never trust unverified payloads.

Official RazCrypto SDKs

Integrate our payment gateway in minutes using professional SDKs in your favorite programming language.

PHP SDK (v2.0.0)

The easiest and most secure way for Laravel and Core PHP projects.

Install via Composer
composer require worldxgrowth/razcrypto-php-sdk
Quick Init
use RazCrypto\Api;
$api = new Api("GATEWAY_ID", "SECRET_KEY");

Non-Custodial Model

Your Keys, Your Crypto: We never hold your funds. Payments go directly to your wallet addresses that you control.

🔐 How Non-Custodial Works

You Control Wallets

You provide your own wallet addresses. We never have access to your private keys.

Real-time Monitoring

We monitor your wallet addresses for incoming payments using blockchain technology.

Instant Notifications

Get webhook notifications when payments are detected on your wallets.

🔄 Payment Flow

  1. Customer Pays: Sends crypto directly to YOUR wallet address
  2. Blockchain Confirmation: Transaction confirmed on blockchain (2-5 seconds)
  3. We Detect: Our system detects payment to your wallet
  4. You Get Notified: Instant webhook to your application
  5. Funds Available: Immediately in your wallet - no waiting

🎯 Benefits of Non-Custodial

Feature Non-Custodial (RazCrypto) Custodial (Traditional)
Fund Control ✅ You have 100% control ❌ Platform controls funds
Withdrawal Fees ✅ No withdrawal fees ❌ Withdrawal fees apply
Fund Access ✅ Immediate access ❌ Platform approval needed
Security Risk ✅ Your responsibility ❌ Platform risk
KYC Requirements ✅ Not required ❌ Often required

⚡ Wallet Setup Guide

Step 1: Add Wallet Addresses

Dashboard
1. Login to RazCrypto Dashboard
2. Go to "Receive Wallet" section  
3. Add your wallet addresses:
   - BSC Address: 0x...
   - ETH Address: 0x...
   - Polygon Address: 0x...
4. Save addresses

Step 2: Activate Chains

Dashboard
1. For each chain, click "Activate"
2. Wait for activation confirmation
3. Green checkmark = Ready to accept payments
4. Repeat for all chains you want to use
Activation Required: Each chain must be activated individually. Activation enables real-time transaction monitoring for that blockchain network.

Security Best Practices

Essential Security Measures

Important: Never expose your secret key in client-side code. Always keep it secure on your server.
JavaScript
// ❌ NEVER do this - exposing secret key in frontend
RazCrypto.init({
    public_key_id: "rz_pub_...",
    secret_key: "rz_sec_..." // ❌ DANGEROUS!
});

// ✅ ALWAYS do this - keep secret key server-side
// Frontend (JavaScript)
RazCrypto.init({
    public_key_id: "rz_pub_..."
});

// Backend (Node.js/PHP) - keep secret key in environment variables

Security Checklist

Error Handling

Complete Error Codes Reference

Payment Creation Errors (RZ_001 - RZ_009)

Error Code Message Description Solution
RZ_001 Invalid amount Amount must be ≥ 0.01 USDT Ensure amount is numeric and ≥ 0.01
RZ_002 Invalid or inactive public_key_id Public key invalid or account inactive Check public key in dashboard
RZ_005 Failed to create transaction Database insertion failed Try again or contact support
RZ_008 Invalid expiry_minutes Expiry must be 1-60 minutes Set expiry between 1-60 minutes

Error Response Format

JSON
{
    "status": "error",
    "message": "Invalid amount",
    "error_code": "RZ_001",
    "retry_after": null,
    "timestamp": "2024-01-15T10:30:00Z"
}

Webhook Status Check

JSON

   https://razcryptogateway.com/api/v2/webhooks/payid_id/status?auth_key=your_auth_key_from_dashboard

                        
 {

    
  "status": "success",
  "data": {
    "payment_id": "payid_4dfdb2439",
    "merchant": "Raj",
    "webhook_delivered": true,
    "status_code": 200,
    "status_message": "Webhook delivered successfully",
    "attempts": 0,
    "last_attempt": "2025-12-02 19:14:58",
    "callback_url": "https://digiworldx.in/?razcrypto_webhook=1&order_id=2853",
    "create_at": "2025-12-02 19:14:46",
    "updated_at": "2025-12-02 19:14:58",
    "documentation": "https://razcryptogateway.com/docs"
}

Handling Errors in JavaScript

JavaScript
try {
    const result = await RazCrypto.createPayment({
        amount: 10.00,
        email: "[email protected]"
    });
} catch (error) {
    // Handle specific error codes
    switch (error.message) {
        case 'RZ_001':
            alert('Please enter a valid amount (minimum 0.01 USDT)');
            break;
        case 'RZ_002':
            alert('Invalid API key. Please check your configuration.');
            break;
        case 'RZ_020':
            alert('Too many requests. Please wait a minute and try again.');
            break;
        default:
            alert('Payment failed: ' + error.message);
    }
    
    // Log error for debugging
    console.error('Payment error:', error);
}

Rate Limiting

Current Rate Limits

Rate Limit Headers

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59  
X-RateLimit-Reset: 1642176300

Best Practices

JavaScript
// Implement exponential backoff for retries
async function createPaymentWithRetry(payload, maxRetries = 3) {
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
        try {
            return await RazCrypto.createPayment(payload);
        } catch (error) {
            if (error.message.includes('RZ_020')) {
                // Rate limit exceeded - wait and retry
                const waitTime = Math.pow(2, attempt) * 1000; // Exponential backoff
                console.log(Rate limit hit, waiting ${waitTime}ms...);
                await new Promise(resolve => setTimeout(resolve, waitTime));
                continue;
            }
            throw error; // Re-throw other errors
        }
    }
    throw new Error('Max retries exceeded');
}

Frequently Asked Questions

Find answers to common questions about RazCrypto Payment Gateway integration, USDT BEP-20 payments, and business solutions.

Is RazCrypto an international payment gateway that works worldwide?

Yes, RazCrypto is a global cryptocurrency payment gateway that works worldwide. You can accept USDT (BEP-20) payments from customers anywhere in the world without any geographical restrictions. Whether your business is in India, USA, Europe, Asia, or any other region, RazCrypto enables seamless cross-border transactions. The borderless nature of cryptocurrency makes it perfect for international e-commerce, freelancers, SaaS businesses, and global service providers.

Can any business owner use RazCrypto without KYC verification?

Absolutely! RazCrypto is designed to be accessible to all types of business owners without mandatory KYC verification. This includes:
• Gaming Business Owners: Accept payments for in-game purchases, subscriptions, and gaming services
• Multi-Level Marketing (MLM): Perfect for MLM companies and network marketing businesses
• E-commerce Stores: Online retailers of all sizes can integrate easily
• Freelancers & Consultants: Accept international payments for services
• SaaS Companies: Subscription-based software businesses
• Content Creators: YouTubers, bloggers, and digital creators
Simply sign up at razcryptogateway.com/user/signup and start accepting payments immediately.

Do you have a WordPress plugin for easy integration?

Yes! RazCrypto offers a dedicated WordPress plugin that makes integration incredibly easy. With our plugin, you can:
• Quick Installation: Install directly from your WordPress dashboard
• Simple Configuration: Just add your public key in settings
• WooCommerce Support: Works seamlessly with WooCommerce stores
• Shortcode Support: Add payment buttons anywhere using shortcodes
• Automatic Payment Processing: Handles everything automatically
Download and installation guide available at: razcryptogateway.com/docs/razcrypto-plugin

Can I create payment links to share with customers?

Yes, RazCrypto allows you to create instant payment links that you can share via:
• Email: Send payment links directly to customer emails
• SMS/WhatsApp: Share links via messaging apps
• Social Media: Post payment links on social platforms
• QR Codes: Generate QR codes for easy scanning
Each payment link includes:
• Custom amount setting
• Product/service description
• Customer information fields
• Automatic expiry management
• Real-time status tracking
Perfect for invoices, service payments, and one-time transactions.

Can I create a professional business page without integration?

Yes! RazCrypto offers a complete business page builder feature where you can create stunning professional pages:
Step 1: Sign up at razcryptogateway.com/user/signup
Step 2: Create your API keys
Step 3: Go to Business Page section and add:
• Business name & description
• Owner photo (optional)
• Business logo
• Contact details (mobile, email)
• Social media links (YouTube, Instagram, Facebook)
• Testimonial videos (YouTube links)
• Achievement images
• Additional YouTube video links
Step 4: Choose from 10+ advanced premium templates
Step 5: Share your unique business page link
This feature is completely FREE forever with premium templates included!

What is RazCrypto Payment Gateway and how does it work?

RazCrypto is India's leading cryptocurrency payment gateway that enables businesses to accept USDT (BEP-20) payments on the Binance Smart Chain network. It provides a seamless integration experience with simple API endpoints and JavaScript SDK for quick implementation. The gateway handles payment processing, blockchain confirmations, and instant settlement, making it easy for merchants to accept crypto payments without deep technical knowledge of blockchain technology.

What is the minimum and maximum payment amount for USDT transactions?

The minimum payment amount accepted by RazCrypto Gateway is 0.01 USDT (BEP-20), making it suitable for micro-transactions and small payments. For maximum limits, we support high-volume transactions suitable for enterprise businesses. There are no upper limits for individual transactions, but for large amounts, we recommend contacting our support team at [email protected] for personalized assistance and optimized processing.

How long do cryptocurrency payments take to confirm?

Confirmation times vary by blockchain network:

Blockchain Average Confirmation Maximum Time Network Fee
BNB Smart Chain (BSC) 2-3 seconds 30 seconds Very Low ($0.01-0.10)
Ethereum (ETH) 3-5 seconds 1-2 minutes Medium ($1-5)
Polygon 2-4 seconds 30 seconds Very Low ($0.01-0.05)

Factors affecting confirmation time:

  • Network Congestion: During high traffic, confirmations may take longer
  • Gas Fees: Higher fees can prioritize your transaction
  • Block Time: Each blockchain has different block generation times

RazCrypto monitors all transactions in real-time and provides instant webhook notifications upon confirmation.

Is KYC verification required for merchants using RazCrypto Gateway?

No, RazCrypto does not require KYC verification for merchants to start accepting USDT payments. You can sign up at razcryptogateway.com/user/signup and begin integrating immediately. This makes RazCrypto one of the most accessible cryptocurrency payment gateways for businesses of all sizes. However, we maintain strict security protocols and monitoring systems to ensure compliant operations.

What cryptocurrencies and blockchain networks does RazCrypto support?

RazCrypto supports multiple blockchain networks and stablecoins:

Blockchain Supported Tokens Status Network
BNB Smart Chain (BSC) USDT, USDC, DAI ✅ Live BEP-20
Ethereum (ETH) USDT, USDC, DAI ✅ Live ERC-20
Polygon USDT, USDC, DAI ✅ Live< ERC-20 (Polygon)

Key Features:

  • Multi-Chain Support: Accept payments on BSC and Ethereum networks
  • Multi-Token Support: USDT, USDC, DAI stablecoins on each chain
  • Chain-Specific Contracts: Proper contract addresses for each network
  • Flexible Integration: Specify chain and token in API requests

Use the chain and currency parameters in API requests to select your preferred network and stablecoin.

How do I integrate RazCrypto Payment Gateway into my website or application?

Integrating RazCrypto is straightforward with multiple options:
1. JavaScript SDK: Add our SDK script and initialize with your public key
2. Direct API Integration: Use our REST API endpoints for custom implementations
3. WordPress Plugin: Easy plugin installation for WordPress sites
4. Documentation Reference: Visit razcryptogateway.com/docs/integration for complete guides
Most integrations can be completed in under 30 minutes. Our API supports various programming languages including JavaScript, PHP, Python, and Node.js.

Is there a sandbox or test environment available for development?

Currently, we recommend testing with small amounts (starting from 0.01 USDT) in our live production environment. This approach ensures that your integration works exactly as it will in production. The minimal test amount makes development cost-effective while providing real-world testing conditions. For development assistance, refer to our comprehensive documentation at razcryptogateway.com/docs.

How do webhooks work and how should I handle payment notifications?

RazCrypto Payment Gateway uses webhooks to send real-time payment notifications to your server. Key webhook events include:
- payment.completed: Triggered when payment is confirmed on blockchain
- payment.failed: Triggered when payment fails or expires
- payment.pending: Triggered when payment is waiting confirmation
Configure your webhook URL in the dashboard, and ensure your endpoint returns 200 OK. Always verify webhook signatures for security. Example implementations are available in our documentation for both PHP and Node.js.

What should I do when a payment fails or expires?

Failed payments are automatically handled through our system:
1. Webhook Notifications: You'll receive instant failure notifications
2. Status API: Check payment status via GET /payments/status/{payment_id}
3. Customer Communication: Notify customers to retry payment
4. New Payment Creation: Generate a new payment_id for retry
Payments expire after 30 minutes if not confirmed. Ensure your system handles these scenarios gracefully by monitoring webhooks and implementing retry mechanisms.

What security measures does RazCrypto implement for payment processing?

RazCrypto employs multiple security layers:
1. API Key Authentication: Separate public and secret keys
2. Webhook Signature Verification: HMAC-SHA256 signatures for all webhooks
3. HTTPS Encryption: All API communications are encrypted
4. Input Validation: Comprehensive validation on all endpoints
5. Rate Limiting: DDoS protection and abuse prevention
6. Secure Key Storage: Environment-based key management
Review our security best practices in documentation and ensure you never expose secret keys in client-side code.

How do I handle custom metadata and additional payment information?

RazCrypto supports custom_data field in payment creation requests. You can include:
- Order details (order_id, items, pricing)
- Customer information (user_id, preferences)
- Shipping and billing addresses
- Custom metadata for internal tracking
This data is returned in API responses and webhook notifications, allowing you to maintain context throughout the payment lifecycle. The custom_data supports nested objects and arrays for complex data structures.

What are the transaction fees for using RazCrypto Payment Gateway?

RazCrypto offers competitive pricing with transparent fee structure. Our fees cover:
- Payment processing and blockchain network fees
- Infrastructure and API maintenance
- 24/7 customer support
- Security and compliance monitoring
For detailed pricing information and enterprise plans, please contact our sales team at [email protected] or visit your dashboard after signing up at razcryptogateway.com/user/signup.

How can I contact RazCrypto support for technical issues?

We provide multiple support channels:
1. Email Support: [email protected] for general queries
2. Technical Support: [email protected] for integration issues
3. Emergency Support: [email protected] for critical issues
4. Dashboard Chat: Live chat available in your merchant dashboard
5. Documentation: Comprehensive guides at razcryptogateway.com/docs
Our average response time is under 2 hours for technical queries.

Can I use RazCrypto for subscription-based or recurring payments?

Yes, RazCrypto supports subscription and recurring payment models through our API. You can:
- Use subscription_id field to track recurring payments
- Create new payment links for each billing cycle
- Implement webhook handling for subscription management
- Use custom_data to store subscription-specific information
While we don't automatically charge recurring payments (for security reasons), our API makes it easy to implement subscription logic in your application with proper payment tracking and customer management.

What happens if there's a blockchain network congestion or outage?

RazCrypto is built to handle blockchain network variations:
1. Network Monitoring: We continuously monitor BSC network status
2. Automatic Retries: System handles temporary network issues
3. Status Updates: Real-time payment status through API
4. Customer Communication: Clear status messages for end users
5. Fallback Handling: Proper error handling in SDK and API
In rare cases of extended network issues, we provide status updates through our status page and direct communications to affected merchants.

Does RazCrypto automatically redirect customers to payment pages?

No, you have full control over redirects. Unlike some payment gateways, RazCrypto never automatically redirects your customers. Here's how it works:

API Response: You receive JSON with multiple URL options

Your Decision: You choose when and where to redirect

Your Code: You implement the redirect logic

// You control the redirect timing and destination
const result = await RazCrypto.createPayment({ amount: 10.00 });

// Option 1: Immediate redirect
window.location.href = result.checkout_page;

// Option 2: Redirect after user confirmation
document.getElementById('pay-btn').onclick = () => {
    window.location.href = result.checkout_page;
};

// Option 3: Open in new tab
window.open(result.checkout_page, '_blank');

This gives you complete flexibility to integrate payments seamlessly into your user experience.

How do I ensure my RazCrypto integration is SEO-friendly?

For SEO-optimized RazCrypto integration:
1. Proper Meta Tags: Include relevant keywords like "USDT Payments", "BEP-20 Gateway"
2. Structured Data: Implement JSON-LD for payment pages
3. Fast Loading: Our SDK is optimized for performance
4. Mobile Optimization: Fully responsive payment pages
5. Clear Content: Explain crypto payment benefits to users
6. Internal Linking: Link to razcryptogateway.com/docs for technical details
These practices help search engines understand your payment options and improve user experience.

What programming languages are supported for RazCrypto integration?

RazCrypto is language-agnostic and can be integrated with any programming language that supports HTTP requests and JSON. We provide:
1. JavaScript SDK: For frontend and Node.js applications
2. REST API: Universal HTTP endpoints for all languages
3. WordPress Plugin: For easy WordPress integration
4. Code Examples: PHP, Python, Java, Ruby, Go in documentation
5. Webhook Handlers: Examples for multiple backend frameworks
Whether you're using React, Vue, Angular, Laravel, Django, or any other framework, our API works seamlessly with your technology stack.

How does RazCrypto compare to other cryptocurrency payment gateways?

RazCrypto stands out with several key advantages:
1. Focus on BEP-20: Specialized optimization for Binance Smart Chain
2. No KYC for Merchants: Faster onboarding process
3. Instant Confirmations: 2-5 second payment processing
4. Simple Integration: 30-minute setup with clear documentation
5. WordPress Plugin: Easy integration for WordPress users
6. Free Business Pages: Professional pages with premium templates
7. Global Accessibility: Works worldwide without restrictions
8. Reliable Support: Quick response times and technical assistance
These features make RazCrypto the preferred choice for businesses looking for reliable USDT BEP-20 payment processing.

Where can I find complete API documentation and integration guides?

Complete documentation is available at:
1. Main Documentation: razcryptogateway.com/docs
2. Integration Guide: razcryptogateway.com/docs/integration
3. WordPress Plugin: razcryptogateway.com/docs/razcrypto-plugin
4. API Reference: Detailed endpoint documentation with examples
5. SDK Documentation: JavaScript SDK usage and examples
6. Webhook Guide: Complete webhook implementation guide
7. Support Page: razcryptogateway.com/support for additional help
All documentation includes live examples, code snippets, and best practices for seamless integration.

What does "non-custodial" mean and how is it different?

Non-custodial means we never hold your cryptocurrency funds. Unlike traditional payment gateways that control your money, with RazCrypto:

  • You control the wallets - we never have private keys
  • Direct payments - customers pay directly to YOUR addresses
  • No withdrawal process - funds are immediately available
  • Enhanced security - no central point of failure
  • True ownership - your keys, your crypto

Traditional custodial gateways hold your funds and require you to withdraw, while we simply monitor your wallets for incoming payments.

How do I setup multiple chains (BSC, ETH, Polygon)?

Setting up multiple chains is simple:

  1. Go to Receive Wallet in your dashboard
  2. Add your wallet addresses for each chain:
    • BSC Address (BEP-20)
    • ETH Address (ERC-20)
    • Polygon Address (POL)
  3. Click Activate for each chain
  4. Wait for activation confirmation (2-3 minutes)
  5. Start accepting payments on all activated chains

Each chain must be activated individually. Once activated, you can specify the chain in API requests using the chain parameter.

What tokens are supported on each chain?

We support major stablecoins on each blockchain:

Blockchain Supported Tokens Contract Standards
BSC (Binance Smart Chain) USDT, USDC, DAI BEP-20
Ethereum USDT, USDC, DAI ERC-20
Polygon USDT, USDC, DAI ERC-20 (Polygon)

Specify the token using the currency parameter in API requests. Each token has chain-specific contract addresses for accurate processing.

How does wallet activation work and why is it required?

Wallet activation is required to enable real-time payment monitoring for your addresses. Here's how it works:

  1. Registration: We register your wallet address with blockchain monitoring services
  2. Webhook Setup: Configure real-time notifications for your address
  3. Testing: Verify the monitoring is working correctly
  4. Activation: Enable payment processing for that chain

Why it's required: Without activation, we cannot detect payments sent to your wallet. Activation ensures:

  • ✅ Real-time payment detection
  • ✅ Instant webhook notifications
  • ✅ Accurate payment matching
  • ✅ Reliable service operation

Activation typically takes 2-3 minutes and is a one-time process per chain.

What are the fees and pricing for using RazCrypto Payment Gateway?

RazCrypto offers the most competitive and transparent pricing in the market with zero transaction fees:

Feature Pricing Value
Transaction Fee ✅ 0% No percentage on transactions
Credit System 1 credit per payment attempt ~₹0.50 per credit
Free Trial Credits 🎁 1,000 FREE credits ~500 payment attempts FREE
Setup Fee ✅ FREE No hidden charges
Minimum Amount $1 USDT Start small, scale big

How Credits Work:

  • 1 Credit = 1 Payment creation attempt
  • Successful Payment = 5 credits total (1 create + 4 processing)
  • Failed/Expired Payment = Only 1 credit used
  • Free Credits = 1,000 credits for testing & getting started

Example Cost Calculation:

  • 100 successful payments = 500 credits ≈ ₹250
  • That's just ₹2.50 per successful payment - much cheaper than 2-3% fees!
  • For $100 payment: Traditional gateway (3% fee) = $3 vs RazCrypto = $0.005
Best Value: For high-volume businesses, RazCrypto is 10x cheaper than traditional payment gateways charging 2-3% per transaction.
How does the credit system work and what's included in the free trial?

Our credit-based system is designed to be fair and cost-effective:

Free Trial Includes:

  • 🎁 1,000 FREE Credits - No credit card required
  • 🚀 ~200 Successful Payments - Enough to test thoroughly
  • 💼 All Features Included - Full access to all gateway features
  • No Time Limit - Use at your own pace

Credit Usage:

Payment Creation

1 credit per payment attempt

Successful Payment

5 credits total (processing included)

Failed Payment

Only 1 credit used

After Free Trial:

  • 💰 Affordable Plans - Starting from just 1000 credits/month
  • 📈 Volume Discounts - Higher volumes = lower per-credit cost
  • 🔧 Enterprise Plans - Custom pricing for high-volume businesses

Start with FREE credits and upgrade when you're ready to scale!

Can I customize the payment page with my branding?

Yes! RazCrypto offers comprehensive branding options:

  • Logo Upload: Display your logo on payment pages
  • Color Scheme: Custom primary and secondary colors
  • Page Types: Choose between Direct Hosted Page or advanced Checkout Page
  • Business Information: Add your contact details
  • Custom Styling: Advanced CSS customization (enterprise)

Setup Process:

  1. Go to Branding section in dashboard
  2. Upload your logo and set colors
  3. Choose your preferred page type
  4. Save settings
  5. All future payments will use your branded pages

This creates a seamless brand experience for your customers from your website to payment completion.

Transparent & Competitive Pricing

Zero Transaction Fees + Free Credits: Start with 1,000 FREE credits and pay only for what you use. No percentage fees, no hidden charges.

Zero Transaction Fees

No percentage fees on payments. Flat credit-based pricing only.

1,000 Free Credits

Start with FREE credits worth ~200 successful payments.

Pay Per Use

Only pay for actual payment attempts. No monthly fees.

Cost Comparison

Payment Gateway Fee for 1 ,$1000 Payment Monthly Fees Setup Cost
RazCrypto ₹0.20 (1 Payment 1 credit) None FREE
Traditional Gateway (3%) $3.00 (₹100) $30-100 $50-200
PayPal/Stripe $2.90 + 30¢ None FREE
Savings Calculator: Process $10,000 in payments? Traditional gateways charge $300, RazCrypto costs just ₹100 - that's 90% savings!

Advanced Features

Custom Metadata Support

Send custom JSON data with payments that will be included in webhooks and API responses:

JavaScript
const result = await RazCrypto.createPayment({
    amount: 10.00,
    email: "[email protected]",
    custom_data: {
        "order_id": "ORD_2024_001",
        "user_id": "USER_123",
        "items": [
            {"name": "Product A", "price": 10.00, "quantity": 1}
        ],
        "shipping_address": {
            "street": "123 Main St",
            "city": "Mumbai",
            "country": "India"
        }
    }
});

🎨 Merchant Branding & Customization

Customize the payment experience with your brand identity:

Dashboard
1. Go to "Branding" section in dashboard
2. Upload your logo (PNG, JPG, SVG)
3. Set primary and secondary colors
4. Save settings

Hosted Page Types

Page Type Description Best For Customization
Direct Hosted Page Simple payment page with basic branding Quick integrations, minimal customization Logo, colors, basic info
Checkout Page Advanced checkout experience with full branding E-commerce, professional businesses Full branding, custom fields, advanced styling

Branding Options

Automatic Redirection: Based on your branding settings, customers will be automatically directed to your customized payment or checkout page.

Payment Links

Create shareable payment links:

JavaScript
// After creating payment, share the payment_url
const paymentLink = result.payment_url;
// Share via: email, SMS, messaging apps, etc.

Support & Contact

Technical Support

Business Inquiries

Emergency Support

For urgent issues affecting live payments: