Brevo API: praktični vodič za razvojne inženjere
Vodič kroz Brevo API za razvojne inženjere: autentifikacija, osnovni URL, kontakti, transakcijska e-pošta, kampanje, CRM objekti, webhookovi, ograničenja zahtjeva i stvarna ograničenja.
Brevo izlaže jedan REST API koji obuhvaća transakcijsko slanje poruka, marketinške kampanje, podatke o kontaktima i CRM zapise. Da prvi zahtjev vrati 201 treba vam otprilike dvije minute. Da dobijete produkcijsku integraciju koja tiho ne gubi podatke treba znatno dulje, jer je nekoliko najvažnijih ograničenja ili nedokumentirano ili proturječi onome što API prijavljuje o sebi.
Ovaj vodič pokriva obje polovice: krajnje točke, SDK-ove i autentifikaciju koji vam trebaju prvog dana, te ograničenja platforme oko kojih morate dizajnirati rješenje prije nego što ga pustite u rad.
Što Brevo API pokriva
Sve živi pod jednim hostom i jednom verzijskom putanjom. Razvojna dokumentacija grupira površinu u četiri proizvodna područja:
- Slanje poruka: transakcijska e-pošta, SMS i WhatsApp, uključujući skupna slanja, raspoređivanje i aktivnost poruka.
- Marketinška platforma: kontakti, popisi, segmenti i kampanje e-pošte.
- eCommerce: proizvodi, narudžbe i praćenje događaja kupaca.
- Conversations: chat widget i programsko upravljanje razgovorima.
Ta područja dijele jedan račun, jednu bazu kontakata i jedan API ključ. To je praktično i povremeno opasno: skripta napisana prema pretpostavci o testnim podacima razgovara s istim kontaktima kojima šaljete kampanje.
Transakcijsko naspram marketinškog
Te se dvije obitelji ponašaju dovoljno različito da je njihovo miješanje najčešća pogreška u dizajnu.
| Transakcijsko | Marketinško | |
|---|---|---|
| Glavna krajnja točka | POST /v3/smtp/email | POST /v3/emailCampaigns |
| Adresiranje | Izričiti primatelji u zahtjevu | listIds ili segmentIds |
| Okidač | Vaša aplikacija, u stvarnom vremenu | Raspoređeno ili na zahtjev |
| Tipičan oblik volumena | Kontinuirano, poruka po poruka | U naletima, jedno veliko slanje |
| Stav prema ograničenjima | Vrlo visok, 1.000 zahtjeva u sekundi na standardnim planovima | Nizak, krajnje točke kampanja spadaju pod opće ograničenje |
Ako još odlučujete je li Brevo uopće prava platforma za vas, pregled platforme pokriva to područje.
Autentifikacija i upravljanje ključevima
Brevo koristi običan API ključ u prilagođenom zaglavlju. Zaglavlje se zove api-key, ne Authorization, i nema prefiksa Bearer. Na tome se spotakne gotovo svatko tko je prije radio s nekim drugim API-jem za slanje poruka.
curl https://api.brevo.com/v3/account \ -H "api-key: $BREVO_API_KEY"Ključevi se generiraju u aplikaciji Brevo, u postavkama računa, u odjeljku SMTP and API, na kartici API keys. Svakom ključu dajte opisno ime vezano uz sustav koji ga koristi. Vrijednost ključa prikazuje se točno jednom pri generiranju, pa ako je izgubite, generirate novi umjesto da vraćate stari.
Nekoliko praktičnih pravila:
- Izdajte zaseban ključ po odredištu implementacije i po servisu. Opoziv kompromitiranog ključa nikada ne bi smio srušiti tri nepovezana sustava.
- Standardni API ključevi vrijede za cijeli račun. Svaki ključ tretirajte kao potpuni pristup kontaktima, slanju i CRM podacima.
- Brevo podržava i OAuth 2.0 za aplikacije koje djeluju u ime drugih Brevo računa, što je opisano uz tijek s ključevima u dokumentu authentication schemes.
- MCP poslužitelj koji koriste AI asistenti uzima zaseban token i doista koristi bearer zaglavlje. Taj se token generira na istom zaslonu s API ključevima, ali nije zamjenjiv s REST ključem.
Osnovni URL, verzioniranje i vaš prvi zapis
Osnovni URL je https://api.brevo.com/v3/. Verzija je u putanji, a ne u zaglavlju, i v3 je aktualna generacija. Svaka putanja u ovom vodiču relativna je prema toj osnovi.
Prvi zapis govori više od prvog čitanja, jer aktivira dijelove računa koji su obično krivo konfigurirani, posebno provjerene pošiljatelje:
curl -X POST https://api.brevo.com/v3/smtp/email \ -H "api-key: $BREVO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "sender": { "name": "Ops", "email": "[email protected]" }, "to": [{ "email": "[email protected]", "name": "Dev" }], "subject": "First transactional send", "htmlContent": "<html><body><p>It works.</p></body></html>", "tags": ["smoke-test"] }'Uspješno slanje vraća 201 s vrijednošću messageId. Raspoređeno slanje vraća 202.
Krajnje točke koje ćete stvarno koristiti
Kontakti
POST /v3/contacts stvara kontakt. Tijelo prima email, mapu attributes za prilagođena polja, listIds, ext_id za vaš vlastiti vanjski ključ te dvije zastavice koje u praksi najviše znače: updateEnabled, koja poziv pretvara u upsert, i getId, koja čini da odgovor vrati ID kontakta.
Čitanja idu kroz GET /v3/contacts, koji stranicira uz limit (zadano 50, najviše 1000) i offset, a podržava modifiedSince i createdSince u UTC-u. Inkrementalne sinkronizacije trebale bi se oslanjati na modifiedSince umjesto na prolazak kroz cijeli popis. Imajte na umu da parametar filter podržava samo operator jednakosti, pa sve izražajnije pripada u segment.
Za skupno učitavanje POST /v3/contacts/import prima fileUrl, fileBody ili jsonBody, cilja listIds i izvodi se asinkrono, vraćajući processId. Brevo dokumentira najveće tijelo od 10 MB i preporučuje da ostanete blizu 8 MB jer parsiranje napuhuje sadržaj. Navedite notifyUrl da saznate ishod umjesto da ispitujete stanje u petlji.
Transakcijska e-pošta
POST /v3/smtp/email je radni konj. Osim sender, to, subject i htmlContent, vrijedi znati i ova polja:
templateIduzparams, koji zamjenjuje ugrađeni sadržaj predloškom iz platforme Brevo i njegovim zamjenama varijabli. Parametri pojedinačne verzije ograničeni su na 100 KB, a kumulativni parametri na 1000 KB.messageVersions, koji jednim pozivom šalje personalizirane varijante, uz najviše 99 primatelja po verziji.tags, koje biste uvijek trebali postaviti. Oznake se vraćaju u webhook događajima i jedini su jeftin način da povežete događaj isporuke s dijelom koda koji ga je proizveo.scheduledAtuzbatchId, za buduća slanja koja ćete možda htjeti otkazati kao grupu.headers, u obliku Title-Case, za prilagođena SMTP zaglavlja.
Jedan zahtjev prima najviše 2.000 primatelja. Za razliku između ove krajnje točke i slanja kampanja, vodič za transakcijsku e-poštu donosi pogled iz perspektive strategije poruka.
Kampanje e-pošte
POST /v3/emailCampaigns zahtijeva name i sender, uz točno jedan izvor sadržaja: htmlContent (najmanje 10 znakova, ispod 1 MB), htmlUrl ili templateId. Publika ide u recipients kao listIds ili segmentIds, a scheduledAt koristi UTC format YYYY-MM-DDTHH:mm:ss.SSSZ. Prateće rute pokrivaju trenutno slanje, slanje testa, ažuriranje statusa i dohvat izvještaja o kampanji.
Tvrtke, poslovi i objekti
CRM platforme Brevo ima dvije preklapajuće putanje za zapisivanje i ispravan izbor je važan.
CRM rute su POST /v3/companies, PATCH /v3/companies/{id}, DELETE /v3/companies/{id} i ekvivalentni skup za poslove. One su sinkrone. PATCH vraća 204 čim je promjena primijenjena.
Objects API je skupna putanja: POST /v3/objects/{object_type}/batch/upsert prima do 1000 zapisa i 1 MB po zahtjevu, do 500 atributa po zapisu i do 10 povezanih zapisa po tipu objekta po zapisu. Vraća 202 s vrijednošću processId, što znači prihvaćeno, a ne primijenjeno.
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" } } ] }'Vodič za Brevo CRM pokriva model objekata iz operaterske perspektive.
Službeni SDK-ovi
Brevo održava klijente u GitHub organizaciji getbrevo:
| Jezik | Repozitorij |
|---|---|
| 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 |
Node klijent instalira se kao @getbrevo/brevo:
npm install @getbrevo/brevoimport { BrevoClient } from "@getbrevo/brevo";
const brevo = new BrevoClient({ apiKey: process.env.BREVO_API_KEY });
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);Python klijent instalira se s pip install brevo-python. Ako radije ne biste nosili ovisnost o SDK-u zbog dvije krajnje točke, sirova HTTP površina dovoljno je mala da je pozivate izravno, što vas ujedno štiti od stalnih promjena verzija SDK-a:
import osimport requests
BASE = "https://api.brevo.com/v3"HEADERS = { "api-key": os.environ["BREVO_API_KEY"], "Content-Type": "application/json",}
def upsert_contact(email, attributes, list_ids): response = requests.post( f"{BASE}/contacts", headers=HEADERS, json={ "email": email, "attributes": attributes, "listIds": list_ids, "updateEnabled": True, }, timeout=30, ) response.raise_for_status() return responsePostoji i MCP poslužitelj na https://mcp.brevo.com/v1/brevo/mcp za AI asistente, autentificiran bearer tokenom generiranim na istom zaslonu postavki. Koristan je za istraživanje i pitanja o računu, ne za produkcijske podatkovne putanje.
Webhookovi
Webhookovi su način na koji saznajete što se dogodilo nakon slanja. POST /v3/webhooks stvara jedan, s poljima url, events, type i opcionalno channel (email ili sms), batched, prilagođenim headers i objektom auth.
Postoje tri vrste webhookova s različitim rječnicima događaja:
- Transakcijski:
sent,request,delivered,hardBounce,softBounce,blocked,spam,invalid,deferred,click,opened,uniqueOpened,unsubscribed. - Marketinški:
spam,opened,click,hardBounce,softBounce,unsubscribed,listAddition,delivered,contactUpdated,contactDeleted. - Dolazni:
inboundEmailProcessedireply, koji dodatno zahtijevajudomain.
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" }'Tri stvari treba dobro postaviti. Prvo, račun može držati najviše 40 webhookova kroz sve vrste, pa usmjeravajte prema događaju unutar vlastitog rukovatelja umjesto da registrirate jednu krajnju točku po događaju. Drugo, koristite zastavicu batched kada očekujete volumen, jer je jedan zahtjev s mnogo događaja daleko jeftiniji za obradu od mnogo zahtjeva. Treće, zaštitite primatelja: Brevo objavljuje raspone svojih IP adresa za slanje, a ograničavanje vaše krajnje točke na te raspone dokumentirani je pristup. Dodajte vlastitu dijeljenu tajnu kroz polje headers kao drugi sloj.
Rukovatelji moraju biti idempotentni. Kao ključ za uklanjanje duplikata koristite ID poruke uz vrstu događaja i vremensku oznaku.
Ograničenja zahtjeva i rukovanje pogreškama
Ograničenja zahtjeva u platformi Brevo određuju se po krajnjoj točki i po razini plana, a raspon između krajnjih točaka je ogroman.
| Krajnja točka | Standard | Professional i Enterprise |
|---|---|---|
POST /v3/smtp/email | 1.000 RPS | 2.000 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 | više na planu Enterprise |
GET /v3/smtp/emails | 2 RPS, 7.200 RPH | 3 RPS, 10.800 RPH |
| Sve ostalo | 100 RPH | 200 RPH |
Taj zadnji redak boli. Slanje je praktički nemjereno, dok upravljanje kampanjama, CRM čitanja i većina administrativnih poziva dijele proračun od 100 zahtjeva na sat na standardnim planovima. Naivno popunjavanje podataka koje čita zapis tvrtke prije svakog zapisivanja potrošit će cijelu satnu kvotu u manje od dvije minute.
Svaki odgovor nosi x-sib-ratelimit-limit, x-sib-ratelimit-remaining i x-sib-ratelimit-reset. Čitajte ih pri uspjehu, ne samo pri neuspjehu. Prekoračenje ograničenja vraća 429, a ispravna reakcija jest pričekati interval iz zaglavlja za resetiranje i zatim primijeniti eksponencijalnu odgodu s nasumičnim odmakom.
async function callBrevo(path, init, attempt = 0) { const response = await fetch(`https://api.brevo.com/v3${path}`, { ...init, headers: { "api-key": process.env.BREVO_API_KEY, "Content-Type": "application/json", ...init.headers }, });
if (response.status === 429 && attempt < 5) { const reset = Number(response.headers.get("x-sib-ratelimit-reset") || 1); const backoff = Math.pow(2, attempt) * 250 + Math.random() * 250; await new Promise((r) => setTimeout(r, reset * 1000 + backoff)); return callBrevo(path, init, attempt + 1); }
return response;}Ponavljajte 429 i 5xx. Nikada slijepo ne ponavljajte 400 ili 409, jer oboje obično znači da je zahtjev pogrešan, a ne prerani, a 409 posebno traži drugačiju radnju umjesto ponavljanja.
Testiranje bez slanja pošte
Transakcijskom slanju dodajte zaglavlje X-Sib-Sandbox s vrijednošću drop. Brevo provjerava zahtjev, vraća 201 s vrijednošću messageId, ne isporučuje ništa i ne zapisuje zapis o e-pošti.
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>" }'Shvatite što to dokazuje, a što ne. Sandbox način provjerava samo format zahtjeva. Ne govori ništa o autentifikaciji pošiljatelja, iscrtavanju predloška ili isporučivosti. Držite zaseban Brevo račun za integracijsko testiranje svega što dira kontakte ili CRM podatke, jer sandbox način pokriva slanje, a ne ostatak API-ja.
Ograničenja koja oblikuju dizajn vaše integracije
Ovo su ograničenja koja se pojave tek kada integracija radi nad stvarnim računom pod volumenom. Nekoliko ih proturječi onome što API govori o sebi. Nijedno nije pregovaračko, pa je jedini razuman odgovor dizajnirati rješenje oko njih.
Tvrtke zahtijevaju domenu i samo jednu tvrtku po domeni
GET /v3/crm/attributes/companies prijavljuje svaki atribut kao neobavezan, a referenca za stvaranje tvrtke navodi samo name kao obavezan. U praksi POST /v3/companies bez nepraznog atributa domain vraća 400 s porukom o nedostajućim obaveznim zadanim atributima. Prazan niz znakova ne prolazi jednako kao i njegovo izostavljanje.
Gore od toga, jedinstvenost domene se nameće. Druga tvrtka na već korištenoj domeni vraća 409. Za B2B trgovinu to je strukturno: podružnice koje dijele jednu domenu e-pošte kupca ne mogu sve postojati kao zasebne tvrtke u platformi Brevo. Sinkronizacija kontakta također je dovoljna da se tvrtka pojavi na domeni e-pošte tog kontakta, pa se stvaranje može sudariti s tvrtkom koju nitko nije izričito stvorio. Ispravan rukovatelj na 409 preuzima postojeću tvrtku umjesto da javi pogrešku ili ponovi poziv.
Nedeklarirani atributi se tiho odbacuju
Ovo je najopasnije ponašanje u platformi i Brevo ga otvoreno dokumentira: ako se atribut pojavi u zahtjevu, a nije prethodno definiran u shemi objekta, ne događa se ništa. Bez pogreške, bez stvaranja atributa, bez upozorenja.
Odgovor 2xx stoga nije dokaz da su vaši podaci sletjeli. Pročitajte shemu prije zapisivanja, odbacite sve nedeklarirano u vlastitom klijentu i odbijte pokretanje sinkronizacije čiji atributi ne postoje umjesto da mjesec dana zapisujete pola zapisa prije nego što itko primijeti.
Filtri po atributima prihvaćaju se i ignoriraju
GET /v3/companies?filters[attributes.domain]=... vraća 200 i ignorira filtar. Dva potpuno različita filtra vraćaju iste zapise. Kroz tu rutu ne postoji način da se tvrtka pronađe po atributu.
U kombinaciji s činjenicom da nefiltrirani popis na velikim računima istječe uz 504 pri bilo kojoj veličini stranice, postojeća tvrtka može biti doista nepronalaziva kroz dokumentiranu putanju. Zaobilazno rješenje jest skenirati GET /v3/objects/company/records uz sort=desc, što je brzo, paginirano i vraća atribute, ograničeno na razuman broj stranica. Tvrtka koja je upravo izazvala 409 gotovo je uvijek stvorena trenutak ranije, pa je skeniranje od najnovijeg prema starijem brzo pronalazi.
Milijun zapisa po tipu objekta i bez skupnog brisanja
POST /v3/objects/{type}/batch/upsert vraća 400 čim tip objekta drži milijun zapisa. Blokira i ažuriranja, a ne samo stvaranja: adresiranje postojećeg zapisa vlastitim brojčanim ID-em jednako ne prolazi. Cijela putanja zapisivanja u objekte zatvara se odjednom.
Povratak ispod gornje granice je spor, jer POST /v3/objects/{type}/batch/delete vraća 403 za standardne tipove objekata platforme Brevo poput company. Jedina ruta je DELETE /v3/companies/{id}, jedan zapis po pozivu uz otprilike 156 ms. Čišćenje 124.000 zapisa na taj je način trajalo satima uz 20 paralelnih radnika. Pratite broj zapisa po rasporedu umjesto da gornju granicu otkrijete kroz neuspjelu sinkronizaciju, a ažuriranja velikog volumena usmjerite kroz PATCH /v3/companies/{id}, koji nema takvo ograničenje.
ext_id je ID platforme Brevo, ne vaš
Na zapisima objekata identifiers.ext_id drži vlastiti CRM ID tvrtke iz platforme Brevo, niz znakova u stilu Mongo baze. To nije slobodan vanjski ključ. Ako upsert vežete na ext_id postavljen na identifikator vaše platforme, stvarat ćete duplikate umjesto podudaranja. Vaš vanjski ID pripada u vlastiti deklarirani atribut.
Upserti objekata su asinkroni, CRM zapisi nisu
batch/upsert vraća 202 i processId, a primjenjuje se kasnije. Nepostojeći ID pada asinkrono i vašem pozivatelju svejedno vraća 202. PATCH /v3/companies/{id} vraća 204 i primjenjuje se sinkrono. Ako vaša sinkronizacija prijavi uspjeh, samo sinkrona putanja zaslužuje tu riječ bez naknadnog čitanja.
Kratka kontrolna lista za integraciju
- Zasebni API ključevi po servisu i po okruženju, rotirani pri promjenama u timu.
- Sva zapisivanja idu kroz jednog klijenta koji čita zaglavlja s ograničenjima i odgađa pri 429.
- Shema atributa provjerava se pri pokretanju, a sinkronizacija odbija raditi ako njezini atributi nedostaju.
- 409 pri stvaranju tvrtke znači preuzeti, ne ponoviti.
- Skupne putanje koriste objects API za propusnost, a CRM rute za sve što mora biti potvrđeno.
- Webhookovi su idempotentni, grupirani, ograničeni po IP adresi i nose zaglavlje s dijeljenom tajnom.
- Inkrementalne sinkronizacije kontakata koriste
modifiedSince, a ne prolaske kroz cijeli popis.
Izgradnja i održavanje tog sloja stvaran je inženjerski posao: provjera sheme, odgoda, logika preuzimanja, usklađivanje. Tajo postoji da ga apsorbira, održavajući podatke iz platforme Shopify i trgovine sinkroniziranima s kontaktima, tvrtkama i događajima u platformi Brevo bez da itko ručno piše logiku ponavljanja i uklanjanja duplikata. Ako to ipak spajate sami, vodič za Brevo integraciju vodi vas kroz odluke o modelu podataka koje dolaze prije koda.
Ključne poruke
- API je jedna REST površina na
https://api.brevo.com/v3/, autentificirana zaglavljemapi-keyumjesto bearer tokenom. - Ograničenja zahtjeva su izrazito neujednačena: slanje je praktički nemjereno, dok većina drugih krajnjih točaka dijeli 100 zahtjeva na sat na standardnim planovima.
- Službeni SDK-ovi postoje za sedam jezika, ali je HTTP površina dovoljno jednostavna da je pozivate izravno kada trebate tek nekoliko krajnjih točaka.
- Sandbox način provjerava samo format zahtjeva, pa držite zaseban račun za testiranje svega izvan slanja.
- Odgovor 2xx ne dokazuje da je zapis primijenjen. Nedeklarirani atributi tiho se odbacuju, a upserti objekata su asinkroni.
- Dizajnirajte rješenje oko fiksnih ograničenja: jedna tvrtka po domeni, milijun zapisa po tipu objekta, bez skupnog brisanja za standardne objekte i filtri po atributima koji tiho ne rade ništa.