Referensi Tipe Event
Referensi menyeluruh ini mencakup semua tipe event webhook yang tersedia di Brevo, disertai contoh spesifik untuk integrasi platform loyalitas Tajo.
Event email
delivered
Dipicu ketika sebuah email berhasil dikirim ke kotak surat penerima.
Contoh payload:
{ "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"}Kasus penggunaan integrasi Tajo:
- Memperbarui tingkat keberhasilan pengiriman pada profil pelanggan
- Memicu tindakan lanjutan untuk kampanye loyalitas
- Melacak performa pengiriman email berdasarkan tingkatan
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
Dipicu ketika penerima membuka sebuah email (dilacak melalui pemuatan piksel).
Contoh payload:
{ "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" }}Kasus penggunaan integrasi Tajo:
- Meningkatkan skor keterlibatan pelanggan
- Melacak efektivitas kampanye loyalitas
- Memicu hadiah berbasis perilaku
- Mempersonalisasi komunikasi berikutnya
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
Dipicu ketika penerima mengeklik sebuah tautan di dalam email.
Contoh payload:
{ "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"}Kasus penggunaan integrasi Tajo:
- Melacak performa corong konversi
- Memberikan bonus click-through
- Mengidentifikasi konten bernilai tinggi
- Mengoptimalkan alur dari email ke situs web
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
Dipicu ketika sebuah email mengalami bounce (kegagalan sementara) atau hard bounce (kegagalan permanen).
Contoh payload:
{ "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"}Kasus penggunaan integrasi Tajo:
- Memperbarui status validitas email
- Beralih ke saluran komunikasi alternatif
- Membersihkan basis data pelanggan
- Mencegah pengiriman berikutnya ke alamat yang tidak valid
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
Dipicu ketika penerima menandai sebuah email sebagai spam.
Contoh payload:
{ "event": "spam", "date": "2024-01-25 17:10:00", "ts": 1641005400, "template_id": 101, "tags": ["loyalty", "promotional"]}Kasus penggunaan integrasi Tajo:
- Menghentikan komunikasi email dengan segera
- Meninjau dan memperbaiki konten email
- Menganalisis pola spam berdasarkan segmen
- Menerapkan proses opt-in yang lebih ketat
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'); }}Event SMS
sms_delivered
Dipicu ketika sebuah SMS berhasil dikirim ke ponsel penerima.
Contoh payload:
{ "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."}Kasus penggunaan integrasi Tajo:
- Mengonfirmasi keberhasilan pengiriman SMS
- Melacak tingkat keterlibatan SMS
- Memvalidasi keakuratan nomor telepon
- Memantau performa pengiriman operator
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
Dipicu ketika pengiriman SMS gagal.
Contoh payload:
{ "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"}Kasus penggunaan integrasi Tajo:
- Memperbarui validitas nomor telepon
- Beralih ke notifikasi email
- Membersihkan basis data nomor telepon
- Memberi tahu layanan pelanggan untuk verifikasi manual
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
Dipicu ketika penerima membalas sebuah SMS.
Contoh payload:
{ "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"}Kasus penggunaan integrasi Tajo:
- Memproses perintah program loyalitas
- Menangani permintaan layanan pelanggan
- Memperbarui preferensi komunikasi
- Memicu balasan otomatis
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) }); }}Event kontak
contact_created
Dipicu ketika sebuah kontak baru ditambahkan ke Brevo.
Contoh payload:
{ "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]}Kasus penggunaan integrasi Tajo:
- Memicu kampanye sambutan
- Menyiapkan pendaftaran program loyalitas
- Menginisialisasi perjalanan pelanggan
- Memberikan bonus pendaftaran
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
Dipicu ketika informasi kontak diperbarui.
Contoh payload:
{ "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 }}Kasus penggunaan integrasi Tajo:
- Mendeteksi kenaikan tingkatan
- Melacak perubahan saldo poin
- Memantau kelengkapan profil
- Memicu kampanye khusus per tingkatan
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 }); }}Praktik terbaik pemrosesan event
1. Penanganan idempotensi
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. Pengurutan event
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. Pemrosesan batch
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); } }}Langkah berikutnya
- Panduan keamanan webhook - Praktik terbaik keamanan
- Menguji webhook - Pengujian dan debugging
- Analitik webhook - Pemantauan performa
- Integrasi platform - Panduan integrasi lengkap