---
title: "Comment importer des contacts CSV ou Excel dans Brevo avec un script (Python, Node.js, cURL)"
description: "Importez en masse les contacts d’un fichier CSV ou Excel dans Brevo via l’API import-contacts. Inclut des scripts Python et Node.js prêts à l’emploi, un one-liner cURL, la gestion des erreurs et des conseils pour les fichiers de plus de 10 Mo."
url: https://tajo.io/fr/blog/import-csv-contacts-to-brevo-with-a-script/
markdown: https://tajo.io/fr/blog/import-csv-contacts-to-brevo-with-a-script.md
lang: fr-FR
author: "Set Noa"
author_url: https://tajo.io/fr/set-noa/
published: 2026-04-30
updated: 2026-05-16
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, 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, pl-PL: /pl/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}
---

[Synchronisation des données](https://tajo.io/fr/blog/?category=data-sync)

# Comment importer des contacts CSV ou Excel dans Brevo avec un script (Python, Node.js, cURL)

Importez en masse les contacts d’un fichier CSV ou Excel dans Brevo via l’API import-contacts. Inclut des scripts Python et Node.js prêts à l’emploi, un one-liner cURL, la gestion des erreurs et des conseils pour les fichiers de plus de 10 Mo.

import csv contacts to brevo

Comment importer un CSV dans Brevo ?

Utilisez POST /v3/contacts/import. Passez un CSV en fileBody (≤10 Mo), du JSON en jsonBody, ou une URL via fileUrl pour les gros fichiers. L’endpoint est asynchrone et renvoie un processId. Exemples Python, Node.js et cURL ci-dessous.

[En savoir plus](https://tajo.io/fr/blog/import-csv-contacts-to-brevo-with-a-script/#lendpoint-en-un-coup-d%C5%93il)

| Champ source | Champ de destination | Valeur d’exemple |
| --- | --- | --- |
| `EMAIL` | `EMAIL` | `alex@example.com` |
| `FIRSTNAME` | `FIRSTNAME` | `Alex` |
| `LASTNAME` | `LASTNAME` | `Example` |

Si vous avez déjà eu besoin de pousser quelques milliers de contacts d’un tableur vers Brevo, vous savez que la voie manuelle de l’interface devient vite pénible : choisir le fichier, mapper les colonnes, choisir une liste, attendre, recommencer. Un script fait le même travail en quelques secondes et, plus important encore, vous pouvez le relancer de façon planifiée, après un export de base de données, ou chaque fois que votre CRM crache un nouveau CSV.

Ce guide couvre l’endpoint API que Brevo prévoit exactement pour ça, avec des scripts complets et fonctionnels en Python, Node.js et un one-liner cURL. Tout dans ce guide tape sur **`POST /v3/contacts/import`**.

## L’endpoint en un coup d’œil

```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
}
```

La réponse arrive vite :

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

C’est un 202 Accepted : Brevo a accepté l’import et le traite en arrière-plan. Le `processId` est votre poignée de suivi si vous voulez interroger l’état d’avancement ou configurer un webhook `notifyUrl`.

Quelques points à connaître avant d’écrire du code :

- **Le corps peut être du CSV (`fileBody`), du JSON (`jsonBody`) ou une URL distante (`fileUrl`).** Choisissez-en un. La forme CSV utilise des points-virgules (`;`) pour séparer les colonnes, pas des virgules, c’est un piège classique.
- **`fileBody` et `jsonBody` sont plafonnés à 10 Mo.** Brevo recommande de rester aux alentours de 8 Mo pour être tranquille. Pour quoi que ce soit de plus grand, uploadez le fichier sur S3, GCS ou n’importe quel hôte HTTPS et passez `fileUrl` à la place.
- **Les attributs personnalisés qui n’existent pas dans votre compte sont ignorés silencieusement.** Créez-les dans l’interface Brevo (ou via l’API Attributes) avant d’importer des lignes qui les utilisent, sans quoi les données disparaissent simplement.
- **`updateExistingContacts` vaut `true` par défaut.** Si vous le mettez à `false`, Brevo ignore les contacts dont l’e-mail existe déjà, pratique pour les jobs « ajouter uniquement les nouveaux ».
- **`emptyContactsAttributes`** détermine si les cellules vides de votre CSV effacent les valeurs existantes. Par défaut `false` (les cellules vides sont ignorées). Passez à `true` si votre CSV est la source de vérité et que les blancs doivent effacer des données obsolètes.

## Obtenir une clé API

Connectez-vous à Brevo → **Paramètres → SMTP & API → API Keys** → créez une nouvelle clé. Elle ressemble à `xkeysib-...`. Vous la passerez en en-tête HTTP `api-key` à chaque requête. Traitez-la comme un mot de passe, elle a un accès complet en lecture/écriture sur votre compte.

Bonne pratique : mettez-la dans une variable d’environnement pour qu’elle ne se retrouve jamais dans votre code source.

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

## Python : lire un CSV, l’envoyer à Brevo

C’est le script le plus simple possible : lire un CSV local avec la bibliothèque standard, envoyer le corps directement à Brevo. Aucun SDK tiers nécessaire en dehors de `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}")
```

Lancez-le :

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

La première ligne de votre CSV est l’en-tête. Les noms de colonne se mappent aux attributs Brevo par **majuscules, correspondance exacte** : `EMAIL`, `FIRSTNAME`, `LASTNAME`, plus tout attribut personnalisé que vous avez défini. `EMAIL` est obligatoire.

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

C’est tout le flux. Le script revient en moins d’une seconde, l’import réel tourne côté serveur et prend de quelques secondes à quelques minutes selon le volume.

## Fichiers Excel : trois pistes viables

L’endpoint d’import de Brevo ne lit pas directement les `.xlsx`, vous avez donc trois vraies options selon l’endroit où le travail doit vivre :

1. **Lancer une macro VBA dans le classeur**, synchronisation en un clic depuis Excel lui-même, sans script externe. C’est la bonne réponse quand le fichier vit sur un poste de travail et que votre équipe veut un bouton sur la feuille. Code complet dans le [guide de la macro VBA Excel vers Brevo](https://tajo.io/fr/blog/import-excel-contacts-to-brevo-with-vba-macro).
2. **Office Scripts + Power Automate**, si le classeur est dans OneDrive/SharePoint et que vous voulez une synchronisation planifiée et sans surveillance. Également couvert dans le [guide Excel](https://tajo.io/fr/blog/import-excel-contacts-to-brevo-with-vba-macro).
3. **Convertir le `.xlsx` en CSV depuis un script**, ce que couvre le reste de cette section. C’est le mieux si vous faites déjà tourner Python ou Node sur un serveur et qu’il vous suffit d’aspirer un classeur une fois par jour.

Pour l’option 3, pandas le fait en une ligne :

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

Si vous ne voulez pas pandas comme dépendance, `openpyxl` seul fonctionne aussi :

```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 : même travail, SDK officiel

Brevo publie `@getbrevo/brevo` pour Node. Il gère l’auth, les retries et la forme typée de la requête :

```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}`);
```

Ou, si vous ne voulez pas du SDK, un simple `fetch` fait pareil :

```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 : un one-liner pour les imports ad hoc

Quand vous voulez juste tester l’endpoint ou pousser un petit fichier à la main :

```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 .` avale tout le fichier et l’échappe en JSON, ce qui vous évite d’échapper manuellement les sauts de ligne et les guillemets.

## Fichiers de plus de 10 Mo : utilisez `fileUrl`

`fileBody` est plafonné à 10 Mo. Si votre dump de contacts est plus gros, hébergez le fichier à une URL que Brevo peut récupérer et passez-la :

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

Tout ce qui est accessible via une URL HTTPS publique fonctionne : URLs présignées S3, GCS, votre propre hôte statique, voire une URL raw GitHub pour des imports ponctuels. Brevo récupère le fichier depuis votre URL puis lance l’import. Formats acceptés : `.csv`, `.txt`, `.json`.

## Envoyer du JSON plutôt que du CSV

Si vous tirez déjà les contacts d’une base de données, inutile de faire un aller-retour par CSV, envoyez-les directement en 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],
}
```

Même plafond de 10 Mo. Même comportement asynchrone.

## Sondage de l’état d’avancement

L’import est asynchrone, `processId` est votre poignée pour le suivre. Il y a un endpoint séparé pour vérifier l’état du processus :

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

Pour les jobs longs, le motif plus propre est `notifyUrl` : passez un endpoint HTTPS auquel Brevo enverra un POST quand l’import sera terminé, et vous évitez le polling.

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

## Erreurs courantes et comment les corriger

**`400 Bad Request` sans cause évidente.** Presque toujours des points-virgules contre des virgules dans le CSV. L’import de Brevo attend `;`, pas `,`. Revérifiez `fileBody` après votre étape de conversion.

**Les valeurs des attributs personnalisés disparaissent.** L’attribut n’existe pas dans votre compte. Créez-le sous **Contacts → Paramètres → Attributs de contact** avant d’importer, ou utilisez l’[API Attributes](https://developers.brevo.com/reference/create-attribute) pour le créer dans le cadre de votre script.

**`401 Unauthorized`.** Mauvais nom d’en-tête. C’est `api-key` (en minuscules, avec tiret), pas `Authorization` ni `X-API-Key`.

**Import « réussi » mais les contacts n’apparaissent pas dans la liste.** Vérifiez que `listIds` contient bien la bonne liste. De plus : si `updateExistingContacts` est à `false` et que les contacts existent déjà, Brevo les ignore silencieusement plutôt que de les rajouter à la liste.

**Certaines lignes ont été importées, d’autres non.** Brevo vous envoie un rapport d’erreurs ligne par ligne par e-mail à la fin de l’import (sauf si vous avez mis `disableNotification: true`). Le rapport vous dit quelles lignes avaient des e-mails invalides, des champs requis manquants ou des problèmes de formatage.

## Quand scripter et quand utiliser l’interface

L’interface convient pour les imports ponctuels de moins de mille lignes. Un script gagne dès que :

- Vous importez plus d’une fois (par ex. un export hebdomadaire de votre CRM)
- Les données source ont besoin d’un nettoyage avant d’arriver dans Brevo (déduplication, formatage des numéros de téléphone, séparation des noms complets en prénom/nom)
- Vous voulez que ça tourne de façon planifiée sans que personne ne clique
- Le fichier dépasse la zone de confort de l’interface

Enveloppez le script ci-dessus dans un cron ou une GitHub Action et vous avez une synchronisation automatique des contacts. Le prochain article de cette série montre comment faire la même chose directement depuis un Google Sheet via Apps Script, sans serveur.

## Pour aller plus loin

- [API Brevo : référence import-contacts](https://developers.brevo.com/reference/import-contacts)
- [API Brevo : attributs de contact](https://developers.brevo.com/reference/create-attribute)
- [Construire des listes de contacts pour vos campagnes e-mail](https://help.brevo.com/hc/en-us/articles/209499265)

## Questions fréquemment posées

**Quel est l'endpoint de l'API Brevo pour l'import de contacts en masse ?**

POST https://api.brevo.com/v3/contacts/import. Il accepte du contenu CSV (fileBody), une URL de fichier distant (fileUrl) ou un tableau JSON (jsonBody). L’endpoint est asynchrone, il renvoie immédiatement un processId et termine l’import en arrière-plan.

**Quelle est la taille maximale du fichier ?**

10 Mo pour un CSV en ligne (fileBody) ou un JSON (jsonBody). Pour les fichiers plus gros, hébergez le fichier à un endroit accessible et passez son URL via fileUrl, cette voie n’a pas de limite de taille documentée.

**Comment importer un fichier .xlsx ?**

L'API d'import de Brevo n'accepte que .csv, .txt ou .json. Convertissez d'abord le .xlsx en .csv : pandas, openpyxl ou LibreOffice headless le font en une ligne. Le script de ce guide inclut une conversion xlsx vers csv.

**Est-ce que cela écrasera les contacts existants ?**

Par défaut, oui : updateExistingContacts est à true et fait la correspondance par e-mail. Mettez-le à false pour ignorer les contacts qui existent déjà. Mettez emptyContactsAttributes à true si vous voulez que les cellules vides du CSV effacent les valeurs existantes (sinon, les cellules vides sont ignorées).

## Articles connexes

### [Importer des contacts Google Sheets dans Brevo avec Apps Script](https://tajo.io/fr/blog/import-google-sheet-contacts-to-brevo-apps-script/)

30 avr. 2026 · 3 min de lecture

Google Sheets → Brevo

### [Comment pousser des contacts Excel vers Brevo avec une macro VBA (et l’alternative Office Scripts)](https://tajo.io/fr/blog/import-excel-contacts-to-brevo-with-vba-macro/)

30 avr. 2026 · 7 min de lecture

Microsoft Excel → Brevo

### [Export et migration des données Brevo : comment faire entrer ou sortir vos données](https://tajo.io/fr/blog/brevo-data-export-migration/)

19 août 2026 · 11 min de lecture

8 sections
