Event Types Reference
This comprehensive reference covers all webhook event types available in Brevo, with specific examples for Tajo loyalty platform integration.
Email Events
delivered
Triggered when an email is successfully delivered to the recipient’s mailbox.
Payload Example:
{ "event": "delivered", "id": 123456, "date": "2024-01-25 14:30:00", "ts": 1640995200, "template_id": 101, "tags": ["loyalty", "points-earned"], "sending_ip": "185.107.232.1", "event_id": "evt_abc123"}Tajo Integration Use Cases:
- Update delivery success rate in customer profiles
- Trigger follow-up actions for loyalty campaigns
- Track email delivery performance by tier
async function handleEmailDelivered(event) { const customer = await loyaltyService.getCustomer(event.email);
// Update delivery stats await loyaltyService.updateEngagement(event.email, { emailsDelivered: customer.emailsDelivered + 1, lastEmailDelivered: new Date(event.date), deliveryRate: calculateDeliveryRate(customer) });
// Track loyalty campaign delivery if (event.tags.includes('loyalty')) { await loyaltyService.trackCampaignMetric('loyalty_email_delivered', { email: event.email, template_id: event.template_id, tier: customer.loyaltyTier }); }}opened
Triggered when a recipient opens an email (tracks pixel loading).
Payload Example:
{ "event": "opened", "date": "2024-01-25 15:45:00", "ts": 1641000300, "template_id": 101, "tags": ["loyalty", "tier-upgrade"], "user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X)", "geo": { "country": "US", "region": "CA", "city": "San Francisco" }}Tajo Integration Use Cases:
- Boost customer engagement scores
- Track loyalty campaign effectiveness
- Trigger behavior-based rewards
- Personalize future communications
async function handleEmailOpened(event) { const customer = await loyaltyService.getCustomer(event.email);
// Significant engagement - boost score await loyaltyService.updateEngagement(event.email, { emailsOpened: customer.emailsOpened + 1, lastEmailOpened: new Date(event.date), engagementScore: customer.engagementScore + 5, preferredDevice: getDeviceType(event['user-agent']) });
// Reward engagement for loyalty members if (event.tags.includes('loyalty') && customer.loyaltyTier) { await loyaltyService.awardEngagementBonus(event.email, { type: 'email_engagement', points: getEngagementPoints(customer.loyaltyTier), reason: 'Email opened' }); }
// Track timing patterns for optimization await loyaltyService.recordEngagementTime(event.email, { campaign: event.template_id, openTime: new Date(event.date), timezone: getTimezone(event.geo) });}clicked
Triggered when a recipient clicks on a link in an email.
Payload Example:
{ "event": "clicked", "date": "2024-01-25 16:20:00", "ts": 1641002400, "template_id": 101, "tags": ["loyalty", "rewards-reminder"], "link": "https://yourdomain.com/rewards?utm_source=brevo&utm_campaign=loyalty", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}Tajo Integration Use Cases:
- Track conversion funnel performance
- Award click-through bonuses
- Identify high-value content
- Optimize email-to-website flow
async function handleEmailClicked(event) { const customer = await loyaltyService.getCustomer(event.email); const clickedUrl = new URL(event.link);
// High-value engagement await loyaltyService.updateEngagement(event.email, { emailsClicked: customer.emailsClicked + 1, lastEmailClicked: new Date(event.date), engagementScore: customer.engagementScore + 15, clickThroughRate: calculateCTR(customer) });
// Track specific link types if (clickedUrl.pathname.includes('/rewards')) { await loyaltyService.trackEvent(event.email, 'Rewards Page Clicked', { source: 'email', campaign: event.template_id, utm_campaign: clickedUrl.searchParams.get('utm_campaign') });
// Award exploration bonus await loyaltyService.awardEngagementBonus(event.email, { type: 'rewards_exploration', points: 10, reason: 'Clicked rewards link' }); }
// Track product interest if (clickedUrl.pathname.includes('/products')) { const productId = extractProductId(clickedUrl); await loyaltyService.trackProductInterest(event.email, productId, { source: 'email_click', timestamp: new Date(event.date) }); }}bounced / hard_bounced
Triggered when an email bounces (temporary failure) or hard bounces (permanent failure).
Payload Example:
{ "event": "hard_bounced", "date": "2024-01-25 14:35:00", "ts": 1640995500, "template_id": 101, "tags": ["loyalty"], "reason": "550 5.1.1 User unknown", "bounce_type": "hard"}Tajo Integration Use Cases:
- Update email validity status
- Switch to alternative communication channels
- Clean customer database
- Prevent further sending to invalid addresses
async function handleEmailBounced(event) { const isHardBounce = event.event === 'hard_bounced' || event.bounce_type === 'hard';
if (isHardBounce) { // Permanent failure - mark email as invalid await loyaltyService.updateCustomerStatus(event.email, { emailStatus: 'invalid', emailBounced: true, bounceReason: event.reason, lastBounce: new Date(event.date), communicationPreference: 'sms' // Switch to SMS if available });
// Remove from email marketing lists await loyaltyService.removeFromEmailMarketing(event.email);
// Suggest phone verification const customer = await loyaltyService.getCustomer(event.email); if (customer?.phone) { await loyaltyService.suggestPhoneVerification(customer.phone); }
} else { // Soft bounce - temporary issue await loyaltyService.updateEngagement(event.email, { softBounceCount: customer.softBounceCount + 1, lastSoftBounce: new Date(event.date) });
// Retry logic for soft bounces if (customer.softBounceCount < 5) { await loyaltyService.scheduleEmailRetry(event.email, event.template_id); } }}spam
Triggered when a recipient marks an email as spam.
Payload Example:
{ "event": "spam", "date": "2024-01-25 17:10:00", "ts": 1641005400, "template_id": 101, "tags": ["loyalty", "promotional"]}Tajo Integration Use Cases:
- Immediately stop email communications
- Review and improve email content
- Analyze spam patterns by segment
- Implement stricter opt-in processes
async function handleEmailSpam(event) { // Immediately disable email marketing await loyaltyService.updateCustomerPreferences(event.email, { emailMarketing: false, marketingEnabled: false, spamReported: true, spamReportDate: new Date(event.date) });
// Alert marketing team for review await loyaltyService.alertMarketing('spam_complaint', { email: event.email, template: event.template_id, campaign_tags: event.tags, severity: 'high' });
// Analyze spam patterns await loyaltyService.analyzeSpamPattern({ template_id: event.template_id, tags: event.tags, customer_segment: await loyaltyService.getCustomerSegment(event.email) });
// Consider account review if multiple spam reports const customer = await loyaltyService.getCustomer(event.email); if (customer.spamReports > 2) { await loyaltyService.flagForReview(event.email, 'multiple_spam_reports'); }}SMS Events
sms_delivered
Triggered when an SMS is successfully delivered to the recipient’s phone.
Payload Example:
{ "event": "sms_delivered", "phone": "+1234567890", "date": "2024-01-25 14:45:00", "ts": 1640996700, "message-id": "sms_abc123", "tags": ["loyalty", "points-alert"], "sender": "TAJO", "content": "🎉 Great news! You earned 150 points from your recent purchase. Total: 1,250 points."}Tajo Integration Use Cases:
- Confirm successful SMS delivery
- Track SMS engagement rates
- Validate phone number accuracy
- Monitor carrier delivery performance
async function handleSMSDelivered(event) { const customer = await loyaltyService.getCustomerByPhone(event.phone);
await loyaltyService.updateEngagement(customer.email, { smsDelivered: customer.smsDelivered + 1, lastSMSDelivered: new Date(event.date), smsDeliveryRate: calculateSMSDeliveryRate(customer), phoneStatus: 'valid' });
// Track loyalty SMS performance if (event.tags.includes('loyalty')) { await loyaltyService.trackCampaignMetric('loyalty_sms_delivered', { phone: event.phone, content_type: getSMSContentType(event.content), customer_tier: customer.loyaltyTier }); }}sms_failed
Triggered when SMS delivery fails.
Payload Example:
{ "event": "sms_failed", "phone": "+1234567890", "date": "2024-01-25 14:32:00", "ts": 1640996320, "message-id": "sms_def456", "tags": ["loyalty", "urgent"], "sender": "TAJO", "reason": "Invalid phone number format", "error_code": "30006"}Tajo Integration Use Cases:
- Update phone number validity
- Switch to email notifications
- Clean phone number database
- Alert customer service for manual verification
async function handleSMSFailed(event) { const customer = await loyaltyService.getCustomerByPhone(event.phone);
await loyaltyService.updateCustomerStatus(customer.email, { phoneStatus: 'invalid', smsEnabled: false, smsFailureReason: event.reason, lastSMSFailure: new Date(event.date), communicationPreference: 'email' });
// For urgent loyalty notifications, fall back to email if (event.tags.includes('urgent') || event.tags.includes('loyalty')) { await loyaltyService.sendEmailFallback(customer.email, { originalSMS: event.content, reason: 'SMS delivery failed' }); }
// Flag for phone number verification await loyaltyService.flagForPhoneVerification(customer.email);}sms_reply
Triggered when a recipient replies to an SMS.
Payload Example:
{ "event": "sms_reply", "phone": "+1234567890", "date": "2024-01-25 15:20:00", "ts": 1641000000, "message-id": "sms_reply_123", "text": "BALANCE", "original_message_id": "sms_abc123"}Tajo Integration Use Cases:
- Process loyalty program commands
- Handle customer service requests
- Update communication preferences
- Trigger automated responses
async function handleSMSReply(event) { const customer = await loyaltyService.getCustomerByPhone(event.phone); const replyText = event.text.toUpperCase().trim();
// High engagement - customer actively participating await loyaltyService.updateEngagement(customer.email, { smsReplies: customer.smsReplies + 1, lastSMSReply: new Date(event.date), engagementScore: customer.engagementScore + 10 });
// Process loyalty commands switch (replyText) { case 'BALANCE': await loyaltyService.sendPointsBalance(event.phone); break;
case 'REWARDS': await loyaltyService.sendAvailableRewards(event.phone, customer.loyaltyTier); break;
case 'TIER': await loyaltyService.sendTierInfo(event.phone, customer); break;
case 'HELP': await loyaltyService.sendSMSHelp(event.phone); break;
case 'STOP': case 'UNSUBSCRIBE': await loyaltyService.unsubscribeFromSMS(event.phone); break;
default: // Forward to customer service await loyaltyService.forwardToSupport(customer.email, { channel: 'sms', message: event.text, timestamp: new Date(event.date) }); }}Contact Events
contact_created
Triggered when a new contact is added to Brevo.
Payload Example:
{ "event": "contact_created", "date": "2024-01-25 13:15:00", "ts": 1640992500, "attributes": { "FIRSTNAME": "John", "LASTNAME": "Doe", "LOYALTY_ID": "LYL-2024-001", "LOYALTY_TIER": "Bronze", "LOYALTY_POINTS": 0 }, "lists": [1, 5]}Tajo Integration Use Cases:
- Trigger welcome campaigns
- Set up loyalty program enrollment
- Initialize customer journey
- Award signup bonuses
async function handleContactCreated(event) { const isLoyaltyMember = event.attributes?.LOYALTY_ID;
if (isLoyaltyMember) { // New loyalty member - trigger welcome flow await loyaltyService.triggerWelcomeFlow(event.email, { loyaltyId: event.attributes.LOYALTY_ID, tier: event.attributes.LOYALTY_TIER || 'Bronze', signupBonus: 500 });
// Award signup bonus await loyaltyService.awardPoints(event.email, { amount: 500, reason: 'Welcome bonus', type: 'signup_bonus' });
// Schedule onboarding emails await loyaltyService.scheduleOnboardingSequence(event.email, { tier: event.attributes.LOYALTY_TIER, preferences: event.attributes }); }
// Track signup source await loyaltyService.trackSignupSource(event.email, { lists: event.lists, attributes: event.attributes, timestamp: new Date(event.date) });}contact_updated
Triggered when contact information is updated.
Payload Example:
{ "event": "contact_updated", "date": "2024-01-25 16:45:00", "ts": 1641003900, "updated_attributes": { "LOYALTY_POINTS": 1250, "LOYALTY_TIER": "Silver", "TOTAL_SPENT": 899.99 }, "previous_attributes": { "LOYALTY_POINTS": 750, "LOYALTY_TIER": "Bronze", "TOTAL_SPENT": 549.99 }}Tajo Integration Use Cases:
- Detect tier upgrades
- Track point balance changes
- Monitor profile completeness
- Trigger tier-specific campaigns
async function handleContactUpdated(event) { const updated = event.updated_attributes; const previous = event.previous_attributes;
// Check for tier upgrade if (updated.LOYALTY_TIER && updated.LOYALTY_TIER !== previous.LOYALTY_TIER) { await loyaltyService.handleTierUpgrade(event.email, { previousTier: previous.LOYALTY_TIER, newTier: updated.LOYALTY_TIER, pointsBalance: updated.LOYALTY_POINTS });
// Send congratulations await loyaltyService.sendTierUpgradeEmail(event.email, { newTier: updated.LOYALTY_TIER, benefits: loyaltyService.getTierBenefits(updated.LOYALTY_TIER) }); }
// Track significant point increases const pointIncrease = updated.LOYALTY_POINTS - previous.LOYALTY_POINTS; if (pointIncrease > 0) { await loyaltyService.trackPointsEarned(event.email, { amount: pointIncrease, newTotal: updated.LOYALTY_POINTS, source: 'profile_update' }); }
// Monitor spending milestones if (updated.TOTAL_SPENT > previous.TOTAL_SPENT) { await loyaltyService.checkSpendingMilestones(event.email, { currentSpend: updated.TOTAL_SPENT, previousSpend: previous.TOTAL_SPENT }); }}Event Processing Best Practices
1. Idempotency Handling
class WebhookProcessor { constructor() { this.processedEvents = new Set(); }
async processEvent(event) { const eventKey = `${event.event}_${event.email}_${event.ts}`;
if (this.processedEvents.has(eventKey)) { console.log('Duplicate event ignored:', eventKey); return; }
this.processedEvents.add(eventKey);
try { await this.handleEvent(event); } catch (error) { this.processedEvents.delete(eventKey); // Allow retry throw error; } }}2. Event Sequencing
async function processEventInSequence(event) { const customer = await loyaltyService.getCustomer(event.email); const lastProcessedTime = customer.lastWebhookProcessed || 0;
// Ensure events are processed in chronological order if (event.ts < lastProcessedTime) { console.warn('Out-of-order event received, queuing for later processing'); await loyaltyService.queueEventForLaterProcessing(event); return; }
await handleWebhookEvent(event);
// Update last processed timestamp await loyaltyService.updateCustomer(event.email, { lastWebhookProcessed: event.ts });}3. Batch Processing
class BatchEventProcessor { constructor() { this.eventBatch = []; this.batchSize = 100; this.flushInterval = 5000; // 5 seconds
setInterval(() => this.flushBatch(), this.flushInterval); }
addEvent(event) { this.eventBatch.push(event);
if (this.eventBatch.length >= this.batchSize) { this.flushBatch(); } }
async flushBatch() { if (this.eventBatch.length === 0) return;
const batch = this.eventBatch.splice(0);
try { await loyaltyService.processBatchEvents(batch); } catch (error) { console.error('Batch processing failed:', error); // Re-queue failed events this.eventBatch.unshift(...batch); } }}Next Steps
- Webhook Security Guide - Security best practices
- Testing Webhooks - Testing and debugging
- Webhook Analytics - Performance monitoring
- Platform Integration - Complete integration guide