DEV Community

Cover image for How to Use Brevo APIs for SMS Marketing ?
Preecha
Preecha

Posted on

How to Use Brevo APIs for SMS Marketing ?

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.

Try Apidog today

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

  1. Log in to Brevo.
  2. Go to SMTP & API → API Keys.
  3. Create a key with the permissions your integration needs.
  4. 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"
Enter fullscreen mode Exit fullscreen mode

API base URL

All API requests use this base URL:

https://api.brevo.com/v3/
Enter fullscreen mode Exit fullscreen mode

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."
  }'
Enter fullscreen mode Exit fullscreen mode

A successful response includes a message ID:

{
  "messageId": "<20260324123456.123456@relay.brevo.com>"
}
Enter fullscreen mode Exit fullscreen mode

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"
    }
  }'
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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
      }
    ]
  })
})
Enter fullscreen mode Exit fullscreen mode

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"
  }'
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

Get campaign statistics

curl -X GET "https://api.brevo.com/v3/emailCampaigns/{campaignId}" \
  -H "api-key: your-api-key"
Enter fullscreen mode Exit fullscreen mode

The response includes delivery and engagement statistics:

{
  "statistics": {
    "delivered": 4850,
    "opened": 1455,
    "clicked": 291,
    "unsubscribed": 12,
    "bounces": 150
  }
}
Enter fullscreen mode Exit fullscreen mode

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
  }'
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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"]
  }'
Enter fullscreen mode Exit fullscreen mode

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"]
  }'
Enter fullscreen mode Exit fullscreen mode

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
  }'
Enter fullscreen mode Exit fullscreen mode

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"
  }'
Enter fullscreen mode Exit fullscreen mode

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"
  }'
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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')
})
Enter fullscreen mode Exit fullscreen mode

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.

Image

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>/)
})
Enter fullscreen mode Exit fullscreen mode

Image

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"
}
Enter fullscreen mode Exit fullscreen mode

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')
})
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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')
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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-key header
  • 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:

  1. Create a Brevo account and generate an API key.
  2. Send a transactional email from a development environment.
  3. Create a reusable template in Brevo’s visual editor.
  4. Add webhook handlers for bounces and unsubscribes.
  5. 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>
Enter fullscreen mode Exit fullscreen mode

Can I send emails from my own domain?

Yes. Configure SPF, DKIM, and DMARC records. Brevo provides the required values in:

Settings → Sender & IP
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
topstar_ai profile image
Luis Cruz

I appreciated the section on sending transactional emails, particularly the example of sending a simple email using the Brevo API. The use of curl commands 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?