Documentation Index Fetch the complete documentation index at: https://mintlify.com/sockudo/sockudo/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Webhooks allow Sockudo to send HTTP notifications when events occur, such as channel occupancy changes, client connections/disconnections, and custom events. With batching support, you can efficiently handle high-volume events.
Key Features:
HTTP webhook endpoints
AWS Lambda integration
Event batching for efficiency
Configurable batch size and duration
Retry logic with exponential backoff
Quick Start
Basic Configuration
{
"webhooks" : {
"batching" : {
"enabled" : false ,
"duration" : 50 ,
"size" : 50
}
},
"apps" : [
{
"id" : "my-app" ,
"key" : "my-key" ,
"secret" : "my-secret" ,
"webhooks" : [
{
"url" : "https://example.com/webhook" ,
"event_types" : [ "channel_occupied" , "channel_vacated" ]
}
]
}
]
}
Environment Variables
WEBHOOK_BATCHING_ENABLED = true
WEBHOOK_BATCHING_DURATION = 50
WEBHOOK_BATCHING_SIZE = 50
Webhook Configuration
Per-App Webhooks
Configure webhooks for individual applications:
{
"apps" : [
{
"id" : "my-app" ,
"webhooks" : [
{
"url" : "https://example.com/webhook" ,
"event_types" : [
"channel_occupied" ,
"channel_vacated" ,
"member_added" ,
"member_removed"
],
"headers" : {
"X-Custom-Header" : "value" ,
"Authorization" : "Bearer token"
}
}
]
}
]
}
Option Type Description urlstringWebhook endpoint URL (HTTP/HTTPS) event_typesarrayList of events to trigger webhook headersobjectOptional custom HTTP headers
Supported Event Types
Event Type Description Payload channel_occupiedFirst client subscribes to channel {"channel": "...", "time_ms": 123}channel_vacatedLast client unsubscribes from channel {"channel": "...", "time_ms": 123}member_addedMember joins presence channel {"channel": "...", "user_id": "..."}member_removedMember leaves presence channel {"channel": "...", "user_id": "..."}client_eventCustom client event (if enabled) {"channel": "...", "event": "...", "data": {...}}
Batching
Why Batching?
Without batching, each event triggers a separate HTTP request:
100 events/sec = 100 HTTP requests/sec
1000 events/sec = 1000 HTTP requests/sec
With batching, events are grouped:
1000 events/sec with batch_size=50 = 20 HTTP requests/sec
Saving: 98% reduction in HTTP requests
Batching Configuration
{
"webhooks" : {
"batching" : {
"enabled" : true ,
"duration" : 50 , // milliseconds
"size" : 50 // max events per batch
}
}
}
Option Default Description enabledfalseEnable/disable batching duration50Max time (ms) to wait before sending batch size50Max events per batch
Batching Behavior
Batch is sent when either condition is met:
Batch size reaches size (e.g., 50 events)
Duration timeout reaches duration (e.g., 50ms)
Example with duration=50ms, size=50:
High traffic (>50 events/50ms):
→ Batch sent when 50 events collected (before 50ms)
→ Result: Maximum efficiency
Low traffic (<50 events/50ms):
→ Batch sent after 50ms timeout
→ Result: Maximum 50ms delay
Batched Webhook Payload
{
"time_ms" : 1678901234567 ,
"events" : [
{
"name" : "channel_occupied" ,
"channel" : "presence-room-1" ,
"time_ms" : 1678901234567
},
{
"name" : "member_added" ,
"channel" : "presence-room-1" ,
"user_id" : "user-123"
},
{
"name" : "channel_vacated" ,
"channel" : "presence-room-2" ,
"time_ms" : 1678901234600
}
]
}
Non-Batched Webhook Payload
{
"name" : "channel_occupied" ,
"channel" : "presence-room-1" ,
"time_ms" : 1678901234567
}
AWS Lambda Integration
Webhooks can trigger AWS Lambda functions directly:
Configuration
{
"apps" : [
{
"id" : "my-app" ,
"webhooks" : [
{
"url" : "lambda://arn:aws:lambda:us-east-1:123456789:function:my-webhook" ,
"event_types" : [ "channel_occupied" , "channel_vacated" ]
}
]
}
]
}
Lambda Function Example
import json
def lambda_handler ( event , context ):
# Parse webhook payload
body = json.loads(event[ 'body' ])
if 'events' in body: # Batched
for webhook_event in body[ 'events' ]:
process_event(webhook_event)
else : # Single event
process_event(body)
return {
'statusCode' : 200 ,
'body' : json.dumps({ 'status' : 'ok' })
}
def process_event ( webhook_event ):
event_type = webhook_event[ 'name' ]
channel = webhook_event[ 'channel' ]
if event_type == 'channel_occupied' :
print ( f "Channel occupied: { channel } " )
elif event_type == 'channel_vacated' :
print ( f "Channel vacated: { channel } " )
Lambda Permissions
Ensure Sockudo has permission to invoke Lambda:
{
"Version" : "2012-10-17" ,
"Statement" : [
{
"Effect" : "Allow" ,
"Action" : "lambda:InvokeFunction" ,
"Resource" : "arn:aws:lambda:us-east-1:123456789:function:my-webhook"
}
]
}
Retry Logic
Webhooks include automatic retry with exponential backoff:
Retry Configuration
Max retries: 3
Backoff: exponential
Initial delay: 1 second
Max delay: 60 seconds
Retry Behavior
Attempt 1: Immediate
Attempt 2: Wait 1 second, retry
Attempt 3: Wait 2 seconds, retry
Attempt 4: Wait 4 seconds, retry
Failed: Log error, give up
Retryable Errors
Status Code Retry? Reason 429 (Too Many Requests)✅ Yes Temporary rate limit 500 (Internal Server Error)✅ Yes Temporary server issue 502 (Bad Gateway)✅ Yes Temporary proxy issue 503 (Service Unavailable)✅ Yes Temporary unavailability 504 (Gateway Timeout)✅ Yes Temporary timeout 400 (Bad Request)❌ No Invalid payload 401 (Unauthorized)❌ No Authentication failed 404 (Not Found)❌ No Endpoint doesn’t exist
Use Cases
1. Channel Activity Tracking
Problem: Need to track when channels become active/inactive
Solution:
{
"webhooks" : [
{
"url" : "https://analytics.example.com/channel-activity" ,
"event_types" : [ "channel_occupied" , "channel_vacated" ]
}
]
}
Webhook Handler:
app . post ( '/channel-activity' , ( req , res ) => {
const { name , channel , time_ms } = req . body ;
if ( name === 'channel_occupied' ) {
// Track channel becoming active
analytics . track ( 'channel_active' , { channel , time_ms });
} else if ( name === 'channel_vacated' ) {
// Track channel becoming inactive
analytics . track ( 'channel_inactive' , { channel , time_ms });
}
res . status ( 200 ). send ( 'OK' );
});
2. Presence Tracking
Problem: Need to track users joining/leaving presence channels
Solution:
{
"webhooks" : [
{
"url" : "https://presence.example.com/updates" ,
"event_types" : [ "member_added" , "member_removed" ]
}
]
}
Webhook Handler:
app . post ( '/updates' , ( req , res ) => {
const { name , channel , user_id } = req . body ;
if ( name === 'member_added' ) {
// Update presence database
db . query (
'INSERT INTO presence (channel, user_id, joined_at) VALUES (?, ?, NOW())' ,
[ channel , user_id ]
);
} else if ( name === 'member_removed' ) {
// Remove from presence database
db . query (
'DELETE FROM presence WHERE channel = ? AND user_id = ?' ,
[ channel , user_id ]
);
}
res . status ( 200 ). send ( 'OK' );
});
3. Real-Time Analytics
Problem: Need to aggregate real-time events for dashboards
Solution:
{
"webhooks" : {
"batching" : {
"enabled" : true ,
"duration" : 1000 , // 1 second
"size" : 100
}
}
}
Webhook Handler:
app . post ( '/analytics' , ( req , res ) => {
const { events } = req . body ;
// Batch process events
const stats = {
channel_occupied: 0 ,
channel_vacated: 0 ,
member_added: 0 ,
member_removed: 0
};
events . forEach ( event => {
stats [ event . name ] ++ ;
});
// Send to analytics service
analytics . sendBatch ( stats );
res . status ( 200 ). send ( 'OK' );
});
4. Lambda Processing
Problem: Need serverless event processing
Solution:
{
"webhooks" : [
{
"url" : "lambda://arn:aws:lambda:us-east-1:123:function:process-events" ,
"event_types" : [ "channel_occupied" , "member_added" ]
}
]
}
Result: Events processed serverlessly, no dedicated infrastructure
Best Practices
1. Enable Batching for High Volume
For high-traffic applications, always enable batching:
{
"webhooks" : {
"batching" : {
"enabled" : true ,
"duration" : 50 ,
"size" : 50
}
}
}
2. Use Appropriate Batch Size
Small batch (10-20): Low latency, more HTTP requests
Medium batch (50-100): Balanced latency and efficiency
Large batch (100+): Maximum efficiency, higher latency
3. Secure Webhook Endpoints
Verify webhook requests:
const crypto = require ( 'crypto' );
function verifyWebhook ( req , secret ) {
const signature = req . headers [ 'x-sockudo-signature' ];
const body = JSON . stringify ( req . body );
const expected = crypto
. createHmac ( 'sha256' , secret )
. update ( body )
. digest ( 'hex' );
return signature === expected ;
}
app . post ( '/webhook' , ( req , res ) => {
if ( ! verifyWebhook ( req , process . env . WEBHOOK_SECRET )) {
return res . status ( 401 ). send ( 'Invalid signature' );
}
// Process webhook
res . status ( 200 ). send ( 'OK' );
});
4. Handle Retries Idempotently
Webhooks may be delivered multiple times:
app . post ( '/webhook' , async ( req , res ) => {
const { name , channel , time_ms } = req . body ;
// Use time_ms as idempotency key
const key = `webhook: ${ channel } : ${ time_ms } ` ;
// Check if already processed
if ( await cache . exists ( key )) {
return res . status ( 200 ). send ( 'Already processed' );
}
// Process event
await processEvent ( req . body );
// Mark as processed (TTL: 24 hours)
await cache . set ( key , '1' , 86400 );
res . status ( 200 ). send ( 'OK' );
});
5. Monitor Webhook Health
Track webhook delivery success/failure:
app . post ( '/webhook' , async ( req , res ) => {
try {
await processEvent ( req . body );
metrics . increment ( 'webhook.success' );
res . status ( 200 ). send ( 'OK' );
} catch ( error ) {
metrics . increment ( 'webhook.error' );
console . error ( 'Webhook error:' , error );
res . status ( 500 ). send ( 'Error' );
}
});
Troubleshooting
Webhooks Not Being Sent
Check 1: Are webhooks configured?
grep -A 10 "webhooks" config/config.json
Check 2: Are event types correct?
{
"event_types" : [ "channel_occupied" ] // Check spelling
}
Check 3: Check Sockudo logs
grep "webhook" sockudo.log
Webhook Endpoint Not Receiving Events
Check 1: Is endpoint accessible?
curl -X POST https://example.com/webhook \
-H "Content-Type: application/json" \
-d '{"test": true}'
Check 2: Check firewall rules
Check 3: Verify SSL certificate (if HTTPS)
High Webhook Latency
Symptom: Webhooks taking seconds to arrive
Solution 1: Reduce batch duration
{
"webhooks" : {
"batching" : {
"duration" : 10 // Reduce from 50ms
}
}
}
Solution 2: Disable batching for low-traffic apps
{
"webhooks" : {
"batching" : {
"enabled" : false
}
}
}
Lambda Invocation Failures
Check 1: Lambda ARN correct?
{
"url" : "lambda://arn:aws:lambda:us-east-1:123456789:function:name"
}
Check 2: IAM permissions configured?
aws lambda get-policy --function-name my-webhook
Check 3: Lambda timeout sufficient?
aws lambda update-function-configuration \
--function-name my-webhook \
--timeout 30
Next Steps
Presence Channels Track online users with presence channels
Delta Compression Reduce bandwidth usage by 60-90%