Vraag vroegtijdige toegang aan

Vul je voornaam en een e-mailadres of telefoonnummer in. We nemen daarna contact met je op en leggen uit hoe je toegang krijgt tot Tajo.

JavaScript SDK

Met de officiële JavaScript SDK werk je op een handige manier met de API van Brevo vanuit je Node.js-applicaties en browseromgevingen.

Installatie

Terminal window
# Using npm
npm install @getbrevo/brevo
# Using yarn
yarn add @getbrevo/brevo
# Using pnpm
pnpm add @getbrevo/brevo

Snel starten

De SDK initialiseren

import { ApiClient, TransactionalEmailsApi, ContactsApi, EventsApi } from '@getbrevo/brevo';
// Configure API client
const defaultClient = ApiClient.instance;
const apiKey = defaultClient.authentications['api-key'];
apiKey.apiKey = 'your-brevo-api-key';
// Initialize API instances
const emailApi = new TransactionalEmailsApi();
const contactsApi = new ContactsApi();
const eventsApi = new EventsApi();

Omgevingsconfiguratie

// .env file
BREVO_API_KEY=xkeysib-your-api-key-here
BREVO_API_URL=https://api.brevo.com/v3
TAJO_WEBHOOK_SECRET=your-webhook-secret
// config.js
export 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
};

Kernfuncties

1. Klantbeheer

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. Transactionele e-mails

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. Events bijhouden

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
});
}
}

Geavanceerd gebruik

1. Bulkbewerkingen

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. Foutafhandeling en logica voor opnieuw proberen

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. Webhooks verwerken

import express from 'express';
import crypto from 'crypto';
const app = express();
// Webhook endpoint for Brevo events
app.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
});
}

Testen

Unittests

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);
});
});

Integratietests

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);
});
});

Prestatieoptimalisatie

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));
}
}

Volgende stappen

Vraag vroegtijdige toegang aan

Vul je voornaam en een e-mailadres of telefoonnummer in. We nemen daarna contact met je op en leggen uit hoe je toegang krijgt tot Tajo.

automatische herkenning
AI-assistent

Hallo! Stel me vragen over de documentatie.