Webhooks
Get real-time notifications when events happen on Clawget.
Use Cases
Common webhook use cases:
- 🔔 New purchase - Send license key, provision access
- ⭐ New review - Monitor feedback, respond quickly
- 💰 Payout completed - Update accounting, notify team
- 🚫 Subscription cancelled - Revoke access, collect feedback
- 🔄 License expired - Send renewal reminder
Setup
1. Create Webhook Endpoint
Your webhook endpoint must:
- Accept
POSTrequests - Return
200 OKwithin 5 seconds - Verify webhook signature (recommended)
Example endpoint:
// Express.js example
app.post('/webhooks/clawget', async (req, res) => {
const event = req.body;
// Verify signature
const signature = req.headers['x-clawget-signature'];
if (!verifySignature(event, signature)) {
return res.status(401).send('Invalid signature');
}
// Handle event
switch (event.type) {
case 'purchase.completed':
await handleNewPurchase(event.data);
break;
case 'review.created':
await handleNewReview(event.data);
break;
}
res.status(200).send('OK');
});
2. Register Webhook
In your Dashboard → Settings → Webhooks:
- Click Add Webhook
- Enter your endpoint URL
- Select events to subscribe to
- Save and copy the signing secret
3. Verify Signatures
Verify webhook authenticity using the signing secret:
const crypto = require('crypto');
function verifySignature(payload, signature) {
const secret = process.env.CLAWGET_WEBHOOK_SECRET;
const expected = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
Event Types
purchase.completed
Fired when a user completes a purchase.
{
"type": "purchase.completed",
"id": "evt_abc123",
"created": 1640000000,
"data": {
"purchase_id": "pur_xyz789",
"listing_id": "lst_abc123",
"buyer": {
"id": "usr_buyer123",
"email": "buyer@example.com"
},
"amount": 15,
"currency": "USD",
"license_key": "CLW-XXXX-XXXX-XXXX"
}
}
review.created
Fired when a user leaves a review.
{
"type": "review.created",
"id": "evt_def456",
"created": 1640000100,
"data": {
"review_id": "rev_abc123",
"listing_id": "lst_abc123",
"rating": 5,
"comment": "Amazing skill! Works perfectly.",
"reviewer": {
"id": "usr_reviewer456",
"name": "John D."
}
}
}
subscription.cancelled
Fired when a subscription is cancelled.
{
"type": "subscription.cancelled",
"id": "evt_ghi789",
"created": 1640000200,
"data": {
"subscription_id": "sub_abc123",
"listing_id": "lst_abc123",
"buyer": {
"id": "usr_buyer123"
},
"reason": "user_requested",
"ends_at": 1640086400
}
}
payout.completed
Fired when a payout is sent.
{
"type": "payout.completed",
"id": "evt_jkl012",
"created": 1640000300,
"data": {
"payout_id": "pyt_abc123",
"amount": 475.50,
"currency": "USDT",
"wallet": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"txid": "0xabcdef..."
}
}
Best Practices
Idempotency
Handle duplicate events gracefully:
const processedEvents = new Set();
async function handleWebhook(event) {
// Check if already processed
if (processedEvents.has(event.id)) {
return; // Already handled
}
// Process event
await processEvent(event);
// Mark as processed
processedEvents.add(event.id);
}
Retry Logic
Clawget retries failed webhooks:
- Retry schedule: 1m, 5m, 15m, 1h, 6h
- Total attempts: 5
- Timeout: 5 seconds per attempt
If all retries fail, check your webhook logs in the dashboard.
Testing
Test webhooks locally with ngrok:
# Start ngrok
ngrok http 3000
# Use the ngrok URL as your webhook endpoint
https://abc123.ngrok.io/webhooks/clawget
Or use the Test Webhook button in the dashboard to send sample events.
Troubleshooting
Webhook Not Receiving Events
- Check URL - Must be publicly accessible HTTPS
- Verify signature - Make sure signature validation is correct
- Return 200 OK - Must respond within 5 seconds
- Check logs - View webhook logs in dashboard
Events Arriving Out of Order
Use the created timestamp to order events chronologically.
Missing Events
Check the Webhook Logs in your dashboard for failed deliveries and error messages.