---
seo_title: API de conversion de fichiers par lot en PDF/ZIP | EnConvert
meta_desc: Convertissez plusieurs URLs en PDF ou captures d'écran en une requête via POST /v1/convert/url-to-pdf. API batch avec sortie ZIP, webhooks et polling.
keywords: api conversion de fichiers par lot, convertir plusieurs urls en pdf api, api url vers pdf en masse zip, api capture d'écran par lot, suivi statut batch api polling, api zip sortie pdf, conversion asynchrone par lot api, webhook callback conversion par lot
---

# API de conversion de fichiers par lot

L'API batch d'EnConvert convertit plusieurs URLs en une seule requête : passez un tableau d'URLs à `/v1/convert/url-to-pdf` ou `/v1/convert/url-to-screenshot` et recevez une réponse HTTP 202 avec un `batch_id`. Chaque URL est convertie de manière asynchrone en arrière-plan, et les résultats sont livrés sous forme d'URLs de téléchargement présignées, soit une par fichier, soit regroupées dans une seule archive ZIP. Suivez la progression en interrogeant `GET /v1/convert/batch/{batch_id}`, ou soyez notifié par webhook ou email à la fin du traitement.

<div class="alert alert-warning">
<strong>Clés privées uniquement :</strong> Le traitement par lot n'est disponible qu'en vous authentifiant avec une <strong>clé API privée</strong> (<code>X-API-Key: sk_...</code>). Les clés publiques sont limitées aux requêtes synchrones à URL unique.
</div>

---

## Fonctionnement

1. Envoyez une requête avec un **tableau d'URLs** dans le paramètre `url` vers `/v1/convert/url-to-pdf` ou `/v1/convert/url-to-screenshot`.
2. L'API valide le lot par rapport aux limites de votre plan et renvoie **HTTP 202** avec un `batch_id`.
3. Chaque URL est convertie en arrière-plan et facture une op. Le nombre total d'éléments du lot est vérifié au préalable par rapport à votre quota mensuel d'ops restant avant le début du traitement.
4. Suivez la progression via `GET /v1/convert/batch/{batch_id}`, ou recevez un webhook ou une notification par email à la fin du traitement.
5. Téléchargez les résultats via les URLs présignées présentes dans la réponse de statut du lot.

---

## Modes de sortie

### Mode individuel (par défaut)

Chaque URL produit un fichier distinct. Chaque fichier reçoit sa propre URL de téléchargement présignée dans la réponse de statut du lot.

**Requête :**

```bash
curl -X POST https://api.enconvert.com/v1/convert/url-to-pdf \
  -H "X-API-Key: sk_your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": [
      "https://example.com/page-1",
      "https://example.com/page-2",
      "https://example.com/page-3"
    ]
  }'
```

**Réponse (HTTP 202 Accepted) :**

```json
{
    "status": "processing",
    "batch_id": "550e8400-e29b-41d4-a716-446655440000",
    "url_count": 3,
    "output_format": "individual"
}
```

<div class="alert alert-info">
<strong>Remarque :</strong> Lorsque vous passez plusieurs URLs, <code>async_mode</code> est automatiquement défini sur <code>true</code>, que vous l'incluiez explicitement dans la requête ou non.
</div>

### Mode archive ZIP

Définissez `output_format` sur `true` pour recevoir tous les fichiers convertis regroupés dans une seule archive ZIP. Nécessite un plan avec accès à la sortie ZIP.

**Requête :**

```bash
curl -X POST https://api.enconvert.com/v1/convert/url-to-pdf \
  -H "X-API-Key: sk_your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": [
      "https://example.com/page-1",
      "https://example.com/page-2",
      "https://example.com/page-3"
    ],
    "output_format": true,
    "output_filename": "monthly-reports"
  }'
```

**Réponse (HTTP 202 Accepted) :**

```json
{
    "status": "processing",
    "batch_id": "550e8400-e29b-41d4-a716-446655440000",
    "url_count": 3,
    "output_format": "zip"
}
```

En mode ZIP, toutes les URLs sont traitées séquentiellement, et les résultats réussis sont regroupés dans une seule archive ZIP nommée `{output_filename}_{timestamp}.zip` (ou `batch_{timestamp}.zip` si aucun nom personnalisé n'est fourni).

---

## Paramètres du lot

| Paramètre | Type | Par défaut | Description | Restriction de plan |
|-----------|------|---------|-------------|-------------|
| `url` | `string[]` | *(obligatoire)* | Tableau d'URLs à convertir. | -- |
| `output_format` | `boolean` | `false` | Définissez sur `true` pour regrouper tous les résultats dans une archive ZIP. Nécessite plusieurs URLs. | Nécessite l'accès à la sortie ZIP |
| `output_filename` | `string` | Généré automatiquement | Nom de fichier personnalisé pour la sortie. En mode ZIP, il nomme l'archive ZIP. | -- |
| `async_mode` | `boolean` | `true` (implicite) | Toujours `true` pour un lot. Activé automatiquement lorsque plusieurs URLs sont fournies. | Nécessite l'accès asynchrone |
| `notification_email` | `string` | Email du propriétaire du projet | Adresse email à notifier à la fin du traitement. Si omise, l'email du propriétaire du projet est utilisé par défaut. | -- |
| `callback_url` | `string` | `null` | URL du webhook qui recevra un POST à la fin du traitement. | Nécessite l'accès aux webhooks |
| `direct_download` | -- | -- | **Non pris en charge** pour un lot. Renvoie une erreur 400 si défini avec plusieurs URLs. | -- |

### Paramètres du navigateur et du rendu

Ces paramètres s'appliquent à chaque URL du lot :

| Paramètre | Type | Par défaut | Description |
|-----------|------|---------|-------------|
| `viewport_width` | `integer` | `1920` | Largeur de la fenêtre d'affichage du navigateur en pixels. |
| `viewport_height` | `integer` | `1080` | Hauteur de la fenêtre d'affichage du navigateur en pixels. |
| `single_page` | `boolean` | `true` | Génère le rendu sous forme d'une seule page continue (url-to-pdf uniquement). |
| `load_media` | `boolean` | `true` | Attend le chargement des images et des médias. |
| `enable_scroll` | `boolean` | `true` | Fait défiler les pages pour déclencher le chargement du contenu différé (lazy-loaded). |
| `handle_sticky_header` | `boolean` | `true` | Détecte et gère les en-têtes collants/fixes. |
| `handle_cookies` | `boolean` | `true` | Ferme automatiquement les bannières de consentement aux cookies. |
| `wait_for_images` | `boolean` | `true` | Attend que toutes les images aient fini de charger. |

### Authentification et requêtes personnalisées

Ces paramètres s'appliquent à chaque URL du lot. Nécessitent un plan avec accès à l'authentification de base.

| Paramètre | Type | Par défaut | Description |
|-----------|------|---------|-------------|
| `auth` | `object` | `null` | Identifiants d'authentification HTTP Basic : `{"username": "...", "password": "..."}`. |
| `cookies` | `array` | `null` | Tableau d'objets cookie injectés avant chaque chargement de page. Max 50. |
| `headers` | `object` | `null` | En-têtes HTTP personnalisés envoyés avec chaque requête. Max 20. |

### Options PDF (url-to-pdf uniquement)

Passez un objet `pdf_options` pour contrôler le format de sortie PDF de chaque page du lot :

| Paramètre | Type | Par défaut | Description |
|-----------|------|---------|-------------|
| `page_size` | `string` | `"A4"` | Nom du format de page. |
| `orientation` | `string` | `"portrait"` | `"portrait"` ou `"landscape"`. |
| `margins` | `object` | `{"top": 10, "bottom": 10, "left": 10, "right": 10}` | Marges en mm. |
| `grayscale` | `boolean` | `false` | Sortie en niveaux de gris via Ghostscript. |

---

## Interrogation du statut du lot {: #batch-status-polling }

Utilisez l'endpoint de statut du lot pour vérifier la progression et récupérer les URLs de téléchargement.

```
GET /v1/convert/batch/{batch_id}
X-API-Key: sk_your_private_key
```

Remplacez `{batch_id}` par le `batch_id` renvoyé par la requête initiale.

### État en cours de traitement

Pendant que les conversions sont encore en cours :

```json
{
    "batch_id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "processing",
    "total": 3,
    "completed": 1,
    "failed": 0,
    "in_progress": 2,
    "output_mode": "individual",
    "zip_download_url": null,
    "items": [
        {
            "source_url": "https://example.com/page-1",
            "status": "Success",
            "download_url": "https://spaces.example.com/...",
            "output_file_size": 184320,
            "duration": "3.12"
        },
        {
            "source_url": "https://example.com/page-2",
            "status": "In Progress",
            "download_url": null,
            "output_file_size": null,
            "duration": null
        },
        {
            "source_url": "https://example.com/page-3",
            "status": "In Progress",
            "download_url": null,
            "output_file_size": null,
            "duration": null
        }
    ]
}
```

### État terminé

Lorsque toutes les URLs ont été converties avec succès :

```json
{
    "batch_id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "completed",
    "total": 3,
    "completed": 3,
    "failed": 0,
    "in_progress": 0,
    "output_mode": "individual",
    "zip_download_url": null,
    "items": [
        {
            "source_url": "https://example.com/page-1",
            "status": "Success",
            "download_url": "https://spaces.example.com/...",
            "output_file_size": 184320,
            "duration": "3.12"
        },
        {
            "source_url": "https://example.com/page-2",
            "status": "Success",
            "download_url": "https://spaces.example.com/...",
            "output_file_size": 210944,
            "duration": "4.55"
        },
        {
            "source_url": "https://example.com/page-3",
            "status": "Success",
            "download_url": "https://spaces.example.com/...",
            "output_file_size": 97280,
            "duration": "2.87"
        }
    ]
}
```

### État partiel

Lorsque toutes les URLs sont terminées mais que certaines ont échoué :

```json
{
    "batch_id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "partial",
    "total": 3,
    "completed": 2,
    "failed": 1,
    "in_progress": 0,
    "output_mode": "individual",
    "zip_download_url": null,
    "items": [
        {
            "source_url": "https://example.com/page-1",
            "status": "Success",
            "download_url": "https://spaces.example.com/...",
            "output_file_size": 184320,
            "duration": "3.12"
        },
        {
            "source_url": "https://example.com/page-2",
            "status": "Success",
            "download_url": "https://spaces.example.com/...",
            "output_file_size": 210944,
            "duration": "4.55"
        },
        {
            "source_url": "https://invalid-url.example",
            "status": "Failed",
            "download_url": null,
            "output_file_size": null,
            "duration": "0.87"
        }
    ]
}
```

### Mode ZIP terminé

En mode ZIP, une seule `zip_download_url` est fournie pour l'archive entière :

```json
{
    "batch_id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "completed",
    "total": 3,
    "completed": 3,
    "failed": 0,
    "in_progress": 0,
    "output_mode": "zip",
    "zip_download_url": "https://spaces.example.com/...",
    "items": [
        {
            "source_url": "https://example.com/page-1",
            "status": "Success",
            "download_url": "https://spaces.example.com/...",
            "output_file_size": 184320,
            "duration": "3.12"
        },
        {
            "source_url": "https://example.com/page-2",
            "status": "Success",
            "download_url": "https://spaces.example.com/...",
            "output_file_size": 210944,
            "duration": "4.55"
        },
        {
            "source_url": "https://example.com/page-3",
            "status": "Success",
            "download_url": "https://spaces.example.com/...",
            "output_file_size": 97280,
            "duration": "2.87"
        }
    ]
}
```

### Valeurs de statut du lot

| Statut | Signification |
|--------|---------|
| `processing` | Au moins une URL est encore en cours de conversion. |
| `completed` | Toutes les URLs ont été converties avec succès. |
| `partial` | Toutes les URLs sont terminées, mais certaines ont échoué. |
| `failed` | Toutes les URLs ont échoué. |

---

## Callbacks webhook

Fournissez un `callback_url` dans la requête pour recevoir une notification POST automatique à la fin du traitement. Le webhook est envoyé avec `Content-Type: application/json` et un timeout de 30 secondes. Aucune nouvelle tentative n'est effectuée en cas d'échec de la livraison.

### Callback en mode individuel

En mode individuel, un **POST webhook distinct est envoyé pour chaque URL** à mesure qu'elle se termine :

```json
{
    "job_id": "12345",
    "status": "success",
    "batch_id": "550e8400-e29b-41d4-a716-446655440000",
    "gcs_uri": "env/files/{project_id}/url-to-pdf/page1_20260405_123456789.pdf",
    "filename": "page1_20260405_123456789.pdf",
    "file_size": 184320
}
```

### Callback en mode ZIP

En mode ZIP, un **seul POST webhook est envoyé lorsque le lot entier est terminé** :

```json
{
    "job_id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "success",
    "batch_id": "550e8400-e29b-41d4-a716-446655440000",
    "gcs_uri": "env/files/{project_id}/url-to-pdf/batch_20260405_123456789.zip",
    "filename": "batch_20260405_123456789.zip",
    "file_size": 456789,
    "total_tasks": 3,
    "successful_tasks": 2,
    "failed_tasks": 1,
    "tasks": [
        {"url": "https://example.com/page-1", "status": "success", "filename": "page1.pdf"},
        {"url": "https://example.com/page-2", "status": "success", "filename": "page2.pdf"},
        {"url": "https://invalid.example", "status": "failed", "error": "Page load timeout"}
    ]
}
```

<div class="alert alert-info">
<strong>Différence de comportement des notifications :</strong> En mode individuel, vous recevez N POSTs webhook distincts (un par URL) et N emails distincts. En mode ZIP, vous recevez un seul POST webhook et un seul email pour l'ensemble du lot. Planifiez en conséquence lors de la conception de votre gestionnaire de webhook.
</div>

---

## Notifications par email

Un email de fin de traitement est envoyé à `notification_email` lorsque le lot se termine. Si aucun `notification_email` n'est fourni, l'email est envoyé par défaut à l'adresse du propriétaire du projet.

L'email contient :

- Le statut de la tâche (succès/échec) avec une bannière colorée
- L'ID du lot
- Pour les tâches par lot : un tableau listant chaque URL, son statut et le nom du fichier de sortie
- Un lien pour télécharger les résultats depuis le tableau de bord

---

## Restrictions par plan d'abonnement

| Fonctionnalité | Founding | Indie | Studio | Enterprise |
|---------|------|---------|-----|------------|
| Traitement par lot | Non | Oui | Oui | Oui |
| Mode asynchrone | Non | Oui | Oui | Oui |
| Regroupement en sortie ZIP | Non | Non | Oui | Oui |
| Callbacks webhook | Non | Non | Oui | Oui |
| HTTP Basic Auth / Cookies / Headers | Non | Oui | Oui | Oui |
| Limite de taille du lot | 0 | Selon le plan | Selon le plan | Illimité |
| Conversions mensuelles | 100 | Selon le plan | Selon le plan | Illimité |

---

## Exemples de code

### Python -- Mode individuel avec interrogation (polling)

```python
import requests
import time

# Submit batch
response = requests.post(
    "https://api.enconvert.com/v1/convert/url-to-pdf",
    headers={"X-API-Key": "sk_your_private_key"},
    json={
        "url": [
            "https://example.com/page-1",
            "https://example.com/page-2",
            "https://example.com/page-3"
        ]
    }
)

data = response.json()
batch_id = data["batch_id"]
print(f"Batch started: {batch_id} ({data['url_count']} URLs)")

# Poll for completion
while True:
    status = requests.get(
        f"https://api.enconvert.com/v1/convert/batch/{batch_id}",
        headers={"X-API-Key": "sk_your_private_key"}
    ).json()

    print(f"Status: {status['status']} ({status['completed']}/{status['total']})")

    if status["status"] in ("completed", "partial", "failed"):
        for item in status["items"]:
            if item["download_url"]:
                print(f"  {item['source_url']} -> {item['download_url']}")
        break

    time.sleep(5)
```

### Python -- Mode ZIP avec webhook

```python
import requests

response = requests.post(
    "https://api.enconvert.com/v1/convert/url-to-pdf",
    headers={"X-API-Key": "sk_your_private_key"},
    json={
        "url": [
            "https://example.com/page-1",
            "https://example.com/page-2",
            "https://example.com/page-3"
        ],
        "output_format": True,
        "output_filename": "monthly-reports",
        "callback_url": "https://your-server.com/webhook/enconvert",
        "pdf_options": {
            "page_size": "A4",
            "orientation": "portrait"
        }
    }
)

data = response.json()
print(f"Batch started: {data['batch_id']}")
print(f"URLs: {data['url_count']}, Format: {data['output_format']}")
# Results will be delivered to your webhook URL
```

### Node.js -- Captures d'écran par lot

```javascript
const response = await fetch("https://api.enconvert.com/v1/convert/url-to-screenshot", {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "X-API-Key": "sk_your_private_key"
    },
    body: JSON.stringify({
        url: [
            "https://example.com/page-1",
            "https://example.com/page-2",
            "https://example.com/page-3"
        ],
        output_format: true,
        output_filename: "screenshots-bundle"
    })
});

const data = await response.json();
console.log(`Batch ${data.batch_id}: ${data.url_count} screenshots queued`);
```

---

## Réponses d'erreur

| Statut | Condition |
|--------|-----------|
| `400 Bad Request` | `url` est vide ou manquant |
| `400 Bad Request` | `output_format=true` avec une seule URL (plusieurs URLs requises) |
| `400 Bad Request` | `direct_download=true` avec plusieurs URLs (non pris en charge) |
| `400 Bad Request` | `direct_download=true` avec `async_mode=true` |
| `400 Bad Request` | Clé publique tentant d'utiliser plusieurs URLs |
| `402 Payment Required` | Le lot dépasserait le quota mensuel d'ops restant |
| `402 Payment Required` | Limite de stockage atteinte |
| `403 Forbidden` | Traitement asynchrone non disponible sur le plan actuel |
| `403 Forbidden` | Traitement par lot non disponible (limite de lot à 0) |
| `403 Forbidden` | La taille du lot dépasse la limite de lot du plan |
| `403 Forbidden` | Sortie ZIP non disponible sur le plan actuel |
| `403 Forbidden` | Callbacks webhook non disponibles sur le plan actuel |
| `404 Not Found` | Lot introuvable (mauvais batch_id ou mauvais projet) |

---

## Limites

| Limite | Valeur |
|-------|-------|
| Taille du lot | Dépend du plan (Founding : désactivé) |
| Conversions mensuelles | Dépend du plan (le lot entier est vérifié au préalable) |
| Timeout de livraison du webhook | 30 secondes (sans nouvelle tentative) |
| Nombre maximum de cookies par requête | 50 |
| Nombre maximum d'en-têtes personnalisés par requête | 20 |
| Conservation des fichiers | Dépend du plan |

## Questions fréquentes

### Comment convertir plusieurs URLs en PDF en une seule requête API ?

Envoyez un POST à `/v1/convert/url-to-pdf` avec un tableau d'URLs dans le paramètre `url`, authentifié avec une clé API privée (`sk_...`). L'API répond avec `HTTP 202` et un `batch_id`, et chaque URL est convertie en arrière-plan.

### Puis-je obtenir tous les résultats de conversion par lot dans un seul fichier ZIP ?

Oui. Définissez `output_format` sur `true` pour regrouper tous les résultats réussis dans une archive ZIP nommée `{output_filename}_{timestamp}.zip` (ou `batch_{timestamp}.zip` si aucun nom personnalisé n'est fourni). La sortie ZIP nécessite un plan avec accès à la sortie ZIP (Studio, Production ou Enterprise) et plusieurs URLs dans la requête.

### Comment vérifier le statut d'une tâche de conversion par lot ?

Interrogez `GET /v1/convert/batch/{batch_id}` avec votre clé API privée. La réponse indique `processing`, `completed`, `partial` ou `failed`, ainsi que des éléments par URL contenant `download_url`, `output_file_size` et `duration`.

### Pourquoi ma requête par lot renvoie-t-elle 403 Forbidden ?

Une réponse `403 Forbidden` signifie qu'une restriction de plan a été atteinte : le traitement asynchrone n'est pas disponible sur votre plan, le traitement par lot est désactivé (limite de lot à 0), la taille du lot dépasse la limite de votre plan, ou une fonctionnalité restreinte comme la sortie ZIP ou les callbacks webhook n'est pas incluse dans votre plan.

### Puis-je utiliser le traitement par lot avec une clé API publique ?

Non. Le traitement par lot nécessite une clé API privée (`sk_...`). Les clés publiques sont limitées aux requêtes synchrones à URL unique, et l'envoi de plusieurs URLs avec une clé publique renvoie `400 Bad Request`.
