Real-time webhook notifications sent when payments are received via custom payment flow. CryptAPI sends two types of webhooks: pending (payment detected in mempool) and confirmed (payment verified by blockchain).
Method: You choose when creating the payment:
GET
(default) - Webhook data sent as URL query parametersPOST
(setpost=1
) - Webhook data sent in request body
Content-Type: You choose when creating the payment:
application/x-www-form-urlencoded
(default) - Standard form encodingapplication/json
(setjson=1
) - JSON format in request body
Tracking Payments with Custom Parameters
Important: Add Custom Parameters to Your Webhook URL
When creating custom payment flow payments, always add your own query parameters to the notify_url
to track which order or user the payment belongs to. For example, adding ?order_id=123
or ?user_id=456
will ensure that these parameters are included in the webhook payload.
This is the recommended way to link a CryptAPI payment to a specific order or user in your system.
Webhook Types
Pending Webhook
Sent when a payment is detected in the blockchain mempool but not yet confirmed. Particularly useful for slower blockchains (Bitcoin, Litecoin, Bitcoin Cash) to provide immediate user feedback.
Confirmed Webhook
Sent when a payment receives the specified number of confirmations. The transaction is considered final and funds are forwarded to your address.
Webhook Fields
Common Fields (Both Pending & Confirmed)
These fields are included in both pending and confirmed webhooks:
uuid
string
•Required
Unique identifier for each payment transaction. Use this to prevent processing duplicate webhooks.
Important: Always store and check this UUID in your database before processing any payment to avoid duplicates.
address_out
string
•Required
Your destination address(es) where CryptAPI forwards the payment.
Format:
- Single address:
1H6ZZpRmMnrw8ytepV3BYwMjYYnEkWDqVP
- Multiple addresses:
{1H6ZZpRmMnrw8ytepV3BYwMjYYnEkWDqVP: 0.70, 1PE5U4temq1rFzseHHGE2L8smwHCyRbkx3: 0.30}
coin
string
•Required
Cryptocurrency ticker used for the payment.
Format:
- Native coins:
btc
,eth
,ltc
,bch
,trx
- ERC-20 tokens:
erc20_usdt
,erc20_usdc
- TRC-20 tokens:
trc20_usdt
,trc20_usdc
- BEP-20 tokens:
bep20_usdt
,bep20_usdc
- Polygon tokens:
polygon_usdt
,polygon_usdc
pending
integer
•Required
Indicates webhook type:
1
= Pending webhook (payment detected, not confirmed)0
= Confirmed webhook (payment verified and forwarded)
Confirmed Webhook Only Fields
These additional fields are only included in confirmed webhooks (pending=0
):
value_coin
number
•Required
Payment amount sent by your customer before any fees are deducted.
Note: For the amount after fees, use value_forwarded_coin
value_coin_convert
string
JSON-encoded object with FIAT currency conversions of value_coin
.
Availability: Only when convert=1
was set during payment creation
Format: {"USD": "3.20", "EUR": "3.05", "GBP": "2.62", "CAD": "4.16", ...}
value_forwarded_coin
number
•Required
Amount forwarded to your address after CryptAPI fees are deducted.
value_forwarded_coin_convert
string
JSON-encoded object with FIAT currency conversions of value_forwarded_coin
.
Note: Only present when convert=1
was set during payment creation
Format: {"USD": "3.17", "EUR": "3.01", "GBP": "2.59", "CAD": "4.12", ...}
Security: Verify Webhook Signatures
Security Warning! Always verify incoming webhook signatures. For a complete guide, see our Verify Webhook Signatures Guide.
Reliability and Best Practices
For important information on how CryptAPI handles webhook delivery, retries, and timeouts, along with essential best practices for building a reliable webhook handler, please see our main guide.
➡️ Read the How Webhooks Work Guide
Implementation Examples
// Express.js webhook handler
app.post('/webhook', express.json(), (req, res) => {
// 1. Verify the webhook signature
if (!verifyWebhookSignature(req)) {
return res.status(401).send('Unauthorized');
}
// 2. Extract data from the payload
const { uuid, pending, value_coin, coin, order_id, user_id } = req.body;
// Note: order_id and user_id come from custom parameters you added to notify_url
// 3. Check for duplicates using UUID
if (isWebhookAlreadyProcessed(uuid)) {
return res.status(200).send('*ok*');
}
// 4. Handle based on webhook type
if (pending === 1) {
// Handle pending payment
notifyUser(user_id, 'Payment detected, awaiting confirmation...');
} else if (pending === 0) {
// Handle confirmed payment
processSuccessfulPayment({
uuid,
value_coin,
coin,
orderId: order_id,
userId: user_id
});
}
// 5. Mark this webhook as processed using the UUID
markWebhookAsProcessed(uuid);
// Always respond to stop retries
res.status(200).send('*ok*');
});