Brevo API:面向开发者的实用指南

Brevo API 开发指南:身份验证、联系人更新、Webhook、速率限制和安全重试。

Brevo API

简短的回答是什么?

标准 API 密钥通过 https://api.brevo.com/v3/ 和 api-key 请求头使用。同步联系人时,设置稳定的来源 ID、已定义的属性和明确的列表,并保留退订状态。回读结果并查看限流头;429 重试要有边界。Webhook 是经过验证的变更信号,还需去重和状态核对。

了解更多
在本页面

创建联系人可能返回 201,但结果仍然错误:来源 ID 丢失、选错列表,或者忽略了此前的退订。这些是数据决策,不只是 HTTP 细节。

本文先展示可运行的联系人写入,再说明小规模、可重复同步所需的检查。

Brevo API 覆盖哪些能力

所有能力都在同一个域名和同一个版本路径下。开发者文档把整个接口面分成四个产品领域:

  • 消息:事务性邮件、SMS 和 WhatsApp,包括批量发送、定时发送和消息活动记录。
  • 营销平台:联系人、列表、细分和邮件营销活动。
  • 电商:商品、订单和客户事件跟踪。
  • 对话:聊天挂件以及通过程序管理对话。

这些领域共用一个账号、一个联系人数据库和一个 API 密钥。这既方便,偶尔也危险:一个按预演数据写出来的脚本,操作的是营销活动实际发送的那批联系人。

事务性与营销的区别

这两类的行为差别足够大,把它们弄混是最常见的设计错误。

事务性营销
主要端点POST /v3/smtp/emailPOST /v3/emailCampaigns
寻址方式请求里显式指定收件人listIds 或 segmentIds
触发方式你的应用实时触发定时发送或按需发送
典型流量形态持续不断,一次一条突发式,一次一大批
速率限制姿态非常高,general 档位每秒 1,000 次请求低,营销活动端点归入通用上限

如果你还在判断 Brevo 是不是合适的平台,平台概览覆盖了这部分内容。

鉴权与密钥管理

Brevo 使用放在自定义请求头里的纯 API 密钥。请求头名为 api-key,不是 Authorization,也没有 Bearer 前缀。先用过其他消息 API 的人几乎都会在这里栽跟头。

支持 OAuth 的操作可以使用 Bearer 令牌;普通 API 密钥仍应放在 api-key 请求头中。

Terminal window
curl https://api.brevo.com/v3/account \
-H "api-key: $BREVO_API_KEY"

密钥在 Brevo 应用的账号设置里生成,位置是 SMTP and API 板块下的 API keys 标签页。给每个密钥起一个与使用它的系统对应的描述性名称。密钥值在生成时只显示一次,一旦丢失就只能重新生成,无法找回。

几条实操规则:

  • 按部署环境和服务分别签发独立密钥。吊销一个泄露的密钥,不应该同时搞垮三个无关系统。
  • 标准 API 密钥的作用范围是整个账号。把任何一个密钥都视为对联系人、发送和 CRM 数据的完全访问权限。
  • 对于代表其他 Brevo 账号操作的应用,Brevo 还支持 OAuth 2.0,具体流程与密钥流程一并写在鉴权方案文档中。
  • AI 助手使用的 MCP 服务器需要另一个令牌,而且确实使用 bearer 请求头。该令牌在同一个 API keys 页面生成,但与 REST 密钥不能互换。

基础 URL、版本以及第一次写入

基础 URL 是 https://api.brevo.com/v3/。版本写在路径里而不是请求头里,v3 是当前一代。本指南里的每个路径都相对于这个基础 URL。

首次写入请使用自己控制的测试邮箱、有效列表 ID 和稳定的来源 ID。先在 Brevo 创建 FNAME 属性。使用真实密钥时,以下请求会直接写入:

Terminal window
curl -X POST https://api.brevo.com/v3/contacts \
-H "api-key: $BREVO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"ext_id": "test-source-contact-1",
"attributes": { "FNAME": "Dev" },
"listIds": [42],
"updateEnabled": true,
"getId": true
}'

将 42 换成测试列表 ID。回读联系人,核对 ID、姓名、列表及屏蔽状态。仅有 2xx 不代表结果符合预期。

你真正会用到的端点

联系人

POST /v3/contacts 创建联系人。请求体接受 email、已定义的 attributes、listIds,以及作为稳定来源键的 ext_id。updateEnabled: true 更新已有联系人;getId: true 请求返回最终 ID。Brevo 文档列出了这些字段。每次运行都使用同一 ext_id,并保存来源 ID 与 Brevo ID 的映射。

写入前确定每个属性由哪个系统管理,以及哪些已同意的联系人应进入哪个列表。明确填写 listIds。常规更新不要发送 emailBlacklisted: false。Brevo 提醒,修改被屏蔽联系人的邮箱可能解除屏蔽,地址变更需要单独处理。加入营销列表前检查屏蔽和退订。读取与写入之间仍存在短暂竞态;严格要求下应在发送前再次核验。

读取走 GET /v3/contacts,用 limit(默认 50,最大 1000)和 offset 分页,并支持 UTC 格式的 modifiedSince 和 createdSince。增量同步应该依赖 modifiedSince,而不是遍历整个列表。注意 filter 参数只支持等值运算符,表达力更强的条件应该放进细分里。

批量导入用 POST /v3/contacts/import,它接受 fileUrl、fileBody 或 jsonBody,指向 listIds,异步执行并返回一个 processId。Brevo 文档写明请求体上限 10 MB,并建议控制在 8 MB 附近,因为解析会让载荷膨胀。记得传 notifyUrl,这样你就能得知结果,而不用轮询。

事务性邮件

POST /v3/smtp/email 是主力端点。除了 sender、to、subject 和 htmlContent,还有几个字段值得了解:

  • templateId 配合 params,用 Brevo 模板及其变量替换取代内联内容。单个版本的 params 上限 100 KB,累计上限 1000 KB。
  • messageVersions,一次调用发送个性化变体,每个版本最多 99 个收件人。
  • tags 有助于将送达事件关联到触发该事件的应用流程。
  • scheduledAt 加上 batchId,用于你可能想整批取消的未来发送。
  • headers,采用 Title-Case,用于自定义 SMTP 请求头。

单次请求最多接受 2,000 个收件人。关于这个端点与营销活动发送的区别,事务性邮件指南给出了消息策略层面的视角。

邮件营销活动

POST /v3/emailCampaigns 需要 name 和 sender,外加恰好一个内容来源:htmlContent(至少 10 个字符,小于 1 MB)、htmlUrl 或 templateId。受众放在 recipients 里,以 listIds 或 segmentIds 形式给出,scheduledAt 使用 YYYY-MM-DDTHH:mm:ss.SSSZ 的 UTC 格式。配套路由分别负责立即发送、发送测试、更新状态和拉取活动报告。

公司、交易与对象

Brevo 的 CRM 有两条相互重叠的写入路径,选对很重要。

CRM 路由是 POST /v3/companies、PATCH /v3/companies/{id}、DELETE /v3/companies/{id},以及交易对应的同一组路由。它们是同步的。变更应用后 PATCH 返回 204。

对象 API 是批量路径:POST /v3/objects/{object_type}/batch/upsert 每次请求最多接受 1000 条记录和 1 MB,每条记录最多 500 个属性,每条记录每个对象类型最多 10 条关联记录。它返回 202 和一个 processId,意思是已受理而不是已应用。

Terminal window
curl -X POST https://api.brevo.com/v3/objects/company/batch/upsert \
-H "api-key: $BREVO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"records": [
{
"identifiers": { "id": 12345 },
"attributes": { "domain": "acme.example", "industry": "retail" }
}
]
}'

Brevo CRM 指南从运营者视角讲解了这套对象模型。

官方 SDK

Brevo 在 getbrevo GitHub 组织下维护这些客户端:

语言代码仓库
Node.jsgithub.com/getbrevo/brevo-node
Pythongithub.com/getbrevo/brevo-python
PHPgithub.com/getbrevo/brevo-php
Javagithub.com/getbrevo/brevo-java
C#github.com/getbrevo/brevo-csharp
Gogithub.com/getbrevo/brevo-go
Rubygithub.com/getbrevo/brevo-ruby

Node 客户端以 @getbrevo/brevo 安装:

Terminal window
npm install @getbrevo/brevo
import { BrevoClient } from "@getbrevo/brevo";
// Reconcile uncertain send outcomes before retrying.
const brevo = new BrevoClient({ apiKey: process.env.BREVO_API_KEY, maxRetries: 0 });
const result = await brevo.transactionalEmails.sendTransacEmail({
subject: "Order confirmed",
htmlContent: "<html><body><p>Thanks for your order.</p></body></html>",
sender: { name: "Acme", email: "[email protected]" },
to: [{ email: "[email protected]", name: "Customer" }],
tags: ["order-confirmation"],
});
console.log("Message ID:", result.messageId);

Python 客户端用 pip install brevo-python 安装。如果你不想为两个端点背上一个 SDK 依赖,原始 HTTP 接口面小到可以直接调用,这样也能让你免受 SDK 版本变动的影响:

可通过 pip install brevo-python 安装 Python 客户端。只调用少量端点时,也可直接使用 HTTP:

import os
import requests
BASE = "https://api.brevo.com/v3"
HEADERS = {"api-key": os.environ["BREVO_API_KEY"]}
def upsert_consented_contact(source_id, email, first_name, list_id, consent):
if not consent:
raise ValueError("No marketing consent in the source")
if not source_id or not isinstance(list_id, int):
raise ValueError("Stable source ID and numeric list ID required")
# Configure FNAME in Brevo before using this explicit field mapping.
response = requests.post(
f"{BASE}/contacts",
headers=HEADERS,
json={
"email": email,
"ext_id": source_id,
"attributes": {"FNAME": first_name},
"listIds": [list_id],
"updateEnabled": True,
"getId": True,
},
timeout=30,
)
response.raise_for_status()
return response.json().get("id") if response.content else None

成功更新可能返回空的 204 响应。此时 None 表示需要重新读取联系人以获取 ID。

示例假设调用方已核验同意记录及 Brevo 屏蔽状态,不会解除屏蔽。真实密钥会写入账户,请先用模拟响应测试。标识冲突可能返回不同的 4xx;应读取响应并核对 ID,不能总是假定为 409。

Webhook

Webhook 是你得知发送之后发生了什么的途径。POST /v3/webhooks 创建一个,参数有 url、events、type,还可以选填 channel(email 或 sms)、batched、自定义 headers 以及一个 auth 对象。

Webhook 有三种类型,事件词汇各不相同:

  • 事务性:sent、request、delivered、hardBounce、softBounce、blocked、spam、invalid、deferred、click、opened、uniqueOpened、unsubscribed。
  • 营销:spam、opened、click、hardBounce、softBounce、unsubscribed、listAddition、delivered、contactUpdated、contactDeleted。
  • 入站:inboundEmailProcessed 和 reply,这两者还额外需要一个 domain。
Terminal window
curl -X POST https://api.brevo.com/v3/webhooks \
-H "api-key: $BREVO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.example/hooks/brevo",
"type": "transactional",
"events": ["delivered", "hardBounce", "spam", "unsubscribed"],
"description": "Deliverability signals"
}'

联系人变化应注册带有 contactUpdated 的营销 Webhook。Brevo 在事件载荷中使用 contact_updated。按安全文档,通过 auth Bearer 令牌或自定义请求头验证接收请求。处理前校验密钥,不要记录密钥。

以事件类型、联系人 ID 和时间戳组成去重键,并保留整个重投窗口。时间戳本身并不唯一。事件可能重复或乱序到达。收到事件后重新读取当前联系人,与可信来源核对。限定重放窗口,恢复后拒绝过期事件,并定期做增量核对以补上遗漏。Webhook 本身不构成双向同步。参见连接器指南。

速率限制与错误处理

Brevo 的速率限制按端点和套餐档位区分,各端点之间的差距极大。

端点General(所有套餐)Advanced(Professional 与 Enterprise)
POST /v3/smtp/email1,000 RPS2,000 RPS
POST /v3/transactionalSMS/send150 RPS200 RPS
/v3/contacts/...10 RPS,36,000 RPH20 RPS,72,000 RPH
POST /v3/events10 RPS,36,000 RPH20 RPS,72,000 RPH
GET /v3/smtp/emails2 RPS,7,200 RPH3 RPS,10,800 RPH
没有单独限制的端点100 RPH200 RPH

Brevo 对受限端点提供 x-sib-ratelimit-limit、x-sib-ratelimit-remaining 和 x-sib-ratelimit-reset 请求头。成功响应也要读取。遇到 429,等待重置,并在固定次数与时间预算内重试。reset 是限流窗口单位表示的时长,通常为秒,不是 Unix 时间戳。

async function callBrevo(path, init) {
for (let attempt = 0; attempt < 3; attempt++) {
const response = await fetch(`https://api.brevo.com/v3${path}`, {
...init,
headers: { "api-key": process.env.BREVO_API_KEY, ...init.headers },
});
if (response.status !== 429 || attempt === 2) return response;
const raw = Number(response.headers.get("x-sib-ratelimit-reset"));
const seconds = Number.isFinite(raw) && raw > 0 ? raw : 2 ** attempt;
const delayMs = (seconds + 2 ** attempt) * 1000;
if (delayMs > 60_000) return response;
await new Promise(resolve => setTimeout(resolve, delayMs));
}
}

若所需等待超过 60 秒,函数会返回 429。请稍后安排下一次运行。

辅助函数只适用于已确认可安全重复的请求。发送结果不明时,先用自己的消息 ID 核对,再考虑发送。记录状态和限流头,不记录 API 密钥或联系人数据。

不要盲目重试所有 4xx。联系人创建文档列出 400 和 425;冲突不一定返回 409。写入后的 5xx 要先核实变更是否已经生效。

返回了什么状态?

  1. 429

    按预算等待

    遵守重置时间和重试次数上限。

  2. 写入后 5xx

    回读结果

    服务器可能已写入。

  3. 400

    修正请求

    通常是输入错误。

  4. 标识冲突

    核对 ID

    API 不保证固定冲突状态码。

不发真实邮件的测试方法

在事务性发送请求里加上值为 drop 的 X-Sib-Sandbox 请求头。Brevo 会校验请求,返回 201 和一个 messageId,不投递任何东西,也不写入邮件日志。

Terminal window
curl -X POST https://api.brevo.com/v3/smtp/email \
-H "api-key: $BREVO_API_KEY" \
-H "X-Sib-Sandbox: drop" \
-H "Content-Type: application/json" \
-d '{ "sender": { "email": "[email protected]" }, "to": [{ "email": "[email protected]" }], "subject": "Sandbox", "htmlContent": "<p>hi</p>" }'

要清楚它能证明什么、不能证明什么。沙盒模式只校验请求格式,对发件人鉴权、模板渲染或送达能力什么都说明不了。凡是涉及联系人或 CRM 数据的集成测试,都要单独准备一个 Brevo 账号,因为沙盒模式只覆盖发送,不覆盖 API 的其余部分。

联系人同步前检查

  • 为 ext_id 选定稳定来源 ID,并保存 Brevo ID。
  • 先定义属性,写入后回读测试联系人。
  • 指定列表并保存可靠的同意证据;跳过屏蔽和退订者。
  • 分别统计已接受、已应用、跳过和失败的写入。202 起初只表示已接收。
  • 验证营销 Webhook、去重,再核对当前状态。
  • 监测限流头,达到预算后停止重试。

Tajo 可将商务数据同步到 Brevo。自行构建时,可参考 Brevo 连接器指南。

常见问题

Brevo API 的基础 URL 是什么?

所有 Brevo REST 调用都指向 https://api.brevo.com/v3/。版本号写在路径里,v3 是当前一代,因此像事务性发送这样的端点,完整路径就是 https://api.brevo.com/v3/smtp/email。

如何完成 Brevo API 的鉴权?

把密钥放在名为 api-key 的 HTTP 请求头里发送。标准 API 密钥不使用 Authorization 或 Bearer 请求头。密钥在账号设置的 SMTP and API 里的 API keys 页面生成,值只显示一次。

Brevo API 的速率限制是多少?

限制按端点和速率限制档位区分。在所有套餐都享有的 general 档位上,事务性发送端点允许每秒 1,000 次请求,联系人端点允许每秒 10 次,没有单独限制的端点每小时上限 100 次请求。Professional 和 Enterprise 套餐可以使用 advanced 档位,Enterprise 还可以使用 extended 档位。超出限制会返回 429。

Brevo 有官方 SDK 吗?

有。Brevo 在 getbrevo 这个 GitHub 组织下发布了 Node.js、Python、PHP、Java、C#、Go 和 Ruby 的客户端。Node 包在 npm 上是 @getbrevo/brevo,Python 包在 PyPI 上是 brevo-python。

怎样在不发出真实邮件的情况下测试 Brevo API?

在事务性发送请求里加上值为 drop 的 X-Sib-Sandbox 请求头。Brevo 会校验请求,返回 201 和一个 messageId,但不发送任何邮件,也不写入邮件日志。它只检查请求格式,不检查送达能力。

Brevo 支持哪些 Webhook 事件?

事务性 Webhook 涵盖送达、退信和退订。营销 Webhook 包括 contactUpdated 和 contactDeleted。入站事件的文档列出 inboundEmailProcessed。

联系人更新如何保留已有退订?

使用稳定的来源 ID 和已定义的属性。常规更新中不要设置 emailBlacklisted: false。加入营销列表前,检查联系人状态及同意记录。

Webhook 足以实现双向同步吗?

不足以。验证接收端身份、去除重复投递,并与可信来源核对遗漏或乱序事件。Webhook 只提示发生了变化,不证明两个系统状态一致。

申请抢先体验

请输入您的名字和公司电子邮箱地址。我们会发送确认 Tajo 访问申请的链接。

获取Brevo