Dieser Inhalt ist noch nicht in deiner Sprache verfügbar.
CoinsSend uses webhooks to notify your application about events that happen in your merchant account. Webhooks are HTTP callbacks that receive notification payloads when events occur.
Setting Up Webhooks
Section titled “Setting Up Webhooks”You can set up a webhook URL in your merchant settings. This URL will receive POST requests when specific events occur.
Authentication
Section titled “Authentication”For security, all webhook requests include an HMAC signature in the X-Signature header. You should validate this signature to ensure the webhook was sent by CoinsSend.
The signature is generated using HMAC-SHA256, with your API key as the secret:
// PHP example for validating a webhook signaturefunction isValidSignature($payload, $signature, $secretKey) { $computedSignature = hash_hmac('sha256', $payload, $secretKey); return hash_equals($computedSignature, $signature);}
// Usage$payload = file_get_contents('php://input');$signature = $_SERVER['HTTP_X_SIGNATURE'];$secretKey = 'your_api_key';
if (!isValidSignature($payload, $signature, $secretKey)) { http_response_code(401); echo json_encode(['error' => 'Invalid signature']); exit;}Important: calculate the HMAC from the exact raw request body bytes that were received. Do not decode the JSON and re-encode it before verification, because key order, spacing, and escaping may change the payload and produce a different signature.
This raw-body rule is specific to receiving webhooks. Merchant API request signing uses the separate canonical-JSON contract in Authentication.
AI assistant prompt: Implement a CoinsSend webhook receiver that preserves the raw request body before JSON parsing. Read
X-Signature, verify it with HMAC-SHA256 and the merchant API key, then parse the payload only after the signature passes. Add idempotent processing for duplicate deliveries and persist outcomes forinvoice.paid,invoice.expired, andaml.rejected.invoice. Use AI Integration Prompts for the full webhook receiver prompt.
Webhook Events
Section titled “Webhook Events”The externally emitted event values are:
invoice.paidinvoice.expiredwallet.transactionaml.rejected.invoiceaml.rejected.static_walletwithdrawal.in_progresswithdrawal.successwithdrawal.failedtest
Use only the public event values listed above when routing webhook payloads.
Fee Payer Information
Section titled “Fee Payer Information”For invoice webhooks (invoice.paid and invoice.expired), the fee_payer object indicates who pays each fee:
merchant_fee:trueif customer pays,falseif merchant paysnetwork_fee:trueif customer pays,falseif merchant pays
For withdrawal webhooks the boolean direction is different: true means the
merchant pays that withdrawal fee. Treat invoice and withdrawal payloads as
event-discriminated schemas rather than sharing one ambiguous fee_payer type.
invoice.paid
Section titled “invoice.paid”Sent when an invoice is paid.
{ "event": "invoice.paid", "timestamp": 1746984000, "data": { "invoice_id": "12345678-1234-1234-1234-123456789012", "order_id": "order_12345", "code": "invoice_code", "status": "paid", "amounts": { "requested": { "amount": "100.50", "currency": "usd", "crypto": "100.5" }, "paid": { "amount": "100.50", "currency": "usd", "crypto": "100.5" } }, "fees": { "merchant": { "amount": "2.0100", "currency": "usd", "crypto": "2.0100" }, "network": { "amount": "1.4000", "currency": "usd", "crypto": "1.4000" }, "total": { "amount": "3.4100", "currency": "usd", "crypto": "3.4100" } }, "payment": { "coin": "usdt", "network": "tron", "address": "TXHXiQ2aXYqtz3y9gEGiVjzxXxXechdLwE", "rate": "1.0001" }, "fee_payer": { "merchant_fee": true, "network_fee": true }, "created_at": "2025-01-01T11:30:00Z", "paid_at": "2025-01-01T12:00:00Z" }}invoice.expired
Section titled “invoice.expired”Sent when an invoice expires without being paid (after 24 hours).
payment field is optional and will only be present if a payment method was selected before the invoice expired.
{ "event": "invoice.expired", "timestamp": 1746984000, "data": { "invoice_id": "12345678-1234-1234-1234-123456789012", "order_id": "order_12345", "code": "invoice_code", "status": "expired", "amounts": { "requested": { "amount": "100.50", "currency": "usd", "crypto": "100.5" }, "paid": { "amount": "0", "currency": "usd", "crypto": "0" } }, "fees": { "merchant": { "amount": "0", "currency": "usd", "crypto": "0" }, "network": { "amount": "0", "currency": "usd", "crypto": "0" }, "total": { "amount": "0", "currency": "usd", "crypto": "0" } }, "payment": { "coin": "usdt", "network": "tron", "address": "TXHXiQ2aXYqtz3y9gEGiVjzxXxXechdLwE", "rate": "1.0001" }, "fee_payer": { "merchant_fee": true, "network_fee": true }, "created_at": "2025-01-01T11:30:00Z", "expired_at": "2025-01-02T11:30:00Z" }}wallet.transaction
Section titled “wallet.transaction”Sent when a static wallet receives a deposit.
{ "event": "wallet.transaction", "timestamp": 1746984120, "data": { "wallet": { "address": "TXHXiQ2aXYqtz3y9gEGiVjzxXxXechdLwE", "network": "tron", "coin": "usdt", "label": "Main wallet", "rate": "1.0001" }, "transaction": { "id": "87654321-4321-4321-4321-210987654321", "hash": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", "block_number": 53214321, "amounts": { "gross": { "amount": "10.05", "currency": "usd", "crypto": "10.05" }, "net": { "amount": "9.849", "currency": "usd", "crypto": "9.849" } }, "fees": { "merchant": { "amount": "0.201", "currency": "usd", "crypto": "0.201" }, "network": { "amount": "0", "currency": "usd", "crypto": "0" }, "total": { "amount": "0.201", "currency": "usd", "crypto": "0.201" } }, "from_address": "TMDKznuDWaZwfZHcM61FYFRx9dAVPndpNv", "to_address": "TXHXiQ2aXYqtz3y9gEGiVjzxXxXechdLwE", "status": "success", "timestamp": 1746984100 } }}aml.rejected.invoice
Section titled “aml.rejected.invoice”Sent when AML screening blocks an invoice deposit. Snapshot details supplied by
the AML flow are carried inside risk_details.
{ "event": "aml.rejected.invoice", "timestamp": 1765472000, "data": { "wallet_address": "TXHXiQ2aXYqtz3y9gEGiVjzxXxXechdLwE", "coin": "usdt", "network": "tron", "amounts": { "amount": "100.00", "currency": "usd", "crypto": "1" }, "invoice": { "id": "5118a064-d5b9-4fab-ad14-8cf42f0020de", "code": "INV123", "order_id": "ORDER-1" }, "risk_score": 95, "risk_level": "severe", "risk_details": { "amount_smallest": "1000000", "usd_cents": "10000", "balance_snapshot": "1000000", "source": "misttrack" } }}aml.rejected.static_wallet
Section titled “aml.rejected.static_wallet”Sent when AML blocks a static-wallet deposit. Snapshot details supplied by the
AML flow are carried inside risk_details.
{ "event": "aml.rejected.static_wallet", "timestamp": 1765472000, "data": { "wallet_address": "TXHXiQ2aXYqtz3y9gEGiVjzxXxXechdLwE", "coin": "usdt", "network": "tron", "amounts": { "amount": "250.00", "currency": "usd", "crypto": "2.5" }, "static_wallet": { "id": "87654321-4321-4321-4321-210987654321", "label": "USDT Payment Address" }, "risk_score": 87, "risk_level": "high", "risk_details": { "amount_smallest": "2500000", "usd_cents": "25000", "balance_snapshot": "2500000", "source": "misttrack" } }}withdrawal.in_progress
Section titled “withdrawal.in_progress”Sent when a withdrawal request is being processed.
{ "event": "withdrawal.in_progress", "timestamp": 1746984100, "data": { "withdrawal_id": "5118a064-d5b9-4fab-ad14-8cf42f0020de", "status": "processing", "amounts": { "requested": { "amount": "5.0000", "currency": "usd", "crypto": "5" }, "net": { "amount": "5.0000", "currency": "usd", "crypto": "5" } }, "fees": { "merchant": { "amount": "0.0225", "currency": "usd", "crypto": "0.0225" }, "network": { "amount": "1.4000", "currency": "usd", "crypto": "1.4" }, "total": { "amount": "1.4225", "currency": "usd", "crypto": "1.4225" } }, "payment": { "coin": "usdt", "network": "tron", "to_address": "TLbqtn4EPerCj5a3TmbSffadYgDZ3UEmoe", "rate": "1.0001" }, "created_at": "2025-05-11T17:20:50+00:00", "updated_at": "2025-05-11T17:21:40+00:00", "transaction_hash": "22255482649487ca9f6f70a618c5b2e5e93399c09fd85ab589eff20cb0996e34", "fee_payer": { "merchant_fee": false, "network_fee": false } }}withdrawal.success
Section titled “withdrawal.success”Sent when a withdrawal has been successfully completed.
{ "event": "withdrawal.success", "timestamp": 1746984108, "data": { "withdrawal_id": "5118a064-d5b9-4fab-ad14-8cf42f0020de", "status": "completed", "amounts": { "requested": { "amount": "5.0000", "currency": "usd", "crypto": "5" }, "net": { "amount": "5.0000", "currency": "usd", "crypto": "5" } }, "fees": { "merchant": { "amount": "0.0225", "currency": "usd", "crypto": "0.0225" }, "network": { "amount": "1.4000", "currency": "usd", "crypto": "1.4" }, "total": { "amount": "1.4225", "currency": "usd", "crypto": "1.4225" } }, "payment": { "coin": "usdt", "network": "tron", "to_address": "TLbqtn4EPerCj5a3TmbSffadYgDZ3UEmoe", "rate": "1.0001" }, "created_at": "2025-05-11T17:20:50+00:00", "transaction_hash": "934cc03cfac6a1fe99be9156fde1807cfbe74e1ed7fe5e184596b932b7c9f30a", "updated_at": "2025-05-11T17:21:48+00:00", "fee_payer": { "merchant_fee": false, "network_fee": false } }}withdrawal.failed
Section titled “withdrawal.failed”Sent when a withdrawal has failed.
{ "event": "withdrawal.failed", "timestamp": 1746984110, "data": { "withdrawal_id": "5118a064-d5b9-4fab-ad14-8cf42f0020de", "status": "failed", "amounts": { "requested": { "amount": "5.0000", "currency": "usd", "crypto": "5" }, "net": { "amount": "5.0000", "currency": "usd", "crypto": "5" } }, "fees": { "merchant": { "amount": "0.0225", "currency": "usd", "crypto": "0.0225" }, "network": { "amount": "1.4000", "currency": "usd", "crypto": "1.4" }, "total": { "amount": "1.4225", "currency": "usd", "crypto": "1.4225" } }, "payment": { "coin": "usdt", "network": "tron", "to_address": "TLbqtn4EPerCj5a3TmbSffadYgDZ3UEmoe", "rate": "1.0001" }, "created_at": "2025-05-11T17:20:50+00:00", "updated_at": "2025-05-11T17:21:50+00:00", "error_message": "Insufficient energy on network", "fee_payer": { "merchant_fee": false, "network_fee": false } }}Responding to Webhooks
Section titled “Responding to Webhooks”Your server should respond with a 2xx HTTP status to acknowledge receipt. A non-2xx response or transport failure can result in another delivery. The exact attempt count and schedule are not guaranteed, so do not depend on a fixed retry count.
Delivery Idempotency
Section titled “Delivery Idempotency”Withdrawal events currently include a stable header:
X-Idempotency-Key: withdrawal:{withdrawal_id}:{event}The same key is reused across withdrawal delivery attempts and manual resends. Invoice, wallet, AML, and test events do not currently guarantee this header. For those events, store a receiver-side deduplication key built from the event and its stable entity identifier where available. Make processing idempotent even when the header is absent.
Testing Webhooks
Section titled “Testing Webhooks”You can test your webhook integration from your merchant dashboard using the “Test Webhook” feature. This will send a test webhook to your configured webhook URL with sample data.
Test Webhook Payload
Section titled “Test Webhook Payload”The dashboard sends a simple payload when you trigger a test:
{ "event": "test", "timestamp": 1746984000, "data": { "merchant_id": "12345678-1234-1234-1234-123456789012", "test": true, "message": "This is a test webhook to verify your integration / - ё" }}Webhook Delivery
Section titled “Webhook Delivery”- Webhooks are delivered in real-time as events occur
- Delivery can be attempted more than once; the exact retry policy is not a public constant
- Delivery outcomes are logged for operational review
- Failed webhooks can be manually resent from the merchant dashboard
Best Practices
Section titled “Best Practices”-
Respond Quickly: Your webhook endpoint should respond as quickly as possible, ideally within a few seconds.
-
Process Asynchronously: To ensure quick responses, process the webhook data asynchronously after acknowledging receipt.
-
Verify Signatures: Always verify the webhook signature to ensure the request is legitimate.
-
Handle Duplicate Events: Use
X-Idempotency-Keywhen present and an event/entity deduplication key otherwise. -
Monitor Webhook Failures: Regularly check your merchant dashboard for failed webhook deliveries.
-
Test Your Integration: Use the test webhook feature to ensure your endpoint properly handles and processes webhook data.