Na této stránce
- Endpoint v kostce
- Získejte API klíč
- Python: načtěte CSV a pošlete ho do Brevo
- Excel soubory: tři životaschopné cesty
- Node.js: stejná úloha, oficiální SDK
- cURL: jednořádkovka pro ad-hoc importy
- Soubory větší než 10 MB: použijte fileUrl
- Pošlete JSON místo CSV
- Dotazování na dokončení
- Časté chyby a jak je opravit
- Kdy skriptovat a kdy použít UI
- Další čtení
Pokud jste někdy potřebovali poslat několik tisíc kontaktů z tabulky do Brevo, ruční cesta přes UI začne brzy bolet: vybrat soubor, namapovat sloupce, vybrat seznam, počkat, opakovat. Skript zvládne stejnou práci za pár sekund a, což je důležitější, můžete ho spustit znovu podle plánu, po exportu z databáze nebo kdykoli vaše CRM vyplivne čerstvé CSV.
Tato příručka pokrývá API endpoint, který vám Brevo dává přesně pro tohle, s plně funkčními skripty v Pythonu, Node.js a jednořádkovým cURL. Vše v této příručce volá POST /v3/contacts/import.
Endpoint v kostce
POST https://api.brevo.com/v3/contacts/importContent-Type: application/jsonapi-key: YOUR_API_KEY
{ "listIds": [42], "updateExistingContacts": true, "emailBlacklist": false, "smsBlacklist": false}Odpověď přijde rychle:
{ "processId": 78 }Je to 202 Accepted. Brevo přijalo import a zpracovává ho na pozadí. processId je vaše sledovací rukojeť, pokud chcete dotazovat na dokončení nebo nastavit notifyUrl webhook.
Pár věcí, které stojí za zmínku, než začnete psát kód:
- Tělo může být CSV (
fileBody), JSON (jsonBody) nebo vzdálená URL (fileUrl). Vyberte jedno. CSV forma používá středníky (;) jako oddělovače sloupců, ne čárky. To je častý zádrhel. fileBodyajsonBodyjsou omezeny na 10 MB. Brevo doporučuje zůstat kolem 8 MB pro jistotu. Pro cokoli většího nahrajte soubor na S3, GCS nebo jakýkoli HTTPS hosting a předejte místo tohofileUrl.- Vlastní atributy, které ve vašem účtu neexistují, jsou tiše ignorovány. Vytvořte je v UI Brevo (nebo přes Attributes API) ještě před importem řádků, které je používají, jinak data prostě zmizí.
updateExistingContactsmá výchozí hodnotutrue. Pokud nastavíte nafalse, Brevo přeskočí kontakty, jejichž e-mail již existuje. Užitečné pro úlohy „pouze nové”.emptyContactsAttributesřídí, zda prázdné buňky ve vašem CSV smažou existující hodnoty. Výchozífalse(prázdné buňky jsou ignorovány). Nastavte natrue, pokud je CSV zdrojem pravdy a chcete, aby prázdné hodnoty vyčistily zastaralá data.
Získejte API klíč
Přihlaste se do Brevo → Settings → SMTP & API → API Keys → vytvořte nový klíč. Vypadá jako xkeysib-.... Předáváte ho jako HTTP hlavičku api-key při každém požadavku. Zacházejte s ním jako s heslem, má plný čtecí i zápisový přístup k vašemu účtu.
Čistý vzor: dejte ho do proměnné prostředí, aby se nikdy nedostal do vašeho zdrojového stromu.
export BREVO_API_KEY="xkeysib-..."Python: načtěte CSV a pošlete ho do Brevo
Toto je nejjednodušší možný skript: načtete lokální CSV pomocí standardní knihovny a tělo pošlete přímo do Brevo. Není potřeba žádné SDK třetí strany kromě requests.
import csvimport ioimport osimport sysimport requests
API_KEY = os.environ["BREVO_API_KEY"]LIST_ID = 42 # the Brevo list to add contacts toINPUT_FILE = sys.argv[1] if len(sys.argv) > 1 else "contacts.csv"
# Brevo wants semicolon-separated CSV. If your file uses commas (most do),# convert it on the fly so you don't have to edit the source spreadsheet.def to_brevo_csv(path: str) -> str: with open(path, newline="", encoding="utf-8") as f: reader = csv.reader(f) # default: comma-separated out = io.StringIO() writer = csv.writer(out, delimiter=";") for row in reader: writer.writerow(row) return out.getvalue()
body = { "fileBody": to_brevo_csv(INPUT_FILE), "listIds": [LIST_ID], "updateExistingContacts": True, "emptyContactsAttributes": False, "emailBlacklist": False, "smsBlacklist": False,}
resp = requests.post( "https://api.brevo.com/v3/contacts/import", json=body, headers={"api-key": API_KEY, "Content-Type": "application/json"}, timeout=60,)
if resp.status_code != 202: print(f"Import failed: {resp.status_code} {resp.text}") sys.exit(1)
process_id = resp.json()["processId"]print(f"Import accepted. Process ID: {process_id}")Spusťte to:
python import_csv_to_brevo.py contacts.csvPrvní řádek vašeho CSV je hlavička. Názvy sloupců se mapují na atributy Brevo podle velkých písmen, přesné shody: EMAIL, FIRSTNAME, LASTNAME, plus jakýkoli vlastní atribut, který jste definovali. EMAIL je povinný.
EMAIL,FIRSTNAME,LASTNAME,COMPANY,CITYTo je celý postup. Skript se vrátí během sekundy, samotný import běží na straně serveru a trvá od několika sekund po několik minut podle objemu.
Excel soubory: tři životaschopné cesty
Import endpoint Brevo nečte .xlsx přímo, takže máte tři reálné možnosti podle toho, kde má práce probíhat:
- Spustit VBA makro uvnitř sešitu. Synchronizace jedním kliknutím přímo z Excelu, bez externího skriptu. To je správná odpověď, když soubor leží na pracovní stanici a váš tým chce tlačítko v listu. Plný kód v příručce VBA makra Excel do Brevo.
- Office Scripts + Power Automate. Pokud sešit žije v OneDrive/SharePoint a chcete bezobslužnou plánovanou synchronizaci. Také pokryto v příručce Excelu.
- Převod
.xlsxna CSV ze skriptu. To pokrývá zbytek této sekce. Nejlepší, pokud již na serveru spouštíte Python nebo Node a potřebujete jen jednou denně stáhnout sešit.
Pro variantu 3 je pandas jednořádkovka:
# pip install pandas openpyxlimport pandas as pd
def xlsx_to_brevo_csv(path: str, sheet_name: str | int = 0) -> str: df = pd.read_excel(path, sheet_name=sheet_name) return df.to_csv(sep=";", index=False)
body["fileBody"] = xlsx_to_brevo_csv("contacts.xlsx")Pokud nechcete pandas jako závislost, samotné openpyxl funguje:
from openpyxl import load_workbookimport csv, io
def xlsx_to_brevo_csv(path: str) -> str: wb = load_workbook(path, read_only=True) ws = wb.active out = io.StringIO() writer = csv.writer(out, delimiter=";") for row in ws.iter_rows(values_only=True): writer.writerow(["" if v is None else v for v in row]) return out.getvalue()Node.js: stejná úloha, oficiální SDK
Brevo publikuje @getbrevo/brevo pro Node. Řeší autentizaci, opakované pokusy a typovaný tvar požadavku:
// npm install @getbrevo/brevoimport fs from 'node:fs/promises';import { BrevoClient } from '@getbrevo/brevo';
const API_KEY = process.env.BREVO_API_KEY;const LIST_ID = 42;const INPUT_FILE = process.argv[2] ?? 'contacts.csv';
const client = new BrevoClient({ apiKey: API_KEY });
// Read the CSV and convert commas to semicolons if neededconst raw = await fs.readFile(INPUT_FILE, 'utf-8');const csv = raw.includes(';') ? raw : raw.replace(/,/g, ';');
const result = await client.contacts.importContacts({ fileBody: csv, listIds: [LIST_ID], updateExistingContacts: true, emptyContactsAttributes: false,});
console.log(`Import accepted. Process ID: ${result.processId}`);Nebo, pokud nechcete SDK, obyčejný fetch funguje stejně:
const resp = await fetch('https://api.brevo.com/v3/contacts/import', { method: 'POST', headers: { 'api-key': process.env.BREVO_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ fileBody: csv, listIds: [42], updateExistingContacts: true, }),});
if (resp.status !== 202) { throw new Error(`Import failed: ${resp.status} ${await resp.text()}`);}
const { processId } = await resp.json();console.log(`Process ID: ${processId}`);cURL: jednořádkovka pro ad-hoc importy
Když chcete jen otestovat endpoint nebo ručně poslat malý soubor:
# Convert commas to semicolons, then send the file inlinecsv=$(sed 's/,/;/g' contacts.csv | jq -Rs .)
curl -X POST https://api.brevo.com/v3/contacts/import \ -H "api-key: $BREVO_API_KEY" \ -H "Content-Type: application/json" \ -d "{\"fileBody\": $csv, \"listIds\": [42], \"updateExistingContacts\": true}"jq -Rs . načte celý soubor a JSON-escapuje ho, ušetří vám ruční escapování nových řádků a uvozovek.
Soubory větší než 10 MB: použijte fileUrl
fileBody je omezen na 10 MB. Pokud je váš export kontaktů větší, hostujte soubor na URL, kterou Brevo dokáže stáhnout, a předejte tu:
body = { "fileUrl": "https://files.example.com/contacts/2026-04-30.csv", "listIds": [42], "updateExistingContacts": True,}Cokoli dostupné přes veřejnou HTTPS URL funguje, předem podepsané S3 URL, GCS, váš vlastní statický hosting, dokonce GitHub raw URL pro jednorázové importy. Brevo si stáhne soubor z vaší URL a pak spustí import. Přijímané formáty: .csv, .txt, .json.
Pošlete JSON místo CSV
Pokud už táháte kontakty z databáze, nemusíte je posílat oklikou přes CSV. Pošlete je rovnou jako JSON:
body = { "jsonBody": [ { "attributes": { "FIRSTNAME": "Jane", "LASTNAME": "Doe", "COMPANY": "Acme", }, }, { "attributes": { "FIRSTNAME": "John", "LASTNAME": "Smith", "COMPANY": "Globex", }, }, ], "listIds": [42],}Stejný limit 10 MB. Stejné asynchronní chování.
Dotazování na dokončení
Import je asynchronní, processId je vaše rukojeť pro sledování. Existuje samostatný endpoint pro kontrolu stavu procesu:
def wait_for_import(process_id: int, timeout_s: int = 600) -> dict: import time deadline = time.time() + timeout_s while time.time() < deadline: r = requests.get( f"https://api.brevo.com/v3/processes/{process_id}", headers={"api-key": API_KEY}, timeout=30, ) r.raise_for_status() status = r.json() if status["status"] in ("completed", "failed"): return status time.sleep(5) raise TimeoutError(f"Import {process_id} did not finish in {timeout_s}s")
result = wait_for_import(process_id)print(f"Import {result['status']}: {result}")Pro dlouho běžící úlohy je čistší vzor notifyUrl: předejte HTTPS endpoint, na který Brevo POSTne, až import skončí, a vynechte dotazování.
body["notifyUrl"] = "https://your-app.example.com/webhooks/brevo-import"Časté chyby a jak je opravit
400 Bad Request bez zjevné příčiny. Téměř vždy středníky vs. čárky v CSV. Import Brevo očekává ;, ne ,. Po konverzním kroku zkontrolujte fileBody znovu.
Hodnoty vlastních atributů mizí. Atribut ve vašem účtu neexistuje. Vytvořte ho pod Contacts → Settings → Contact attributes před importem nebo použijte Attributes API k jeho vytvoření jako součást vašeho skriptu.
401 Unauthorized. Špatný název hlavičky. Je to api-key (malá písmena, pomlčka), ne Authorization ani X-API-Key.
Import „uspěl”, ale kontakty se v seznamu neobjevily. Zkontrolujte, že listIds obsahuje správný seznam. Také: pokud je updateExistingContacts false a kontakty již existují, Brevo je tiše přeskočí místo toho, aby je znovu přidalo do seznamu.
Některé řádky se naimportovaly, jiné ne. Brevo vám po dokončení importu pošle e-mail s chybovou zprávou pro každý řádek (pokud nenastavíte disableNotification: true). Zpráva říká, které řádky měly špatné e-maily, chybějící povinná pole nebo formátovací problémy.
Kdy skriptovat a kdy použít UI
UI je v pohodě pro jednorázové importy pod tisíc řádků. Skript vyhrává, jakmile:
- Importujete víckrát než jednou (např. týdenní export z vašeho CRM)
- Zdrojová data potřebují čištění, než se dostanou do Brevo (deduplikace, formátování telefonů, rozdělení celých jmen na křestní/příjmení)
- Chcete, aby běžel podle plánu bez toho, aby někdo klikal na tlačítka
- Soubor je větší, než je pohodlná zóna UI
Zabalte výše uvedený skript do cron úlohy nebo GitHub Action a máte automatizovanou synchronizaci kontaktů. Další článek v této sérii ukazuje, jak udělat totéž přímo z Google Sheet pomocí Apps Script, bez serveru.
Další čtení
Často Kladené Otázky
Jaký je API endpoint Brevo pro hromadný import kontaktů?
POST https://api.brevo.com/v3/contacts/import. Přijímá CSV obsah (fileBody), URL vzdáleného souboru (fileUrl) nebo JSON pole (jsonBody). Endpoint je asynchronní, vrací processId okamžitě a import dokončí na pozadí.
Jaká je maximální velikost souboru?
10 MB pro inline CSV (fileBody) nebo JSON (jsonBody). U větších souborů hostujte soubor někde, kam je dostupný, a předejte jeho URL přes fileUrl. Tato cesta nemá zdokumentovaný limit velikosti.
Jak naimportuji soubor .xlsx?
Import API Brevo přijímá pouze .csv, .txt nebo .json. Nejprve převeďte .xlsx na .csv. pandas, openpyxl nebo LibreOffice headless to zvládnou jedním řádkem. Skript v této příručce zahrnuje konverzi xlsx na csv.
Přepíše to existující kontakty?
Ve výchozím nastavení ano. updateExistingContacts má výchozí hodnotu true a párování probíhá podle e-mailu. Nastavte na false, abyste přeskočili kontakty, které již existují. Nastavte emptyContactsAttributes na true, pokud chcete, aby prázdné buňky CSV vymazaly existující hodnoty (jinak jsou prázdné buňky ignorovány).