integration-guides
Index

Integration Guides

Comprehensive step-by-step guides for integrating Fiatsend into your applications for different use cases and scenarios.


Quick Navigation

🏪 Merchant Integration

Accept crypto payments and receive fiat settlements

Scroll down to view →

👥 P2P Transfer App

Build a peer-to-peer money transfer application

Scroll down to view →

📱 Mobile Money Integration

Integrate with African mobile money providers

Scroll down to view →

🔄 Onramp/Offramp Service

Build fiat-to-crypto conversion services

Scroll down to view →

🔐 Identity Management

Implement NFT-based identity verification

Scroll down to view →

🌐 Webhook Integration

Set up real-time event notifications

Scroll down to view →


Merchant Integration

Learn how to integrate Fiatsend into your e-commerce or business application to accept crypto payments.

Step 1: Setup and Configuration

import { FiatsendSDK } from "@fiatsend/sdk";
 
const sdk = new FiatsendSDK({
  apiKey: process.env.FIATSEND_API_KEY,
  environment: "production"
});

Step 2: Create Payment Request

// Create a payment request for an order
const paymentRequest = await sdk.payment.generateRequestAddress({
  amount: 100,
  currency: "USDT",
  description: "Order #12345 - T-Shirt",
  merchantId: "merchant_123",
  orderId: "order_12345",
  callbackUrl: "https://your-store.com/webhook/payment",
  successUrl: "https://your-store.com/order/success",
  cancelUrl: "https://your-store.com/order/cancel"
});
 
console.log("Payment Address:", paymentRequest.address);
console.log("QR Code:", paymentRequest.qrCode);

Step 3: Display Payment Options

import React, { useState, useEffect } from 'react';
 
function PaymentComponent({ orderId, amount, currency }) {
  const [paymentRequest, setPaymentRequest] = useState(null);
  const [paymentStatus, setPaymentStatus] = useState('pending');
 
  useEffect(() => {
    // Create payment request when component mounts
    const createPaymentRequest = async () => {
      const request = await sdk.payment.generateRequestAddress({
        amount,
        currency,
        description: `Order #${orderId}`,
        merchantId: process.env.MERCHANT_ID,
        orderId,
        callbackUrl: `${window.location.origin}/webhook/payment`
      });
      setPaymentRequest(request);
    };
 
    createPaymentRequest();
  }, [orderId, amount, currency]);
 
  return (
    <div className="payment-container">
      <h3>Complete Your Payment</h3>
      <p>Amount: {amount} {currency}</p>
      
      {paymentRequest && (
        <div>
          <p>Send payment to:</p>
          <code>{paymentRequest.address}</code>
          
          <div className="qr-code">
            <img src={paymentRequest.qrCode} alt="Payment QR Code" />
          </div>
          
          <p>Status: {paymentStatus}</p>
        </div>
      )}
    </div>
  );
}

Step 4: Handle Payment Webhooks

// Express.js webhook handler
app.post('/webhook/payment', async (req, res) => {
  try {
    const result = await sdk.payment.handlePaymentWebhook(req.body);
    
    if (result.status === 'completed') {
      // Update order status in your database
      await updateOrderStatus(result.orderId, 'paid');
      
      // Send confirmation email
      await sendOrderConfirmation(result.orderId);
      
      console.log('Payment completed:', result.transactionId);
    }
    
    res.json({ success: true });
  } catch (error) {
    console.error('Webhook error:', error);
    res.status(400).json({ error: error.message });
  }
});

Step 5: Check Payment Status

// Check payment status for an order
const checkPaymentStatus = async (orderId) => {
  const status = await sdk.payment.getPaymentStatus(orderId);
  
  switch (status.status) {
    case 'completed':
      // Payment successful
      break;
    case 'pending':
      // Payment still processing
      break;
    case 'failed':
      // Payment failed
      break;
  }
  
  return status;
};

P2P Transfer App

Build a peer-to-peer money transfer application using mobile numbers.

Step 1: Setup React Application

import React, { useState } from 'react';
import { FiatsendSDK } from "@fiatsend/sdk";
 
const sdk = new FiatsendSDK({
  apiKey: process.env.REACT_APP_FIATSEND_API_KEY,
  environment: "production"
});
 
function TransferApp() {
  const [recipient, setRecipient] = useState('');
  const [amount, setAmount] = useState('');
  const [currency, setCurrency] = useState('USDT');
  const [loading, setLoading] = useState(false);
 
  const handleTransfer = async (e) => {
    e.preventDefault();
    setLoading(true);
 
    try {
      const transfer = await sdk.payment.initiatePayment({
        amount: parseFloat(amount),
        currency,
        recipient,
        description: `P2P Transfer to ${recipient}`,
        country: 'GH'
      });
 
      console.log('Transfer initiated:', transfer.transactionId);
      // Show success message
    } catch (error) {
      console.error('Transfer failed:', error);
      // Show error message
    } finally {
      setLoading(false);
    }
  };
 
  return (
    <form onSubmit={handleTransfer}>
      <div>
        <label>Recipient Mobile Number:</label>
        <input
          type="tel"
          value={recipient}
          onChange={(e) => setRecipient(e.target.value)}
          placeholder="+233551234567"
          required
        />
      </div>
      
      <div>
        <label>Amount:</label>
        <input
          type="number"
          value={amount}
          onChange={(e) => setAmount(e.target.value)}
          placeholder="100"
          required
        />
      </div>
      
      <div>
        <label>Currency:</label>
        <select value={currency} onChange={(e) => setCurrency(e.target.value)}>
          <option value="USDT">USDT</option>
          <option value="USDC">USDC</option>
          <option value="GHSFIAT">GHSFIAT</option>
        </select>
      </div>
      
      <button type="submit" disabled={loading}>
        {loading ? 'Sending...' : 'Send Money'}
      </button>
    </form>
  );
}

Step 2: Add Contact Management

import React, { useState, useEffect } from 'react';
 
function ContactManager() {
  const [contacts, setContacts] = useState([]);
  const [newContact, setNewContact] = useState({ name: '', phone: '' });
 
  const addContact = async () => {
    // Check if phone number exists in Fiatsend
    const exists = await sdk.identity.checkNumberExists(newContact.phone);
    
    if (exists.exists) {
      setContacts([...contacts, newContact]);
      setNewContact({ name: '', phone: '' });
    } else {
      alert('Phone number not found in Fiatsend network');
    }
  };
 
  return (
    <div>
      <h3>My Contacts</h3>
      
      <div>
        <input
          type="text"
          placeholder="Contact Name"
          value={newContact.name}
          onChange={(e) => setNewContact({...newContact, name: e.target.value})}
        />
        <input
          type="tel"
          placeholder="Phone Number"
          value={newContact.phone}
          onChange={(e) => setNewContact({...newContact, phone: e.target.value})}
        />
        <button onClick={addContact}>Add Contact</button>
      </div>
      
      <ul>
        {contacts.map((contact, index) => (
          <li key={index}>
            {contact.name} - {contact.phone}
          </li>
        ))}
      </ul>
    </div>
  );
}

Step 3: Transaction History

import React, { useState, useEffect } from 'react';
 
function TransactionHistory({ walletAddress }) {
  const [transactions, setTransactions] = useState([]);
  const [loading, setLoading] = useState(true);
 
  useEffect(() => {
    const fetchTransactions = async () => {
      try {
        const result = await sdk.wallet.getTransactions({
          walletAddress,
          page: 1,
          limit: 50
        });
        setTransactions(result.data);
      } catch (error) {
        console.error('Failed to fetch transactions:', error);
      } finally {
        setLoading(false);
      }
    };
 
    fetchTransactions();
  }, [walletAddress]);
 
  if (loading) return <div>Loading transactions...</div>;
 
  return (
    <div>
      <h3>Transaction History</h3>
      <ul>
        {transactions.map((tx) => (
          <li key={tx.id}>
            <div>
              <strong>{tx.type}</strong> - {tx.amount} {tx.currency}
            </div>
            <div>Status: {tx.status}</div>
            <div>Date: {new Date(tx.createdAt).toLocaleDateString()}</div>
          </li>
        ))}
      </ul>
    </div>
  );
}

Mobile Money Integration

Integrate with African mobile money providers for seamless fiat transactions.

Step 1: MTN Mobile Money Integration

// MTN Mobile Money payment
const mtnPayment = await sdk.payment.createMTNPayment({
  amount: 100,
  phoneNumber: "0551234567",
  externalRef: "PAY-12345",
  wallet: "0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6",
  description: "Payment for services"
});
 
console.log("MTN Payment ID:", mtnPayment.paymentId);
console.log("Status:", mtnPayment.status);

Step 2: AirtelTigo Money Integration

// AirtelTigo Money payment
const airtelPayment = await sdk.payment.createAirtelTigoPayment({
  amount: 50,
  phoneNumber: "0241234567",
  externalRef: "PAY-12346",
  wallet: "0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6",
  description: "Payment for services"
});
 
console.log("AirtelTigo Payment ID:", airtelPayment.paymentId);

Step 3: Telecel Cash Integration

// Telecel Cash payment
const telecelPayment = await sdk.payment.createTelecelPayment({
  amount: 75,
  phoneNumber: "0271234567",
  externalRef: "PAY-12347",
  wallet: "0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6",
  description: "Payment for services"
});
 
console.log("Telecel Payment ID:", telecelPayment.paymentId);

Step 4: Universal Mobile Money Component

import React, { useState } from 'react';
 
function MobileMoneyPayment({ amount, currency, onSuccess, onError }) {
  const [provider, setProvider] = useState('mtn');
  const [phoneNumber, setPhoneNumber] = useState('');
  const [loading, setLoading] = useState(false);
 
  const handlePayment = async () => {
    setLoading(true);
 
    try {
      let payment;
      
      switch (provider) {
        case 'mtn':
          payment = await sdk.payment.createMTNPayment({
            amount,
            phoneNumber,
            externalRef: `PAY-${Date.now()}`,
            wallet: userWalletAddress,
            description: `Payment of ${amount} ${currency}`
          });
          break;
          
        case 'airtel':
          payment = await sdk.payment.createAirtelTigoPayment({
            amount,
            phoneNumber,
            externalRef: `PAY-${Date.now()}`,
            wallet: userWalletAddress,
            description: `Payment of ${amount} ${currency}`
          });
          break;
          
        case 'telecel':
          payment = await sdk.payment.createTelecelPayment({
            amount,
            phoneNumber,
            externalRef: `PAY-${Date.now()}`,
            wallet: userWalletAddress,
            description: `Payment of ${amount} ${currency}`
          });
          break;
      }
 
      onSuccess(payment);
    } catch (error) {
      onError(error);
    } finally {
      setLoading(false);
    }
  };
 
  return (
    <div>
      <h3>Mobile Money Payment</h3>
      
      <div>
        <label>Provider:</label>
        <select value={provider} onChange={(e) => setProvider(e.target.value)}>
          <option value="mtn">MTN Mobile Money</option>
          <option value="airtel">AirtelTigo Money</option>
          <option value="telecel">Telecel Cash</option>
        </select>
      </div>
      
      <div>
        <label>Phone Number:</label>
        <input
          type="tel"
          value={phoneNumber}
          onChange={(e) => setPhoneNumber(e.target.value)}
          placeholder="0551234567"
        />
      </div>
      
      <div>
        <label>Amount:</label>
        <span>{amount} {currency}</span>
      </div>
      
      <button onClick={handlePayment} disabled={loading}>
        {loading ? 'Processing...' : 'Pay with Mobile Money'}
      </button>
    </div>
  );
}

Onramp/Offramp Service

Build a service for converting between fiat and crypto currencies.

Step 1: Onramp Service (Fiat to Crypto)

// Create onramp service
class OnrampService {
  constructor(sdk) {
    this.sdk = sdk;
  }
 
  async createOnrampRequest(amount, currency, userWallet) {
    // Generate unique request ID
    const requestId = `ONRAMP-${Date.now()}`;
    
    // Create payment request
    const paymentRequest = await this.sdk.payment.generateRequestAddress({
      amount,
      currency: 'USDT', // Convert to USDT
      description: `Onramp request for ${amount} ${currency}`,
      merchantId: 'onramp_service',
      orderId: requestId,
      callbackUrl: `${process.env.BASE_URL}/webhook/onramp`
    });
 
    return {
      requestId,
      paymentAddress: paymentRequest.address,
      qrCode: paymentRequest.qrCode,
      amount,
      currency: 'USDT',
      instructions: `Send ${amount} ${currency} to the provided address to receive USDT`
    };
  }
 
  async processOnramp(requestId, transactionHash) {
    // Verify transaction on blockchain
    const transaction = await this.sdk.core.getTransaction(transactionHash);
    
    if (transaction && transaction.status === 'confirmed') {
      // Transfer USDT to user's wallet
      const transfer = await this.sdk.wallet.transferTokens({
        to: userWallet,
        amount: transaction.amount,
        currency: 'USDT',
        description: `Onramp completion for request ${requestId}`
      });
 
      return {
        success: true,
        transferId: transfer.transactionId,
        amount: transaction.amount,
        currency: 'USDT'
      };
    }
 
    return { success: false, error: 'Transaction not confirmed' };
  }
}

Step 2: Offramp Service (Crypto to Fiat)

// Create offramp service
class OfframpService {
  constructor(sdk) {
    this.sdk = sdk;
  }
 
  async createOfframpRequest(amount, currency, recipientPhone, provider) {
    const requestId = `OFFRAMP-${Date.now()}`;
    
    // Check user balance
    const balance = await this.sdk.wallet.getBalance(userWallet);
    if (balance.balances[currency] < amount) {
      throw new Error('Insufficient balance');
    }
 
    // Create mobile money payment
    let payment;
    switch (provider) {
      case 'mtn':
        payment = await this.sdk.payment.createMTNPayment({
          amount,
          phoneNumber: recipientPhone,
          externalRef: requestId,
          wallet: userWallet,
          description: `Offramp request ${requestId}`
        });
        break;
      case 'airtel':
        payment = await this.sdk.payment.createAirtelTigoPayment({
          amount,
          phoneNumber: recipientPhone,
          externalRef: requestId,
          wallet: userWallet,
          description: `Offramp request ${requestId}`
        });
        break;
    }
 
    return {
      requestId,
      paymentId: payment.paymentId,
      status: payment.status,
      amount,
      currency,
      recipientPhone,
      provider
    };
  }
 
  async checkOfframpStatus(requestId) {
    const status = await this.sdk.payment.getPaymentStatus(requestId);
    return status;
  }
}

Step 3: Onramp/Offramp UI Component

import React, { useState } from 'react';
 
function OnrampOfframpService() {
  const [mode, setMode] = useState('onramp'); // 'onramp' or 'offramp'
  const [amount, setAmount] = useState('');
  const [currency, setCurrency] = useState('GHS');
  const [phoneNumber, setPhoneNumber] = useState('');
  const [provider, setProvider] = useState('mtn');
  const [loading, setLoading] = useState(false);
  const [result, setResult] = useState(null);
 
  const handleOnramp = async () => {
    setLoading(true);
    try {
      const onrampService = new OnrampService(sdk);
      const request = await onrampService.createOnrampRequest(
        parseFloat(amount),
        currency,
        userWallet
      );
      setResult(request);
    } catch (error) {
      console.error('Onramp failed:', error);
    } finally {
      setLoading(false);
    }
  };
 
  const handleOfframp = async () => {
    setLoading(true);
    try {
      const offrampService = new OfframpService(sdk);
      const request = await offrampService.createOfframpRequest(
        parseFloat(amount),
        'USDT',
        phoneNumber,
        provider
      );
      setResult(request);
    } catch (error) {
      console.error('Offramp failed:', error);
    } finally {
      setLoading(false);
    }
  };
 
  return (
    <div>
      <div>
        <button 
          onClick={() => setMode('onramp')}
          className={mode === 'onramp' ? 'active' : ''}
        >
          Onramp (Fiat → Crypto)
        </button>
        <button 
          onClick={() => setMode('offramp')}
          className={mode === 'offramp' ? 'active' : ''}
        >
          Offramp (Crypto → Fiat)
        </button>
      </div>
 
      {mode === 'onramp' ? (
        <div>
          <h3>Convert Fiat to Crypto</h3>
          <div>
            <label>Amount:</label>
            <input
              type="number"
              value={amount}
              onChange={(e) => setAmount(e.target.value)}
            />
          </div>
          <div>
            <label>Currency:</label>
            <select value={currency} onChange={(e) => setCurrency(e.target.value)}>
              <option value="GHS">GHS</option>
              <option value="USD">USD</option>
            </select>
          </div>
          <button onClick={handleOnramp} disabled={loading}>
            {loading ? 'Processing...' : 'Create Onramp Request'}
          </button>
        </div>
      ) : (
        <div>
          <h3>Convert Crypto to Fiat</h3>
          <div>
            <label>Amount (USDT):</label>
            <input
              type="number"
              value={amount}
              onChange={(e) => setAmount(e.target.value)}
            />
          </div>
          <div>
            <label>Recipient Phone:</label>
            <input
              type="tel"
              value={phoneNumber}
              onChange={(e) => setPhoneNumber(e.target.value)}
              placeholder="0551234567"
            />
          </div>
          <div>
            <label>Provider:</label>
            <select value={provider} onChange={(e) => setProvider(e.target.value)}>
              <option value="mtn">MTN Mobile Money</option>
              <option value="airtel">AirtelTigo Money</option>
            </select>
          </div>
          <button onClick={handleOfframp} disabled={loading}>
            {loading ? 'Processing...' : 'Create Offramp Request'}
          </button>
        </div>
      )}
 
      {result && (
        <div>
          <h4>Result:</h4>
          <pre>{JSON.stringify(result, null, 2)}</pre>
        </div>
      )}
    </div>
  );
}

Identity Management

Implement NFT-based identity verification and management.

Step 1: Identity Verification Component

import React, { useState, useEffect } from 'react';
 
function IdentityVerification({ walletAddress }) {
  const [hasIdentity, setHasIdentity] = useState(false);
  const [phoneNumber, setPhoneNumber] = useState('');
  const [verificationStatus, setVerificationStatus] = useState('unverified');
  const [loading, setLoading] = useState(false);
 
  useEffect(() => {
    checkIdentityStatus();
  }, [walletAddress]);
 
  const checkIdentityStatus = async () => {
    try {
      const hasAccount = await sdk.core.hasAccount(walletAddress);
      setHasIdentity(hasAccount);
      
      if (hasAccount) {
        const mobile = await sdk.resolver.resolveMobile(walletAddress);
        setPhoneNumber(mobile.phoneNumber);
        setVerificationStatus('verified');
      }
    } catch (error) {
      console.error('Failed to check identity status:', error);
    }
  };
 
  const mintIdentity = async () => {
    setLoading(true);
    try {
      const identity = await sdk.identity.mintIdentity({
        phoneNumber,
        countryCode: 'GH',
        metadata: 'User identity verification',
        walletAddress
      });
 
      console.log('Identity minted:', identity.tokenId);
      setHasIdentity(true);
      setVerificationStatus('verified');
    } catch (error) {
      console.error('Failed to mint identity:', error);
    } finally {
      setLoading(false);
    }
  };
 
  const createKycSession = async () => {
    try {
      const session = await sdk.identity.createVeriffSession(walletAddress);
      // Redirect to Veriff verification
      window.open(session.verificationUrl, '_blank');
    } catch (error) {
      console.error('Failed to create KYC session:', error);
    }
  };
 
  return (
    <div>
      <h3>Identity Verification</h3>
      
      {!hasIdentity ? (
        <div>
          <p>You need to create an identity NFT to use Fiatsend services.</p>
          <div>
            <label>Phone Number:</label>
            <input
              type="tel"
              value={phoneNumber}
              onChange={(e) => setPhoneNumber(e.target.value)}
              placeholder="+233551234567"
            />
          </div>
          <button onClick={mintIdentity} disabled={loading}>
            {loading ? 'Creating Identity...' : 'Create Identity NFT'}
          </button>
        </div>
      ) : (
        <div>
          <p>✅ Identity verified</p>
          <p>Phone: {phoneNumber}</p>
          <p>Status: {verificationStatus}</p>
          
          {verificationStatus === 'unverified' && (
            <button onClick={createKycSession}>
              Complete KYC Verification
            </button>
          )}
        </div>
      )}
    </div>
  );
}

Step 2: Phone Number Resolution

import React, { useState } from 'react';
 
function PhoneResolver() {
  const [phoneNumber, setPhoneNumber] = useState('');
  const [resolution, setResolution] = useState(null);
  const [loading, setLoading] = useState(false);
 
  const resolvePhone = async () => {
    setLoading(true);
    try {
      const result = await sdk.identity.resolvePhoneToAddress(phoneNumber);
      setResolution(result);
    } catch (error) {
      console.error('Failed to resolve phone number:', error);
    } finally {
      setLoading(false);
    }
  };
 
  return (
    <div>
      <h3>Phone Number Resolution</h3>
      
      <div>
        <label>Phone Number:</label>
        <input
          type="tel"
          value={phoneNumber}
          onChange={(e) => setPhoneNumber(e.target.value)}
          placeholder="+233551234567"
        />
        <button onClick={resolvePhone} disabled={loading}>
          {loading ? 'Resolving...' : 'Resolve'}
        </button>
      </div>
 
      {resolution && (
        <div>
          <h4>Resolution Result:</h4>
          <p>Wallet Address: {resolution.wallet}</p>
          <p>Has Identity: {resolution.hasIdentity ? 'Yes' : 'No'}</p>
          {resolution.hasIdentity && (
            <p>Token ID: {resolution.tokenId}</p>
          )}
        </div>
      )}
    </div>
  );
}

Webhook Integration

Set up real-time event notifications for your application.

Step 1: Webhook Server Setup

const express = require('express');
const crypto = require('crypto');
const app = express();
 
app.use(express.json());
 
// Webhook verification middleware
const verifyWebhook = (req, res, next) => {
  const signature = req.headers['x-fiatsend-signature'];
  const payload = JSON.stringify(req.body);
  const secret = process.env.WEBHOOK_SECRET;
  
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  
  if (signature !== expectedSignature) {
    return res.status(401).send('Unauthorized');
  }
  
  next();
};
 
// Payment webhook
app.post('/webhook/payment', verifyWebhook, async (req, res) => {
  const { event, data } = req.body;
  
  switch (event) {
    case 'payment.completed':
      await handlePaymentCompleted(data);
      break;
    case 'payment.failed':
      await handlePaymentFailed(data);
      break;
    default:
      console.log('Unknown event:', event);
  }
  
  res.json({ success: true });
});
 
// Withdrawal webhook
app.post('/webhook/withdrawal', verifyWebhook, async (req, res) => {
  const { event, data } = req.body;
  
  switch (event) {
    case 'withdrawal.completed':
      await handleWithdrawalCompleted(data);
      break;
    case 'withdrawal.failed':
      await handleWithdrawalFailed(data);
      break;
  }
  
  res.json({ success: true });
});
 
// Identity webhook
app.post('/webhook/identity', verifyWebhook, async (req, res) => {
  const { event, data } = req.body;
  
  if (event === 'identity.verified') {
    await handleIdentityVerified(data);
  }
  
  res.json({ success: true });
});
 
// Event handlers
async function handlePaymentCompleted(data) {
  console.log('Payment completed:', data.transactionId);
  
  // Update order status in database
  await updateOrderStatus(data.orderId, 'paid');
  
  // Send confirmation email
  await sendOrderConfirmation(data.orderId);
  
  // Update inventory
  await updateInventory(data.orderId);
}
 
async function handlePaymentFailed(data) {
  console.log('Payment failed:', data.transactionId);
  
  // Update order status
  await updateOrderStatus(data.orderId, 'failed');
  
  // Send failure notification
  await sendPaymentFailureNotification(data.orderId);
}
 
async function handleWithdrawalCompleted(data) {
  console.log('Withdrawal completed:', data.withdrawalId);
  
  // Update user balance
  await updateUserBalance(data.userId, data.amount);
  
  // Send confirmation
  await sendWithdrawalConfirmation(data.userId);
}
 
async function handleIdentityVerified(data) {
  console.log('Identity verified:', data.walletAddress);
  
  // Update user verification status
  await updateUserVerificationStatus(data.walletAddress, 'verified');
  
  // Send verification confirmation
  await sendVerificationConfirmation(data.walletAddress);
}
 
app.listen(3000, () => {
  console.log('Webhook server running on port 3000');
});

Step 2: Webhook Configuration

// Configure webhooks for your application
const webhookConfig = {
  payment: {
    url: 'https://your-app.com/webhook/payment',
    events: ['payment.completed', 'payment.failed']
  },
  withdrawal: {
    url: 'https://your-app.com/webhook/withdrawal',
    events: ['withdrawal.completed', 'withdrawal.failed']
  },
  identity: {
    url: 'https://your-app.com/webhook/identity',
    events: ['identity.verified']
  }
};
 
// Register webhooks
const registerWebhooks = async () => {
  for (const [type, config] of Object.entries(webhookConfig)) {
    await sdk.webhooks.create({
      type,
      url: config.url,
      events: config.events,
      secret: process.env.WEBHOOK_SECRET
    });
  }
};

Step 3: Webhook Testing

// Test webhook locally using ngrok
const ngrok = require('ngrok');
 
async function testWebhooks() {
  // Start ngrok tunnel
  const url = await ngrok.connect(3000);
  console.log('Webhook URL:', url);
  
  // Update webhook URLs
  await sdk.webhooks.update('payment', {
    url: `${url}/webhook/payment`
  });
  
  // Test webhook
  await sdk.webhooks.test('payment', {
    event: 'payment.completed',
    data: {
      transactionId: 'test-123',
      orderId: 'order-123',
      amount: 100,
      currency: 'USDT'
    }
  });
}

Best Practices

Security

  1. API Key Management

    • Store API keys securely using environment variables
    • Rotate keys regularly
    • Use different keys for different environments
  2. Webhook Security

    • Always verify webhook signatures
    • Use HTTPS for webhook endpoints
    • Implement rate limiting
  3. Error Handling

    • Implement comprehensive error handling
    • Log errors for debugging
    • Provide user-friendly error messages

Performance

  1. Caching

    • Cache frequently accessed data
    • Use Redis for session storage
    • Implement proper cache invalidation
  2. Rate Limiting

    • Implement client-side rate limiting
    • Handle rate limit responses gracefully
    • Use exponential backoff for retries
  3. Monitoring

    • Monitor API response times
    • Set up alerts for failures
    • Track key metrics

User Experience

  1. Loading States

    • Show loading indicators during API calls
    • Provide progress feedback for long operations
    • Handle network timeouts gracefully
  2. Error Messages

    • Provide clear, actionable error messages
    • Suggest solutions for common errors
    • Implement retry mechanisms
  3. Offline Support

    • Cache critical data locally
    • Queue operations when offline
    • Sync when connection is restored

Need Help?