Na tej stronie
Import kontaktu może zwrócić 201 i nadal być błędny: zgubione ID źródła, zła lista albo pominięte wypisanie. To decyzje o danych, nie szczegóły HTTP.
Ten przewodnik pokazuje działające żądanie Brevo, a potem kontrole potrzebne do powtarzalnej małej synchronizacji.
Co obejmuje Brevo API
Wszystko żyje pod jednym hostem i jedną ścieżką wersji. Dokumentacja dla programistów dzieli tę powierzchnię na cztery obszary produktowe:
- Wiadomości: email transakcyjny, SMS i WhatsApp, w tym wysyłki wsadowe, harmonogramowanie i aktywność wiadomości.
- Platforma marketingowa: kontakty, listy, segmenty i kampanie emailowe.
- eCommerce: produkty, zamówienia i śledzenie zdarzeń klienta.
- Conversations: widżet czatu i programowe zarządzanie rozmowami.
Te obszary dzielą jedno konto, jedną bazę kontaktów i jeden klucz API. To wygodne i czasami niebezpieczne: skrypt napisany z myślą o testowej wersji danych rozmawia z tymi samymi kontaktami, do których wysyłasz kampanie.
Transakcyjny kontra marketingowy
Te dwie rodziny zachowują się na tyle różnie, że pomylenie ich to najczęstszy błąd projektowy.
| Transakcyjny | Marketingowy | |
|---|---|---|
| Główny endpoint | POST /v3/smtp/email | POST /v3/emailCampaigns |
| Adresowanie | Jawni odbiorcy w zapytaniu | listIds lub segmentIds |
| Wyzwalacz | Twoja aplikacja, w czasie rzeczywistym | Zaplanowany lub wysłany na żądanie |
| Typowy kształt wolumenu | Ciągły, jedna wiadomość naraz | Skokowy, jedna duża wysyłka |
| Postawa wobec limitów | Bardzo wysoka, 1000 zapytań na sekundę na poziomie ogólnym | Niska, endpointy kampanii podlegają ogólnemu pułapowi |
Jeśli wciąż zastanawiasz się, czy Brevo to w ogóle właściwa platforma, przegląd platformy opisuje ten temat.
Uwierzytelnianie i zarządzanie kluczami
Brevo używa zwykłego klucza API w niestandardowym nagłówku. Nagłówek nazywa się api-key, a nie Authorization, i nie ma prefiksu Bearer. Potyka się o to niemal każdy, kto wcześniej korzystał z innego API do wysyłki wiadomości.
OAuth może używać tokenu Bearer dla obsługiwanych operacji; zwykły klucz API nadal trafia do nagłówka api-key.
curl https://api.brevo.com/v3/account \ -H "api-key: $BREVO_API_KEY"Klucze generujesz w aplikacji Brevo, w ustawieniach konta, w sekcji SMTP and API, na karcie API keys. Nadaj każdemu kluczowi opisową nazwę powiązaną z systemem, który go używa. Wartość klucza wyświetla się dokładnie raz, w momencie wygenerowania, więc jeśli ją zgubisz, generujesz nowy klucz, a nie odzyskujesz stary.
Kilka praktycznych zasad:
- Wydawaj osobny klucz na każde środowisko wdrożeniowe i każdą usługę. Unieważnienie skompromitowanego klucza nigdy nie powinno wyłączać trzech niepowiązanych systemów.
- Standardowe klucze API działają na całym koncie. Traktuj każdy klucz jak pełny dostęp do kontaktów, wysyłki i danych CRM.
- Brevo obsługuje też OAuth 2.0 dla aplikacji działających w imieniu innych kont Brevo, co opisano obok przepływu z kluczami w schematach uwierzytelniania.
- Serwer MCP używany przez asystentów AI przyjmuje osobny token i faktycznie korzysta z nagłówka bearer. Ten token generujesz na tym samym ekranie API keys, ale nie jest on wymienny z kluczem REST.
Adres bazowy, wersjonowanie i pierwszy zapis
Adres bazowy to https://api.brevo.com/v3/. Wersja jest w ścieżce, a nie w nagłówku, a v3 to aktualna generacja. Każda ścieżka w tym przewodniku jest podana względem tego adresu.
Do pierwszego zapisu kontaktu użyj własnego adresu testowego, prawdziwego ID listy i stałego ID źródła. Najpierw utwórz atrybut FNAME w Brevo. Z prawdziwym kluczem przykład zapisuje dane live:
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 }'Zastąp 42 ID listy testowej. Odczytaj kontakt i sprawdź ID, imię, listę oraz blokady. Sam kod 2xx nie dowodzi oczekiwanego wyniku.
Endpointy, których naprawdę użyjesz
Kontakty
POST /v3/contacts tworzy kontakt. Przyjmuje email, zdefiniowane attributes, listIds i ext_id jako stały klucz źródłowy. updateEnabled: true aktualizuje istniejący kontakt, a getId: true zwraca końcowe ID. Brevo dokumentuje pola. Używaj tej samej ext_id w każdym przebiegu i zapisuj powiązanie ID źródła z ID Brevo.
Przed zapisem ustal, który system jest właścicielem każdego atrybutu i która lista ma otrzymać kontakty ze zgodą. Podaj listIds jawnie. Nie ustawiaj emailBlacklisted: false w zwykłym upsercie. Brevo ostrzega, że zmiana adresu zablokowanego kontaktu usuwa blokadę. Traktuj ją osobno. Sprawdź blokady i wypisania przed dodaniem do listy marketingowej. Między odczytem i zapisem pozostaje krótka luka; przy ścisłym wymaganiu sprawdź blokadę jeszcze raz przed wysyłką.
Odczyty idą przez GET /v3/contacts, które stronicuje przez limit (domyślnie 50, maksymalnie 1000) i offset oraz obsługuje modifiedSince i createdSince w UTC. Synchronizacje przyrostowe powinny opierać się na modifiedSince, zamiast przechodzić całą listę. Zwróć uwagę, że parametr filter obsługuje wyłącznie operator równości, więc wszystko bardziej wyraziste należy do segmentu.
Do masowego ładowania POST /v3/contacts/import przyjmuje fileUrl, fileBody lub jsonBody, celuje w listIds, działa asynchronicznie i zwraca processId. Brevo dokumentuje maksymalny rozmiar ciała 10 MB i zaleca trzymanie się blisko 8 MB, bo parsowanie zwiększa ładunek. Podaj notifyUrl, żeby poznać wynik zamiast odpytywać.
Email transakcyjny
POST /v3/smtp/email to koń roboczy. Poza sender, to, subject i htmlContent warto znać te pola:
templateIdwraz zparams, które zastępuje treść wpisaną wprost szablonem Brevo i podstawieniami zmiennych. Parametry pojedynczej wersji mają pułap 100 KB, a łącznie 1000 KB.messageVersions, które wysyła spersonalizowane warianty w jednym wywołaniu, po maksymalnie 99 odbiorców na wersję.tagsmogą pomóc powiązać zdarzenia dostarczenia z przepływem aplikacji, który je wywołał.scheduledAtrazem zbatchId, dla przyszłych wysyłek, które możesz chcieć anulować grupowo.headers, zapisane w Title-Case, dla niestandardowych nagłówków SMTP.
Pojedyncze zapytanie przyjmuje maksymalnie 2000 odbiorców. Różnicę między tym endpointem a wysyłką kampanii z perspektywy strategii komunikacji opisuje przewodnik po emailu transakcyjnym.
Kampanie emailowe
POST /v3/emailCampaigns wymaga name i sender oraz dokładnie jednego źródła treści: htmlContent (minimum 10 znaków, poniżej 1 MB), htmlUrl lub templateId. Odbiorcy trafiają do recipients jako listIds lub segmentIds, a scheduledAt używa formatu UTC YYYY-MM-DDTHH:mm:ss.SSSZ. Trasy towarzyszące obsługują natychmiastową wysyłkę, wysyłkę testu, aktualizację statusu i pobranie raportu kampanii.
Firmy, szanse sprzedaży i obiekty
CRM w Brevo ma dwie nakładające się ścieżki zapisu i poprawny wybór ma znaczenie.
Trasy CRM to POST /v3/companies, PATCH /v3/companies/{id}, DELETE /v3/companies/{id} oraz odpowiedni zestaw dla szans sprzedaży. Są synchroniczne. PATCH zwraca 204, gdy zmiana zostanie zastosowana.
API obiektów to ścieżka masowa: POST /v3/objects/{object_type}/batch/upsert przyjmuje do 1000 rekordów i 1 MB na zapytanie, do 500 atrybutów na rekord i do 10 rekordów powiązań na typ obiektu na rekord. Zwraca 202 z polem processId, co znaczy „przyjęte”, a nie „zastosowane”.
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" } } ] }'Przewodnik po Brevo CRM opisuje model obiektowy od strony operatora.
Oficjalne SDK
Brevo utrzymuje klienty w organizacji GitHub getbrevo:
| Język | Repozytorium |
|---|---|
| Node.js | github.com/getbrevo/brevo-node |
| Python | github.com/getbrevo/brevo-python |
| PHP | github.com/getbrevo/brevo-php |
| Java | github.com/getbrevo/brevo-java |
| C# | github.com/getbrevo/brevo-csharp |
| Go | github.com/getbrevo/brevo-go |
| Ruby | github.com/getbrevo/brevo-ruby |
Klient Node instaluje się jako @getbrevo/brevo:
npm install @getbrevo/brevoimport { 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>", tags: ["order-confirmation"],});
console.log("Message ID:", result.messageId);Klient Pythona instaluje się przez pip install brevo-python. Jeśli wolisz nie ciągnąć zależności SDK dla dwóch endpointów, surowa powierzchnia HTTP jest na tyle mała, że można wołać ją bezpośrednio, co dodatkowo uodparnia Cię na zmiany wersji SDK:
Klienta Python instalujesz przez pip install brevo-python. Przy kilku endpointach możesz też wywoływać HTTP bezpośrednio:
import osimport 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 NoneUdana aktualizacja może zwrócić pustą odpowiedź 204. None oznacza wtedy, że trzeba ponownie odczytać kontakt, aby uzyskać ID.
Przykład zakłada, że wywołujący sprawdził już zgodę i blokady w Brevo. Nie odblokowuje kontaktu. Z prawdziwym kluczem zapisuje dane na żywo; najpierw przetestuj go na symulacji. Konflikty identyfikatorów mogą zwracać różne kody 4xx. Odczytaj odpowiedź i uzgodnij ID, nie zakładaj zawsze 409.
Webhooki
Webhooki to sposób, w jaki dowiadujesz się, co stało się po wysyłce. POST /v3/webhooks tworzy webhook z polami url, events, type oraz opcjonalnie channel (email lub sms), batched, niestandardowymi headers i obiektem auth.
Istnieją trzy typy webhooków o odrębnych słownikach zdarzeń:
- Transakcyjne:
sent,request,delivered,hardBounce,softBounce,blocked,spam,invalid,deferred,click,opened,uniqueOpened,unsubscribed. - Marketingowe:
spam,opened,click,hardBounce,softBounce,unsubscribed,listAddition,delivered,contactUpdated,contactDeleted. - Przychodzące:
inboundEmailProcessedireply, które dodatkowo wymagają poladomain.
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" }'Dla zmian kontaktu zarejestruj webhook marketingowy z contactUpdated. Brevo nazywa zdarzenie w payloadzie contact_updated. Uwierzytelnij odbiorcę tokenem bearer auth albo własnymi nagłówkami z instrukcji Brevo. Sprawdź sekret przed obsługą i nie zapisuj go w logach.
Przechowuj klucz deduplikacji z typu zdarzenia, ID kontaktu i znacznika czasu przez okres obejmujący powtórne dostawy. Sam znacznik czasu nie jest unikatowy. Zdarzenia mogą się powtarzać albo przyjść poza kolejnością. Po sygnale odczytaj bieżący kontakt i uzgodnij go ze źródłem prawdy. Ustal okno odtwarzania, odrzucaj przestarzałe zdarzenia po awarii i okresowo wykonuj kontrolę przyrostową. Webhook sygnalizuje zmianę; sam nie tworzy synchronizacji w obie strony. Przewodnik po konektorach omawia wybór.
Limity zapytań i obsługa błędów
Limity zapytań w Brevo są ustalane per endpoint i per poziom planu, a rozrzut między endpointami jest ogromny.
| Endpoint | General (każdy plan) | Advanced (Professional i Enterprise) |
|---|---|---|
POST /v3/smtp/email | 1000 RPS | 2000 RPS |
POST /v3/transactionalSMS/send | 150 RPS | 200 RPS |
/v3/contacts/... | 10 RPS, 36 000 RPH | 20 RPS, 72 000 RPH |
POST /v3/events | 10 RPS, 36 000 RPH | 20 RPS, 72 000 RPH |
GET /v3/smtp/emails | 2 RPS, 7200 RPH | 3 RPS, 10 800 RPH |
| Endpointy bez własnego limitu | 100 RPH | 200 RPH |
Brevo dokumentuje x-sib-ratelimit-limit, x-sib-ratelimit-remaining i x-sib-ratelimit-reset dla limitowanych endpointów. Czytaj je również po sukcesie. Przy 429 odczekaj do resetu i ponawiaj tylko w ustalonym limicie prób i czasu. Reset jest czasem trwania w jednostce okna, zwykle sekundach, a nie znacznikiem 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)); }}Jeśli wymagane oczekiwanie przekracza 60 sekund, funkcja zwraca 429. Zaplanuj kolejną próbę później.
Ta funkcja jest tylko dla żądań, których ponawianie sprawdziłeś jako bezpieczne. Po niejednoznacznym błędzie wysyłki uzgodnij ID wiadomości przed kolejną próbą. Loguj status i limity, ale nie klucz API ani dane kontaktów.
Nie ponawiaj 4xx bez sprawdzenia. Dokumentacja tworzenia kontaktu wymienia 400 i 425; konflikt nie musi oznaczać 409. Po 5xx przy zapisie sprawdź, czy zmiana już zaszła.
Jaki status wrócił?
-
429
Czekaj w granicach limitu
Użyj czasu resetu i zatrzymaj się po kilku próbach.
-
5xx po zapisie
Sprawdź wynik
Serwer mógł zapisać przed błędem.
-
400
Popraw żądanie
Zwykle jest nieprawidłowe.
-
Konflikt identyfikatorów
Odczytaj i uzgodnij ID
API nie gwarantuje konkretnego kodu.
Testowanie bez wysyłania poczty
Dodaj do wysyłki transakcyjnej nagłówek X-Sib-Sandbox z wartością drop. Brevo zweryfikuje zapytanie, zwróci 201 z polem messageId, niczego nie dostarczy i nie zapisze logu emaila.
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>" }'Zrozum, co to dowodzi, a czego nie. Tryb sandbox weryfikuje wyłącznie format zapytania. Nie mówi nic o uwierzytelnieniu nadawcy, renderowaniu szablonu ani dostarczalności. Trzymaj osobne konto Brevo do testów integracyjnych wszystkiego, co dotyka kontaktów lub danych CRM, bo tryb sandbox obejmuje wysyłkę, a nie resztę API.
Przed synchronizacją kontaktów
- Wybierz stałe ID źródłowe dla
ext_idi zapisz zwrócone ID Brevo. - Sprawdź atrybuty przed zapisem. Brevo może pominąć nieznane lub błędnie typowane pola; odczytaj kontakt testowy.
- Użyj jawnej listy i wiarygodnego dowodu zgody. Pomijaj blokady i wypisania.
- Licz osobno rekordy przyjęte, zastosowane, pominięte i błędne. Kod 202 dla partii lub obiektu potwierdza tylko przyjęcie.
- Webhooki marketingowe traktuj jak sygnały; uzgadniaj aktualny stan. Uwierzytelniaj, deduplikuj i ograniczaj odtwarzanie.
- Monitoruj nagłówki limitów i kończ po kilku próbach.
Tajo synchronizuje dane handlowe z Brevo. Jeśli budujesz tę warstwę samodzielnie, przewodnik po konektorach Brevo porównuje ścieżki i obsługę błędów.
Najczęściej Zadawane Pytania
Jaki jest adres bazowy Brevo API?
Wszystkie wywołania REST w Brevo trafiają pod https://api.brevo.com/v3/. Wersja jest częścią ścieżki, a v3 to aktualna generacja, więc endpoint taki jak wysyłka transakcyjna ma pełną ścieżkę https://api.brevo.com/v3/smtp/email.
Jak uwierzytelnić się w Brevo API?
Wyślij swój klucz w nagłówku HTTP o nazwie api-key. Brevo nie używa nagłówka Authorization ani Bearer dla standardowych kluczy API. Klucze generujesz w ustawieniach konta, w sekcji SMTP and API, na karcie API keys, a wartość wyświetla się tylko raz.
Jakie są limity zapytań w Brevo API?
Limity są ustalane per endpoint i per poziom limitów zapytań. Na poziomie ogólnym, który ma każdy plan, endpoint wysyłki transakcyjnej dopuszcza 1000 zapytań na sekundę, endpointy kontaktów 10 na sekundę, a endpointy bez własnego limitu mają pułap 100 zapytań na godzinę. Plany Professional i Enterprise mogą korzystać z poziomu Advanced, a Enterprise także z poziomu Extended. Przekroczenie limitu zwraca 429.
Czy Brevo ma oficjalne SDK?
Tak. Brevo publikuje klienty dla Node.js, Pythona, PHP, Javy, C#, Go i Ruby w organizacji GitHub getbrevo. Paczka dla Node to @getbrevo/brevo w npm, a paczka Pythona to brevo-python w PyPI.
Jak przetestować Brevo API bez wysyłania prawdziwych emaili?
Dodaj do wysyłki transakcyjnej nagłówek X-Sib-Sandbox z wartością drop. Brevo zweryfikuje zapytanie, zwróci 201 z polem messageId, nic nie wyśle i nie zapisze logu emaila. Sprawdza wyłącznie format zapytania, a nie dostarczalność.
Jakie zdarzenia webhooków obsługuje Brevo?
Webhooki transakcyjne obejmują dostarczenie, odbicia i wypisania. Marketingowe obejmują contactUpdated i contactDeleted. Dla zdarzeń przychodzących Brevo dokumentuje inboundEmailProcessed.
Jak aktualizacja kontaktu chroni wcześniejsze wypisanie?
Użyj stałego ID źródłowego i zdefiniowanych atrybutów. Nie ustawiaj emailBlacklisted na false przy zwykłych aktualizacjach. Przed dodaniem do listy marketingowej sprawdź kontakt i źródło zgody.
Czy webhook wystarczy do synchronizacji w obie strony?
Nie. Uwierzytelnij odbiorcę, usuń zdublowane dostawy i uzgodnij zdarzenia pominięte lub poza kolejnością z wiarygodnym źródłem. Webhook sygnalizuje zmianę, nie dowodzi zgodności systemów.