Webhook Configuration & Events
Receive real-time notifications when important events happen in your account
Webhook Configuration & Events
Turn Selgora events into real-time actions in your apps. Webhooks let you build powerful automations that respond instantly to what happens in your account.
Understanding Webhooks
What Are Webhooks?
Think of webhooks as automated phone calls:
- Something happens in Selgora (event)
- Selgora calls your URL (webhook)
- Sends event details (payload)
- Your app takes action (response)
Webhooks vs. API Polling
API Polling (Inefficient):
Your App: "Anything new?"
Selgora: "No"
Your App: "Anything new?"
Selgora: "No"
Your App: "Anything new?"
Selgora: "Yes! Order #123"
Webhooks (Efficient):
Selgora: "Order #123 just happened!"
Your App: "Thanks, processing..."
Setting Up Webhooks
Step 1: Create Endpoint
Your webhook endpoint requirements:
- Publicly accessible HTTPS URL
- Accepts POST requests
- Returns 200 status quickly (<5 seconds)
- Handles JSON payload
Example Endpoint:
// Express.js webhook handler
app.post('/webhooks/selgora', (req, res) => {
const event = req.body;
// Acknowledge receipt immediately
res.status(200).send('OK');
// Process event asynchronously
processWebhookEvent(event);
});
Step 2: Configure in Selgora
Dashboard > Settings > Webhooks
Click: Add Webhook Endpoint
URL: https://yourapp.com/webhooks/selgora
Events: Select events to receive
Secret: Generate signing secret
Status: Active
Step 3: Test Your Webhook
Dashboard > Settings > Webhooks > Your Webhook
Click: Send Test Event
Select: Event type
Click: Send
Check: Your server logs
Available Events
Order Events
order.created
{
"event": "order.created",
"created_at": "2024-11-15T10:00:00Z",
"data": {
"order_id": "ord_123",
"customer_email": "customer@example.com",
"amount": 19700,
"currency": "USD",
"status": "pending"
}
}
order.completed
{
"event": "order.completed",
"data": {
"order_id": "ord_123",
"customer_email": "customer@example.com",
"products": [
{
"id": "prod_456",
"name": "Complete Course",
"price": 19700
}
],
"payment_method": "card"
}
}
order.refunded
{
"event": "order.refunded",
"data": {
"order_id": "ord_123",
"refund_amount": 19700,
"reason": "requested_by_customer"
}
}
Contact Events
contact.created
{
"event": "contact.created",
"data": {
"contact_id": "con_456",
"email": "new@example.com",
"source": "landing_page",
"tags": ["lead"],
"custom_fields": {}
}
}
contact.updated
{
"event": "contact.updated",
"data": {
"contact_id": "con_456",
"changes": {
"tags": {
"added": ["customer"],
"removed": ["lead"]
},
"custom_fields": {
"company": "New Company"
}
}
}
}
contact.deleted
{
"event": "contact.deleted",
"data": {
"contact_id": "con_456",
"email": "deleted@example.com",
"deleted_at": "2024-11-15T10:00:00Z"
}
}
Subscription Events
subscription.created
{
"event": "subscription.created",
"data": {
"subscription_id": "sub_789",
"customer_email": "customer@example.com",
"plan": "monthly",
"amount": 9700,
"next_billing_date": "2024-12-15"
}
}
subscription.updated
{
"event": "subscription.updated",
"data": {
"subscription_id": "sub_789",
"changes": {
"plan": {
"from": "monthly",
"to": "annual"
}
}
}
}
subscription.cancelled
{
"event": "subscription.cancelled",
"data": {
"subscription_id": "sub_789",
"cancelled_at": "2024-11-15T10:00:00Z",
"reason": "voluntary",
"feedback": "Too expensive"
}
}
Course Events
course.enrolled
{
"event": "course.enrolled",
"data": {
"contact_id": "con_456",
"course_id": "course_123",
"enrolled_at": "2024-11-15T10:00:00Z"
}
}
course.completed
{
"event": "course.completed",
"data": {
"contact_id": "con_456",
"course_id": "course_123",
"completed_at": "2024-11-15T10:00:00Z",
"completion_rate": 100,
"time_spent_minutes": 480
}
}
lesson.completed
{
"event": "lesson.completed",
"data": {
"contact_id": "con_456",
"lesson_id": "lesson_789",
"course_id": "course_123",
"quiz_score": 95
}
}
Email Events
email.sent
{
"event": "email.sent",
"data": {
"email_id": "em_123",
"to": "customer@example.com",
"subject": "Welcome to Selgora",
"campaign": "welcome_series"
}
}
email.opened
{
"event": "email.opened",
"data": {
"email_id": "em_123",
"opened_at": "2024-11-15T10:30:00Z",
"ip_address": "192.168.1.1",
"user_agent": "Mozilla/5.0..."
}
}
email.clicked
{
"event": "email.clicked",
"data": {
"email_id": "em_123",
"link": "https://selgora.com/offer",
"clicked_at": "2024-11-15T10:35:00Z"
}
}
Webhook Security
Signature Verification
Every webhook includes a signature header:
X-Selgora-Signature: sha256=3b4c5d6e7f8a9b0c1d2e3f4g5h6i7j8k
Verify in Node.js:
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex');
return `sha256=${expectedSignature}` === signature;
}
app.post('/webhook', (req, res) => {
const signature = req.headers['x-selgora-signature'];
const isValid = verifyWebhookSignature(
JSON.stringify(req.body),
signature,
process.env.WEBHOOK_SECRET
);
if (!isValid) {
return res.status(401).send('Invalid signature');
}
// Process webhook...
});
Verify in Python:
import hmac
import hashlib
def verify_webhook_signature(payload, signature, secret):
expected = hmac.new(
secret.encode(),
payload.encode(),
hashlib.sha256
).hexdigest()
return f"sha256={expected}" == signature
@app.route('/webhook', methods=['POST'])
def handle_webhook():
signature = request.headers.get('X-Selgora-Signature')
if not verify_webhook_signature(
request.data,
signature,
WEBHOOK_SECRET
):
return 'Invalid signature', 401
# Process webhook...
Handling Webhooks
Best Practices
1. Acknowledge Quickly:
app.post('/webhook', async (req, res) => {
// Acknowledge immediately
res.status(200).send('OK');
// Process asynchronously
await queue.add('process-webhook', req.body);
});
2. Idempotency:
// Store processed event IDs
const processedEvents = new Set();
async function processWebhook(event) {
if (processedEvents.has(event.id)) {
return; // Already processed
}
// Process event...
processedEvents.add(event.id);
}
3. Error Handling:
async function processWebhook(event) {
try {
switch(event.event) {
case 'order.completed':
await handleOrderCompleted(event.data);
break;
case 'subscription.cancelled':
await handleSubscriptionCancelled(event.data);
break;
default:
console.log(`Unhandled event: ${event.event}`);
}
} catch (error) {
console.error('Webhook processing error:', error);
// Log to error tracking service
await errorTracker.report(error, { event });
}
}
Retry Logic
Selgora retries failed webhooks:
- First retry: 5 minutes
- Second retry: 30 minutes
- Third retry: 2 hours
- Fourth retry: 8 hours
- Final retry: 24 hours
Your endpoint should:
- Return 200 for success
- Return 4xx for client errors (no retry)
- Return 5xx for server errors (will retry)
Common Use Cases
Sync with CRM
// Sync new customers to CRM
async function handleOrderCompleted(data) {
const { customer_email, products } = data;
await crm.createOrUpdate({
email: customer_email,
customFields: {
selgora_customer: true,
products_purchased: products.map(p => p.name),
lifetime_value: await calculateLTV(customer_email)
}
});
}
Slack Notifications
// Notify team of new sales
async function handleOrderCompleted(data) {
await slack.postMessage({
channel: '#sales',
text: `🎉 New sale! ${data.customer_email} purchased ${data.products[0].name} for $${data.amount/100}`
});
}
Email Automation
// Trigger external email sequences
async function handleCourseCompleted(data) {
await emailProvider.addToSequence({
email: data.contact_email,
sequence: 'course_graduate',
customFields: {
course_name: data.course_name,
completion_date: data.completed_at
}
});
}
Analytics Tracking
// Track events in analytics
async function handleWebhookEvent(event) {
await analytics.track({
userId: event.data.contact_id,
event: event.event,
properties: event.data,
timestamp: event.created_at
});
}
Testing Webhooks
Local Development
Use ngrok for local testing:
# Install ngrok
npm install -g ngrok
# Start local server
node server.js # Runs on port 3000
# Expose to internet
ngrok http 3000
# Use ngrok URL in Selgora
https://abc123.ngrok.io/webhooks
Test Payload
# Test with curl
curl -X POST https://yourapp.com/webhooks \
-H "Content-Type: application/json" \
-H "X-Selgora-Signature: sha256=test" \
-d '{
"event": "order.completed",
"data": {
"order_id": "test_123",
"amount": 10000
}
}'
Webhook Logs
View webhook activity:
Dashboard > Settings > Webhooks > Your Webhook > Logs
Shows:
- Event type
- Timestamp
- Response code
- Response time
- Retry attempts
Troubleshooting
Common Issues
Webhook not receiving events:
- Verify URL is correct
- Check endpoint is publicly accessible
- Ensure HTTPS (not HTTP)
- Verify events are selected
Signature verification failing:
- Check secret key matches
- Verify payload is raw (not parsed)
- Ensure proper encoding (UTF-8)
Duplicate events:
- Implement idempotency
- Store processed event IDs
- Check for retry header
Timeouts:
- Return 200 immediately
- Process asynchronously
- Optimize processing logic
Your Webhook Checklist
Setup
- [ ] Create webhook endpoint
- [ ] Implement signature verification
- [ ] Add error handling
- [ ] Setup async processing
- [ ] Configure in Selgora
Testing
- [ ] Test with ngrok locally
- [ ] Verify signature validation
- [ ] Test each event type
- [ ] Check retry behavior
- [ ] Monitor logs
Production
- [ ] Use HTTPS only
- [ ] Implement idempotency
- [ ] Add monitoring/alerting
- [ ] Log all events
- [ ] Handle scaling
Remember: Webhooks are powerful but require proper handling. Always verify signatures, process asynchronously, and handle errors gracefully. Start with a few events and expand as needed!
Was this article helpful?
Your feedback helps us improve our content