Brevo API: Hướng dẫn thực chiến cho lập trình viên

Hướng dẫn Brevo API về xác thực, cập nhật liên hệ, webhook, giới hạn tốc độ và thử lại an toàn.

Brevo API

Câu trả lời ngắn gọn là gì?

Dùng https://api.brevo.com/v3/ với header api-key cho khóa API thông thường. Khi đồng bộ liên hệ, chọn ID nguồn ổn định, thuộc tính đã khai báo và danh sách cụ thể; giữ nguyên trạng thái hủy đăng ký. Đọc lại kết quả và header giới hạn. Chỉ thử lại 429 trong ngân sách cố định; coi webhook là tín hiệu đã xác thực cần khử trùng lặp và đối soát.

Tìm hiểu thêm
Trên trang này

Tạo liên hệ có thể trả về 201 mà kết quả vẫn sai: mất ID nguồn, chọn nhầm danh sách hoặc bỏ qua lần hủy đăng ký trước đó. Đây là quyết định về dữ liệu, không chỉ là chi tiết HTTP.

Bài này bắt đầu bằng lệnh ghi liên hệ hoạt động được, rồi nêu các kiểm tra cho đồng bộ nhỏ, chạy lặp lại.

Brevo API bao gồm những gì

Mọi thứ nằm dưới một host duy nhất và một đường dẫn phiên bản duy nhất. Tài liệu dành cho lập trình viên chia bề mặt API thành bốn mảng sản phẩm:

  • Nhắn tin: email giao dịch, SMS và WhatsApp, gồm cả gửi hàng loạt, lên lịch và theo dõi hoạt động tin nhắn.
  • Nền tảng marketing: danh bạ, danh sách, phân khúc và chiến dịch email.
  • Thương mại điện tử: sản phẩm, đơn hàng và theo dõi sự kiện khách hàng.
  • Conversations: widget chat và quản lý hội thoại bằng chương trình.

Bốn mảng đó dùng chung một tài khoản, một cơ sở dữ liệu danh bạ và một khóa API. Điều đó vừa tiện lợi vừa đôi khi nguy hiểm: một script viết theo hình dung về dữ liệu staging thực ra đang nói chuyện với đúng những danh bạ mà chiến dịch của bạn gửi tới.

Giao dịch so với marketing

Hai nhóm này hoạt động khác nhau đủ nhiều để việc nhầm lẫn giữa chúng trở thành lỗi thiết kế phổ biến nhất.

Giao dịchMarketing
Endpoint chínhPOST /v3/smtp/emailPOST /v3/emailCampaigns
Cách chỉ định người nhậnNgười nhận khai báo tường minh trong requestlistIds hoặc segmentIds
Yếu tố kích hoạtỨng dụng của bạn, theo thời gian thựcLên lịch trước hoặc gửi khi cần
Hình dạng lưu lượng điển hìnhLiên tục, mỗi lần một tin nhắnDồn dập, một lượt gửi lớn
Thế của giới hạn tốc độRất cao, 1.000 request mỗi giây ở bậc generalThấp, endpoint chiến dịch nằm trong hạn mức chung

Nếu bạn vẫn đang cân nhắc liệu Brevo có phải nền tảng phù hợp hay không, bài tổng quan nền tảng đã bàn kỹ chuyện đó.

Xác thực và quản lý khóa

Brevo dùng một khóa API thuần trong header tùy chỉnh. Header có tên là api-key, không phải Authorization, và không có tiền tố Bearer. Điểm này khiến gần như ai từng dùng một API nhắn tin khác trước đó đều vấp phải.

OAuth có thể dùng Bearer token cho thao tác hỗ trợ; khóa API tiêu chuẩn vẫn gửi qua header api-key.

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

Khóa được tạo trong ứng dụng Brevo, ở phần cài đặt tài khoản, mục SMTP and API, tab API keys. Hãy đặt cho mỗi khóa một cái tên mô tả gắn với hệ thống sử dụng nó. Giá trị khóa chỉ hiển thị đúng một lần khi được tạo, nên nếu làm mất, bạn phải tạo khóa mới chứ không khôi phục lại khóa cũ.

Một vài nguyên tắc thực dụng:

  • Cấp một khóa riêng cho từng môi trường triển khai và từng dịch vụ. Việc thu hồi một khóa bị lộ không bao giờ nên kéo sập ba hệ thống không liên quan.
  • Khóa API tiêu chuẩn có phạm vi toàn tài khoản. Hãy coi mọi khóa như quyền truy cập đầy đủ vào danh bạ, khả năng gửi và dữ liệu CRM.
  • Brevo cũng hỗ trợ OAuth 2.0 cho các ứng dụng hành động thay mặt tài khoản Brevo khác, được mô tả cùng luồng khóa trong authentication schemes.
  • Máy chủ MCP dùng cho trợ lý AI cần một token riêng và có dùng header bearer. Token đó được tạo trong cùng màn hình API keys nhưng không thể dùng thay cho khóa REST.

Base URL, phiên bản và lệnh ghi đầu tiên

Base URL là https://api.brevo.com/v3/. Phiên bản nằm trong đường dẫn chứ không nằm trong header, và v3 là thế hệ hiện tại. Mọi đường dẫn trong hướng dẫn này đều tương đối so với base đó.

Lần ghi đầu hãy dùng địa chỉ thử nghiệm do bạn kiểm soát, ID danh sách hợp lệ và ID nguồn ổn định. Tạo thuộc tính FNAME trong Brevo trước. Với khóa thật, ví dụ này ghi trực tiếp:

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
}'

Thay 42 bằng ID danh sách thử nghiệm của bạn. Đọc lại liên hệ để kiểm tra ID, tên, danh sách và trạng thái chặn. Mã 2xx đơn lẻ không chứng minh kết quả mong đợi.

Những endpoint bạn thực sự sẽ dùng

Danh bạ

POST /v3/contacts tạo liên hệ. Body nhận email, attributes đã khai báo, listIds và ext_id làm khóa nguồn ổn định. updateEnabled: true cập nhật liên hệ có sẵn, còn getId: true yêu cầu ID cuối. Brevo ghi rõ các trường này. Dùng cùng ext_id mỗi lần chạy và lưu ánh xạ ID nguồn với ID Brevo.

Trước khi ghi, xác định hệ thống nào sở hữu từng thuộc tính và danh sách nào nhận liên hệ có đồng ý. Khai báo listIds rõ ràng. Đừng gửi emailBlacklisted: false khi upsert thông thường. Brevo cảnh báo rằng đổi email của liên hệ bị chặn có thể xóa trạng thái chặn. Xử lý đổi địa chỉ riêng. Kiểm tra chặn và hủy đăng ký trước khi thêm vào danh sách tiếp thị. Có khoảng trống ngắn giữa đọc và ghi; nếu cần bảo đảm nghiêm ngặt, kiểm tra lần cuối trước khi gửi.

Việc đọc đi qua GET /v3/contacts, phân trang bằng limit (mặc định 50, tối đa 1000) và offset, đồng thời hỗ trợ modifiedSince và createdSince theo giờ UTC. Các luồng đồng bộ gia tăng nên dựa vào modifiedSince thay vì duyệt toàn bộ danh sách. Lưu ý rằng tham số filter chỉ hỗ trợ toán tử bằng, nên bất cứ điều kiện nào phức tạp hơn đều thuộc về một phân khúc.

Để nạp hàng loạt, POST /v3/contacts/import nhận fileUrl, fileBody hoặc jsonBody, nhắm tới listIds và chạy bất đồng bộ, trả về một processId. Brevo ghi rõ giới hạn body tối đa 10 MB và khuyến nghị giữ quanh mức 8 MB vì quá trình phân tích cú pháp làm phình payload. Hãy cung cấp notifyUrl để biết kết quả thay vì phải hỏi liên tục.

Email giao dịch

POST /v3/smtp/email là con ngựa kéo chính. Ngoài sender, to, subject và htmlContent, những trường đáng biết là:

  • templateId đi kèm params, thay nội dung nội tuyến bằng một mẫu của Brevo cùng các phép thay biến. Params của từng phiên bản bị giới hạn ở 100 KB, tổng cộng ở mức 1000 KB.
  • messageVersions, gửi các biến thể được cá nhân hóa trong một lệnh gọi, với tối đa 99 người nhận cho mỗi phiên bản.
  • tags có thể giúp liên hệ sự kiện gửi với quy trình ứng dụng đã tạo ra nó.
  • scheduledAt cùng batchId, cho những lượt gửi tương lai mà bạn có thể muốn hủy theo nhóm.
  • headers, viết theo Title-Case, cho các header SMTP tùy chỉnh.

Một request đơn lẻ chấp nhận tối đa 2.000 người nhận. Về khác biệt giữa endpoint này và việc gửi chiến dịch, hướng dẫn email giao dịch trình bày góc nhìn chiến lược nhắn tin.

Chiến dịch email

POST /v3/emailCampaigns yêu cầu name và sender, cộng đúng một nguồn nội dung: htmlContent (tối thiểu 10 ký tự, dưới 1 MB), htmlUrl hoặc templateId. Đối tượng nhận nằm trong recipients dưới dạng listIds hoặc segmentIds, còn scheduledAt dùng định dạng UTC YYYY-MM-DDTHH:mm:ss.SSSZ. Các route đi kèm bao gồm gửi ngay, gửi bản thử, cập nhật trạng thái và lấy báo cáo chiến dịch.

Công ty, thương vụ và object

CRM của Brevo có hai đường ghi chồng lấn nhau, và chọn đúng là chuyện quan trọng.

Các route CRM là POST /v3/companies, PATCH /v3/companies/{id}, DELETE /v3/companies/{id} và bộ tương đương cho thương vụ. Chúng là đồng bộ. Một lệnh PATCH trả về 204 ngay khi thay đổi được áp dụng.

API object là đường đi hàng loạt: POST /v3/objects/{object_type}/batch/upsert nhận tối đa 1000 bản ghi và 1 MB mỗi request, tối đa 500 thuộc tính cho mỗi bản ghi, và tối đa 10 bản ghi liên kết cho mỗi loại object trên mỗi bản ghi. Nó trả về 202 kèm một processId, nghĩa là đã tiếp nhận chứ chưa áp dụng.

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" }
}
]
}'

Hướng dẫn Brevo CRM trình bày mô hình dữ liệu này từ góc nhìn người vận hành.

SDK chính thức

Brevo duy trì các client dưới tổ chức GitHub getbrevo:

Ngôn ngữKho mã
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

Client Node cài đặt dưới tên @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);

Client Python cài bằng pip install brevo-python. Nếu bạn không muốn gánh thêm một phụ thuộc SDK chỉ vì hai endpoint, bề mặt HTTP thô đủ nhỏ để gọi trực tiếp, và cách đó cũng giúp bạn tránh được những đợt thay đổi phiên bản SDK:

Cài ứng dụng Python bằng pip install brevo-python. Với vài endpoint, gọi HTTP trực tiếp cũng phù hợp:

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

Cập nhật thành công có thể trả phản hồi 204 rỗng. Khi đó None nghĩa là bạn phải đọc lại liên hệ để lấy ID.

Ví dụ giả định bên gọi đã kiểm tra đồng ý và chặn trong Brevo. Nó không yêu cầu bỏ chặn. Khóa thật sẽ ghi vào tài khoản; hãy thử bằng phản hồi giả lập trước. Xung đột định danh có thể trả nhiều mã 4xx. Đọc phản hồi và đối soát ID, đừng luôn giả định 409.

Webhook

Webhook là cách bạn biết chuyện gì đã xảy ra sau khi gửi. POST /v3/webhooks tạo một webhook, với url, events, type, và tùy chọn channel (email hoặc sms), batched, headers tùy chỉnh cùng một đối tượng auth.

Có ba loại webhook với ba bộ từ vựng sự kiện riêng:

  • Giao dịch: sent, request, delivered, hardBounce, softBounce, blocked, spam, invalid, deferred, click, opened, uniqueOpened, unsubscribed.
  • Marketing: spam, opened, click, hardBounce, softBounce, unsubscribed, listAddition, delivered, contactUpdated, contactDeleted.
  • Thư đến: inboundEmailProcessed, cần 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"
}'

Với thay đổi liên hệ, đăng ký webhook tiếp thị có contactUpdated. Brevo gọi sự kiện trong payload là contact_updated. Xác thực bên nhận bằng bearer token auth hoặc header riêng theo hướng dẫn bảo mật. Kiểm tra bí mật trước khi xử lý, không ghi vào log.

Lưu khóa khử trùng lặp gồm loại sự kiện, ID liên hệ và dấu thời gian trong suốt thời gian giao lại. Chỉ dấu thời gian không bảo đảm duy nhất. Sự kiện có thể lặp hoặc đến sai thứ tự. Đọc lại liên hệ hiện tại và đối soát với nguồn tin cậy. Giới hạn cửa sổ phát lại, bỏ sự kiện cũ sau khôi phục và kiểm tra tăng dần định kỳ để bù phần thiếu. Webhook tự nó không tạo đồng bộ hai chiều. Xem hướng dẫn kết nối.

Giới hạn tốc độ và xử lý lỗi

Giới hạn tốc độ của Brevo được đặt theo từng endpoint và từng bậc gói dịch vụ, và khoảng cách giữa các endpoint là rất lớn.

EndpointGeneral (mọi gói)Advanced (Professional và 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
Endpoint không có giới hạn riêng100 RPH200 RPH

Brevo ghi rõ x-sib-ratelimit-limit, x-sib-ratelimit-remaining và x-sib-ratelimit-reset cho endpoint bị giới hạn. Đọc cả khi thành công. Với 429, đợi thời điểm đặt lại và chỉ thử lại trong số lần cùng thời gian cố định. Reset là khoảng thời gian theo đơn vị của cửa sổ, thường là giây, không phải Unix timestamp.

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

Nếu cần đợi hơn 60 giây, hàm trả 429. Hãy lên lịch thử lại sau.

Hàm hỗ trợ chỉ dùng cho yêu cầu bạn đã xác nhận có thể lặp an toàn. Nếu lỗi gửi không rõ kết quả, đối soát ID thư của bạn trước khi gửi lại. Ghi trạng thái và header giới hạn, không ghi khóa hay dữ liệu liên hệ.

Đừng thử lại mọi 4xx. Tài liệu tạo liên hệ liệt kê 400 và 425; xung đột không nhất thiết là 409. Sau 5xx khi ghi, kiểm tra thay đổi đã áp dụng hay chưa.

Trạng thái nào được trả về?

  1. 429

    Đợi trong giới hạn

    Dùng thời gian reset và dừng sau vài lần thử.

  2. 5xx sau khi ghi

    Kiểm tra kết quả

    Máy chủ có thể đã ghi trước lỗi.

  3. 400

    Sửa yêu cầu

    Thường do đầu vào không hợp lệ.

  4. Xung đột ID

    Đối soát ID

    API không hứa một mã xung đột cố định.

Thử nghiệm mà không gửi thư

Hãy thêm header X-Sib-Sandbox với giá trị drop vào một lệnh gửi giao dịch. Brevo kiểm tra request, trả về 201 kèm messageId, không chuyển phát gì và không ghi nhật ký email.

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>" }'

Hãy hiểu rõ điều này chứng minh được gì và không chứng minh được gì. Chế độ sandbox chỉ kiểm tra định dạng request. Nó không nói gì về xác thực người gửi, kết xuất mẫu hay khả năng vào hộp thư. Hãy giữ một tài khoản Brevo riêng để kiểm thử tích hợp cho bất cứ thứ gì chạm vào danh bạ hoặc dữ liệu CRM, vì chế độ sandbox chỉ bao phủ việc gửi chứ không bao phủ phần còn lại của API.

Kiểm tra trước khi đồng bộ liên hệ

  • Chọn ID nguồn ổn định cho ext_id và lưu ID Brevo trả về.
  • Khai báo thuộc tính trước khi ghi, sau đó đọc lại liên hệ thử nghiệm.
  • Dùng danh sách rõ ràng và bằng chứng đồng ý tin cậy; bỏ qua liên hệ bị chặn hay hủy đăng ký.
  • Đếm riêng bản ghi được nhận, áp dụng, bỏ qua và lỗi. 202 ban đầu chỉ nghĩa là đã nhận.
  • Xác thực, khử trùng lặp webhook tiếp thị và đối soát trạng thái.
  • Theo dõi header giới hạn và dừng sau số lần thử cố định.

Tajo đồng bộ dữ liệu thương mại với Brevo. Nếu tự xây tầng này, xem hướng dẫn connector.

Câu hỏi Thường gặp

Base URL của Brevo API là gì?

Mọi lệnh gọi REST của Brevo đều đi tới https://api.brevo.com/v3/. Phiên bản nằm ngay trong đường dẫn và v3 là thế hệ hiện tại, nên một endpoint như gửi email giao dịch có đường dẫn đầy đủ là https://api.brevo.com/v3/smtp/email.

Bạn xác thực với Brevo API như thế nào?

Bạn gửi khóa của mình trong một HTTP header tên là api-key. Brevo không dùng header Authorization hay Bearer cho khóa API tiêu chuẩn. Khóa được tạo trong phần cài đặt tài khoản, mục SMTP and API, tab API keys, và giá trị chỉ hiển thị đúng một lần.

Giới hạn tốc độ của Brevo API là bao nhiêu?

Giới hạn được đặt theo từng endpoint và theo từng bậc giới hạn tốc độ. Ở bậc general, bậc mà mọi gói đều có, endpoint gửi email giao dịch cho phép 1.000 request mỗi giây, các endpoint danh bạ cho phép 10 request mỗi giây, và các endpoint không có giới hạn riêng bị giới hạn ở 100 request mỗi giờ. Gói Professional và Enterprise có thể dùng bậc advanced, và gói Enterprise có thể dùng bậc extended. Vượt giới hạn sẽ nhận về mã 429.

Brevo có SDK chính thức không?

Có. Brevo phát hành client cho Node.js, Python, PHP, Java, C#, Go và Ruby dưới tổ chức GitHub getbrevo. Gói Node là @getbrevo/brevo trên npm và gói Python là brevo-python trên PyPI.

Làm sao để thử nghiệm Brevo API mà không gửi email thật?

Hãy thêm header X-Sib-Sandbox với giá trị drop vào lệnh gửi email giao dịch. Brevo sẽ kiểm tra request, trả về 201 kèm messageId, không gửi gì cả và không ghi nhật ký email. Chế độ này chỉ kiểm tra định dạng request, không kiểm tra khả năng gửi tới hộp thư.

Brevo hỗ trợ những sự kiện webhook nào?

Webhook giao dịch bao gồm gửi, trả về và hủy đăng ký. Webhook tiếp thị có contactUpdated và contactDeleted. Brevo ghi nhận inboundEmailProcessed cho sự kiện email đến.

Upsert liên hệ bảo vệ việc hủy đăng ký trước đó ra sao?

Dùng ID nguồn ổn định và thuộc tính đã khai báo. Đừng đặt emailBlacklisted: false trong lần cập nhật thông thường. Kiểm tra liên hệ và nguồn đồng ý trước khi thêm vào danh sách tiếp thị.

Webhook có đủ để đồng bộ hai chiều không?

Không. Xác thực bên nhận, loại bỏ lần giao trùng và đối soát sự kiện thiếu hoặc sai thứ tự với nguồn tin cậy. Webhook báo thay đổi, không chứng minh hai hệ thống cùng trạng thái.

Đăng ký quyền truy cập sớm

Nhập tên và địa chỉ email công việc của bạn. Chúng tôi sẽ gửi liên kết để xác nhận yêu cầu truy cập Tajo.

Nhận Brevo