Skip to content

Deposit Monitoring

Automatically detect and track incoming transactions to your customer wallet addresses across all supported networks.

Overview

The Wallet Service includes built-in deposit monitoring that watches blockchain addresses for incoming native token deposits (BNB, ETH, MATIC, TRX, SOL) and sends webhooks to your application instantly when deposits are detected.

You Control Balance Management

This is a notification-only service. We detect deposits and send webhooks - you manage your own internal balances. This architecture gives you complete control over your accounting and balance tracking.


How It Works

Key Points:

  • 🔍 Automatic Monitoring - No polling needed from your side
  • 30-Second Intervals - Fast deposit detection
  • 🌐 5 Networks Supported - BSC, Ethereum, Polygon, Tron, Solana
  • 💰 Native Tokens Only - BNB, ETH, MATIC, TRX, SOL (not ERC-20 tokens)
  • 📡 Webhook Notifications - HMAC-signed webhooks sent instantly
  • 🎯 You Control Balances - We detect, you manage

Supported Networks

NetworkNative TokenMonitoredDecimals
BSCBNB18
EthereumETH18
PolygonMATIC (POL)18
TronTRX6
SolanaSOL9

Why Native Tokens Only?

Monitoring focuses on native tokens because:

  • Most common for wallet deposits
  • Simpler balance checking (no token contract calls)
  • Lower RPC overhead
  • For ERC-20 monitoring, use our Crypto Gateway product instead

Enable Monitoring on Address

When deriving an address, set the monitored flag to true:

javascript
async function deriveMonitoredAddress(customerId, network) {
  const response = await axios.post(
    `https://payments-api-dev-966260606560.europe-west2.run.app/api/v1/wallet/customer/${customerId}/derive`,
    {
      network: network,     // BTC, ETH, BSC, POL, TRX, SOL
      index: 0,
      monitored: true       // ← Enable automatic deposit monitoring
    },
    {
      headers: {
        'X-API-Key': process.env.RACH_API_KEY,
        'Content-Type': 'application/json'
      }
    }
  );
  
  return response.data;
}

// Create monitored addresses for common networks
const bscAddr = await deriveMonitoredAddress('user_123', 'BSC');
const ethAddr = await deriveMonitoredAddress('user_123', 'ETH');
const polAddr = await deriveMonitoredAddress('user_123', 'POL');
python
def derive_monitored_address(customer_id, network):
    """Derive an address with monitoring enabled"""
    url = f'https://payments-api-dev-966260606560.europe-west2.run.app/api/v1/wallet/customer/{customer_id}/derive'
    
    payload = {
        'network': network,
        'index': 0,
        'monitored': True  # ← Enable monitoring
    }
    
    headers = {
        'X-API-Key': os.getenv('RACH_API_KEY'),
        'Content-Type': 'application/json'
    }
    
    response = requests.post(url, json=payload, headers=headers)
    response.raise_for_status()
    return response.json()

# Create monitored addresses
bsc = derive_monitored_address('user_123', 'BSC')
eth = derive_monitored_address('user_123', 'ETH')
pol = derive_monitored_address('user_123', 'POL')
php
function deriveMonitoredAddress($customerId, $network) {
    $apiKey = getenv('RACH_API_KEY');
    
    $payload = [
        'network' => $network,
        'index' => 0,
        'monitored' => true  // ← Enable monitoring
    ];
    
    $url = "https://payments-api-dev-966260606560.europe-west2.run.app/api/v1/wallet/customer/{$customerId}/derive";
    
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'X-API-Key: ' . $apiKey,
        'Content-Type: application/json'
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    
    $response = curl_exec($ch);
    curl_close($ch);
    
    return json_decode($response, true);
}

// Enable monitoring
$bscAddr = deriveMonitoredAddress('user_123', 'BSC');

Configure Webhook URL

Set your webhook endpoint to receive deposit notifications:

bash
curl -X PATCH https://payments-api-dev-966260606560.europe-west2.run.app/api/v1/business/settings \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "webhook_url": "https://yourapp.com/webhooks/deposits",
    "webhook_secret": "your_secret_key_here"
  }'

Generate a Strong Secret

bash
# Generate a random webhook secret
openssl rand -hex 32

Save this secret securely - you'll use it to verify webhook signatures.


Webhook Event: wallet.deposit.detected

When a deposit is detected, you'll receive this webhook:

Payload Structure

json
{
  "event": "wallet.deposit.detected",
  "data": {
    "customer_id": "user_123",
    "network": "BSC",
    "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
    "amount": "1.5",
    "currency": "BNB",
    "tx_hash": "pending_detection",
    "confirmations": 0,
    "detected_at": "2025-12-22T12:00:00Z"
  }
}

Field Descriptions

FieldTypeDescription
eventstringAlways "wallet.deposit.detected"
customer_idstringYour customer identifier
networkstringNetwork where deposit occurred
addressstringWallet address that received funds
amountstringAmount receivedas decimal string
currencystringNative token symbol (BNB, ETH, etc.)
tx_hashstringTransaction hash (may be "pending_detection" initially)
confirmationsintegerNumber of confirmations (usually 0 when detected)
detected_attimestampWhen deposit was detected (ISO 8601)

Handle Webhook in Your App

Create an endpoint to receive and process deposit webhooks:

javascript
const express = require('express');
const crypto = require('crypto');

const app = express();
app.use(express.json());

app.post('/webhooks/deposits', async (req, res) => {
  // 1. Verify HMAC signature
  const signature = req.headers['x-webhook-signature'];
  const secret = process.env.WEBHOOK_SECRET;
  
  const hmac = crypto.createHmac('sha256', secret);
  hmac.update(JSON.stringify(req.body));
  const expectedSignature = hmac.digest('hex');
  
  if (signature !== expectedSignature) {
    return res.status(401).send('Invalid signature');
  }
  
  // 2. Extract deposit data
  const { event, data } = req.body;
  
  if (event === 'wallet.deposit.detected') {
    const { customer_id, network, address, amount, currency } = data;
    
    // 3. Update YOUR database
    await db.query(`
      UPDATE user_balances 
      SET ${currency.toLowerCase()}_balance = ${currency.toLowerCase()}_balance + $1,
          updated_at = NOW()
      WHERE customer_id = $2
    `, [parseFloat(amount), customer_id]);
    
    // 4. Create transaction record
    await db.query(`
      INSERT INTO transactions (customer_id, type, network, amount, currency, address, created_at)
      VALUES ($1, 'deposit', $2, $3, $4, $5, NOW())
    `, [customer_id, network, amount, currency, address]);
    
    // 5. Notify user (optional)
    await sendDepositNotification(customer_id, amount, currency);
    
    console.log(`✅ Deposit credited: ${amount} ${currency} for ${customer_id}`);
  }
  
  // 6. Return 200 OK
  res.status(200).send('Webhook processed');
});

function sendDepositNotification(customerId, amount, currency) {
  // Send email/push notification to user
  // "You received ${amount} ${currency}"
}
python
from flask import Flask, request, jsonify
import hmac
import hashlib
import json
import os
from decimal import Decimal

app = Flask(__name__)

@app.route('/webhooks/deposits', methods=['POST'])
def handle_deposit_webhook():
    # 1. Verify signature
    signature = request.headers.get('X-Webhook-Signature')
    secret = os.getenv('WEBHOOK_SECRET')
    payload = request.get_json()
    
    expected_signature = hmac.new(
        secret.encode(),
        json.dumps(payload).encode(),
        hashlib.sha256
    ).hexdigest()
    
    if not hmac.compare_digest(signature, expected_signature):
        return jsonify({'error': 'Invalid signature'}), 401
    
    # 2. Extract data
    event = payload.get('event')
    data = payload.get('data', {})
    
    if event == 'wallet.deposit.detected':
        customer_id = data['customer_id']
        network = data['network']
        address = data['address']
        amount = Decimal(data['amount'])
        currency = data['currency']
        
        # 3. Update YOUR database
        db.execute(f"""
            UPDATE user_balances 
            SET {currency.lower()}_balance = {currency.lower()}_balance + %s,
                updated_at = NOW()
            WHERE customer_id = %s
        """, (amount, customer_id))
        
        # 4. Record transaction
        db.execute("""
            INSERT INTO transactions 
            (customer_id, type, network, amount, currency, address, created_at)
            VALUES (%s, 'deposit', %s, %s, %s, %s, NOW())
        """, (customer_id, network, amount, currency, address))
        
        # 5. Notify user
        send_deposit_notification(customer_id, amount, currency)
        
        print(f"✅ Deposit credited: {amount} {currency} for {customer_id}")
    
    return jsonify({'success': True}), 200

Important: You Manage Balances

Critical Implementation Note

The monitoring service ONLY sends webhooks - it does NOT update any internal balances.

Your Responsibilities:

  • ✅ Store and manage user balances in YOUR database
  • ✅ Update balances when webhook received
  • ✅ Handle double-spending/duplicate webhooks (idempotency)
  • ✅ Maintain transaction history
  • ✅ Display balances to users

Rach's Responsibilities:

  • ✅ Monitor blockchain addresses
  • ✅ Detect balance changes
  • ✅ Send webhook notifications
  • ✅ Retry failed webhooks

Why This Architecture?

This design gives you:

  • 🎯 Full Control - You own the balance logic
  • 🔒 Security - No external service can modify your balances
  • 🔄 Flexibility - Implement custom logic (fees, bonuses, etc.)
  • 📊 Compliance - Your accounting, your audit trail

Example Integration Flow

javascript
// 1. User signup - Create wallet
const wallet = await createWallet('user_123');

// 2. Derive monitored addresses
const addresses = await Promise.all([
  deriveMonitoredAddress('user_123', 'BSC'),
  deriveMonitoredAddress('user_123', 'ETH'),
  deriveMonitoredAddress('user_123', 'POL')
]);

// 3. Save addresses to YOUR database
await db.addresses.insertMany(addresses.map(addr => ({
  user_id: 'user_123',
  network: addr.network,
  address: addr.address,
  monitored: true
})));

// 4. Initialize balances in YOUR database
await db.balances.create({
  user_id: 'user_123',
  bnb_balance: 0,
  eth_balance: 0,
  matic_balance: 0
});

// 5. Display addresses to user
// User sends crypto to any address

// 6. Webhook arrives (within 30 seconds)
// Your webhook handler updates YOUR balance

// 7. User sees updated balance in your app

Testing

1. Enable Test Mode

javascript
// Derive address on testnet
const testAddr = await axios.post(
  `https://payments-api-dev-966260606560.europe-west2.run.app/api/v1/wallet/customer/user_123/derive`,
  {
    network: 'BSC',
    index: 0,
    testnet: true,      // ← Use testnet
    monitored: true
  },
  { headers: { 'X-API-Key': process.env.RACH_TEST_API_KEY } }
);

2. Send Test Deposit

Send testnet tokens to the address:

3. Verify Webhook Delivery

Check your webhook endpoint logs within 30-60 seconds.


Monitoring Status

Check which addresses are being monitored:

bash
curl https://payments-api-dev-966260606560.europe-west2.run.app/api/v1/wallet/customer/user_123/addresses \
  -H "X-API-Key: YOUR_API_KEY"

Response includes monitored flag:

json
{
  "addresses": [
    {
      "network": "BSC",
      "address": "0x...",
      "monitored": true,  // ← Monitoring enabled
      "total_received": "2.5"  // Total deposits received
    }
  ]
}

FAQ

Q: What tokens are monitored?

A: Only native tokens (BNB, ETH, MATIC, TRX, SOL). For ERC-20/BEP-20 tokens like USDT, use our Crypto Gateway product.

Q: How fast are deposits detected?

A: Typically within 30-60 seconds of blockchain confirmation.

Q: Do you update user balances automatically?

A: NO. We only send webhooks. You must update your own database balances.

Q: What if my webhook endpoint is down?

A: We retry up to 5 times with exponential backoff over ~8 minutes.

Q: Can I monitor multiple addresses per user?

A: Yes! Derive multiple addresses with different index values, all with monitored: true.

Q: Is there a fee for monitoring?

A: No additional fees. Monitoring is included with the Wallet Service.

Q: What about transaction confirmations?

A: Initial webhook sent at detection (0 confirmations). You can implement your own confirmation delay logic based on the network.


Best Practices

Production Recommendations

  1. Idempotency - Store detected_at timestamp and ignore duplicate webhooks
  2. Async Processing - Use a queue (Redis, RabbitMQ) to process webhooks
  3. Database Transactions - Use DB transactions when updating balances
  4. Logging - Log all webhooks for audit trail
  5. Alerting - Monitor for failed webhook deliveries
  6. Security - Always verify HMAC signatures
  7. Balance Reconciliation - Periodic on-chain balance checks

Next Steps

Built with ❤️ by Rach Finance