---
title: "Jak zaimportować kontakty CSV lub Excel do Brevo za pomocą skryptu (Python, Node.js, cURL)"
description: "Masowy import kontaktów z pliku CSV lub Excel do Brevo przy użyciu API import-contacts. Zawiera gotowe do uruchomienia skrypty w Pythonie i Node.js, jednolinijkowy cURL, obsługę błędów oraz wskazówki dla plików większych niż 10 MB."
url: https://tajo.io/pl/blog/import-csv-contacts-to-brevo-with-a-script/
markdown: https://tajo.io/pl/blog/import-csv-contacts-to-brevo-with-a-script.md
lang: pl-PL
author: "Set Noa"
author_url: https://tajo.io/pl/set-noa/
published: 2026-04-30
updated: 2026-05-11
alternates: {en-US: /blog/import-csv-contacts-to-brevo-with-a-script.md, bg-BG: /bg/blog/import-csv-contacts-to-brevo-with-a-script.md, cs-CZ: /cz/blog/import-csv-contacts-to-brevo-with-a-script.md, de-DE: /de/blog/import-csv-contacts-to-brevo-with-a-script.md, da-DK: /dk/blog/import-csv-contacts-to-brevo-with-a-script.md, es-ES: /es/blog/import-csv-contacts-to-brevo-with-a-script.md, fr-FR: /fr/blog/import-csv-contacts-to-brevo-with-a-script.md, el-GR: /gr/blog/import-csv-contacts-to-brevo-with-a-script.md, hi-IN: /hi/blog/import-csv-contacts-to-brevo-with-a-script.md, id-ID: /in/blog/import-csv-contacts-to-brevo-with-a-script.md, hr-HR: /hr/blog/import-csv-contacts-to-brevo-with-a-script.md, hu-HU: /hu/blog/import-csv-contacts-to-brevo-with-a-script.md, it-IT: /it/blog/import-csv-contacts-to-brevo-with-a-script.md, ja-JP: /jp/blog/import-csv-contacts-to-brevo-with-a-script.md, ko-KR: /kr/blog/import-csv-contacts-to-brevo-with-a-script.md, ar-SA: /ar/blog/import-csv-contacts-to-brevo-with-a-script.md, nl-NL: /nl/blog/import-csv-contacts-to-brevo-with-a-script.md, no-NO: /no/blog/import-csv-contacts-to-brevo-with-a-script.md, pt-BR: /pt/blog/import-csv-contacts-to-brevo-with-a-script.md, ro-RO: /ro/blog/import-csv-contacts-to-brevo-with-a-script.md, ru-RU: /ru/blog/import-csv-contacts-to-brevo-with-a-script.md, sv-SE: /se/blog/import-csv-contacts-to-brevo-with-a-script.md, zh-CN: /zh-cn/blog/import-csv-contacts-to-brevo-with-a-script.md, sl-SI: /sl/blog/import-csv-contacts-to-brevo-with-a-script.md, sr-Latn-RS: /sr/blog/import-csv-contacts-to-brevo-with-a-script.md, th-TH: /th/blog/import-csv-contacts-to-brevo-with-a-script.md, tr-TR: /tr/blog/import-csv-contacts-to-brevo-with-a-script.md, ur-PK: /ur/blog/import-csv-contacts-to-brevo-with-a-script.md, vi-VN: /vi/blog/import-csv-contacts-to-brevo-with-a-script.md, sk-SK: /sk/blog/import-csv-contacts-to-brevo-with-a-script.md}
---

[Synchronizacja danych](https://tajo.io/pl/blog/?category=data-sync)

# Jak zaimportować kontakty CSV lub Excel do Brevo za pomocą skryptu (Python, Node.js, cURL)

Masowy import kontaktów z pliku CSV lub Excel do Brevo przy użyciu API import-contacts. Zawiera gotowe do uruchomienia skrypty w Pythonie i Node.js, jednolinijkowy cURL, obsługę błędów oraz wskazówki dla plików większych niż 10 MB.

import csv contacts to brevo

Jak zaimportować kontakty CSV lub Excel do Brevo za pomocą skryptu?

Użyj POST /v3/contacts/import. Przekaż CSV jako fileBody (≤10 MB), JSON jako jsonBody lub adres URL przez fileUrl dla dużych plików. Endpoint jest asynchroniczny i zwraca processId. Przykłady w Pythonie, Node.js i cURL poniżej.

[Dowiedz się więcej](https://tajo.io/pl/blog/import-csv-contacts-to-brevo-with-a-script/#endpoint-w-skr%C3%B3cie)

| Pole źródłowe | Pole docelowe | Przykładowa wartość |
| --- | --- | --- |
| `EMAIL` | `EMAIL` | `alex@example.com` |
| `FIRSTNAME` | `FIRSTNAME` | `Alex` |
| `LASTNAME` | `LASTNAME` | `Example` |

Jeśli kiedykolwiek musiałeś przesłać kilka tysięcy kontaktów z arkusza kalkulacyjnego do Brevo, ręczna ścieżka UI szybko staje się męcząca: wybierz plik, zmapuj kolumny, wybierz listę, czekaj, powtórz. Skrypt wykonuje tę samą pracę w sekundach, a co ważniejsze, możesz uruchomić go ponownie według harmonogramu, po eksporcie z bazy danych lub gdy Twój CRM wypluje świeży CSV.

Ten przewodnik omawia endpoint API, który Brevo oferuje dokładnie do tego celu, wraz z kompletnymi działającymi skryptami w Pythonie, Node.js oraz jednolinijkowym cURL. Wszystko w tym przewodniku trafia w **`POST /v3/contacts/import`**.

## Endpoint w skrócie

```http
POST https://api.brevo.com/v3/contacts/import
Content-Type: application/json
api-key: YOUR_API_KEY

{
  "fileBody": "EMAIL;FIRSTNAME;LASTNAME\njane@example.com;Jane;Doe",
  "listIds": [42],
  "updateExistingContacts": true,
  "emailBlacklist": false,
  "smsBlacklist": false
}
```

Odpowiedź wraca szybko:

```json
{ "processId": 78 }
```

To 202 Accepted. Brevo zaakceptował import i przetwarza go w tle. `processId` to Twój uchwyt do śledzenia, jeśli chcesz pollować status zakończenia lub skonfigurować webhook `notifyUrl`.

Kilka rzeczy wartych uwagi przed napisaniem kodu:

- **Treść może być CSV (`fileBody`), JSON (`jsonBody`) lub zdalnym URL (`fileUrl`).** Wybierz jedno. Forma CSV używa średników (`;`) do oddzielania kolumn, a nie przecinków. To częsta pułapka.
- **`fileBody` i `jsonBody` są ograniczone do 10 MB.** Brevo zaleca pozostanie w okolicach 8 MB dla bezpieczeństwa. Dla większych plików prześlij plik na S3, GCS lub dowolny host HTTPS i przekaż `fileUrl`.
- **Niestandardowe atrybuty, które nie istnieją w Twoim koncie, są po cichu ignorowane.** Utwórz je w UI Brevo (lub przez API atrybutów) przed importem wierszy, które ich używają, w przeciwnym razie dane po prostu znikną.
- **`updateExistingContacts` ma domyślnie wartość `true`.** Jeśli ustawisz na `false`, Brevo pomija kontakty, których e-mail już istnieje. Przydatne dla zadań typu “tylko nowe”.
- **`emptyContactsAttributes`** kontroluje, czy puste komórki w CSV wymazują istniejące wartości. Domyślnie `false` (puste komórki są ignorowane). Ustaw na `true`, jeśli Twój CSV jest źródłem prawdy i chcesz, by puste pola czyściły nieaktualne dane.

## Pobierz klucz API

Zaloguj się do Brevo, przejdź do **Settings → SMTP & API → API Keys** i utwórz nowy klucz. Wygląda jak `xkeysib-...`. Przekażesz go jako nagłówek HTTP `api-key` przy każdym żądaniu. Traktuj go jak hasło, ma pełne prawa odczytu/zapisu na Twoim koncie.

Czysty wzorzec: umieść go w zmiennej środowiskowej, by nigdy nie trafił do drzewa źródłowego.

```bash
export BREVO_API_KEY="xkeysib-..."
```

## Python: odczyt CSV i wysyłka do Brevo

To najprostszy możliwy skrypt: odczytaj lokalny CSV ze standardowej biblioteki, wyślij body bezpośrednio do Brevo. Nie potrzeba żadnego SDK firm trzecich poza `requests`.

```python
import csv
import io
import os
import sys
import requests

API_KEY = os.environ["BREVO_API_KEY"]
LIST_ID = 42  # the Brevo list to add contacts to
INPUT_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}")
```

Uruchom go:

```bash
python import_csv_to_brevo.py contacts.csv
```

Pierwszy wiersz Twojego CSV to nagłówek. Nazwy kolumn mapują się do atrybutów Brevo poprzez **dokładne dopasowanie wielkimi literami**: `EMAIL`, `FIRSTNAME`, `LASTNAME` plus dowolny niestandardowy atrybut, który zdefiniowałeś. `EMAIL` jest obowiązkowy.

```csv
EMAIL,FIRSTNAME,LASTNAME,COMPANY,CITY
jane@example.com,Jane,Doe,Acme,Berlin
john@example.com,John,Smith,Globex,Paris
```

To cały przepływ. Skrypt wraca w ciągu sekundy; faktyczny import działa po stronie serwera i zajmuje od kilku sekund do kilku minut, w zależności od wolumenu.

## Pliki Excel: trzy realne ścieżki

Endpoint importu Brevo nie czyta `.xlsx` bezpośrednio, więc masz trzy realne opcje w zależności od tego, gdzie ma się odbywać praca:

1. **Uruchom makro VBA wewnątrz skoroszytu.** Synchronizacja jednym kliknięciem z samego Excela, bez zewnętrznego skryptu. To właściwa odpowiedź, gdy plik znajduje się na pulpicie i Twój zespół chce mieć przycisk na arkuszu. Pełny kod w [przewodniku Excel-do-Brevo VBA](https://tajo.io/pl/blog/import-excel-contacts-to-brevo-with-vba-macro).
2. **Office Scripts + Power Automate.** Jeśli skoroszyt znajduje się w OneDrive/SharePoint i chcesz nienadzorowanej zaplanowanej synchronizacji. Również omówione w [przewodniku Excel](https://tajo.io/pl/blog/import-excel-contacts-to-brevo-with-vba-macro).
3. **Konwertuj `.xlsx` na CSV ze skryptu.** Co obejmuje reszta tej sekcji. Najlepsze, jeśli już uruchamiasz Pythona lub Node na serwerze i potrzebujesz pobrać skoroszyt raz dziennie.

Dla opcji 3 pandas robi z tego jednolinijkowca:

```python
# pip install pandas openpyxl
import 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")
```

Jeśli nie chcesz pandas jako zależności, sam `openpyxl` też działa:

```python
from openpyxl import load_workbook
import 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: ta sama praca, oficjalny SDK

Brevo publikuje `@getbrevo/brevo` dla Node. Obsługuje uwierzytelnianie, ponawianie i typowany kształt żądania:

```javascript
// npm install @getbrevo/brevo
import 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 needed
const 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}`);
```

Lub, jeśli nie chcesz SDK, zwykły `fetch` działa tak samo:

```javascript
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: jednolinijkowiec dla doraźnych importów

Gdy chcesz po prostu przetestować endpoint lub ręcznie wepchnąć mały plik:

```bash
# Convert commas to semicolons, then send the file inline
csv=$(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 .` wciąga cały plik i JSON-escape’uje go, oszczędzając Ci ręcznego escape’owania nowych linii i cudzysłowów.

## Pliki większe niż 10 MB: użyj `fileUrl`

`fileBody` jest ograniczony do 10 MB. Jeśli Twój zrzut kontaktów jest większy, hostuj plik pod adresem URL, który Brevo może pobrać, i przekaż go:

```python
body = {
    "fileUrl": "https://files.example.com/contacts/2026-04-30.csv",
    "listIds": [42],
    "updateExistingContacts": True,
}
```

Wszystko, co jest osiągalne przez publiczny adres URL HTTPS, działa: pre-podpisane URL-e S3, GCS, Twój własny statyczny host, nawet surowy URL GitHub dla jednorazowych importów. Brevo pobiera plik z Twojego URL, a następnie uruchamia import. Zaakceptowane formaty: `.csv`, `.txt`, `.json`.

## Wyślij JSON zamiast CSV

Jeśli już wyciągasz kontakty z bazy danych, nie musisz przechodzić przez CSV. Wyślij je bezpośrednio jako JSON:

```python
body = {
    "jsonBody": [
        {
            "email": "jane@example.com",
            "attributes": {
                "FIRSTNAME": "Jane",
                "LASTNAME": "Doe",
                "COMPANY": "Acme",
            },
        },
        {
            "email": "john@example.com",
            "attributes": {
                "FIRSTNAME": "John",
                "LASTNAME": "Smith",
                "COMPANY": "Globex",
            },
        },
    ],
    "listIds": [42],
}
```

Ten sam limit 10 MB. To samo asynchroniczne zachowanie.

## Polling do zakończenia

Import jest asynchroniczny. `processId` to Twój uchwyt do śledzenia. Istnieje osobny endpoint do sprawdzania statusu procesu:

```python
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}")
```

Dla długo działających zadań czystszym wzorcem jest `notifyUrl`: przekaż endpoint HTTPS, do którego Brevo wyśle POST po zakończeniu importu, i pomiń polling.

```python
body["notifyUrl"] = "https://your-app.example.com/webhooks/brevo-import"
```

## Częste błędy i jak je naprawić

**`400 Bad Request` bez oczywistej przyczyny.** Prawie zawsze chodzi o średniki kontra przecinki w CSV. Import Brevo oczekuje `;`, a nie `,`. Sprawdź dwukrotnie `fileBody` po kroku konwersji.

**Wartości niestandardowych atrybutów znikają.** Atrybut nie istnieje w Twoim koncie. Utwórz go w **Contacts → Settings → Contact attributes** przed importem lub użyj [API atrybutów](https://developers.brevo.com/reference/create-attribute), aby utworzyć go jako część swojego skryptu.

**`401 Unauthorized`.** Zła nazwa nagłówka. To `api-key` (małe litery, łącznik), a nie `Authorization` ani `X-API-Key`.

**Import “powiódł się”, ale kontakty nie pojawiły się na liście.** Sprawdź, czy `listIds` zawiera właściwą listę. Również: jeśli `updateExistingContacts` jest `false`, a kontakty już istnieją, Brevo po cichu je pomija, zamiast dodawać ponownie do listy.

**Niektóre wiersze zaimportowane, niektóre nie.** Brevo wysyła Ci e-mail z raportem błędów dla poszczególnych wierszy po zakończeniu importu (chyba że ustawisz `disableNotification: true`). Raport mówi, które wiersze miały złe e-maile, brakujące wymagane pola lub problemy z formatowaniem.

## Kiedy skryptować, a kiedy używać UI

UI jest w porządku dla jednorazowych importów poniżej tysiąca wierszy. Skrypt wygrywa, gdy tylko:

- Importujesz więcej niż raz (np. cotygodniowy eksport z Twojego CRM)
- Dane źródłowe wymagają oczyszczenia, zanim trafią do Brevo (deduplikacja, formatowanie numerów telefonów, dzielenie pełnych imion na imię/nazwisko)
- Chcesz, żeby działało według harmonogramu bez klikania
- Plik jest większy niż strefa komfortu UI

Owin powyższy skrypt w cron job lub GitHub Action i masz zautomatyzowaną synchronizację kontaktów. Następny wpis w tej serii pokazuje, jak zrobić to samo bezpośrednio z Google Sheet używając Apps Script. Bez serwera.

## Dalsza lektura

- [Brevo API: Import contacts reference](https://developers.brevo.com/reference/import-contacts)
- [Brevo API: Contact attributes](https://developers.brevo.com/reference/create-attribute)
- [Buduj listy kontaktów dla swoich kampanii e-mail](https://help.brevo.com/hc/en-us/articles/209499265)

## Najczęściej Zadawane Pytania

**Jaki jest endpoint API Brevo do masowego importu kontaktów?**

POST https://api.brevo.com/v3/contacts/import. Akceptuje zawartość CSV (fileBody), zdalny adres URL pliku (fileUrl) lub tablicę JSON (jsonBody). Endpoint jest asynchroniczny, zwraca processId natychmiast i kończy import w tle.

**Jaki jest maksymalny rozmiar pliku?**

10 MB dla inline CSV (fileBody) lub JSON (jsonBody). Dla większych plików hostuj plik w dostępnym miejscu i przekaż jego URL przez fileUrl. Ta ścieżka nie ma udokumentowanego limitu rozmiaru.

**Jak zaimportować plik .xlsx?**

API importu Brevo przyjmuje tylko .csv, .txt lub .json. Najpierw przekonwertuj .xlsx na .csv. Pandas, openpyxl lub LibreOffice headless zrobią to w jednej linijce. Skrypt w tym przewodniku zawiera konwersję xlsx do csv.

**Czy nadpisze istniejące kontakty?**

Domyślnie tak. updateExistingContacts domyślnie ma wartość true i dopasowuje po e-mailu. Ustaw na false, aby pominąć kontakty, które już istnieją. Ustaw emptyContactsAttributes na true, jeśli chcesz, by puste komórki CSV usuwały istniejące wartości (w przeciwnym razie puste komórki są ignorowane).

## Powiązane artykuły

### [Import kontaktów z Google Sheets do Brevo przez Apps Script](https://tajo.io/pl/blog/import-google-sheet-contacts-to-brevo-apps-script/)

30 kwi 2026 · 3 min czytania

Google Sheets → Brevo

### [Jak wysłać kontakty Excel do Brevo za pomocą makra VBA (i alternatywa Office Scripts)](https://tajo.io/pl/blog/import-excel-contacts-to-brevo-with-vba-macro/)

30 kwi 2026 · 6 min czytania

Microsoft Excel → Brevo

### [Eksport danych i migracja w Brevo: jak przenieść dane do środka lub na zewnątrz](https://tajo.io/pl/blog/brevo-data-export-migration/)

19 sie 2026 · 9 min czytania

8 sekcji
