Overview
BlockBee sends webhooks to notify your application about subscription events. There are two types of webhook notifications:
- Payment Notification (
action=renew) - Sent when a user makes a payment to extend or create a subscription - Expiration Notification (
action=expired) - Sent when a subscription reaches its end date
Important: Always verify webhook signatures to ensure requests are from BlockBee. See our Verify Webhook Signature guide for implementation details.
Payment Notification Webhook
Sent when a user makes a payment (initial subscription payment or renewal).
Webhook Fields
actionstring•Required
Action performed: renew if user made a payment, either the initial one or the extension.
Notes:
- Important to check the
subscription_end_date_tsas it will be updated with the current subscription end date.
renewsubscription_idstring•Required
Unique token of the subscription.
I55hhRINHptLJPwsqwYNxJOKBItRiq1osubscription_urlstring•Required
Link to the subscription page.
https://pay.blockbee.io/subscription/I55hhRINHptLJPwsqwYNxJOKBItRiq1osubscription_start_date_tsinteger•Required
Timestamp when the subscription started.
1718131200subscription_end_date_tsinteger•Required
Timestamp when the subscription will expire.
1720723200subscription_option_slugstring•Required
Slug of the subscription option selected by the user.
pro-plansubscription_option_duration_tsnumber•Required
Duration of the subscription option selected by the user, in seconds.
2592000subscription_option_valuenumber•Required
Value of the subscription option in fiat you selected in the Payment Settings.
5subscription_user_idstring•Required
User identifier of your system provided in the here.
user_123subscription_user_emailstring•Required
Email address of the user, provided here.
[email protected]payment_urlstring•Required
Payment link associated with this subscription renewal.
https://pay.blockbee.io/subscription/payment/ls25hhRINHptLJPwsqwYNxJOKBItRiq1opayment_redirect_urlstring•Required
URL where the user will be redirected after payment.
https://example.com/payment-successfulpayment_success_tokenstring•Required
Success token used to validate the payment.
sU7EGOlRRxsxJu4zZoYLa69UXrSijzb73eP6nbQQgpJYAfSL3NiI407lpYqsMbR2payment_received_amount_fiatnumber•Required
Amount received after fee deductions in fiat.
4.85payment_txidstring•Required
Comma-separated transaction IDs of the payment.
0xa1234...,0xa5678...Example Payload
{
"action": "renew",
"subscription_id": "I55hhRINHptLJPwsqwYNxJOKBItRiq1o",
"subscription_url": "https://pay.blockbee.io/subscription/I55hhRINHptLJPwsqwYNxJOKBItRiq1o",
"subscription_start_date_ts": 1718131200,
"subscription_end_date_ts": 1720723200,
"subscription_option_slug": "pro-plan",
"subscription_option_duration_ts": 2592000,
"subscription_option_value": 5,
"subscription_user_id": "user_123",
"subscription_user_email": "[email protected]",
"payment_url": "https://pay.blockbee.io/subscription/payment/ls25hhRINHptLJPwsqwYNxJOKBItRiq1o",
"payment_redirect_url": "https://example.com/payment-successful",
"payment_value": 5,
"payment_success_token": "sU7EGOlRRxsxJu4zZoYLa69UXrSijzb73eP6nbQQgpJYAfSL3NiI407lpYqsMbR2",
"payment_currency": "usd",
"payment_is_paid": 1,
"payment_paid_amount": 5,
"payment_paid_amount_fiat": 4.85,
"payment_received_amount": 5,
"payment_received_amount_fiat": 4.85,
"payment_paid_coin": "btc",
"payment_exchange_rate": 0.97,
"payment_txid": "0xa1234...,0xa5678...",
"payment_address": "0xabc123...",
"payment_type": "payment",
"payment_status": "done"
}Expiration Notification Webhook
Sent when a subscription has reached its end date and is no longer active.
Webhook Fields
actionstring•Required
Indicates that the subscription has reached its end date and is no longer active. No further payments will be processed for expired subscriptions.
expiredsubscription_idstring•Required
Unique token of the subscription.
I55hhRINHptLJPwsqwYNxJOKBItRiq1osubscription_urlstring•Required
Link to the subscription page.
https://pay.blockbee.io/subscription/I55hhRINHptLJPwsqwYNxJOKBItRiq1osubscription_start_date_tsinteger•Required
Timestamp when the subscription started.
1718131200subscription_end_date_tsinteger•Required
Timestamp when the subscription will expire.
1720723200subscription_option_slugstring•Required
Slug of the subscription option selected by the user.
pro-plansubscription_option_duration_tsnumber•Required
Duration of the subscription option selected by the user, in seconds.
2592000subscription_option_valuenumber•Required
Value of the subscription option in fiat you selected in the Payment Settings.
5subscription_user_idstring•Required
User identifier of your system provided in the here.
user_123subscription_user_emailstring•Required
Email address of the user, provided here.
[email protected]Example Payload
{
"action": "expired",
"subscription_id": "I55hhRINHptLJPwsqwYNxJOKBItRiq1o",
"subscription_url": "https://pay.blockbee.io/subscription/I55hhRINHptLJPwsqwYNxJOKBItRiq1o",
"subscription_start_date_ts": 1718131200,
"subscription_end_date_ts": 1720723200,
"subscription_option_slug": "pro-plan",
"subscription_option_duration_ts": 2592000,
"subscription_option_value": 5,
"subscription_user_id": "user_123",
"subscription_user_email": "[email protected]"
}Webhook Handling
Here are code examples for handling subscription webhooks in different programming languages:
// Express.js webhook handler
app.post('/subscription-webhook', express.json(), (req, res) => {
// 1. Verify the webhook signature
if (!verifyWebhookSignature(req)) {
return res.status(401).send('Unauthorized');
}
const { action, subscription_id, subscription_user_id, payment_status } = req.body;
// Use subscription_id to prevent duplicate processing
if (isWebhookAlreadyProcessed(subscription_id)) {
return res.status(200).send('*ok*');
}
if (action === 'renew' && payment_status === 'done') {
// Grant or extend access for the user
// Update subscription end date in your database
// Send confirmation email to user
console.log(`Subscription renewed for user: ${subscription_user_id}`);
} else if (action === 'expired') {
// Revoke access for the user
// Update subscription status in your database
// Send expiration notification to user
console.log(`Subscription expired for user: ${subscription_user_id}`);
}
// Mark this webhook as processed
markWebhookAsProcessed(subscription_id);
// Always respond with *ok*
res.status(200).send('*ok*');
});Best Practices
- Verify Signatures: Always verify webhook signatures to ensure requests are from BlockBee
- Idempotency: Use the
subscription_idto prevent processing the same webhook multiple times - Respond Quickly: Always respond with
*ok*and a200status code to prevent BlockBee from resending the webhook - Asynchronous Processing: For long-running tasks, process them in a background job after responding to the webhook
- Error Handling: Log errors but don't let them prevent the webhook response
- Database Updates: Update your database with the new subscription end date when processing renewal webhooks
Implementation Guide: For detailed instructions on how to verify webhook signatures, see our Verify Webhook Signature guide.
Webhook Verification
Always verify that webhooks are coming from BlockBee by checking the signature. This prevents malicious requests from impersonating BlockBee.
Security: Never skip signature verification in production. This is crucial for the security of your application.
For implementation details, see our Verify Webhook Signature guide.