Creating a Webhook
Creating a webhook allows you to receive real-time notifications about events in your application and track changes in your subscribers’ status.
Quick Start
Create a webhook
Log into your account and navigate to Settings → Webhooks in the control panel.
Fill out the form and save settings
Fill in the required fields of the webhook creation form:
- Name - give a descriptive name to your webhook
- URL - specify the URL of your endpoint to receive notifications
- Events - select the events you want to subscribe to
- Status - activate the webhook
Click “Create” to create the webhook. The system will start sending notifications to the specified URL.
Available Events
Select one or more events to subscribe to:
Event | Description |
---|---|
Payment Completed | Successfully completed payment (one-time or first subscription payment) |
Subscription Created | Creation of a new subscription |
Subscription Updated | Subscription update (plan change, status change, etc.) |
Subscription Cancelled | Subscription cancellation |
Refund Created | Creation of a refund |
Event subscription: Select only the events that are necessary for your application to avoid unnecessary load on your server.
Endpoint Requirements
Mandatory Requirements
- HTTPS: Webhooks are sent only to HTTPS URLs
- Response Status: Your endpoint must return HTTP status 200-299 for successful processing
- Timeout: Response timeout is 10 seconds
- Idempotency: Be prepared to receive duplicate events
Endpoint Example
Node.js/Express
const express = require('express');
const app = express();
app.use(express.json());
app.post('/monetize/webhook', async (req, res) => {
try {
const event = req.body;
// Process event by type
switch (event.type) {
case 'payment.completed':
await handlePaymentCompleted(event.data);
break;
case 'subscription.created':
await handleSubscriptionCreated(event.data);
break;
// ... other event types
default:
console.log(`Unhandled event type: ${event.type}`);
}
res.status(200).json({ status: 'success' });
} catch (err) {
console.error(`Webhook error: ${err}`);
res.status(500).json({ error: 'Internal error' });
}
});
async function handlePaymentCompleted(data) {
console.log(`Payment completed: ${data.payment.id}`);
// Activate user access
await activateUserAccess(data.user.id);
}
Secret Key Setup
Why Secret Key is Needed
The secret key is used to create an HMAC SHA256 signature, which allows you to:
- Verify authenticity of notifications from Monetize.software
- Prevent attacks with fake webhook notifications
- Ensure security of your endpoint
Secret Key Generation
Create a cryptographically strong secret key:
Node.js
const crypto = require('crypto');
// Generate 32-byte key
const secret = crypto.randomBytes(32).toString('hex');
console.log('Secret key:', secret);
Signature Verification
When specifying a secret key, each request will contain the X-Monetize-Signature
header:
Node.js
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
// Remove "sha256=" prefix from header
signature = signature.replace('sha256=', '');
return crypto.timingSafeEqual(
Buffer.from(expectedSignature),
Buffer.from(signature)
);
}
// Usage in middleware
app.post('/monetize/webhook', (req, res) => {
const signature = req.headers['x-monetize-signature'];
const payload = JSON.stringify(req.body);
if (!verifyWebhookSignature(payload, signature, YOUR_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process webhook...
});
Security: Always verify the webhook signature in production to ensure the request is truly from Monetize.software.
Testing Functionality
After creating a webhook:
- Create a test transaction in your application
- Check the logs in the control panel (Settings → Webhooks → your webhook → View Logs)
- Ensure receipt of notifications at your endpoint
- Verify correctness of data processing
Webhook Management
Viewing Created Webhooks
The webhooks table displays:
- Name - webhook name
- Status - active/inactive
- Events - subscribed events
- Creation Date - when the webhook was created
- Last Call - time of the last successful call
Webhook Actions
For each webhook, the following actions are available:
- View Logs - history of all notification delivery attempts
- Edit - modify webhook settings
- Delete - complete webhook deletion
Viewing Logs
Logs contain detailed information about each delivery attempt:
- Date and Time - when the delivery attempt was made
- Event Type - which event triggered the notification
- Paywall ID - identifier of the associated paywall
- HTTP Status - response code from your endpoint
- Response Body - response content
- Attempt Count - delivery attempt number
- Error Message - error details for failed deliveries
Limits and Restrictions
Limitation | Value |
---|---|
Maximum payload size | 1 MB |
Timeout | 10 seconds |
Maximum webhooks per account | 10 |
Log retention | 30 days |
Retry delivery attempts | 5 attempts |
Retry Delivery
The system automatically retries delivery in case of failure:
- Number of attempts: 5 attempts
- Intervals: 5, 10, 20, 40, and 80 minutes
- Retry conditions: HTTP status 5xx or connection timeout
Attempt logging: All delivery attempts are logged and available in the control panel.
Security Recommendations
Basic Principles
- Always verify the signature when using a secret key
- Use HTTPS for all webhook URLs
- Don’t log full webhook data in plain text
- Restrict access to webhook endpoints
- Validate data before processing
Error Handling
app.post('/monetize/webhook', async (req, res) => {
try {
// Verify signature
if (!verifySignature(req)) {
return res.status(401).json({ error: 'Unauthorized' });
}
// Validate data structure
if (!isValidEvent(req.body)) {
return res.status(400).json({ error: 'Invalid payload' });
}
// Idempotent processing
const eventId = req.body.id;
if (await isEventProcessed(eventId)) {
return res.status(200).json({ status: 'already_processed' });
}
// Process event
await processEvent(req.body);
await markEventAsProcessed(eventId);
res.status(200).json({ status: 'success' });
} catch (error) {
console.error('Webhook error:', error);
res.status(500).json({ error: 'Internal error' });
}
});
Troubleshooting
Common Issues
Issue | Cause | Solution |
---|---|---|
HTTP 401 | Invalid signature | Check secret key |
HTTP 404 | URL unavailable | Check URL correctness |
HTTP 500 | Error on your server | Check your application logs |
Timeout | Slow processing | Optimize processing time |
Duplicate events | Network issues | Implement idempotent processing |
Debugging
- Check webhook logs in the control panel
- Review payload of sent events
- Check response status of your endpoint
- Ensure URL availability through browser or curl
- Check headers of requests and responses