Overview
Webhooks let you receive real-time HTTP notifications when events occur in Offergrid, enabling immediate response to new orders and status changes.
Webhook functionality may be under development. Check with support for current availability and configuration options.
How Webhooks Work
Configure endpoint : Tell Offergrid where to send notifications
Event occurs : New order, status change, etc.
Offergrid sends POST : HTTP POST to your endpoint
You respond : Process the event and return 200 OK
Retry on failure : Offergrid retries if your endpoint is down
Webhook Events
Provider Events
order.created
New order received from reseller
Includes order ID and item ID
Action: Review and accept/reject
order.cancelled
Reseller cancelled an order
Includes order ID and reason
Action: Stop fulfillment if in progress
offer.ordered (Future)
One of your offers was ordered
Includes offer ID and order details
Setting Up Webhooks
Configuration process may vary. Contact support for current webhook setup instructions.
Step 1: Create an Endpoint
Build an HTTPS endpoint to receive webhooks:
import express from 'express' ;
const app = express ();
app . use ( express . json ());
app . post ( '/webhooks/offergrid' , async ( req , res ) => {
const { event , data } = req . body ;
try {
// Verify webhook signature (recommended)
if ( ! verifySignature ( req )) {
return res . status ( 401 ). send ( 'Invalid signature' );
}
// Process the event
await handleWebhook ( event , data );
// Always respond quickly
res . status ( 200 ). send ( 'OK' );
} catch ( error ) {
console . error ( 'Webhook error:' , error );
res . status ( 500 ). send ( 'Internal error' );
}
});
async function handleWebhook ( event , data ) {
switch ( event ) {
case 'order.created' :
await processNewOrder ( data . itemId );
break ;
case 'order.cancelled' :
await handleOrderCancellation ( data . orderId );
break ;
default :
console . log ( `Unhandled event: ${ event } ` );
}
}
Go to Settings → Webhooks
Click Add Webhook Endpoint
Enter your endpoint URL
Select which events to receive
Save the webhook secret for signature verification
Step 3: Test the Connection
Send a test event to verify your endpoint works:
Click Send Test Event in dashboard
Check your endpoint received the event
Verify signature validation works
Confirm proper error handling
Webhook Payload Structure
All webhooks follow this structure:
{
"id" : "evt_abc123" ,
"event" : "order.created" ,
"timestamp" : "2025-01-02T10:00:00Z" ,
"data" : {
// Event-specific data
}
}
order.created Payload
{
"id" : "evt_abc123" ,
"event" : "order.created" ,
"timestamp" : "2025-01-02T10:00:00Z" ,
"data" : {
"orderId" : "ord-123-abc" ,
"itemId" : "item-456-def" ,
"offerId" : "off-789-ghi" ,
"offerName" : "High-Speed Internet 1000 Mbps" ,
"resellerTeamId" : "team-xyz-789" ,
"serviceAddress" : {
"street" : "123 Main St" ,
"city" : "San Francisco" ,
"state" : "CA" ,
"zipCode" : "94102"
}
}
}
order.cancelled Payload
{
"id" : "evt_def456" ,
"event" : "order.cancelled" ,
"timestamp" : "2025-01-02T11:00:00Z" ,
"data" : {
"orderId" : "ord-123-abc" ,
"itemId" : "item-456-def" ,
"reason" : "Customer changed mind" ,
"cancelledBy" : "reseller"
}
}
Verifying Webhook Signatures
Always verify webhooks are from Offergrid:
import crypto from 'crypto' ;
function verifySignature ( req : Request ) : boolean {
const signature = req . headers [ 'x-offergrid-signature' ] as string ;
const timestamp = req . headers [ 'x-offergrid-timestamp' ] as string ;
const payload = JSON . stringify ( req . body );
// Reconstruct the signed payload
const signedPayload = ` ${ timestamp } . ${ payload } ` ;
// Compute expected signature
const expectedSignature = crypto
. createHmac ( 'sha256' , process . env . WEBHOOK_SECRET ! )
. update ( signedPayload )
. digest ( 'hex' );
// Compare signatures (timing-safe comparison)
return crypto . timingSafeEqual (
Buffer . from ( signature ),
Buffer . from ( expectedSignature )
);
}
Always verify signatures in production! This prevents attackers from sending fake webhooks to your endpoint.
Handling Webhooks
Respond Quickly
Return 200 OK within 5 seconds:
// ✅ Good - Respond immediately, process async
app . post ( '/webhooks/offergrid' , async ( req , res ) => {
const { event , data } = req . body ;
// Verify signature
if ( ! verifySignature ( req )) {
return res . status ( 401 ). send ( 'Invalid signature' );
}
// Queue for processing
await enqueueWebhook ( event , data );
// Respond immediately
res . status ( 200 ). send ( 'OK' );
});
// Process in background
async function enqueueWebhook ( event , data ) {
await queue . add ( 'process-webhook' , { event , data });
}
// ❌ Bad - Slow processing blocks response
app . post ( '/webhooks/offergrid' , async ( req , res ) => {
const { event , data } = req . body ;
// This might take 30 seconds!
await processNewOrder ( data . itemId );
await updateDatabase ();
await sendEmails ();
res . status ( 200 ). send ( 'OK' ); // Too slow!
});
Handle Duplicates
You might receive the same webhook multiple times:
async function handleWebhook ( event , data ) {
const eventId = data . eventId || generateEventId ( event , data );
// Check if already processed
const exists = await db . events . exists ( eventId );
if ( exists ) {
console . log ( `Event ${ eventId } already processed` );
return ;
}
// Process the event
await processEvent ( event , data );
// Mark as processed
await db . events . create ({ id: eventId , processedAt: new Date () });
}
Implement Retry Logic
Handle temporary failures gracefully:
async function processWebhookEvent ( event , data ) {
const maxRetries = 3 ;
for ( let attempt = 1 ; attempt <= maxRetries ; attempt ++ ) {
try {
await processEvent ( event , data );
return ; // Success!
} catch ( error ) {
if ( attempt === maxRetries ) {
// Failed all retries - log and alert
await logFailedWebhook ( event , data , error );
await alertOps ( 'Webhook processing failed' , { event , error });
throw error ;
}
// Wait before retry (exponential backoff)
await sleep ( 2 ** attempt * 1000 );
}
}
}
Testing Webhooks Locally
Use ngrok for Local Development
# Install ngrok
npm install -g ngrok
# Start your local server
npm run dev # Runs on localhost:3000
# Expose locally with ngrok
ngrok http 3000
# Use the ngrok URL in Offergrid webhook config
# https://abc123.ngrok.io/webhooks/offergrid
Send Test Events
# Manually send test events to your endpoint
curl -X POST http://localhost:3000/webhooks/offergrid \
-H "Content-Type: application/json" \
-H "x-offergrid-signature: test-signature" \
-H "x-offergrid-timestamp: $( date +%s)" \
-d '{
"id": "evt_test_123",
"event": "order.created",
"timestamp": "2025-01-02T10:00:00Z",
"data": {
"orderId": "ord-test-123",
"itemId": "item-test-456",
"offerId": "off-test-789"
}
}'
Monitoring Webhooks
Log All Events
async function handleWebhook ( event , data ) {
const startTime = Date . now ();
try {
await processEvent ( event , data );
logger . info ( 'Webhook processed successfully' , {
event ,
eventId: data . eventId ,
duration: Date . now () - startTime ,
});
} catch ( error ) {
logger . error ( 'Webhook processing failed' , {
event ,
eventId: data . eventId ,
error: error . message ,
duration: Date . now () - startTime ,
});
throw error ;
}
}
Track Metrics
Monitor:
Delivery rate : % of webhooks successfully received
Processing time : How long processing takes
Error rate : % of webhooks that fail processing
Retry rate : % of webhooks that need retries
Webhook Best Practices
Never process webhooks without verifying the signature. This prevents fake events.
Return 200 OK quickly. Process the event asynchronously in a background job.
Use idempotency keys to prevent processing the same event twice.
Handle temporary failures with exponential backoff. Alert on repeated failures.
Log all webhook events for debugging and auditing. Include timestamps and durations.
Track delivery rates, error rates, and processing times. Alert on anomalies.
Troubleshooting
Webhooks Not Arriving
Check endpoint URL : Ensure URL is correct and publicly accessible
Verify HTTPS : Endpoint must use HTTPS (not HTTP)
Check firewall : Ensure your firewall allows incoming requests
Review webhook settings : Confirm webhook is enabled for the event type
Signature Verification Fails
Check webhook secret : Ensure using correct secret from dashboard
Verify timestamp : Check x-offergrid-timestamp header exists
Payload format : Ensure payload is parsed as raw JSON string
Webhooks Timing Out
Respond faster : Return 200 OK before processing
Use async processing : Queue events for background processing
Optimize database : Ensure database queries are fast
Scale horizontally : Add more webhook processing workers
Next Steps