Pe această pagină
Un import de contact poate întoarce 201 și totuși să fie greșit: ID-ul sursă s-a pierdut, lista este greșită sau o dezabonare a fost ignorată. Sunt decizii despre date, nu detalii HTTP.
Ghidul pornește cu o cerere Brevo funcțională și continuă cu verificările pentru o sincronizare mică, repetabilă.
Ce acoperă Brevo API
Totul stă sub o singură gazdă și o singură cale de versiune. Documentația pentru dezvoltatori grupează suprafața în patru zone de produs:
- Mesagerie: e-mail tranzacțional, SMS și WhatsApp, inclusiv trimiteri în lot, programare și activitatea mesajelor.
- Platformă de marketing: contacte, liste, segmente și campanii de e-mail.
- eCommerce: produse, comenzi și urmărirea evenimentelor clienților.
- Conversations: widgetul de chat și gestionarea programatică a conversațiilor.
Aceste zone împart un singur cont, o singură bază de date de contacte și o singură cheie API. Este convenabil și, ocazional, periculos: un script scris pornind de la o idee de staging despre date vorbește cu aceleași contacte către care trimit campaniile tale.
Tranzacțional față de marketing
Cele două familii se comportă suficient de diferit încât confundarea lor este cea mai frecventă eroare de proiectare.
| Tranzacțional | Marketing | |
|---|---|---|
| Endpoint principal | POST /v3/smtp/email | POST /v3/emailCampaigns |
| Adresare | Destinatari expliciți în cerere | listIds sau segmentIds |
| Declanșator | Aplicația ta, în timp real | Programat sau trimis la cerere |
| Forma tipică a volumului | Continuu, câte un mesaj o dată | În valuri, o singură trimitere mare |
| Poziția față de limita de rată | Foarte ridicată, 1.000 de cereri pe secundă pe nivelul general | Scăzută, endpointurile de campanii intră sub plafonul general |
Dacă încă decizi dacă Brevo este platforma potrivită, prezentarea generală a platformei acoperă acel teren.
Autentificare și gestionarea cheilor
Brevo folosește o cheie API simplă într-un antet propriu. Antetul se numește api-key, nu Authorization, și nu există niciun prefix Bearer. Asta încurcă aproape pe oricine a folosit mai întâi un alt API de mesagerie.
OAuth poate folosi un token Bearer pentru operațiunile acceptate; o cheie API standard se trimite în antetul api-key.
curl https://api.brevo.com/v3/account \ -H "api-key: $BREVO_API_KEY"Cheile se generează în aplicația Brevo, în setările contului, în secțiunea SMTP and API, pe fila API keys. Dă fiecărei chei un nume descriptiv legat de sistemul care o folosește. Valoarea cheii este afișată exact o singură dată, la generare, deci dacă o pierzi generezi una nouă în loc să o recuperezi pe cea veche.
Câteva reguli practice:
- Emite o cheie separată pentru fiecare mediu de implementare și pentru fiecare serviciu. Revocarea unei chei compromise nu ar trebui niciodată să pice trei sisteme fără legătură între ele.
- Cheile API standard sunt valabile la nivel de cont. Tratează orice cheie ca acces complet la contacte, trimitere și date CRM.
- Brevo acceptă și OAuth 2.0 pentru aplicațiile care acționează în numele altor conturi Brevo, descris alături de fluxul cu chei în schemele de autentificare.
- Serverul MCP folosit de asistenții AI ia un token separat și chiar folosește un antet bearer. Tokenul se generează din același ecran de chei API, dar nu este interschimbabil cu o cheie REST.
URL de bază, versionare și prima ta scriere
URL-ul de bază este https://api.brevo.com/v3/. Versiunea stă în cale, nu într-un antet, iar v3 este generația curentă. Fiecare cale din acest ghid este relativă la acea bază.
Pentru prima scriere de contact folosește o adresă de test controlată de tine, un ID de listă real și un ID sursă stabil. Creează mai întâi atributul FNAME în Brevo. Cu o cheie reală, exemplul scrie în cont:
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 }'Înlocuiește 42 cu ID-ul listei de test. Recitește contactul și verifică ID-ul, numele, lista și blocările. Un 2xx singur nu dovedește rezultatul dorit.
Endpointurile pe care chiar le vei folosi
Contacte
POST /v3/contacts creează un contact. Corpul acceptă email, attributes declarate, listIds și ext_id ca identificator sursă stabil. updateEnabled: true actualizează un contact existent, iar getId: true solicită ID-ul rezultat. Brevo documentează aceste câmpuri. Refolosește același ext_id la fiecare rulare și păstrează legătura dintre ID-ul sursă și cel Brevo.
Înainte de scriere, decide ce sistem deține fiecare atribut și ce listă primește contactele cu consimțământ. Specifică listIds explicit. Nu seta emailBlacklisted: false în actualizări obișnuite. Brevo avertizează că schimbarea adresei unui contact blocat îi elimină blocarea. Trateaz-o separat. Verifică blocările și dezabonările înainte de a adăuga persoana la o listă de marketing. Între citire și scriere rămâne o scurtă fereastră; pentru garanție strictă verifică încă o dată înainte de trimitere.
Citirile trec prin GET /v3/contacts, care paginează cu limit (implicit 50, maximum 1000) și offset și acceptă modifiedSince și createdSince în UTC. Sincronizările incrementale ar trebui să se sprijine pe modifiedSince, nu pe parcurgerea listei complete. Reține că parametrul filter acceptă doar un operator de egalitate, așa că orice lucru mai expresiv aparține unui segment.
Pentru încărcare în masă, POST /v3/contacts/import acceptă fileUrl, fileBody sau jsonBody, țintește listIds și rulează asincron, returnând un processId. Brevo documentează un corp maxim de 10 MB și recomandă să rămâi în jur de 8 MB, pentru că parsarea umflă payloadul. Furnizează notifyUrl ca să afli rezultatul în loc să interoghezi repetat.
E-mail tranzacțional
POST /v3/smtp/email este calul de povară. Dincolo de sender, to, subject și htmlContent, câmpurile pe care merită să le cunoști sunt:
templateIdîmpreună cuparams, care înlocuiește conținutul inline cu un șablon Brevo și substituțiile lui de variabile. Parametrii unei versiuni individuale sunt plafonați la 100 KB, iar parametrii cumulați la 1000 KB.messageVersions, care trimite variante personalizate într-un singur apel, cu până la 99 de destinatari per versiune.tagspot ajuta la corelarea evenimentelor de livrare cu fluxul aplicației care le-a produs.scheduledAtplusbatchId, pentru trimiteri viitoare pe care ai putea vrea să le anulezi ca grup.headers, scrise în Title-Case, pentru anteturi SMTP personalizate.
O singură cerere acceptă cel mult 2.000 de destinatari. Pentru diferența dintre acest endpoint și trimiterea de campanii, ghidul de e-mail tranzacțional oferă perspectiva de strategie a mesajelor.
Campanii de e-mail
POST /v3/emailCampaigns cere name și sender, plus exact o sursă de conținut: htmlContent (minimum 10 caractere, sub 1 MB), htmlUrl sau templateId. Publicul se pune în recipients ca listIds sau segmentIds, iar scheduledAt folosește formatul UTC YYYY-MM-DDTHH:mm:ss.SSSZ. Rutele însoțitoare acoperă trimiterea imediată, trimiterea unui test, actualizarea statusului și extragerea raportului campaniei.
Companii, tranzacții și obiecte
CRM-ul Brevo are două căi de scriere care se suprapun, iar alegerea corectă contează.
Rutele CRM sunt POST /v3/companies, PATCH /v3/companies/{id}, DELETE /v3/companies/{id} și setul echivalent pentru tranzacții. Acestea sunt sincrone. Un PATCH returnează 204 imediat ce modificarea este aplicată.
API-ul de obiecte este calea de masă: POST /v3/objects/{object_type}/batch/upsert acceptă până la 1000 de înregistrări și 1 MB per cerere, până la 500 de atribute per înregistrare și până la 10 înregistrări de asociere per tip de obiect per înregistrare. Returnează 202 cu un processId, adică acceptat, nu aplicat.
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" } } ] }'Ghidul Brevo CRM acoperă modelul de obiecte din perspectiva operatorului.
SDK-uri oficiale
Brevo întreține clienți în organizația GitHub getbrevo:
| Limbaj | Repository |
|---|---|
| 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 |
Clientul Node se instalează ca @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);Clientul Python se instalează cu pip install brevo-python. Dacă preferi să nu cari o dependență de SDK pentru două endpointuri, suprafața HTTP brută este suficient de mică încât să o apelezi direct, ceea ce te ține și izolat de schimbările de versiune ale SDK-ului:
Clientul Python se instalează cu pip install brevo-python. Pentru câteva endpointuri poți apela HTTP direct:
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 NoneO actualizare reușită poate întoarce 204 fără corp. None înseamnă atunci că trebuie să recitești contactul pentru ID.
Exemplul presupune că apelantul a verificat consimțământul și blocările Brevo. Nu solicită deblocare. Cu o cheie reală, codul scrie în cont; testează-l întâi cu simulări. Conflictele de identitate pot da coduri 4xx diferite. Citește răspunsul și reconciliază ID-urile, fără să presupui 409.
Webhook-uri
Webhook-urile sunt modul în care afli ce s-a întâmplat după o trimitere. POST /v3/webhooks creează unul, cu url, events, type și, opțional, channel (email sau sms), batched, headers personalizate și un obiect auth.
Există trei tipuri de webhook, cu vocabulare de evenimente distincte:
- Tranzacțional:
sent,request,delivered,hardBounce,softBounce,blocked,spam,invalid,deferred,click,opened,uniqueOpened,unsubscribed. - Marketing:
spam,opened,click,hardBounce,softBounce,unsubscribed,listAddition,delivered,contactUpdated,contactDeleted. - Inbound:
inboundEmailProcessed, care necesită undomain.
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" }'Pentru schimbări de contacte înregistrează un webhook marketing cu contactUpdated. Brevo numește evenimentul contact_updated în datele primite. Autentifică receptorul prin tokenul bearer auth sau antetele personalizate din ghidul de securitate. Verifică secretul înainte de procesare și nu îl salva în jurnale.
Păstrează o cheie de deduplicare din tipul evenimentului, ID-ul contactului și marcajul temporal pentru o perioadă care acoperă retransmiterile. Timpul singur nu este unic. Evenimentele pot fi duplicate sau sosesc în altă ordine. După eveniment recitește contactul și reconciliază starea cu sursa de încredere. Definește o fereastră de replay, respinge evenimente vechi după recuperare și verifică periodic schimbările incremental. Webhook-ul anunță o schimbare, dar nu creează singur sincronizare în ambele sensuri. Ghidul conectorilor explică alegerea.
Limite de rată și tratarea erorilor
Limitele de rată ale Brevo sunt per endpoint și per nivel de plan, iar distanța dintre endpointuri este enormă.
| Endpoint | General (orice plan) | Advanced (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 | 20 RPS, 72.000 RPH |
GET /v3/smtp/emails | 2 RPS, 7.200 RPH | 3 RPS, 10.800 RPH |
| Endpointuri fără o limită proprie | 100 RPH | 200 RPH |
Brevo documentează x-sib-ratelimit-limit, x-sib-ratelimit-remaining și x-sib-ratelimit-reset pentru endpointurile limitate. Citește-le și după succes. La 429 așteaptă resetarea și reîncearcă numai în limite fixe de încercări și timp. Valoarea reset este o durată în unitatea ferestrei, de obicei secunde, nu un timp 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)); }}Dacă așteptarea necesară depășește 60 de secunde, funcția returnează 429. Programează o încercare ulterioară.
Acest ajutor este numai pentru cereri pe care le-ai verificat ca sigure pentru reluare. După o eroare ambiguă de trimitere, reconciliază ID-ul mesajului înainte de a retrimite. Înregistrează starea și antetele de limită, niciodată cheia API sau datele contactului.
Nu relua un 4xx orbește. Referința pentru creare enumeră 400 și 425; un conflict nu garantează 409. După un 5xx la scriere, verifică dacă modificarea s-a aplicat deja.
Ce cod ai primit?
-
429
Așteaptă în limita stabilită
Folosește durata reset și oprește-te după câteva încercări.
-
5xx după scriere
Verifică rezultatul
Serverul putea scrie înainte de eroare.
-
400
Corectează cererea
De obicei cererea este greșită.
-
Conflict de identificatori
Citește și reconciliază ID-urile
API-ul nu promite un cod exact.
Testare fără a trimite e-mailuri
Adaugă antetul X-Sib-Sandbox cu valoarea drop la o trimitere tranzacțională. Brevo validează cererea, returnează 201 cu un messageId, nu livrează nimic și nu scrie niciun jurnal de e-mail.
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>" }'Înțelege ce dovedește și ce nu dovedește asta. Modul sandbox validează doar formatul cererii. Nu spune nimic despre autentificarea expeditorului, randarea șabloanelor sau livrabilitate. Ține un cont Brevo separat pentru testarea integrării a orice atinge contacte sau date CRM, pentru că modul sandbox acoperă trimiterea, nu restul API-ului.
Înainte de sincronizarea contactelor
- Alege un ID sursă stabil pentru
ext_idși păstrează ID-ul Brevo returnat. - Verifică atributele înainte de scriere. Brevo poate ignora câmpuri necunoscute sau cu tip greșit; recitește un contact de test.
- Folosește o listă explicită și o dovadă sigură a consimțământului. Omite blocările și dezabonările.
- Numără separat înregistrările acceptate, aplicate, omise și eșuate. Un 202 pentru loturi ori obiecte arată inițial doar acceptarea.
- Folosește webhook-uri marketing ca semnale și reconciliază starea curentă. Autentifică, deduplică și limitează replay-ul.
- Urmărește antetele de rată și oprește-te după câteva încercări.
Tajo se concentrează pe sincronizarea datelor comerciale cu Brevo. Dacă construiești singur acest strat, ghidul conectorilor Brevo compară opțiunile și erorile.
Întrebări Frecvente
Care este URL-ul de bază al Brevo API?
Toate apelurile REST către Brevo merg la https://api.brevo.com/v3/. Versiunea face parte din cale, iar v3 este generația curentă, așa că un endpoint precum trimiterea tranzacțională are calea completă https://api.brevo.com/v3/smtp/email.
Cum te autentifici la Brevo API?
Trimite cheia într-un antet HTTP numit api-key. Brevo nu folosește un antet Authorization sau Bearer pentru cheile API standard. Cheile se generează în setările contului, în secțiunea SMTP and API, pe fila API keys, iar valoarea este afișată o singură dată.
Care sunt limitele de rată ale Brevo API?
Limitele sunt per endpoint și per nivel de limită de rată. Pe nivelul general, pe care îl primește orice plan, endpointul de trimitere tranzacțională permite 1.000 de cereri pe secundă, endpointurile de contacte permit 10 pe secundă, iar endpointurile fără o limită proprie sunt plafonate la 100 de cereri pe oră. Planurile Professional și Enterprise pot folosi nivelul advanced, iar Enterprise nivelul extended. Depășirea unei limite returnează 429.
Are Brevo SDK-uri oficiale?
Da. Brevo publică clienți pentru Node.js, Python, PHP, Java, C#, Go și Ruby în organizația GitHub getbrevo. Pachetul Node este @getbrevo/brevo pe npm, iar pachetul Python este brevo-python pe PyPI.
Cum testez Brevo API fără să trimit e-mailuri reale?
Adaugă antetul X-Sib-Sandbox cu valoarea drop la o trimitere tranzacțională. Brevo validează cererea, returnează 201 cu un messageId, nu trimite nimic și nu scrie niciun jurnal de e-mail. Verifică doar formatul cererii, nu livrabilitatea.
Ce evenimente webhook acceptă Brevo?
Webhook-urile tranzacționale acoperă livrări, respingeri și dezabonări. Cele de marketing includ contactUpdated și contactDeleted. Pentru intrare, Brevo documentează inboundEmailProcessed.
Cum protejezi o dezabonare la actualizarea unui contact?
Folosește un ID sursă stabil și atribute declarate. Nu seta emailBlacklisted la false în actualizări obișnuite. Verifică persoana și sursa consimțământului înainte de a o adăuga la o listă de marketing.
Este suficient un webhook pentru sincronizare în ambele sensuri?
Nu. Autentifică receptorul, elimină livrările duplicate și reconciliază evenimentele pierdute sau sosite în altă ordine cu o sursă de încredere. Webhook-ul anunță schimbarea, nu dovedește concordanța.