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 confirmationspayment_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 receivedamount_limited: true if system capped the accepted amountrejected_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
- Customer initiates payment → status:
waiting - Customer sends exact amount → webhook:
confirming - Confirmations complete → webhook:
completed
Scenario 2: Overpayment with Limit
- Overpayment threshold: $500
- Customer sends $800 extra
- System accepts $500, rejects $300
- Webhook shows
amount_limited: true,rejected_amount: "300"
Scenario 3: Multiple Partial Payments
- Customer sends 60% → webhook:
confirming - Customer sends 40% → webhook:
confirming(updated) - Total reaches 100% → webhook:
completed
Scenario 4: Withdrawal with Retry
- Create withdrawal → status:
pending - Hot wallet empty → webhook:
failed - Admin refills wallet
- System retries → webhook:
processing - Success → webhook:
completed
Troubleshooting Webhooks
Missing Webhooks
- Check callback_url is publicly accessible
- Verify webhook configuration in
/user/webhooks/ - Check firewall/security groups
- 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 identifierstatus: Current payment statusamount_usd: Original USD amountamount_crypto: Expected crypto amounttotal_paid_amount: Actual amount receivedpayment_type: full/partial/overpaymentfinal_usd_value: USD value after conversionpayment_history: Array of all depositsconfirmations: Blockchain confirmationstransaction_hash: Blockchain transaction ID
Withdrawal Webhook Fields
withdrawal_id: Unique withdrawal identifierstatus: Current withdrawal statusamount: Amount user receivesrequested_amount: Original requested amountfee: Total fee in USDtransaction_hash: Blockchain transaction IDconfirmations: Current confirmationscompleted_at: Completion timestamperror_message: Error details if failed