JavaScript SDK
The official JavaScript SDK provides a convenient way to interact with Brevo’s API from your Node.js applications and browser environments.
Installation
# Using npmnpm install @brevo/brevo-js
# Using yarnyarn add @brevo/brevo-js
# Using pnpmpnpm add @brevo/brevo-jsQuick Start
Initialize the SDK
import { ApiClient, TransactionalEmailsApi, ContactsApi, EventsApi } from '@brevo/brevo-js';
// 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();Environment Configuration
// .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};Core Features
1. Customer Management
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. Transactional Emails
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. Event Tracking
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 }); }}Advanced Usage
1. Bulk Operations
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. Error Handling and Retry Logic
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. Webhook Handling
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 });}Testing
Unit Tests
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); });});Integration Tests
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); });});Performance Optimization
Caching
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; }}Rate Limiting
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)); }}Next Steps
- Platform Integration Guide - Complete setup guide
- Webhook Configuration - Set up real-time events
- Python SDK - Alternative language SDK
- API Reference - Full API documentation