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.

Clés privées uniquement : Le traitement par lot n'est disponible qu'en vous authentifiant avec une clé API privée (X-API-Key: sk_...). Les clés publiques sont limitées aux requêtes synchrones à URL unique.

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 :

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) :

{
    "status": "processing",
    "batch_id": "550e8400-e29b-41d4-a716-446655440000",
    "url_count": 3,
    "output_format": "individual"
}
Remarque : Lorsque vous passez plusieurs URLs, async_mode est automatiquement défini sur true, que vous l'incluiez explicitement dans la requête ou non.

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 :

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) :

{
    "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#

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 :

{
    "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 :

{
    "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é :

{
    "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 :

{
    "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 :

{
    "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é :

{
    "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"}
    ]
}
Différence de comportement des notifications : 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.

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)#

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#

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#

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.