Perceive

POST /v2/perceive rend une URL une seule fois dans un véritable navigateur et vous renvoie chaque sortie que vous demandez à partir de ce rendu unique : Markdown, HTML nettoyé ou brut, une capture d'écran, un PDF, l'inventaire des liens et des images, et des données structurées (métadonnées de la page, JSON-LD, titres, tableaux). Il remplace toute une pile d'appels séparés — url-to-markdown, url-to-screenshot, url-to-pdf, plus votre propre scraping — par une seule requête.

Voici l'appel utile le plus simple. Envoyez une URL, récupérez du Markdown propre et les métadonnées structurées de la page :

curl -X POST https://api.enconvert.com/v2/perceive \
  -H "X-API-Key: sk_live_your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/pricing",
    "outputs": ["markdown", "structured"]
  }'

La réponse contient une URL de téléchargement pré-signée pour le fichier Markdown et le bloc structuré en ligne :

{
    "operation_id": "per_3f9a2c1b8e7d4a6f90b1c2d3e4f5a6b7",
    "status": "completed",
    "url": "https://example.com/pricing",
    "url_final": "https://example.com/pricing",
    "content_hash": "9f2b8c1a...d4e5",
    "render_quality": 0.93,
    "cache_hit": false,
    "outputs": {
        "markdown": {
            "url": "https://spaces.example.com/...signed...",
            "object_key": "env/files/4127/v2-perceive/per_3f9a..._markdown.md",
            "size_bytes": 8421,
            "content_type": "text/markdown; charset=utf-8",
            "expires_in": 900
        }
    },
    "structured": {
        "metadata": {
            "title": "Pricing",
            "description": "Simple, usage-based pricing."
        },
        "structured_data": [
            {"@type": "Product", "name": "Pro", "offers": {"price": "99"}}
        ]
    },
    "extraction_tier": "heuristic",
    "tokens": {"input": 0, "output": 0},
    "cost_cents": 0.0,
    "duration_ms": 6230,
    "warnings": []
}

À signaler d'emblée. /v2/perceive est un endpoint V2 avec son propre compteur de quota. Les forfaits de conversion V1 n'incluent aucune opération perceive V2 — il vous faut un forfait incluant la V2 pour l'appeler. Voir la page de tarification pour les allocations par palier.


Endpoints

Méthode Chemin Objectif
POST /v2/perceive Perçoit une seule URL et renvoie les sorties que vous avez demandées.
GET /v2/perceive/{operation_id} Récupère à nouveau une opération passée avec des URL de téléchargement fraîchement signées.
POST /v2/perceive/batch Perçoit jusqu'à 1 000 URL partageant un même jeu d'options.
GET /v2/perceive/batch/{job_id} Interroge le statut et les résultats par URL d'un lot.

Content-Type : application/json sur chaque POST.


Authentification

Authentifiez-vous avec une clé privée dans l'en-tête X-API-Key pour les appels serveur à serveur. C'est la voie utilisée par les exemples ci-dessous.

X-API-Key: sk_live_your_private_key

Les clés publiques avec un jeton bearer JWT fonctionnent aussi, en utilisant le même flux que tout autre endpoint — générez un jeton avec votre clé pk_, puis envoyez-le comme Authorization: Bearer <token>. Le flux complet, y compris le verrouillage de domaine et le rafraîchissement du jeton, se trouve dans le guide d'authentification.

Chaque clé API porte une liste d'autorisation d'endpoints. Si /v2/perceive ne figure pas dans la liste de la clé, la requête est rejetée avec un 403.


Fonctionnement de perceive

Une requête déclenche un seul rendu de navigateur via un singleton Chrome headless partagé, puis matérialise chaque sortie à partir de ce rendu. Vous ne payez jamais deux fois pour la même page dans un seul appel.

  1. Rendu. La page se charge dans Chrome headless. Les bannières de cookies sont rejetées, la page est défilée pour déclencher le contenu chargé en différé, les en-têtes collants sont gérés, et les images ont le temps de se charger — le même pipeline de capture qui alimente l'endpoint url-to-pdf.
  2. Matérialisation. À partir du DOM rendu, perceive construit ce que vous avez listé dans outputs : Markdown, HTML nettoyé/brut, liens, images, une capture d'écran, un PDF.
  3. Extraction. Si vous avez demandé une sortie structured, perceive effectue une passe heuristique pour les métadonnées de la page, le JSON-LD, les titres et les tableaux. Si vous envoyez aussi un schema et que votre forfait porte le palier LLM, un modèle Anthropic Claude Haiku remplit le schéma lorsque la passe heuristique reste insuffisante.
  4. Notation. Un score de qualité de rendu (0.0–1.0) signale les pages qui semblent bloquées par une protection anti-bot ou masquées derrière un mur de connexion, afin que vous puissiez distinguer un vrai rendu d'une page de défi.

Les sorties binaires et texte (Markdown, HTML, captures d'écran, PDF, le JSON des liens et des images) sont téléversées vers le stockage et renvoyées sous forme d'URL pré-signées qui expirent après 15 minutes. Le bloc structured est renvoyé en ligne dans le JSON. Récupérez à nouveau n'importe quelle opération avec GET /v2/perceive/{operation_id} pour obtenir un nouveau jeu d'URL signées.


Paramètres de requête

Cœur

Paramètre Type Défaut Description
url string La page à percevoir. Doit commencer par http:// ou https://. Maximum 2 048 caractères. Requis.
outputs string[] ["markdown", "structured"] Quelles sorties produire. Voir Sorties.
extract string[] [] Quels champs structurés extraire lorsque structured figure dans outputs. Voir Extraction structurée.
schema object null Un schéma JSON décrivant les champs que vous voulez extraire. Déclenche le palier d'extraction LLM sur les forfaits qui l'incluent.
cache_mode string "enabled" enabled, bypass ou refresh. Voir Mise en cache.

Sorties

outputs accepte n'importe quelle combinaison de ces noms :

Sortie Renvoyée comme Ce que vous obtenez
markdown URL signée Markdown propre issu du contenu principal, liens et images résolus en URL absolues.
markdown_fit URL signée Markdown « Fit » — une variante élaguée et plus dense, ajustée pour les fenêtres de contexte des LLM.
html_cleaned URL signée Le HTML rendu avec scripts, styles et boilerplate retirés.
html_raw URL signée Le HTML rendu complet exactement tel que le navigateur l'a produit.
screenshot URL signée Un PNG de la zone d'affichage à la taille de viewport demandée (ou par défaut).
screenshot_full_page URL signée Un PNG pleine page capturant toute la hauteur de défilement.
pdf URL signée Un PDF de la page. Accepte l'ensemble de la surface pdf_options (voir ci-dessous).
links URL signée Un tableau JSON de chaque lien trouvé, avec URL absolues et texte d'ancrage.
images URL signée Un tableau JSON de chaque image, avec src absolu et texte alt.
structured JSON en ligne Données structurées extraites de la page (le champ de réponse structured).

Rendu et attente

Paramètre Type Défaut Description
viewport object 1920 x 1080 {"width": <int>, "height": <int>}. Largeur 320–3840, hauteur 240–2160.
mobile boolean false Rendre à un viewport mobile (390 x 844) sauf si viewport est défini explicitement.
wait_for string null Attendre après la navigation un sélecteur CSS (".price" ou "css:.price") ou une expression JS ("js:window.dataReady === true").
wait_timeout_ms integer 30000 Combien de temps wait_for peut attendre, en millisecondes. 0–60 000. Un dépassement se dégrade en avertissement ; la page est capturée telle quelle.
js_code string null JavaScript à exécuter sur la page après la navigation. Maximum 20 000 caractères. Une erreur devient un avertissement, pas un échec.
block_resources string[] [] Types de ressources à interrompre avant leur chargement. N'importe lesquels parmi image, media, font, stylesheet, script, xhr, fetch, websocket, manifest, other. Utile pour des rendus plus rapides, en texte seul.
respect_robots boolean false Lorsque true, une URL interdite par le robots.txt du site est rejetée avec un 403.
pdf_options object null Format de page, marges, en-têtes, pieds de page, échelle et orientation pour la sortie pdf. Même objet que url-to-pdf. Sans pdf_options, perceive produit une seule page continue, identique octet pour octet à url-to-pdf V1.

Requêtes authentifiées et personnalisées

Paramètre Type Défaut Description
auth object null HTTP Basic Auth pour la page cible : {"username": "...", "password": "..."}.
cookies array null Cookies à injecter avant la navigation. Maximum 50. Chacun a besoin de name, value, et soit domain soit url.
headers object null En-têtes de requête personnalisés. Maximum 20. Noms bloqués : host, content-length, transfer-encoding, connection, upgrade, te, trailer.
Réservé, pas encore en service. proxy_url (Business+), geolocation et action_chain sont acceptés par le schéma de requête mais renvoient 422 aujourd'hui. Ils arriveront dans une version ultérieure ; les envoyer maintenant vous indique exactement quel réglage n'est pas prêt au lieu de l'ignorer silencieusement.

Extraction structurée

Lorsque structured figure dans outputs, la liste extract contrôle quels champs perceive extrait. Ne demandez rien et il revient par défaut à metadata et structured_data.

Valeur extract Champ dans structured Statut
metadata metadata En service
structured_data structured_data (JSON-LD) En service
headings headings En service
tables tables En service
main_content main_content (texte, plafonné à 50 000 caractères) En service
all s'étend à chaque champ en service ci-dessus En service
prices Pas encore — renvoie un avertissement, omis
contacts Pas encore — renvoie un avertissement, omis
technologies Pas encore — renvoie un avertissement, omis

Soyons clairs : prices, contacts et technologies sont des noms réservés. Demandez-en un aujourd'hui et cela ne provoque pas d'erreur — il atterrit dans le tableau warnings et est écarté de structured.

Extraction pilotée par schéma

Envoyez un schema pour extraire des champs spécifiques dans structured.extracted :

{
    "url": "https://example.com/product/widget",
    "outputs": ["markdown", "structured"],
    "schema": {
        "type": "object",
        "properties": {
            "name": {"type": "string"},
            "price": {"type": "number"},
            "in_stock": {"type": "boolean"}
        }
    }
}

Le palier d'extraction LLM (Anthropic Claude Haiku) remplit le schéma, et il ne se déclenche que lorsque toutes ces conditions sont réunies : vous avez envoyé un schema, votre forfait porte le palier LLM (Starter et au-dessus), la page n'a pas été notée comme bloquée, et la passe heuristique a laissé les champs du schéma vides. Lorsqu'il s'exécute, extraction_tier vaut "llm", et tokens et cost_cents rapportent ce que cette extraction a coûté ; sinon extraction_tier vaut "heuristic" et les deux sont à zéro.

Note. L'extraction par schéma est strictement plafonnée pour protéger votre facture : une extraction unique est plafonnée par requête, et la dépense quotidienne par projet est plafonnée selon le forfait. Si un plafond est atteint, perceive renvoie le résultat heuristique avec une note dans warnings plutôt que de dépenser au-delà. Sur un forfait sans le palier LLM, vous n'obtenez que des données structured heuristiques.


Réponse

POST /v2/perceive et GET /v2/perceive/{operation_id} renvoient tous deux le même objet.

Champ Type Description
operation_id string ID opaque (per_...). Utilisez-le avec l'endpoint GET et citez-le au support.
status string queued, processing, completed ou failed.
url string L'URL que vous avez envoyée.
url_final string L'URL après redirections.
content_hash string SHA-256 de la page rendue. Pilote le cache d'une heure.
render_quality number 0.0–1.0. Les scores faibles signalent des défis anti-bot ou des murs de connexion.
cache_hit boolean true lorsque le résultat provient du cache au lieu d'un rendu frais.
outputs object Table de correspondance nom de sortie vers {url, object_key, size_bytes, content_type, expires_in}. Les URL signées expirent en 900 secondes.
structured object Données structurées en ligne, présentes lorsque structured a été demandé.
extraction_tier string heuristic, css ou llm.
tokens object {input, output} tokens LLM utilisés. Zéro sauf si le palier LLM s'est exécuté.
cost_cents number Coût LLM en cents pour cette opération. Zéro sauf si le palier LLM s'est exécuté.
duration_ms integer Temps de rendu de bout en bout.
error string Défini uniquement lorsque status est failed.
warnings string[] Notes non fatales : un dépassement de wait_for, une extraction ignorée, un drapeau de page bloquée.

Récupérer une opération

Les URL signées expirent après 15 minutes. Pour télécharger une sortie plus tard, récupérez à nouveau l'opération — perceive re-signe chaque URL à partir des clés d'objet stockées. Aucun nouveau rendu n'a lieu, donc cela ne consomme pas de quota.

curl https://api.enconvert.com/v2/perceive/per_3f9a2c1b8e7d4a6f90b1c2d3e4f5a6b7 \
  -H "X-API-Key: sk_live_your_private_key"

Un ID d'opération inconnu, ou un qui appartient à un projet différent, renvoie un 404 — l'existence n'est jamais divulguée entre projets.


Perception par lot

POST /v2/perceive/batch perçoit une liste d'URL qui partagent un même bloc options. Chaque URL est rendue par le même pipeline qu'un appel unique et produit sa propre ligne d'opération.

curl -X POST https://api.enconvert.com/v2/perceive/batch \
  -H "X-API-Key: sk_live_your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": [
      "https://example.com/a",
      "https://example.com/b",
      "https://example.com/c"
    ],
    "options": {"outputs": ["markdown"]},
    "output_mode": "manifest"
  }'

Les lots de 10 URL ou moins s'exécutent en ligne et répondent 200 avec chaque résultat renseigné. Les lots plus grands répondent 202 avec un job_id ; les URL sont drainées une à une et vous interrogez les résultats :

curl https://api.enconvert.com/v2/perceive/batch/{job_id} \
  -H "X-API-Key: sk_live_your_private_key"

La réponse de lot rapporte la progression agrégée et porte un résultat perceive complet par URL une fois rendue :

{
    "job_id": "bat_8c1a...",
    "status": "partial",
    "output_mode": "manifest",
    "total": 3,
    "completed": 2,
    "failed": 1,
    "pending": 0,
    "items": [
        {"operation_id": "per_...", "status": "completed", "url": "https://example.com/a"},
        {"operation_id": "per_...", "status": "completed", "url": "https://example.com/b"},
        {"operation_id": "per_...", "status": "failed", "url": "https://example.com/c"}
    ]
}

status vaut queued, processing, completed, failed ou partial (certaines URL ont réussi, d'autres ont échoué). Réglez output_mode sur zip pour regrouper chaque artefact dans un seul ZIP, renvoyé sous le champ zip une fois que le lot est terminé. L'accès aux lots et la taille maximale de lot dépendent du forfait ; voir la page de tarification.


Mise en cache

cache_mode contrôle la façon dont perceive traite son cache de résultats d'une heure, clé par votre projet, l'URL et les options de requête affectant le rendu.

cache_mode Comportement
enabled (défaut) Renvoyer un résultat en cache lorsqu'une requête identique a été rendue au cours de la dernière heure. cache_hit est true, cost_cents est 0.
bypass Ignorer le cache et rendre à neuf.
refresh Rendre à neuf et remplacer l'entrée en cache.

À signaler : un hit de cache compte tout de même comme une opération perceive sur votre quota mensuel. Le quota mesure les opérations, pas les rendus de navigateur — le cache vous fait gagner du temps de rendu, pas du quota.


Exemples de code

curl — Markdown seul

curl -X POST https://api.enconvert.com/v2/perceive \
  -H "X-API-Key: sk_live_your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/blog/post",
    "outputs": ["markdown"]
  }'

curl — Markdown plus données structurées

curl -X POST https://api.enconvert.com/v2/perceive \
  -H "X-API-Key: sk_live_your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/pricing",
    "outputs": ["markdown", "structured"],
    "extract": ["metadata", "structured_data", "tables"]
  }'

curl — Sorties complètes plus PDF

curl -X POST https://api.enconvert.com/v2/perceive \
  -H "X-API-Key: sk_live_your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/report",
    "outputs": ["markdown", "html_cleaned", "screenshot_full_page", "pdf"],
    "pdf_options": {"format": "A4", "print_background": true}
  }'

Python

import requests

response = requests.post(
    "https://api.enconvert.com/v2/perceive",
    headers={"X-API-Key": "sk_live_your_private_key"},
    json={
        "url": "https://example.com/pricing",
        "outputs": ["markdown", "structured"],
        "extract": ["metadata", "tables"],
    },
)
response.raise_for_status()
data = response.json()

# Download the Markdown artifact from its signed URL
markdown_url = data["outputs"]["markdown"]["url"]
markdown_text = requests.get(markdown_url).text

print(data["structured"])
print(markdown_text)

Node.js

const res = await fetch("https://api.enconvert.com/v2/perceive", {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "X-API-Key": "sk_live_your_private_key"
    },
    body: JSON.stringify({
        url: "https://example.com/pricing",
        outputs: ["markdown", "structured"],
        extract: ["metadata", "tables"]
    })
});

const data = await res.json();

// Download the Markdown artifact from its signed URL
const markdownText = await fetch(data.outputs.markdown.url).then(r => r.text());

console.log(data.structured);
console.log(markdownText);

Si vous appelez EnConvert depuis Claude, Cursor ou un autre client MCP, la même capacité est exposée sous forme d'outil perceive_url — voir la page du serveur MCP.


Restrictions par forfait

Les opérations perceive V2 sont un compteur séparé des conversions V1. Les forfaits V1 n'incluent aucun quota perceive ; il vous faut un forfait incluant la V2.

Forfait Opérations perceive / mois Extraction par schéma (palier LLM)
Free 50 Non inclus
Starter 850 Claude Haiku
Pro 8,500 Claude Haiku
Business 42,500 Claude Haiku
Enterprise Illimité Inclus

L'accès aux lots et les limites de taille par lot, la prise en charge de basic-auth/cookie/header, et proxy_url (Business+, quand il sortira) dépendent du forfait. Les chiffres actuels se trouvent sur la page de tarification.


Réponses d'erreur

Statut Condition
400 Bad Request L'URL n'est pas http(s), porte des identifiants intégrés, ou se résout vers une adresse privée, loopback ou link-local (protection SSRF).
400 Bad Request auth invalide (username/password manquant), cookies (pas un tableau, plus de 50 entrées, champs manquants), ou headers (pas un objet, plus de 20 entrées, nom bloqué).
401 Unauthorized Clé API / jeton JWT manquant ou invalide.
402 Payment Required Perceive ne fait pas partie de votre forfait actuel, ou votre quota perceive mensuel est épuisé.
403 Forbidden /v2/perceive ne figure pas dans les endpoints autorisés de la clé API.
403 Forbidden Lot non disponible sur votre forfait, ou taille de lot dépassant la limite de votre forfait.
403 Forbidden respect_robots=true et le robots.txt du site interdit l'URL.
404 Not Found operation_id ou job_id inconnu, ou appartenant à un autre projet.
422 Unprocessable Entity La validation de la requête a échoué (mauvais enum dans outputs/extract, wait_timeout_ms hors plage, viewport hors limites).
422 Unprocessable Entity proxy_url, geolocation ou action_chain a été envoyé — réservé pour une version ultérieure.
500 Internal Server Error Le rendu a échoué. Le message inclut l'operation_id à citer au support.

La référence complète des codes de statut se trouve dans le guide des codes d'erreur.


Limites

Limite Valeur
Longueur d'URL 2 048 caractères
wait_timeout_ms 0–60 000 ms
Longueur de js_code 20 000 caractères
Largeur de viewport 320–3 840 px
Hauteur de viewport 240–2 160 px
Cookies par requête 50
En-têtes personnalisés par requête 20
Extraction main_content 50 000 caractères
URL par requête de lot 1 000 (plafond du schéma ; la limite de lot de votre forfait est plus basse)
Seuil de lot en ligne 10 URL (les lots plus grands s'exécutent de manière asynchrone)
TTL du cache de résultats 1 heure
Expiration des URL signées 15 minutes
Opérations perceive mensuelles Dépendant du forfait (Free : 50)