Ingestion de fichiers#

Il y a deux façons d'envoyer des octets à EnConvert : téléverser le fichier vous-même en multipart/form-data, ou passer une url et laisser l'API récupérer la ressource. Celle que vous pouvez utiliser dépend de l'endpoint, pas de votre plan.


Quel endpoint accepte quoi#

Famille d'endpoints Comment arrivent les octets Nom du champ
Formats de données, documents, images Téléversement multipart/form-data, un fichier par requête file
Pages web (url-to-pdf, url-to-screenshot, url-to-markdown, website-to-pdf, website-to-screenshot) Corps JSON, EnConvert récupère la page url
POST /v2/ingest/files multipart/form-data, plusieurs fichiers par job files
POST /v2/perceive, POST /v2/ingest Corps JSON, EnConvert récupère la page url

Il n'y a pas de troisième voie. Les endpoints de téléversement ne récupèrent pas d'URL à votre place, y compris les routes fourre-tout anything-to-pdf et anything-to-markdown. Pour transformer une page en ligne en PDF, appelez plutôt url-to-pdf. Pour savoir quels formats accepte chaque endpoint, voir formats pris en charge.


Téléverser un fichier local#

Le champ de formulaire s'appelle file, et chaque endpoint de téléversement V1 en accepte exactement un. Tout le reste du formulaire est facultatif.

Champ de formulaire Type Description
file file Le fichier à convertir. Son extension doit être acceptée par l'endpoint.
output_filename string Nom de base personnalisé pour la sortie. L'extension cible est ajoutée pour vous.
job_id string ID de tâche fourni par le client pour la reprise après timeout. Interrogez GET /v1/convert/status/{job_id} si la connexion est coupée.
pdf_options string Chaîne JSON d'options PDF, sur les endpoints qui produisent un PDF.
direct_download boolean Accepté pour garder la même forme de requête que les endpoints URL. Sans effet ici : un téléversement répond toujours avec l'enveloppe JSON ci-dessous, quoi que vous envoyiez.

curl#

curl -X POST https://api.enconvert.com/v1/convert/anything-to-pdf \
  -H "X-API-Key: sk_your_private_key" \
  -F "[email protected]" \
  -F "direct_download=false"

La réponse est du JSON avec un lien de téléchargement pré-signé :

{
    "presigned_url": "https://spaces.example.com/...signed...",
    "object_key": "env/files/{project_id}/anything-to-pdf/quarterly-report_20260714_101530123.pdf",
    "filename": "quarterly-report_20260714_101530123.pdf",
    "file_size": 51240,
    "conversion_time_seconds": 2.1,
    "job_id": null
}

Les mêmes valeurs sont reprises dans les en-têtes de réponse X-Object-Key, X-File-Size, X-Conversion-Time et X-Filename, vous pouvez donc les lire sans analyser le corps. Récupérez le fichier rapidement : le lien est de courte durée, et URLs signées précise exactement à quel point.

Python#

import requests

with open("quarterly-report.docx", "rb") as f:
    response = requests.post(
        "https://api.enconvert.com/v1/convert/anything-to-pdf",
        headers={"X-API-Key": "sk_your_private_key"},
        files={"file": ("quarterly-report.docx", f)},
        data={"direct_download": "false"},
    )

response.raise_for_status()
result = response.json()

# Download the PDF from the pre-signed URL.
pdf = requests.get(result["presigned_url"]).content
with open("quarterly-report.pdf", "wb") as out:
    out.write(pdf)

Node.js#

import { readFile, writeFile } from "node:fs/promises";

const form = new FormData();
form.append(
    "file",
    new Blob([await readFile("quarterly-report.docx")]),
    "quarterly-report.docx"
);
form.append("direct_download", "false");

const response = await fetch(
    "https://api.enconvert.com/v1/convert/anything-to-pdf",
    { method: "POST", headers: { "X-API-Key": "sk_your_private_key" }, body: form }
);

const result = await response.json();
const pdf = await fetch(result.presigned_url).then((r) => r.arrayBuffer());
await writeFile("quarterly-report.pdf", Buffer.from(pdf));

Plusieurs fichiers en un seul appel#

POST /v2/ingest/files est le seul endpoint qui accepte plus d'un fichier. Répétez le champ files, jusqu'à 200 fichiers par job :

curl -X POST https://api.enconvert.com/v2/ingest/files \
  -H "X-API-Key: sk_your_private_key" \
  -F "[email protected]" \
  -F "[email protected]" \
  -F "[email protected]" \
  -F "max_words=700" \
  -F "webhook_url=https://your-app.example.com/hooks/ingest"

Chaque fichier est converti en Markdown, découpé en chunks et assemblé dans un seul livrable JSONL. Le job est toujours asynchrone et répond 202 Accepted avec un job_id. Tous les détails sont sur la page de l'endpoint ingest.


Laisser EnConvert récupérer le fichier#

Sur les endpoints URL, vous envoyez un corps JSON au lieu d'un formulaire, et c'est l'API qui effectue la récupération :

curl -X POST https://api.enconvert.com/v1/convert/url-to-markdown \
  -H "X-API-Key: sk_your_private_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/report"}'

url accepte une chaîne ou un tableau de chaînes. Un tableau bascule la requête en asynchrone, ce que couvre Traitement par lot.

Sources derrière une authentification#

Trois champs facultatifs permettent à la récupération de porter des identifiants. Les trois nécessitent un plan avec accès à l'authentification basique (Indie et au-dessus).

Paramètre Type Par défaut Description
auth object null Identifiants HTTP Basic Auth : {"username": "...", "password": "..."}.
cookies array null Tableau d'objets cookie injectés avant la navigation. 50 maximum par requête. Chacun exige name, value, et soit domain, soit url.
headers object null En-têtes HTTP personnalisés envoyés avec les requêtes. 20 maximum par requête. Ne peuvent pas inclure les en-têtes bloqués : host, content-length, transfer-encoding, connection, upgrade, te, trailer.
Portée des identifiants : Les identifiants de l'objet auth, ainsi qu'un en-tête Authorization (par exemple un jeton Bearer) passé via headers, sont envoyés uniquement à l'origine cible, jamais aux sous-ressources tierces que la page demande. Cela évite toute fuite d'identifiants vers des hôtes publicitaires, d'analytics ou de CDN.

Adresses privées et internes#

L'url doit être une adresse publique http:// ou https://. Avant toute récupération, elle est filtrée et rejetée avec 400 Bad Request lorsqu'elle :

  • utilise un schéma autre que http/https ;
  • intègre des identifiants comme https://user:pass@host/ (utilisez plutôt le champ auth) ;
  • vise localhost, un nom d'hôte de métadonnées cloud, ou une IP qui se résout dans une plage privée, loopback, link-local, réservée ou non publique d'une autre manière ;
  • utilise une notation IP non standard (octale, hexadécimale ou entier compact) qui pourrait se résoudre de façon ambiguë.

Cela s'applique à l'URL de départ, à chaque URL d'un lot, et aux pages découvertes par les endpoints de crawl website-to-*.

Dit simplement : EnConvert s'exécute en dehors de votre réseau. Il ne peut pas atteindre http://10.0.0.5/report.docx, un nom d'hôte .internal, ni quoi que ce soit qui ne se résout qu'à l'intérieur de votre VPC. Soit vous rendez le fichier joignable depuis l'internet public, soit vous lisez les octets vous-même et vous les téléversez.


Ce qu'il advient de votre nom de fichier#

Le nom que vous envoyez remplit deux rôles.

Il choisit le convertisseur. L'extension décide quel chemin d'entrée s'exécute : nommez donc le fichier correctement. Un fichier appelé report sans extension est rejeté par tout endpoint doté d'une liste d'extensions autorisées.

Il amorce le nom de sortie. Le nom du fichier de sortie est construit ainsi :

{base}_{YYYYMMDD_HHMMSSmmm}.{ext}

L'horodatage UTC est toujours ajouté, si bien que deux conversions du même fichier n'entrent jamais en collision. base est résolu dans cet ordre :

  1. output_filename, si vous en avez envoyé un. Si vous y avez inclus l'extension cible, celle-ci est d'abord retirée pour que vous n'obteniez pas report.pdf_20260405_123456789.pdf.
  2. Le nom du fichier téléversé sans son extension. report.docx produit report_20260405_123456789.pdf.
  3. Pour les conversions d'URL, le domaine. https://example.com/page produit example_20260405_123456789.pdf.
  4. À défaut de tout cela, le littéral output.

La clé de stockage est assainie avant l'écriture du résultat : seul le nom de base survit, .. est supprimé, les caractères <>:"|?* sont retirés et les espaces deviennent des tirets bas. Téléversez My Report (final).docx et le PDF atterrit sous My_Report_(final)_20260405_123456789.pdf. Ce chemin vous est renvoyé dans object_key et a la forme {env}/files/{project_id}/{endpoint}/{filename}.

Les noms de fichiers envoyés à POST /v2/ingest/files sont en outre plafonnés à 255 caractères.


Plafond de taille et le 413#

Le plafond de téléversement dépend du plan et s'applique à chaque fichier individuellement.

Plan Taille max de téléversement Octets
Founding 5 MB 5242880
Indie 15 MB 15728640
Studio 50 MB 52428800
Production 150 MB 157286400
Enterprise Négociée Selon contrat

La taille est mesurée sur la partie téléversée elle-même, au fil de l'arrivée du corps, et non d'après un en-tête que vous contrôlez : un envoi en chunked sans Content-Length est donc vérifié de la même manière. Un dépassement renvoie 413 Payload Too Large avant tout travail de conversion et avant la facturation de la moindre op :

{
    "detail": {
        "error": "File too large",
        "file_size": 10485760,
        "max_size": 5242880,
        "tier": "free",
        "key_type": "private"
    }
}

file_size et max_size sont tous deux en octets. tier est le slug du plan (free, starter, pro, business, enterprise), pas le nom affiché que vous voyez sur la page tarifaire : un projet Studio rapporte donc "tier": "pro". key_type vaut private, public ou dashboard, avec repli sur unknown.

5 MB, ça part vite. Sur le plan Founding, un PDF scanné de 40 pages ou une présentation avec quelques photos pleine page dépasse généralement déjà la limite. Il n'existe aucune voie de téléversement fragmenté ou reprenable : le remède, c'est un fichier plus petit ou un plan plus grand.

Franchir le contrôle de taille n'est pas le dernier obstacle. Une allocation mensuelle épuisée répond 402 Payment Required, et trop de requêtes dans une fenêtre répondent 429, deux cas décrits dans Limites de débit et quotas.


Type de contenu et octets magiques#

Les téléversements passent deux contrôles, dans cet ordre.

1. La liste d'extensions autorisées. Chaque endpoint déclare les extensions qu'il accepte. Une non-correspondance donne 400 Bad Request :

{
    "detail": "Invalid file format '.pdf' for png-to-jpeg. Allowed: .png"
}

2. Le reniflage des octets magiques. Les premiers octets du fichier sont comparés au groupe que revendique son extension. Une non-correspondance à forte confiance donne elle aussi 400 :

{
    "detail": "File content does not match the 'png-to-jpeg' input type."
}

C'est ce que vous obtenez quand vous renommez un PDF en .png et le téléversez : les octets commencent par %PDF-, l'extension dit PNG, et les deux se contredisent. Ce contrôle existe parce que c'est l'extension qui achemine votre requête. Sans lui, des octets PDF arrivent dans un décodeur d'images et vous récoltez un échec opaque au fond du convertisseur au lieu d'un 400 clair dès la porte, et un fichier délibérément mal étiqueté se retrouve confié à un parseur qui n'aurait jamais dû le voir.

Deux choses que ce contrôle ne fait pas, toutes deux bonnes à connaître :

  • Le Content-Type de la partie n'est jamais inspecté. Il n'y a aucune liste MIME autorisée nulle part dans le chemin de téléversement : application/octet-stream passe donc sans problème. L'extension du nom de fichier est la seule chose qui achemine la requête, ce qui explique pourquoi l'envoi d'un fichier sans extension échoue.
  • Les formats texte n'ont pas de signature fiable et sautent complètement le reniflage : .json, .csv, .xml, .yaml, .toml, .md, .html, .svg, .txt. Un fichier .json qui contient en réalité du CSV est accepté à ce stade et échoue plus tard, dans le parseur.

Les signatures binaires reconnues sont PNG, JPEG, GIF, WebP, HEIC/HEIF, PDF et le groupe bureautique (un conteneur ZIP pour .docx/.xlsx/.pptx/ODF/EPUB, ou l'ancien OLE2 pour .doc/.xls/.ppt). Le reniflage est délibérément permissif : les octets qu'il ne reconnaît pas passent plutôt que d'être bloqués.


Fichiers volumineux : la checklist#

  1. Vérifiez le plafond d'abord. Un 413 est bon marché pour l'API et coûteux pour vous, car vous avez téléversé le corps entier pour l'obtenir.
  2. Attendez-vous à un téléversement synchrone. async_mode n'existe que sur url-to-pdf, url-to-screenshot et url-to-markdown. Les endpoints de téléversement l'ignorent et convertissent toujours à l'intérieur de la requête. Voir tâches synchrones et asynchrones.
  3. Envoyez un job_id que vous avez généré. Si un proxy placé devant vous coupe la connexion avant la fin de la conversion, le travail se termine quand même. Interrogez GET /v1/convert/status/{job_id} et vous obtenez {"status": "processing"}, puis soit {"status": "success", "presigned_url": ..., "object_key": ...}, soit {"status": "failed", "error": ...}. Réutiliser votre propre ID relance cette tâche ; réutiliser l'ID d'un autre projet renvoie 409.
  4. Prévoyez les timeouts. Une requête est plafonnée à 300 secondes de bout en bout, après quoi vous obtenez 504 avec {"error": "Request timeout"}. Les conversions bureautiques adossées à LibreOffice ont leur propre plafond de 120 secondes, remonté lui aussi en 504.
  5. Gérez le 503 avec Retry-After: 10. Les conversions de fichiers s'exécutent derrière un contrôle d'admission doté d'une file d'attente bornée. Quand la file est pleine, la requête est refusée immédiatement plutôt que de patienter : réessayez donc après l'intervalle indiqué dans l'en-tête.
  6. Pour beaucoup de documents, changez d'endpoint. POST /v2/ingest/files accepte jusqu'à 200 fichiers, renvoie 202 immédiatement avec un job_id, et accepte un webhook_url pour que vous n'ayez jamais à interroger. Voir webhooks.
  7. Téléchargez rapidement. Les liens de sortie sont signés et expirent. Si le vôtre a expiré, relisez l'endpoint de statut : chaque interrogation émet un nouveau lien vers le même objet stocké.

Questions fréquentes#

Quel nom de champ l'API EnConvert attend-elle pour un téléversement de fichier ?#

file, envoyé en multipart/form-data, un fichier par requête, sur chaque endpoint de conversion V1 qui accepte un téléversement. L'exception est POST /v2/ingest/files, qui utilise files et accepte jusqu'à 200 fichiers par job.

EnConvert peut-il télécharger le fichier depuis une URL au lieu que je le téléverse ?#

Uniquement sur les endpoints URL (url-to-pdf, url-to-screenshot, url-to-markdown, website-to-pdf, website-to-screenshot) et les endpoints V2 /v2/perceive et /v2/ingest. Les endpoints de conversion par téléversement n'ont pas de paramètre url. Toute URL que vous passez doit être joignable publiquement : les adresses privées, loopback, link-local et de métadonnées cloud sont rejetées avec 400.

Pourquoi mon téléversement a-t-il renvoyé 413 Payload Too Large ?#

Le fichier dépassait le plafond par fichier de votre plan, soit 5 MB sur Founding, 15 MB sur Indie, 50 MB sur Studio et 150 MB sur Production. Le corps de la réponse porte un objet detail avec error, file_size, max_size, tier et key_type pour que vous puissiez montrer à l'appelant les chiffres exacts.

Pourquoi mon téléversement PNG échoue-t-il avec « File content does not match » ?#

Les premiers octets du fichier appartiennent à un format différent de celui que revendique son extension, par exemple un PDF renommé en .png. Envoyez le fichier sous sa véritable extension. Les formats texte comme .json et .csv ne sont jamais vérifiés octet par octet, cette erreur n'apparaît donc que pour les types binaires.

Puis-je téléverser un fichier volumineux de manière asynchrone ?#

Pas sur les endpoints de téléversement V1 : ils convertissent toujours dans la requête. Envoyez un job_id généré par le client et interrogez GET /v1/convert/status/{job_id} pour survivre à une connexion coupée, ou utilisez POST /v2/ingest/files, asynchrone par conception et capable d'appeler un webhook à la fin du job.