Brevo Bridge
Drop-in replacement for the Brevo transactional email API — use your wemail API key in the same api-key header, keep your existing request structure.
The Brevo bridge lets you migrate from Brevo (formerly Sendinblue) to wemail without changing your integration code. Point your base URL to https://api.wemail.io/bridge/brevo, swap your Brevo API key for a wemail API key in the same api-key header, and keep the same request bodies and response shapes. The bridge translates every call into the wemail pipeline — delivery, tracking, webhooks, and suppressions all work the same way.
Authentication
Exactly like Brevo, the bridge authenticates with an api-key header. Use your wemail API key (afn_live_… or afn_test_…) where your Brevo key (xkeysib-…) used to be. Test-environment keys route through the sandbox: messages are accepted, simulated, and never delivered.
api-key: afn_live_YOUR_WEMAIL_KEYSupported Endpoints
POST /bridge/brevo/v3/smtp/email
Send a transactional email — mirrors Brevo's Send a transactional email endpoint.
GET /bridge/brevo/v3/smtp/statistics/events
List email events — mirrors Brevo's transactional event statistics.
GET /bridge/brevo/v3/smtp/blockedContacts
List blocked contacts (bounces and spam complaints) — mirrors Brevo's blocked-contacts list.
Field-Level Compatibility
POST /v3/smtp/email — Request Fields
| Parameter | Type | Required | Description |
|---|---|---|---|
sender | object | Required | { email, name? } — must use a domain verified in your wemail workspace. |
to | array | Required | Recipient list [{ email, name? }]. |
cc / bcc | array | Optional | Carbon-copy recipients, same shape as to. |
subject | string | Optional | Required unless templateId is provided. |
htmlContent | string | Optional | HTML body. At least one of htmlContent, textContent, templateId is required. |
textContent | string | Optional | Plain-text body. |
templateId | string | Optional | A wemail template id (tpl_…). Numeric Brevo template ids are not resolvable — re-point to the migrated template's wemail id. |
params | object | Optional | Template variables, substituted like Brevo params. |
tags | array | Optional | Up to 10 tags, echoed on events and webhooks. |
headers | object | Optional | Custom SMTP headers. |
scheduledAt | string | Optional | ISO-8601 timestamp for scheduled delivery. |
Response
A successful send returns 201 with { "messageId": "<msg_…>" }, matching Brevo's response shape. Validation failures return 400 with { code, message } in Brevo's error format.
GET /v3/smtp/statistics/events
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | integer | Optional | Page size, default 50, max 100. |
offset | integer | Optional | Pagination offset, default 0. |
event | string | Optional | Filter by Brevo event name: requests, delivered, hardBounces, softBounces, opens, clicks, spam, blocked, deferred, unsubscribed. |
startDate / endDate | string | Optional | Date range filters (ISO-8601). |
Returns { events: [{ email, date, subject, messageId, event, tag, from, ip, link, reason, templateId }] } with wemail events mapped back to Brevo event names.
GET /v3/smtp/blockedContacts
Returns { count, contacts: [{ email, reason: { code, message }, blockedAt }] }. count is the total number of blocked contacts. Reason codes follow Brevo's vocabulary: hard bounces report hardBounce, spam complaints report contactFlaggedAsSpam.
Webhooks
When the Brevo bridge is active, webhook deliveries are formatted exactly like Brevo transactional webhooks: a single flat JSON object with event, email, message-id, subject, tags, ts/ts_event (seconds), ts_epoch (milliseconds) and date. Event names use Brevo's vocabulary (request, delivered, hard_bounce, spam, opened, click, unsubscribed, blocked, deferred). Like Brevo, payloads are not signed — restrict your webhook endpoint by URL secrecy or network rules.
Known Deviations from Brevo API
| Parameter | Type | Required | Description |
|---|---|---|---|
templateId | behavior | Optional | Brevo numeric template ids are not resolvable; use the wemail tpl_… id of the migrated template. |
batchId / messageVersions | unsupported | Optional | Brevo batch sending fields are not yet supported — send one request per message. |
attachment | unsupported | Optional | Attachments are not yet supported through the bridge; use the native wemail /v3/send for attachments. |
events feed | behavior | Optional | Events reflect the wemail pipeline; provider-internal Brevo states (e.g. proxy_open) never occur. |
Migrating for good? Follow the Brevo migration guide — templates and suppressions auto-import, and Brevo stays warm for 30 days.
Code examples
curl -X POST https://api.wemail.io/bridge/brevo/v3/smtp/email \
-H "api-key: afn_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"sender": { "email": "sender@yourdomain.com", "name": "Your App" },
"to": [{ "email": "user@example.com" }],
"subject": "Hello from the Brevo bridge",
"htmlContent": "<p>It works — zero code changes.</p>"
}'// Brevo SDK — point the client at the wemail bridge
const brevo = require('@getbrevo/brevo');
const api = new brevo.TransactionalEmailsApi();
api.setApiKey(brevo.TransactionalEmailsApiApiKeys.apiKey, 'afn_live_YOUR_KEY');
api.basePath = 'https://api.wemail.io/bridge/brevo/v3';
await api.sendTransacEmail({
sender: { email: 'sender@yourdomain.com', name: 'Your App' },
to: [{ email: 'user@example.com' }],
subject: 'Hello from the Brevo bridge',
htmlContent: '<p>It works — zero code changes.</p>',
});import requests
resp = requests.post(
"https://api.wemail.io/bridge/brevo/v3/smtp/email",
headers={"api-key": "afn_live_YOUR_KEY"},
json={
"sender": {"email": "sender@yourdomain.com", "name": "Your App"},
"to": [{"email": "user@example.com"}],
"subject": "Hello from the Brevo bridge",
"htmlContent": "<p>It works — zero code changes.</p>",
},
)
print(resp.status_code, resp.json()) # 201 {'messageId': '<msg_…>'}