TL;DR
Brevo APIs let you send marketing emails, transactional emails, and SMS messages programmatically. Authenticate with an API key, send requests to api.brevo.com, and use webhooks to track delivery and engagement.
For testing, use Apidog to validate request payloads, test webhook handlers, and verify that your integration handles bounces and unsubscribes correctly.
Introduction
Brevo (formerly Sendinblue) supports marketing campaigns, transactional email, SMS marketing, and automation workflows.
Sending an email is straightforward. Running email reliably in production is not: you need to account for bounces, spam complaints, unsubscribes, delivery timing, and rate limits. Brevo provides APIs for these workflows.
The main API use cases are:
- Marketing campaigns: bulk emails sent to contact lists
- Transactional emails: password resets, order confirmations, and notifications
- SMS messages: verification codes, alerts, and marketing texts
When integrating email into an application, use Apidog to test template payloads, validate webhook events, mock API responses, and exercise error-handling paths without sending real messages.
Authentication and setup
Get an API key
- Log in to Brevo.
- Go to SMTP & API → API Keys.
- Create a key with the permissions your integration needs.
- Store the key in an environment variable or secret manager.
Send the key in the api-key header:
curl -X GET "https://api.brevo.com/v3/account" \
-H "accept: application/json" \
-H "api-key: your-api-key-here"
API base URL
All API requests use this base URL:
https://api.brevo.com/v3/
Rate limits
Brevo limits requests by plan:
- Free: 300 requests/minute
- Starter: 600 requests/minute
- Business: 1200 requests/minute
Check the X-RateLimit-Remaining response header so your application can slow down before reaching the limit.
Sending transactional emails
Transactional emails are individual messages triggered by user actions, such as password resets, order confirmations, and welcome messages.
Send a simple email
curl -X POST "https://api.brevo.com/v3/smtp/email" \
-H "accept: application/json" \
-H "api-key: your-api-key" \
-H "content-type: application/json" \
-d '{
"sender": {
"name": "Your App",
"email": "noreply@yourapp.com"
},
"to": [
{
"email": "user@example.com",
"name": "John Doe"
}
],
"subject": "Welcome to Our Platform",
"htmlContent": "<html><body><h1>Welcome!</h1><p>Thanks for signing up.</p></body></html>",
"textContent": "Welcome! Thanks for signing up."
}'
A successful response includes a message ID:
{
"messageId": "<20260324123456.123456@relay.brevo.com>"
}
Store this ID with your application event if you need to correlate delivery webhooks later.
Send using a template
Create templates in Brevo’s visual editor, then send a message using the template ID:
curl -X POST "https://api.brevo.com/v3/smtp/email" \
-H "api-key: your-api-key" \
-H "content-type: application/json" \
-d '{
"templateId": 15,
"to": [
{
"email": "user@example.com",
"name": "John Doe"
}
],
"params": {
"name": "John",
"order_number": "ORD-12345",
"tracking_url": "https://tracking.example.com/ORD-12345"
}
}'
Reference parameters in the template with double braces:
<p>Hi {{params.name}},</p>
<p>Your order {{params.order_number}} has shipped.</p>
<p><a href="{{params.tracking_url}}">Track your package</a></p>
Keep template parameter names consistent between your application and Brevo. Missing parameters can result in incomplete messages.
Send an email with attachments
Encode attachment content as Base64 before sending it:
const response = await fetch('https://api.brevo.com/v3/smtp/email', {
method: 'POST',
headers: {
'api-key': process.env.BREVO_API_KEY,
'content-type': 'application/json'
},
body: JSON.stringify({
sender: {
name: 'Your App',
email: 'noreply@yourapp.com'
},
to: [{ email: 'user@example.com' }],
subject: 'Your Invoice',
htmlContent: '<p>Please find your invoice attached.</p>',
attachment: [
{
name: 'invoice.pdf',
content: base64EncodedPdfContent
}
]
})
})
Marketing campaigns
Marketing emails are sent to contact lists. Brevo handles unsubscribe links, scheduling, and campaign analytics.
Create a campaign
curl -X POST "https://api.brevo.com/v3/emailCampaigns" \
-H "api-key: your-api-key" \
-H "content-type: application/json" \
-d '{
"name": "March Newsletter",
"subject": "What'\''s New in March",
"sender": {
"name": "Your Brand",
"email": "newsletter@yourbrand.com"
},
"type": "classic",
"htmlContent": "<html><body>Newsletter content here...</body></html>",
"recipients": {
"listIds": [12, 15]
},
"scheduledAt": "2026-03-25T09:00:00+00:00"
}'
Use scheduledAt to schedule a campaign. Provide an ISO 8601 timestamp with an explicit timezone offset.
Send a campaign immediately
curl -X POST "https://api.brevo.com/v3/emailCampaigns/{campaignId}/sendNow" \
-H "api-key: your-api-key"
Get campaign statistics
curl -X GET "https://api.brevo.com/v3/emailCampaigns/{campaignId}" \
-H "api-key: your-api-key"
The response includes delivery and engagement statistics:
{
"statistics": {
"delivered": 4850,
"opened": 1455,
"clicked": 291,
"unsubscribed": 12,
"bounces": 150
}
}
Use these values to monitor deliverability, engagement, unsubscribe volume, and bounce rates.
Contact management
Contacts are email recipients. You can organize contacts into lists and assign custom attributes for segmentation.
Create or update a contact
curl -X POST "https://api.brevo.com/v3/contacts" \
-H "api-key: your-api-key" \
-H "content-type: application/json" \
-d '{
"email": "new.user@example.com",
"attributes": {
"FIRSTNAME": "Jane",
"LASTNAME": "Smith",
"PLAN": "premium"
},
"listIds": [12, 15],
"updateEnabled": true
}'
Set updateEnabled to true to update an existing contact instead of failing when the email address already exists.
Get contact details
curl -X GET "https://api.brevo.com/v3/contacts/user@example.com" \
-H "api-key: your-api-key"
Add contacts to a list
curl -X POST "https://api.brevo.com/v3/contacts/lists/12/contacts/add" \
-H "api-key: your-api-key" \
-H "content-type: application/json" \
-d '{
"emails": ["user1@example.com", "user2@example.com"]
}'
Remove contacts from a list
curl -X DELETE "https://api.brevo.com/v3/contacts/lists/12/contacts/remove" \
-H "api-key: your-api-key" \
-H "content-type: application/json" \
-d '{
"emails": ["user@example.com"]
}'
Unsubscribe a contact
Set emailBlacklisted to true:
curl -X PUT "https://api.brevo.com/v3/contacts/user@example.com" \
-H "api-key: your-api-key" \
-H "content-type: application/json" \
-d '{
"emailBlacklisted": true
}'
SMS marketing
Brevo can send SMS messages globally through its SMS API.
Send a transactional SMS
Use transactional messages for verification codes, account alerts, and similar user-triggered events:
curl -X POST "https://api.brevo.com/v3/transactionalSMS/sms" \
-H "api-key: your-api-key" \
-H "content-type: application/json" \
-d '{
"sender": "YourApp",
"recipient": "+15551234567",
"content": "Your verification code is: 123456",
"type": "transactional"
}'
Send a marketing SMS
curl -X POST "https://api.brevo.com/v3/transactionalSMS/sms" \
-H "api-key: your-api-key" \
-H "content-type: application/json" \
-d '{
"sender": "YourBrand",
"recipient": "+15551234567",
"content": "Flash sale! 50% off today only. Reply STOP to unsubscribe.",
"type": "marketing"
}'
Get SMS statistics
curl -X GET "https://api.brevo.com/v3/transactionalSMS/statistics?startDate=2026-03-01&endDate=2026-03-31" \
-H "api-key: your-api-key"
Webhooks for tracking
Webhooks notify your application when an email is delivered, opened, clicked, bounced, marked as spam, or unsubscribed.
Configure webhooks
In the Brevo dashboard, go to:
Settings → Webhooks → Add webhook
Track these events:
-
delivered: email reached the inbox -
opened: recipient opened the email -
clicked: recipient clicked a link -
bounced: email bounced, either hard or soft -
spam: recipient marked the email as spam -
unsubscribed: recipient unsubscribed
Handle webhook events
Create an endpoint that accepts Brevo webhook requests and returns a 200 response after processing:
app.post('/webhooks/brevo', (req, res) => {
const event = req.body
switch (event.event) {
case 'delivered':
console.log(`Email ${event.messageId} delivered to ${event.email}`)
break
case 'opened':
console.log(`Email opened by ${event.email} at ${event.date}`)
break
case 'bounced':
console.log(`Bounce: ${event.email} - ${event.reason}`)
// Mark contact as invalid
markContactBounced(event.email)
break
case 'spam':
console.log(`Spam complaint from ${event.email}`)
// Remove from all lists
removeFromAllLists(event.email)
break
case 'unsubscribed':
console.log(`Unsubscribed: ${event.email}`)
break
}
res.status(200).send('OK')
})
For production use, make webhook processing idempotent. A repeated event should not cause duplicate updates in your database.
Testing with Apidog
Email APIs have failure modes beyond a successful 200 response. Test templates, bounce handling, webhook payloads, and rate-limit behavior before sending to real users.
1. Mock email sending
During development, mock the API response instead of sending real emails. Validate that your client expects a messageId:
pm.test('Email API accepts valid payload', () => {
const response = pm.response.json()
pm.expect(response).to.have.property('messageId')
pm.expect(response.messageId).to.match(/<.*@relay\.brevo\.com>/)
})
2. Test webhook handling
Create mock webhook payloads in Apidog:
{
"event": "bounced",
"email": "invalid@example.com",
"messageId": "<12345@relay.brevo.com>",
"reason": "hard_bounce",
"date": "2026-03-24T12:00:00Z",
"subject": "Welcome to Our Platform"
}
Send the payload to your webhook endpoint and verify that your application records the bounce and prevents future sends where appropriate.
3. Validate template payloads
Store template requests and test that required template variables are present:
pm.test('Template variables are valid', () => {
const payload = pm.request.body.toJSON()
pm.expect(payload.params).to.have.property('name')
pm.expect(payload.params).to.have.property('order_number')
})
4. Separate environments
Keep development and production credentials separate:
# Development
BREVO_API_KEY: xkeysib-dev-xxx
BREVO_SENDER: dev@yourapp.com
# Production
BREVO_API_KEY: xkeysib-prod-xxx
BREVO_SENDER: noreply@yourapp.com
Test Brevo email APIs with Apidog - free
Common errors and fixes
400 Bad Request: missing required field
Cause: The payload is missing a required field.
Fix: Read the API error message and correct the payload:
{
"code": "invalid_parameter",
"message": "sender.email is required"
}
401 Unauthorized
Cause: The API key is missing or invalid.
Fix: Verify that the api-key header is present and that the key has not been revoked.
402 Payment Required
Cause: The account exceeded its limits or does not have required credits.
Fix:
- For email, check your plan’s email limits.
- For SMS, purchase SMS credits.
429 Too Many Requests
Cause: Your application exceeded the API rate limit.
Fix: Retry with exponential backoff:
async function sendWithRetry(email, retries = 3) {
for (let i = 0; i < retries; i++) {
const response = await sendEmail(email)
if (response.status === 429) {
await sleep(Math.pow(2, i) * 1000)
} else {
return response
}
}
throw new Error('Rate limit exceeded')
}
Also monitor X-RateLimit-Remaining and X-RateLimit-Reset so you can queue requests before your integration reaches the limit.
404 Contact not found
Cause: You attempted to update a contact that does not exist.
Fix: Use updateEnabled: true while creating contacts:
{
"email": "new@example.com",
"updateEnabled": true
}
This creates the contact if needed or updates it if it already exists.
Alternatives and comparisons
| Feature | Brevo | SendGrid | Mailchimp | Postmark |
|---|---|---|---|---|
| Pricing | 300 emails/day free | 100 emails/day free | 500 emails/month free | 100 emails/month free |
| Marketing emails | Yes | Yes | Yes | No |
| Transactional emails | Yes | Yes | Limited | Yes (specialized) |
| SMS | Yes | No | No | No |
| Automation | Yes | Yes | Yes | Limited |
| Template editor | Visual + code | Code | Visual | Code |
Brevo combines email and SMS support in a single integration.
Real-world use cases
E-commerce order flow
An online store can use Brevo for:
- Order confirmations through transactional email
- Shipping notifications through transactional email
- Abandoned-cart recovery through marketing automation
- Weekly promotions through marketing campaigns
This keeps transactional and marketing messaging in one integration.
SaaS onboarding
A project management tool can use the transactional API for welcome emails, password resets, and team invitations. It can use marketing campaigns to announce new features to opted-in users.
SMS verification
A fintech application can use Brevo’s SMS API for two-factor authentication codes. The transactional SMS endpoint delivers codes within seconds, while webhooks can track delivery failures for retry logic.
Conclusion
You can use Brevo APIs to:
- Send transactional email, marketing campaigns, and SMS
- Authenticate requests with the
api-keyheader - Use templates for consistent, maintainable emails
- Manage contacts and lists for targeted campaigns
- Track delivery, opens, clicks, bounces, and unsubscribes with webhooks
- Test requests and webhook handlers with Apidog before sending to real users
Next steps:
- Create a Brevo account and generate an API key.
- Send a transactional email from a development environment.
- Create a reusable template in Brevo’s visual editor.
- Add webhook handlers for bounces and unsubscribes.
- Test request payloads and webhook events with Apidog.
Test Brevo email APIs with Apidog - free
FAQ
What’s the difference between Brevo and Sendinblue?
They are the same product. Sendinblue rebranded to Brevo in 2023. APIs use api.brevo.com, although older documentation may still reference Sendinblue.
How many emails can I send for free?
The free plan allows 300 emails per day, or 9,000 emails per month. For more volume, paid plans start at $25/month for 20,000 emails.
Can I use Brevo for cold emails?
Technically, yes, but it is risky. Cold emails can have high bounce and spam rates. Brevo monitors sender reputation, and high complaint rates can result in account suspension. Warm up your domain and follow email best practices.
How do I handle email bounces?
Listen for bounced webhook events.
- Remove hard bounces, such as invalid email addresses, permanently.
- Retry soft bounces, such as a full mailbox or temporary delivery issue.
- Monitor bounce rate, because rates above 5% can reduce sender reputation.
What’s the difference between marketing and transactional emails?
Transactional emails are triggered by user actions, such as purchases and signups, and usually go to one recipient. Marketing emails are campaigns sent to many recipients. Brevo separates these workflows for deliverability and compliance reasons.
How do I add an unsubscribe link?
Brevo automatically adds unsubscribe links to marketing emails. For transactional emails, add your own link:
<a href="{{ unsubscribe_url }}">Unsubscribe</a>
Can I send emails from my own domain?
Yes. Configure SPF, DKIM, and DMARC records. Brevo provides the required values in:
Settings → Sender & IP
Without proper authentication, your emails may land in spam.
How do I schedule emails in a specific timezone?
Use the scheduledAt parameter with an ISO 8601 timestamp and timezone offset:
{
"scheduledAt": "2026-03-25T09:00:00-05:00"
}
What happens if I hit the rate limit?
Brevo returns a 429 error. The response includes the X-RateLimit-Reset header with the number of seconds until the limit resets. Implement exponential backoff or queue emails for later.


Top comments (1)
I appreciated the section on sending transactional emails, particularly the example of sending a simple email using the Brevo API. The use of
curlcommands to demonstrate API requests is very helpful. One thing to consider when implementing this in a production environment is handling errors and retries, as network issues or rate limits can cause failures. Have you explored using exponential backoff or circuit breakers to mitigate these issues when sending emails through the Brevo API?