Webhooks
Webhooks notify your server when things happen in Loyali. React to events in real-time to power notifications, fulfillment, and integrations.
Why Webhooks?
Polling vs Webhooks
| Approach | How It Works | Drawback |
|---|---|---|
| Polling | You ask "anything new?" every X seconds | Wasteful, delayed |
| Webhooks | We tell you the moment something happens | Real-time, efficient |
Real-Time Reactions
When a customer earns points, you can immediately:
- Send a push notification
- Update their profile in your app
- Trigger a celebratory animation
- Log to your analytics platform
Available Webhook Events
Customer Events
| Event | When It Fires |
|---|---|
customer.created | New customer added to your program |
customer.updated | Customer profile changed |
Points Events
| Event | When It Fires |
|---|---|
points.earned | Points awarded (from event or direct) |
points.redeemed | Points spent on a reward |
points.expired | Points expired due to inactivity |
points.adjusted | Manual points adjustment |
Tier Events
| Event | When It Fires |
|---|---|
tier.upgraded | Customer moved UP a tier |
tier.downgraded | Customer moved DOWN a tier |
Redemption Events
| Event | When It Fires |
|---|---|
redemption.created | Customer redeemed a reward |
redemption.pending | Redemption awaiting approval |
redemption.approved | Redemption approved |
redemption.fulfilled | Redemption delivered |
redemption.rejected | Redemption rejected |
redemption.cancelled | Redemption cancelled, points refunded |
Achievement Events
| Event | When It Fires |
|---|---|
achievement.earned | Customer earned an achievement badge |
Webhook Payload Structure
Every webhook delivers a consistent structure:
{
"id": "whd_xyz789",
"event_type": "tier.upgraded",
"created_at": "2024-01-20T14:30:00Z",
"data": {
// Event-specific data
}
}
Example Payloads
Tier Upgrade:
{
"event_type": "tier.upgraded",
"data": {
"customer_id": "cust_abc123",
"customer_email": "alex@example.com",
"previous_tier": { "name": "Silver", "id": "tier_silver" },
"new_tier": { "name": "Gold", "id": "tier_gold" }
}
}
Points Earned:
{
"event_type": "points.earned",
"data": {
"customer_id": "cust_abc123",
"amount": 150,
"new_balance": 2350,
"reason": "Purchase - Order #12345"
}
}
Redemption Created:
{
"event_type": "redemption.created",
"data": {
"redemption_id": "red_xyz789",
"customer_id": "cust_abc123",
"reward": { "title": "$25 Gift Card", "type": "digital" },
"points_spent": 2500,
"status": "pending"
}
}
Use Cases
Send Notifications
| Webhook | Notification |
|---|---|
points.earned | "You just earned 150 points! 🎉" |
tier.upgraded | "Congratulations! You're now Gold! ⭐" |
redemption.fulfilled | "Your reward is on its way! 📦" |
Trigger Fulfillment
When redemption.created fires:
- Check reward type (digital vs physical)
- Digital → Send gift card code immediately
- Physical → Create order in fulfillment system
- Update redemption status via API
Sync to Your System
Keep your user database in sync:
| Webhook | Action |
|---|---|
customer.created | Add loyalty data to user profile |
tier.upgraded | Update user's tier badge |
points.earned | Update cached balance |
Analytics & Reporting
Log all webhooks to your analytics platform:
- Track engagement patterns
- Build custom reports
- Feed machine learning models
- Audit trail of all activity
Security: Signature Verification
Always verify webhook signatures. This ensures the webhook came from Loyali, not an attacker.
How It Works
Every webhook includes a signature header:
X-Loyali-Signature: t=1705766400,v1=5257a869e7ece...
This contains:
t— Timestamp when we sent itv1— HMAC-SHA256 signature
Verification Steps
- Extract timestamp and signature from header
- Reject if timestamp is too old (prevents replay attacks)
- Compute expected signature using your webhook secret
- Compare computed signature with received signature
- If they match → Process the webhook
- If they don't → Reject with 401
Why This Matters
Without verification, anyone could send fake webhooks to your endpoint:
- Fake tier upgrades
- Fake redemptions
- Data manipulation
Never skip signature verification in production.
Retry Policy
If your endpoint fails, we retry with exponential backoff:
| Attempt | Delay | Total Time |
|---|---|---|
| 1 | Immediate | 0 |
| 2 | 1 minute | 1 min |
| 3 | 5 minutes | 6 min |
| 4 | 30 minutes | 36 min |
| 5 | 2 hours | ~2.5 hours |
After 5 Failures
- Webhook marked as failed
- Visible in Dashboard
- Can manually resend
- Consider adding monitoring/alerts
Best Practices for Reliability
- Return 200 quickly (process async if needed)
- Implement idempotency (handle duplicate deliveries)
- Use a queue for heavy processing
- Monitor your endpoint uptime
Delivery Monitoring
What to Track
| Metric | Healthy Range |
|---|---|
| Success rate | > 99% |
| Latency | < 500ms response |
| Retry rate | < 5% |
| Failed deliveries | 0 |
In the Dashboard
View delivery logs for each webhook:
- ✅ Successful deliveries
- ⚠️ Retries and eventual success
- ❌ Failed deliveries with error details
- Response codes and timing
Testing Webhooks
During Development
- Use a tool like ngrok to expose localhost
- Register your ngrok URL as webhook endpoint
- Trigger actions in test mode
- See webhooks arrive in real-time
In Dashboard
Click Test on any webhook to send a sample payload with realistic data.
Staging Environment
Before going live:
- Set up webhooks in your staging environment
- Run through full customer journeys
- Verify all handlers work correctly
- Check signature verification
Common Mistakes
❌ Don't Do This
| Mistake | Problem | Better Approach |
|---|---|---|
| No signature verification | Security vulnerability | Always verify |
| Slow processing | Timeouts, retries | Return 200 fast, process async |
| No idempotency | Duplicate actions | Track processed webhook IDs |
| Ignoring failures | Missing critical events | Monitor and alert |
| HTTP (not HTTPS) | Man-in-the-middle attacks | Always use HTTPS |
Dashboard vs API
| Task | Dashboard | API |
|---|---|---|
| Create webhooks | ✅ Visual setup | ✅ POST endpoint |
| Update events | ✅ Checkbox list | ✅ PATCH endpoint |
| View delivery logs | ✅ Built-in viewer | ✅ GET deliveries |
| Test webhooks | ✅ Test button | ❌ |
| Resend failed | ✅ Retry button | ✅ Retry endpoint |
Next Steps
- API Reference → — Full technical documentation for webhook endpoints
- Events Guide — Understand event-driven architecture
- Quick Start — Get integrated fast