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
action
string
•Required
Action performed: renew
if user made a payment, either the initial one or the extension.
Notes:
- Important to check the
subscription_end_date_ts
as it will be updated with the current subscription end date.
renew
subscription_id
string
•Required
Unique token of the subscription.
I55hhRINHptLJPwsqwYNxJOKBItRiq1o
subscription_url
string
•Required
Link to the subscription page.
https://pay.blockbee.io/subscription/I55hhRINHptLJPwsqwYNxJOKBItRiq1o
subscription_start_date_ts
integer
•Required
Timestamp when the subscription started.
1718131200
subscription_end_date_ts
integer
•Required
Timestamp when the subscription will expire.
1720723200
subscription_option_slug
string
•Required
Slug of the subscription option selected by the user.
pro-plan
subscription_option_duration_ts
number
•Required
Duration of the subscription option selected by the user, in seconds.
2592000
subscription_option_value
number
•Required
Value of the subscription option in fiat you selected in the Payment Settings.
5
subscription_user_id
string
•Required
User identifier of your system provided in the here.
user_123
subscription_user_email
string
•Required
Email address of the user, provided here.
[email protected]
payment_url
string
•Required
Payment link associated with this subscription renewal.
https://pay.blockbee.io/subscription/payment/ls25hhRINHptLJPwsqwYNxJOKBItRiq1o
payment_redirect_url
string
•Required
URL where the user will be redirected after payment.
https://example.com/payment-successful
payment_success_token
string
•Required
Success token used to validate the payment.
sU7EGOlRRxsxJu4zZoYLa69UXrSijzb73eP6nbQQgpJYAfSL3NiI407lpYqsMbR2
payment_received_amount_fiat
number
•Required
Amount received after fee deductions in fiat.
4.85
payment_txid
string
•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
action
string
•Required
Indicates that the subscription has reached its end date and is no longer active. No further payments will be processed for expired subscriptions.
expired
subscription_id
string
•Required
Unique token of the subscription.
I55hhRINHptLJPwsqwYNxJOKBItRiq1o
subscription_url
string
•Required
Link to the subscription page.
https://pay.blockbee.io/subscription/I55hhRINHptLJPwsqwYNxJOKBItRiq1o
subscription_start_date_ts
integer
•Required
Timestamp when the subscription started.
1718131200
subscription_end_date_ts
integer
•Required
Timestamp when the subscription will expire.
1720723200
subscription_option_slug
string
•Required
Slug of the subscription option selected by the user.
pro-plan
subscription_option_duration_ts
number
•Required
Duration of the subscription option selected by the user, in seconds.
2592000
subscription_option_value
number
•Required
Value of the subscription option in fiat you selected in the Payment Settings.
5
subscription_user_id
string
•Required
User identifier of your system provided in the here.
user_123
subscription_user_email
string
•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_id
to prevent processing the same webhook multiple times - Respond Quickly: Always respond with
*ok*
and a200
status 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.