JavaScript SDK
SDK JavaScript chính thức mang lại cách thuận tiện để làm việc với API của Brevo từ các ứng dụng Node.js và môi trường trình duyệt của bạn.
Cài đặt
# Using npmnpm install @getbrevo/brevo
# Using yarnyarn add @getbrevo/brevo
# Using pnpmpnpm add @getbrevo/brevoBắt đầu nhanh
Khởi tạo SDK
import { ApiClient, TransactionalEmailsApi, ContactsApi, EventsApi } from '@getbrevo/brevo';
// Configure API clientconst defaultClient = ApiClient.instance;const apiKey = defaultClient.authentications['api-key'];apiKey.apiKey = 'your-brevo-api-key';
// Initialize API instancesconst emailApi = new TransactionalEmailsApi();const contactsApi = new ContactsApi();const eventsApi = new EventsApi();Cấu hình môi trường
// .env fileBREVO_API_KEY=xkeysib-your-api-key-hereBREVO_API_URL=https://api.brevo.com/v3TAJO_WEBHOOK_SECRET=your-webhook-secret
// config.jsexport const brevoConfig = { apiKey: process.env.BREVO_API_KEY, apiUrl: process.env.BREVO_API_URL || 'https://api.brevo.com/v3', webhookSecret: process.env.TAJO_WEBHOOK_SECRET};Tính năng cốt lõi
1. Quản lý khách hàng
class TajoCustomerService { constructor() { this.contactsApi = new ContactsApi(); }
// Create new loyalty customer async createCustomer(customerData) { const createContact = { email: customerData.email, attributes: { FIRSTNAME: customerData.firstName, LASTNAME: customerData.lastName, PHONE: customerData.phone, LOYALTY_ID: customerData.loyaltyId, LOYALTY_POINTS: customerData.points || 0, LOYALTY_TIER: customerData.tier || 'Bronze', SIGNUP_DATE: new Date().toISOString(), TOTAL_SPENT: customerData.totalSpent || 0, PREFERRED_CATEGORIES: customerData.categories || [], BIRTHDAY: customerData.birthday, MARKETING_CONSENT: customerData.marketingConsent || true }, listIds: [this.getListForTier(customerData.tier || 'Bronze')], updateEnabled: true };
try { const response = await this.contactsApi.createContact(createContact); console.log('Customer created in Brevo:', response.id); return response; } catch (error) { console.error('Error creating customer:', error); throw error; } }
// Update customer loyalty data async updateCustomer(email, updates) { const updateContact = { attributes: updates, listIds: updates.LOYALTY_TIER ? [this.getListForTier(updates.LOYALTY_TIER)] : undefined };
try { await this.contactsApi.updateContact(email, updateContact); console.log('Customer updated:', email); } catch (error) { console.error('Error updating customer:', error); throw error; } }
// Get customer by email async getCustomer(email) { try { const response = await this.contactsApi.getContactInfo(email); return response; } catch (error) { if (error.status === 404) { return null; // Customer not found } throw error; } }
// Helper method to get list ID for tier getListForTier(tier) { const tierLists = { 'Bronze': 1, 'Silver': 2, 'Gold': 3, 'Platinum': 4 }; return tierLists[tier] || 1; }}2. Email giao dịch
class TajoEmailService { constructor() { this.emailApi = new TransactionalEmailsApi(); }
// Send loyalty points earned notification async sendPointsEarnedEmail(customerEmail, orderData) { const sendSmtpEmail = { sender: { name: "Tajo Loyalty", }, to: [{ email: customerEmail, name: orderData.customerName }], subject: `You earned ${orderData.pointsEarned} loyalty points!`, htmlContent: this.generatePointsEmailHTML(orderData), textContent: this.generatePointsEmailText(orderData), params: { customerName: orderData.customerName, pointsEarned: orderData.pointsEarned, orderNumber: orderData.orderNumber, totalPoints: orderData.totalPoints }, tags: ['loyalty', 'points-earned'] };
try { const response = await this.emailApi.sendTransacEmail(sendSmtpEmail); return response; } catch (error) { console.error('Error sending points email:', error); throw error; } }
// Send tier upgrade notification async sendTierUpgradeEmail(customerEmail, upgradeData) { const sendSmtpEmail = { templateId: this.getTierUpgradeTemplateId(upgradeData.newTier), to: [{ email: customerEmail }], params: { customerName: upgradeData.customerName, newTier: upgradeData.newTier, previousTier: upgradeData.previousTier, benefits: upgradeData.benefits, pointsBalance: upgradeData.pointsBalance }, tags: ['loyalty', 'tier-upgrade', upgradeData.newTier.toLowerCase()] };
return await this.emailApi.sendTransacEmail(sendSmtpEmail); }
// Generate HTML content for points email generatePointsEmailHTML(orderData) { return ` <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;"> <h1 style="color: #2c5aa0;">🎉 Great news, ${orderData.customerName}!</h1> <p>You've earned <strong>${orderData.pointsEarned} points</strong> from your recent purchase!</p>
<div style="background: #f8f9fa; padding: 20px; border-radius: 8px; margin: 20px 0;"> <h3>Order Details:</h3> <p><strong>Order #:</strong> ${orderData.orderNumber}</p> <p><strong>Points Earned:</strong> ${orderData.pointsEarned}</p> <p><strong>Total Points:</strong> ${orderData.totalPoints}</p> </div>
<p style="margin-top: 30px;"> <a href="https://yourdomain.com/loyalty/rewards" style="background: #2c5aa0; color: white; padding: 12px 24px; text-decoration: none; border-radius: 4px;"> View Rewards </a> </p> </div> `; }
generatePointsEmailText(orderData) { return ` Great news, ${orderData.customerName}!
You've earned ${orderData.pointsEarned} points from your recent purchase!
Order Details: - Order #: ${orderData.orderNumber} - Points Earned: ${orderData.pointsEarned} - Total Points: ${orderData.totalPoints}
View your rewards at: https://yourdomain.com/loyalty/rewards `; }}3. Theo dõi sự kiện
class TajoEventTracker { constructor() { this.eventsApi = new EventsApi(); }
// Track loyalty events async trackLoyaltyEvent(customerEmail, eventType, properties = {}) { const createEvent = { email: customerEmail, event: eventType, properties: { timestamp: new Date().toISOString(), platform: 'tajo', ...properties } };
try { const response = await this.eventsApi.createEvent(createEvent); return response; } catch (error) { console.error(`Error tracking event ${eventType}:`, error); throw error; } }
// Specific event tracking methods async trackPurchase(customerEmail, purchaseData) { return this.trackLoyaltyEvent(customerEmail, 'Purchase Completed', { order_id: purchaseData.orderId, order_total: purchaseData.total, currency: purchaseData.currency, items_count: purchaseData.itemsCount, points_earned: purchaseData.pointsEarned, loyalty_tier: purchaseData.customerTier, categories: purchaseData.categories }); }
async trackPointsRedemption(customerEmail, redemptionData) { return this.trackLoyaltyEvent(customerEmail, 'Points Redeemed', { points_used: redemptionData.pointsUsed, reward_type: redemptionData.rewardType, reward_value: redemptionData.rewardValue, remaining_points: redemptionData.remainingPoints, redemption_method: redemptionData.method }); }
async trackTierUpgrade(customerEmail, upgradeData) { return this.trackLoyaltyEvent(customerEmail, 'Tier Upgraded', { previous_tier: upgradeData.previousTier, new_tier: upgradeData.newTier, points_required: upgradeData.pointsRequired, benefits_unlocked: upgradeData.benefitsUnlocked }); }
async trackReferral(customerEmail, referralData) { return this.trackLoyaltyEvent(customerEmail, 'Referral Made', { referral_method: referralData.method, referee_email: referralData.refereeEmail, referral_bonus: referralData.bonus, referral_code: referralData.code }); }}Sử dụng nâng cao
1. Thao tác hàng loạt
class TajoBulkService { constructor() { this.contactsApi = new ContactsApi(); this.batchSize = 50; // Recommended batch size }
// Bulk customer import async importCustomers(customers) { const batches = this.createBatches(customers, this.batchSize); const results = [];
for (const batch of batches) { try { const contacts = batch.map(customer => ({ email: customer.email, attributes: { FIRSTNAME: customer.firstName, LASTNAME: customer.lastName, LOYALTY_POINTS: customer.points, LOYALTY_TIER: customer.tier, TOTAL_SPENT: customer.totalSpent } }));
const response = await this.contactsApi.importContacts({ contacts, listIds: [1], // Default list updateEnabled: true });
results.push(response); } catch (error) { console.error('Batch import error:', error); // Continue with other batches } }
return results; }
createBatches(array, batchSize) { const batches = []; for (let i = 0; i < array.length; i += batchSize) { batches.push(array.slice(i, i + batchSize)); } return batches; }}2. Xử lý lỗi và logic thử lại
class TajoApiClient { constructor() { this.maxRetries = 3; this.retryDelay = 1000; // 1 second }
async apiCallWithRetry(apiCall, retries = this.maxRetries) { try { return await apiCall(); } catch (error) { if (retries > 0 && this.isRetryableError(error)) { console.log(`Retrying API call. Attempts remaining: ${retries - 1}`); await this.delay(this.retryDelay); return this.apiCallWithRetry(apiCall, retries - 1); } throw error; } }
isRetryableError(error) { // Retry on rate limits, server errors, and network issues return error.status >= 500 || error.status === 429 || error.code === 'NETWORK_ERROR'; }
delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }}3. Xử lý webhook
import express from 'express';import crypto from 'crypto';
const app = express();
// Webhook endpoint for Brevo eventsapp.post('/webhooks/brevo', express.raw({type: 'application/json'}), (req, res) => { const signature = req.headers['x-brevo-signature']; const payload = req.body;
// Verify webhook signature if (!verifyWebhookSignature(payload, signature)) { return res.status(401).json({ error: 'Invalid signature' }); }
const event = JSON.parse(payload);
switch (event.event) { case 'delivered': handleEmailDelivered(event); break; case 'opened': handleEmailOpened(event); break; case 'clicked': handleEmailClicked(event); break; case 'bounced': handleEmailBounced(event); break; default: console.log('Unhandled event type:', event.event); }
res.status(200).json({ success: true });});
function verifyWebhookSignature(payload, signature) { const expectedSignature = crypto .createHmac('sha256', process.env.TAJO_WEBHOOK_SECRET) .update(payload) .digest('hex');
return crypto.timingSafeEqual( Buffer.from(signature, 'hex'), Buffer.from(expectedSignature, 'hex') );}
async function handleEmailOpened(event) { // Update customer engagement score const customerEmail = event.email; const campaignType = event.tags?.includes('loyalty') ? 'loyalty' : 'general';
// Track engagement in your system await updateCustomerEngagement(customerEmail, 'email_opened', { campaign_type: campaignType, subject: event.subject, timestamp: event.ts });}Kiểm thử
Kiểm thử đơn vị
import { jest } from '@jest/globals';import { TajoCustomerService } from '../src/customer-service.js';
describe('TajoCustomerService', () => { let customerService; let mockContactsApi;
beforeEach(() => { mockContactsApi = { createContact: jest.fn(), updateContact: jest.fn(), getContactInfo: jest.fn() }; customerService = new TajoCustomerService(); customerService.contactsApi = mockContactsApi; });
test('should create customer successfully', async () => { const customerData = { firstName: 'John', lastName: 'Doe', loyaltyId: 'LYL-001', tier: 'Bronze' };
mockContactsApi.createContact.mockResolvedValue({ id: 123 });
const result = await customerService.createCustomer(customerData);
expect(mockContactsApi.createContact).toHaveBeenCalledWith({ attributes: expect.objectContaining({ FIRSTNAME: 'John', LASTNAME: 'Doe', LOYALTY_ID: 'LYL-001', LOYALTY_TIER: 'Bronze' }), listIds: [1], updateEnabled: true });
expect(result.id).toBe(123); });});Kiểm thử tích hợp
describe('Brevo Integration Tests', () => { let customerService;
beforeAll(() => { customerService = new TajoCustomerService(); });
test('should sync customer to Brevo', async () => { const testCustomer = { email: `test-${Date.now()}@example.com`, firstName: 'Test', lastName: 'User', loyaltyId: `LYL-${Date.now()}`, tier: 'Bronze', points: 100 };
// Create customer const createResult = await customerService.createCustomer(testCustomer); expect(createResult.id).toBeDefined();
// Verify customer exists const retrievedCustomer = await customerService.getCustomer(testCustomer.email); expect(retrievedCustomer.email).toBe(testCustomer.email); expect(retrievedCustomer.attributes.LOYALTY_POINTS).toBe(100);
// Clean up await customerService.deleteCustomer(testCustomer.email); });});Tối ưu hiệu năng
Bộ nhớ đệm
import Redis from 'ioredis';
class TajoCachedService extends TajoCustomerService { constructor() { super(); this.redis = new Redis(process.env.REDIS_URL); this.cacheTTL = 300; // 5 minutes }
async getCustomer(email) { const cacheKey = `customer:${email}`;
// Try cache first const cached = await this.redis.get(cacheKey); if (cached) { return JSON.parse(cached); }
// Fetch from API const customer = await super.getCustomer(email);
// Cache result if (customer) { await this.redis.setex(cacheKey, this.cacheTTL, JSON.stringify(customer)); }
return customer; }}Giới hạn tốc độ
import { RateLimiter } from 'limiter';
class TajoRateLimitedService extends TajoCustomerService { constructor() { super(); // Brevo API limits: 300 calls per minute this.limiter = new RateLimiter({ tokensPerInterval: 300, interval: 'minute' }); }
async makeApiCall(apiCall) { await this.limiter.removeTokens(1); return apiCall(); }
async createCustomer(customerData) { return this.makeApiCall(() => super.createCustomer(customerData)); }}Bước tiếp theo
- Hướng dẫn tích hợp nền tảng - Hướng dẫn thiết lập đầy đủ
- Cấu hình webhook - Thiết lập sự kiện theo thời gian thực
- Python SDK - SDK cho ngôn ngữ lập trình thay thế
- Tài liệu tham chiếu API - Tài liệu API đầy đủ