Skip to main content

Webhooks

Bridgfy uses webhooks to automatically detect deposits and trigger cross-chain transfers. As an integrator, you don’t need to implement webhooks - Bridgfy handles this automatically. This page explains how the webhook system works for informational purposes.

How It Works

When a user sends funds to their deposit address:
  1. Deposit occurs on the blockchain
  2. Blockchain monitoring service detects the transaction
  3. Webhook is sent to Bridgfy’s API
  4. Bridgfy processes the deposit automatically:
    • Resolves the user’s Deposit Intent
    • Requests routing quote
    • Calculates fees
    • Executes the cross-chain transfer
  5. Execution is created and tracked
As an integrator: You don’t receive webhooks. Instead, you query the Executions API to track transfer status.

Webhook Flow

Webhook Payload

For reference, here’s what a deposit detection webhook looks like:

Alchemy ADDRESS_ACTIVITY Webhook

Endpoint: POST /api/webhooks/alchemy/address-activity Headers:
x-alchemy-signature: <hmac-signature>
Content-Type: application/json
Payload:
{
  "webhookId": "wh_abc123",
  "id": "evt_xyz789",
  "createdAt": "2024-01-01T10:00:00.000Z",
  "type": "ADDRESS_ACTIVITY",
  "event": {
    "network": "BASE_MAINNET",
    "activity": [
      {
        "category": "token",
        "fromAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb8",
        "toAddress": "0x1234567890123456789012345678901234567890",
        "value": 10.0,
        "rawContract": {
          "rawValue": "10000000",
          "decimals": 6,
          "symbol": "USDC",
          "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
        },
        "asset": "USDC",
        "hash": "0xabcdef..."
      }
    ]
  }
}
Key fields:
  • network: Chain where deposit occurred (e.g., “BASE_MAINNET”, “ETH_MAINNET”)
  • activity.toAddress: The deposit address (Modular Account)
  • activity.rawContract.rawValue: Amount in atomic units
  • activity.rawContract.symbol: Token symbol
  • activity.rawContract.address: Token contract address
  • activity.hash: Transaction hash

What Happens After Webhook

When Bridgfy receives a deposit webhook:

1. Validation

  • Verifies webhook signature
  • Checks that the destination address is a known Modular Account
  • Validates the transaction hasn’t been processed before (idempotency)

2. Intent Resolution

  • Looks up the Deposit Intent for the user (based on deposit address)
  • If no intent found, the deposit is held but not routed
  • If intent found, proceeds to routing

3. Routing

  • Queries cross-chain routing providers for the best route
  • Applies routing policies (slippage, max hops, etc.)
  • Verifies the route is viable

4. Fee Calculation

  • Calculates protocol fee from deposit amount
  • Estimates gas fee (if user pays gas)
  • Verifies remaining amount is sufficient

5. Execution

  • Creates an Execution record (status: PENDING)
  • Submits the bridge transaction
  • Updates status to RUNNING
  • Tracks until completion (SUCCESS or FAILED)

Timing

Typical timeline from deposit to execution:
  1. User sends transaction: 0 seconds
  2. Transaction confirmed: 10-60 seconds (varies by chain)
  3. Webhook received: +1-5 seconds after confirmation
  4. Processing & routing: +5-15 seconds
  5. Bridge transaction submitted: +15-30 seconds from deposit
  6. Bridge completion: +1-10 minutes (varies by route)
Total time: Usually 2-15 minutes from deposit to funds arriving at destination.

Monitoring Deposits

As an integrator, you should not monitor for webhooks. Instead:

Poll for Executions

After a user sends funds, poll the Executions API:
async function waitForDeposit(userId, depositTxHash, timeout = 300000) {
  const startTime = Date.now();
  const pollInterval = 10000; // 10 seconds
  
  while (Date.now() - startTime < timeout) {
    const executions = await getExecutions(userId);
    
    // Look for an execution that matches the deposit
    const execution = executions.find(e => 
      e.status !== 'SUCCESS' && // Still processing
      new Date(e.createdAt) > new Date(Date.now() - timeout)
    );
    
    if (execution) {
      return execution;
    }
    
    await new Promise(resolve => setTimeout(resolve, pollInterval));
  }
  
  throw new Error('Deposit not detected within timeout');
}

Show Status to Users

async function trackDeposit(userId) {
  // Initial state
  showStatus('Waiting for deposit confirmation on blockchain...');
  
  // Poll for execution
  const execution = await waitForDeposit(userId);
  
  // Show processing
  showStatus('Deposit detected! Routing your funds...');
  
  // Continue polling for completion
  while (true) {
    const updated = await getExecution(userId, execution.id);
    
    if (updated.status === 'SUCCESS') {
      showStatus('Transfer complete!');
      return updated;
    } else if (isTerminalStatus(updated.status)) {
      showError(`Transfer failed: ${updated.lastErrorMessage}`);
      return updated;
    }
    
    await new Promise(resolve => setTimeout(resolve, 5000));
  }
}

Edge Cases

Deposit Without Intent

If a user sends funds to their deposit address before creating a Deposit Intent:
  • Funds are received by the Modular Account
  • No execution is created (no routing configuration)
  • Funds remain in the account
  • When the user creates an intent later, a manual trigger may be needed
Prevention: Always create Deposit Intent before showing the deposit address.

Multiple Deposits

If a user makes multiple deposits to the same address:
  • Each deposit triggers a separate webhook
  • Each webhook creates a separate Execution
  • All follow the same Deposit Intent configuration
  • Executions are independent and tracked separately

Webhook Failures

If Bridgfy’s webhook endpoint is unavailable:
  • The monitoring service retries automatically
  • Deposits are eventually detected and processed
  • May cause delays in processing (minutes, not hours)
As an integrator: This is transparent to you. Just poll the Executions API.

Duplicate Webhooks

The monitoring service may send the same webhook multiple times:
  • Bridgfy uses idempotency keys to prevent duplicate executions
  • Only one Execution is created per deposit
  • Safe to receive duplicate webhooks

Security

Webhook Validation

Bridgfy validates all incoming webhooks:
  1. Signature verification: HMAC-SHA256 signature check
  2. Timestamp validation: Reject old webhooks (>5 min)
  3. Address verification: Confirm destination is a Modular Account
  4. Idempotency: Check for duplicate transaction hashes
As an integrator: You don’t implement this - Bridgfy handles all validation.

What You Should Do

For security on your end:
  1. Use HTTPS for all API calls
  2. Keep API keys secure (environment variables, secrets managers)
  3. Validate user inputs before creating Deposit Intents
  4. Poll, don’t push - Use the Executions API to check status

Debugging Deposits

If a user reports their deposit wasn’t processed:

Check Transaction Confirmed

Verify the deposit transaction is confirmed on-chain:
// Use a blockchain explorer or RPC
const tx = await provider.getTransaction(txHash);
const receipt = await provider.getTransactionReceipt(txHash);

if (!receipt) {
  console.log('Transaction not confirmed yet');
} else if (receipt.status === 0) {
  console.log('Transaction failed on-chain');
} else {
  console.log('Transaction confirmed');
}

Check Deposit Address

Verify they sent to the correct address:
const intent = await getDepositIntent(userId);
const expectedAddress = intent.depositAddress;

if (receipt.to.toLowerCase() !== expectedAddress.toLowerCase()) {
  console.log('Funds sent to wrong address!');
}

Check for Execution

Look for an execution created after the deposit:
const executions = await getExecutions(userId);
const depositTime = new Date(receipt.timestamp * 1000);

const matchingExecution = executions.find(e => 
  new Date(e.createdAt) >= depositTime
);

if (!matchingExecution) {
  console.log('No execution found - webhook may not have processed');
  // Contact support
}

Check Execution Status

If execution exists but failed:
if (matchingExecution.status === 'FAILED_INSUFFICIENT_AFTER_FEES') {
  console.log('Deposit too small to cover fees');
} else if (matchingExecution.status === 'FAILED_UNROUTABLE_MAIN') {
  console.log('Token pair not supported');
} else if (matchingExecution.status === 'TOKEN_BLACKLISTED') {
  console.log('Token is blacklisted');
}

Best Practices

For Integrators

  1. Don’t implement webhooks - Bridgfy handles deposit detection
  2. Poll the Executions API - Check for new executions after users deposit
  3. Create intent before showing address - Ensure routing is configured
  4. Use simulation first - Verify routes work before users deposit
  5. Show clear instructions - Tell users exactly where to send funds
  6. Track execution status - Poll until terminal status reached
  7. Handle all error cases - Build UI for every execution status

For Users

Provide clear instructions:
1. Copy your deposit address: 0x1234...
2. Send [token] on [chain] to this address
3. Wait for confirmation on the blockchain
4. Your funds will be automatically routed to your destination
5. Track progress in the app
Important notes to users:
  • Funds are automatically routed (no additional steps needed)
  • Routing happens after blockchain confirmation
  • Total time: typically 2-15 minutes
  • Check execution status in the app

Next Steps