JavaScript SDK
L’SDK JavaScript ufficiale fornisce un modo comodo per interagire con l’API Brevo dalle tue applicazioni Node.js e negli ambienti browser.
Installazione
# Usando npmnpm install @brevo/brevo-js
# Usando yarnyarn add @brevo/brevo-js
# Usando pnpmpnpm add @brevo/brevo-jsAvvio Rapido
Inizializza l’SDK
import { ApiClient, TransactionalEmailsApi, ContactsApi, EventsApi } from '@brevo/brevo-js';
// Configura il client APIconst defaultClient = ApiClient.instance;const apiKey = defaultClient.authentications['api-key'];apiKey.apiKey = 'your-brevo-api-key';
// Inizializza le istanze APIconst emailApi = new TransactionalEmailsApi();const contactsApi = new ContactsApi();const eventsApi = new EventsApi();Configurazione dell’Ambiente
// .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};Funzionalità Principali
1. Gestione Clienti
class TajoCustomerService { constructor() { this.contactsApi = new ContactsApi(); }
// Crea un nuovo cliente fedeltà 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('Cliente creato in Brevo:', response.id); return response; } catch (error) { console.error('Errore nella creazione del cliente:', error); throw error; } }
// Aggiorna i dati fedeltà del cliente 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('Cliente aggiornato:', email); } catch (error) { console.error('Errore nell\'aggiornamento del cliente:', error); throw error; } }
// Recupera il cliente tramite email async getCustomer(email) { try { const response = await this.contactsApi.getContactInfo(email); return response; } catch (error) { if (error.status === 404) { return null; // Cliente non trovato } throw error; } }
// Metodo di supporto per ottenere l'ID lista per il livello getListForTier(tier) { const tierLists = { 'Bronze': 1, 'Silver': 2, 'Gold': 3, 'Platinum': 4 }; return tierLists[tier] || 1; }}2. Email Transazionali
class TajoEmailService { constructor() { this.emailApi = new TransactionalEmailsApi(); }
// Invia notifica punti guadagnati async sendPointsEarnedEmail(customerEmail, orderData) { const sendSmtpEmail = { sender: { name: "Tajo Loyalty", }, to: [{ email: customerEmail, name: orderData.customerName }], subject: `Hai guadagnato ${orderData.pointsEarned} punti fedeltà!`, 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('Errore nell\'invio dell\'email punti:', error); throw error; } }
// Invia notifica aggiornamento livello 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); }
// Genera contenuto HTML per l'email punti generatePointsEmailHTML(orderData) { return ` <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;"> <h1 style="color: #2c5aa0;">🎉 Ottime notizie, ${orderData.customerName}!</h1> <p>Hai guadagnato <strong>${orderData.pointsEarned} punti</strong> dal tuo recente acquisto!</p>
<div style="background: #f8f9fa; padding: 20px; border-radius: 8px; margin: 20px 0;"> <h3>Dettagli Ordine:</h3> <p><strong>Ordine #:</strong> ${orderData.orderNumber}</p> <p><strong>Punti Guadagnati:</strong> ${orderData.pointsEarned}</p> <p><strong>Punti Totali:</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;"> Visualizza Premi </a> </p> </div> `; }
generatePointsEmailText(orderData) { return ` Ottime notizie, ${orderData.customerName}!
Hai guadagnato ${orderData.pointsEarned} punti dal tuo recente acquisto!
Dettagli Ordine: - Ordine #: ${orderData.orderNumber} - Punti Guadagnati: ${orderData.pointsEarned} - Punti Totali: ${orderData.totalPoints}
Visualizza i tuoi premi su: https://yourdomain.com/loyalty/rewards `; }}3. Tracciamento degli Eventi
class TajoEventTracker { constructor() { this.eventsApi = new EventsApi(); }
// Traccia eventi fedeltà 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(`Errore nel tracciamento dell'evento ${eventType}:`, error); throw error; } }
// Metodi specifici di tracciamento 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 }); }}Utilizzo Avanzato
1. Operazioni Bulk
class TajoBulkService { constructor() { this.contactsApi = new ContactsApi(); this.batchSize = 50; // Dimensione batch consigliata }
// Importazione clienti in blocco 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], // Lista predefinita updateEnabled: true });
results.push(response); } catch (error) { console.error('Errore importazione batch:', error); // Continua con gli altri batch } }
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. Gestione degli Errori e Logica di Retry
class TajoApiClient { constructor() { this.maxRetries = 3; this.retryDelay = 1000; // 1 secondo }
async apiCallWithRetry(apiCall, retries = this.maxRetries) { try { return await apiCall(); } catch (error) { if (retries > 0 && this.isRetryableError(error)) { console.log(`Nuovo tentativo API. Tentativi rimanenti: ${retries - 1}`); await this.delay(this.retryDelay); return this.apiCallWithRetry(apiCall, retries - 1); } throw error; } }
isRetryableError(error) { // Riprova su rate limit, errori server e problemi di rete return error.status >= 500 || error.status === 429 || error.code === 'NETWORK_ERROR'; }
delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }}3. Gestione dei Webhook
import express from 'express';import crypto from 'crypto';
const app = express();
// Endpoint webhook per gli eventi Brevoapp.post('/webhooks/brevo', express.raw({type: 'application/json'}), (req, res) => { const signature = req.headers['x-brevo-signature']; const payload = req.body;
// Verifica la firma del webhook 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('Tipo di evento non gestito:', 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) { // Aggiorna il punteggio di coinvolgimento del cliente const customerEmail = event.email; const campaignType = event.tags?.includes('loyalty') ? 'loyalty' : 'general';
// Traccia il coinvolgimento nel tuo sistema await updateCustomerEngagement(customerEmail, 'email_opened', { campaign_type: campaignType, subject: event.subject, timestamp: event.ts });}Test
Test Unitari
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('dovrebbe creare il cliente con successo', async () => { const customerData = { firstName: 'Mario', lastName: 'Rossi', loyaltyId: 'LYL-001', tier: 'Bronze' };
mockContactsApi.createContact.mockResolvedValue({ id: 123 });
const result = await customerService.createCustomer(customerData);
expect(mockContactsApi.createContact).toHaveBeenCalledWith({ attributes: expect.objectContaining({ FIRSTNAME: 'Mario', LASTNAME: 'Rossi', LOYALTY_ID: 'LYL-001', LOYALTY_TIER: 'Bronze' }), listIds: [1], updateEnabled: true });
expect(result.id).toBe(123); });});Test di Integrazione
describe('Test di Integrazione Brevo', () => { let customerService;
beforeAll(() => { customerService = new TajoCustomerService(); });
test('dovrebbe sincronizzare il cliente con Brevo', async () => { const testCustomer = { email: `test-${Date.now()}@example.com`, firstName: 'Test', lastName: 'Utente', loyaltyId: `LYL-${Date.now()}`, tier: 'Bronze', points: 100 };
// Crea il cliente const createResult = await customerService.createCustomer(testCustomer); expect(createResult.id).toBeDefined();
// Verifica che il cliente esista const retrievedCustomer = await customerService.getCustomer(testCustomer.email); expect(retrievedCustomer.email).toBe(testCustomer.email); expect(retrievedCustomer.attributes.LOYALTY_POINTS).toBe(100);
// Pulizia await customerService.deleteCustomer(testCustomer.email); });});Ottimizzazione delle Prestazioni
Caching
import Redis from 'ioredis';
class TajoCachedService extends TajoCustomerService { constructor() { super(); this.redis = new Redis(process.env.REDIS_URL); this.cacheTTL = 300; // 5 minuti }
async getCustomer(email) { const cacheKey = `customer:${email}`;
// Prima prova dalla cache const cached = await this.redis.get(cacheKey); if (cached) { return JSON.parse(cached); }
// Recupera dall'API const customer = await super.getCustomer(email);
// Memorizza nella cache 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(); // Limiti API Brevo: 300 chiamate al minuto 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)); }}Passi Successivi
- Guida all’Integrazione della Piattaforma - Guida completa alla configurazione
- Configurazione Webhook - Configura gli eventi in tempo reale
- Python SDK - SDK in linguaggio alternativo
- Riferimento API - Documentazione API completa