Skip to main content

Cryptofuse Webhook Flow Guide

This guide explains the complete webhook flow for payments and withdrawals, including all possible statuses and transitions.

Payment Webhook Flow​

Payment Status Progression​

graph TD
A[waiting] -->|Payment received| B[confirming]
A -->|Time expired| E[expired]
B -->|Confirmations complete| C[completed]
B -->|Partial & expired| D[partially_completed]
B -->|Payment failed| F[failed]

style C fill:#90EE90
style D fill:#FFE4B5
style E fill:#FFB6C1
style F fill:#FFB6C1

Webhook Events by Status​

1. Payment Created (waiting)​

When: After successful payment creation
Webhook: None (you already have the response)

2. Payment Received (confirming)​

When: Customer sends cryptocurrency to the payment address
Webhook Event: payment_status_update

{
"transaction_id": "550e8400-e29b-41d4-a456-426614174000",
"event": "payment_status_update",
"status": "confirming",
"timestamp": "2024-12-27T10:05:00Z",
"data": {
"transaction_id": "550e8400-e89b-12d3-a456-426614174000",
"status": "confirming",
"amount_usd": "100.00",
"amount_crypto": "100.00000000",
"blockchain": "TRX",
"token": "USDT",
"currency": "USDTTRC20",
"address": "TXYZabc123...",
"transaction_hash": "0xabc123...",
"confirmations": 1,
"payment_history": [
{
"deposit_id": "dep_123",
"amount": "100.00000000",
"transaction_hash": "0xabc123...",
"confirmations": 1,
"timestamp": "2024-12-27T10:05:00Z"
}
],
"total_paid_amount": "100.00000000"
}
}

Key Fields:

  • confirmations: Current number of blockchain confirmations
  • payment_history: Array of all deposits (important for multiple payments)
  • total_paid_amount: Sum of all deposits received

3. Payment Completed (completed)​

When: Required confirmations reached and full amount received
Webhook Event: payment_status_update

{
"transaction_id": "550e8400-e89b-12d3-a456-426614174000",
"event": "payment_status_update",
"status": "completed",
"timestamp": "2024-12-27T10:10:00Z",
"data": {
"transaction_id": "550e8400-e89b-12d3-a456-426614174000",
"status": "completed",
"amount_usd": "100.00",
"amount_crypto": "100.00000000",
"payment_type": "full",
"final_usd_value": 99.50,
"transaction_hash": "0xabc123...",
"confirmations": 20,
"payment_history": [...],
"total_paid_amount": "100.00000000"
}
}

Additional Fields:

  • payment_type: "full", "partial", or "overpayment"
  • final_usd_value: Actual USD value merchant receives after conversion

4. Partial Payment Completed (partially_completed)​

When: Payment expires but received amount is above threshold
Webhook Event: payment_status_update

{
"status": "partially_completed",
"payment_type": "partial",
"total_paid_amount": "50.00000000",
"final_usd_value": 49.50,
"data": {
"metadata": {
"partial_conversion": {
"paid_percentage": 50,
"paid_amount": "50.00000000",
"converted_to": "USDT",
"reason": "Partial payment above threshold"
}
}
}
}

5. Overpayment (completed with overpayment)​

When: Customer sends more than requested amount
Webhook Event: payment_status_update

{
"status": "completed",
"payment_type": "overpayment",
"amount_crypto": "100.00000000",
"total_paid_amount": "150.00000000",
"overpayment_amount": "50.00000000",
"overpayment_usd_value": "49.75",
"amount_limited": true,
"rejected_amount": "30.00000000",
"rejected_usd_value": "29.85"
}

Overpayment Fields:

  • overpayment_amount: Excess amount received
  • amount_limited: true if system capped the accepted amount
  • rejected_amount: Amount over the limit that was not credited

6. Payment Expired​

When: Payment time limit reached without payment
Webhook Event: payment_status_update

{
"transaction_id": "550e8400-e89b-12d3-a456-426614174000",
"event": "payment_status_update",
"status": "expired",
"timestamp": "2024-12-27T10:30:00Z",
"data": {
"status": "expired",
"metadata": {
"expiry_details": {
"reason": "No payment received within time limit",
"expired_at": "2024-12-27T10:30:00Z",
"received_amount": "0"
}
}
}
}

Multiple Deposits Scenario​

Some customers may send multiple transactions to pay:

{
"status": "completed",
"payment_history": [
{
"deposit_id": "dep_123",
"amount": "60.00000000",
"transaction_hash": "0xabc123...",
"confirmations": 20,
"timestamp": "2024-12-27T10:05:00Z"
},
{
"deposit_id": "dep_124",
"amount": "40.00000000",
"transaction_hash": "0xdef456...",
"confirmations": 15,
"timestamp": "2024-12-27T10:08:00Z"
}
],
"total_paid_amount": "100.00000000"
}

Withdrawal Webhook Flow​

Withdrawal Status Progression​

graph TD
A[pending] -->|Processing started| B[processing]
B -->|Blockchain broadcast| C[confirming]
C -->|Confirmations complete| D[completed]
A -->|Validation failed| E[failed]
B -->|Processing failed| E[failed]

style D fill:#90EE90
style E fill:#FFB6C1

Withdrawal Webhook Events​

1. Withdrawal Created (pending)​

When: After successful withdrawal creation
Webhook: None (you already have the response)

2. Processing Started​

When: System begins processing the withdrawal
Webhook Event: withdrawal_status_update

{
"withdrawal_id": "660e8400-e29b-12d3-a456-426614174000",
"event": "withdrawal_status_update",
"status": "processing",
"timestamp": "2024-12-27T11:05:00Z",
"data": {
"withdrawal_id": "660e8400-e29b-12d3-a456-426614174000",
"status": "processing",
"amount": "98.50000000",
"requested_amount": "100.00000000",
"fee": "1.500000",
"blockchain": "TRX",
"token": "USDT",
"currency": "USDTTRC20",
"address": "TXYZabc123..."
}
}

3. Blockchain Broadcast (confirming)​

When: Transaction broadcast to blockchain
Webhook Event: withdrawal_status_update

{
"withdrawal_id": "660e8400-e29b-12d3-a456-426614174000",
"event": "withdrawal_status_update",
"status": "confirming",
"timestamp": "2024-12-27T11:07:00Z",
"data": {
"status": "confirming",
"transaction_hash": "0xdef456...",
"confirmations": 1,
"required_confirmations": 20
}
}

4. Withdrawal Completed​

When: Transaction confirmed on blockchain
Webhook Event: withdrawal_status_update

{
"withdrawal_id": "660e8400-e29b-12d3-a456-426614174000",
"event": "withdrawal_status_update",
"status": "completed",
"timestamp": "2024-12-27T11:10:00Z",
"data": {
"status": "completed",
"transaction_hash": "0xdef456...",
"confirmations": 20,
"completed_at": "2024-12-27T11:10:00Z"
}
}

5. Withdrawal Failed​

When: Any error during processing
Webhook Event: withdrawal_status_update

{
"withdrawal_id": "660e8400-e29b-12d3-a456-426614174000",
"event": "withdrawal_status_update",
"status": "failed",
"timestamp": "2024-12-27T11:06:00Z",
"data": {
"status": "failed",
"error_message": "Insufficient balance in hot wallet",
"processing_notes": "Will retry when wallet is refilled"
}
}

Webhook Best Practices​

1. Webhook Security​

// Verify webhook signature
function verifyWebhook($payload, $signature, $secret) {
$expected = hash_hmac('sha256', $payload, $secret);
return hash_equals($signature, $expected);
}

// In your webhook handler
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'];
if (!verifyWebhook($rawBody, $signature, $webhookSecret)) {
http_response_code(401);
exit();
}

2. Idempotency Handling​

// Track processed webhooks
const processedWebhooks = new Set();

async function handleWebhook(data) {
// Create unique key
const webhookKey = `${data.transaction_id}-${data.status}-${data.timestamp}`;

// Skip if already processed
if (processedWebhooks.has(webhookKey)) {
return { status: 'already_processed' };
}

// Process webhook
await processPaymentUpdate(data);

// Mark as processed
processedWebhooks.add(webhookKey);

// Store in database for persistence
await db.webhookLog.create({
key: webhookKey,
processed_at: new Date()
});
}

3. Status Transition Validation​

# Valid status transitions
VALID_TRANSITIONS = {
'waiting': ['confirming', 'expired'],
'confirming': ['completed', 'partially_completed', 'failed'],
'partially_paid': ['partially_completed', 'expired'],
# Final states cannot transition
'completed': [],
'partially_completed': [],
'failed': [],
'expired': []
}

def validate_status_transition(current_status, new_status):
"""Ensure status transition is valid"""
valid_next = VALID_TRANSITIONS.get(current_status, [])
if new_status not in valid_next:
raise ValueError(f"Invalid transition: {current_status} -> {new_status}")

4. Retry Logic​

// Exponential backoff for failed webhook processing
async function processWebhookWithRetry(data, attempt = 1) {
try {
await processWebhook(data);
} catch (error) {
if (attempt < 5) {
const delay = Math.pow(2, attempt) * 1000; // 2s, 4s, 8s, 16s
await sleep(delay);
return processWebhookWithRetry(data, attempt + 1);
}
throw error;
}
}

5. Webhook Response​

Always respond quickly to webhooks:

from threading import Thread

def webhook_handler(request):
# Verify signature
if not verify_signature(request):
return HttpResponse(status=401)

# Parse payload
data = json.loads(request.body)

# Process async to respond quickly
Thread(target=process_webhook_async, args=(data,)).start()

# Respond immediately
return HttpResponse(status=200)

Common Scenarios​

Scenario 1: Standard Payment Flow​

  1. Customer initiates payment → status: waiting
  2. Customer sends exact amount → webhook: confirming
  3. Confirmations complete → webhook: completed

Scenario 2: Overpayment with Limit​

  1. Overpayment threshold: $500
  2. Customer sends $800 extra
  3. System accepts $500, rejects $300
  4. Webhook shows amount_limited: true, rejected_amount: "300"

Scenario 3: Multiple Partial Payments​

  1. Customer sends 60% → webhook: confirming
  2. Customer sends 40% → webhook: confirming (updated)
  3. Total reaches 100% → webhook: completed

Scenario 4: Withdrawal with Retry​

  1. Create withdrawal → status: pending
  2. Hot wallet empty → webhook: failed
  3. Admin refills wallet
  4. System retries → webhook: processing
  5. Success → webhook: completed

Troubleshooting Webhooks​

Missing Webhooks​

  1. Check callback_url is publicly accessible
  2. Verify webhook configuration in /user/webhooks/
  3. Check firewall/security groups
  4. Look for 4xx/5xx responses in logs

Duplicate Webhooks​

  • Normal behavior for reliability
  • Always implement idempotency
  • Use transaction_id + status as unique key

Out-of-Order Webhooks​

  • Possible due to network delays
  • Always check current status via API
  • Validate status transitions

Debugging Tips​

# Test webhook endpoint
curl -X POST https://your-site.com/webhook \
-H "Content-Type: application/json" \
-H "X-Webhook-Signature: test" \
-d '{"test": true}'

# Use webhook testing service
https://webhook.site

# Monitor webhook logs
tail -f /var/log/webhooks.log

Webhook Data Reference​

Payment Webhook Fields​

  • transaction_id: Unique payment identifier
  • status: Current payment status
  • amount_usd: Original USD amount
  • amount_crypto: Expected crypto amount
  • total_paid_amount: Actual amount received
  • payment_type: full/partial/overpayment
  • final_usd_value: USD value after conversion
  • payment_history: Array of all deposits
  • confirmations: Blockchain confirmations
  • transaction_hash: Blockchain transaction ID

Withdrawal Webhook Fields​

  • withdrawal_id: Unique withdrawal identifier
  • status: Current withdrawal status
  • amount: Amount user receives
  • requested_amount: Original requested amount
  • fee: Total fee in USD
  • transaction_hash: Blockchain transaction ID
  • confirmations: Current confirmations
  • completed_at: Completion timestamp
  • error_message: Error details if failed