API de recherche web pour agents LLM#
POST /v2/lookup est une API de recherche web conçue pour les agents LLM :
elle exécute une recherche dans l'une des six catégories et renvoie une liste
de résultats plate, neutre vis-à-vis du fournisseur. Définissez perceive_top
et elle effectue en plus le rendu des N premières URL de résultat dans un vrai
navigateur, de sorte qu'un agent obtient la page de résultats du moteur de
recherche (SERP) et le contenu de la page derrière chaque résultat en un seul
aller-retour. En tant qu'alternative à une API SERP, elle condense la pile
habituelle (interroger une API de recherche, analyser ses résultats, puis
déployer un scraper en éventail) en un seul appel. Ce sera la réponse
d'EnConvert à /search de Firecrawl.
Serper est le fournisseur de recherche qui l'alimente. La requête et la réponse
parlent un vocabulaire de recherche neutre (category, country, locale,
time_filter), de sorte qu'un futur changement de fournisseur ne modifie pas le
contrat sur lequel vous codez.
Voici le plus petit appel utile. Envoyez une requête, récupérez les meilleurs résultats web :
curl -X POST https://api.enconvert.com/v2/lookup \
-H "X-API-Key: sk_your_private_key" \
-H "Content-Type: application/json" \
-d '{
"query": "headless chrome pdf rendering"
}'
La réponse est une liste de résultats plate plus la provenance pour la corrélation côté support :
{
"lookup_id": 81423,
"query": "headless chrome pdf rendering",
"category": "web",
"total": 10,
"results": [
{
"title": "Generate PDFs with headless Chrome",
"url": "https://example.com/guide/chrome-pdf",
"snippet": "Render a page and print it to PDF...",
"position": 1
},
{
"title": "Print to PDF with the Chrome DevTools Protocol",
"url": "https://example.dev/cdp/print-to-pdf",
"snippet": "Page.printToPDF returns base64 PDF data...",
"position": 2
}
],
"perceive_top": 0,
"perceive_operation_ids": [],
"credits": 1,
"cost_cents": 0.06,
"warnings": []
}
Points de terminaison#
| Méthode | Chemin | Objectif |
|---|---|---|
POST |
/v2/lookup |
Exécuter une recherche et, en option, auto-percevoir les N premières URL de résultat. |
/v2/lookup est un point de terminaison à appel unique, sans chemin distinct de
statut ou de récupération. Lorsque vous auto-percevez, chaque page rendue devient
une opération perceive de premier ordre dotée de son propre
operation_id, que vous pouvez récupérer ultérieurement via
GET /v2/perceive/{operation_id}.
Content-Type : application/json.
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 qu'utilisent les exemples ci-dessous.
X-API-Key: sk_your_private_key
Les clés publiques avec un jeton bearer JWT fonctionnent aussi, selon le même flux
que tout autre point de terminaison : générez un jeton avec votre clé pk_, puis envoyez-le
sous la forme Authorization: Bearer <token>. Le flux complet, y compris le
verrouillage de domaine et le rafraîchissement du jeton, figure dans
le guide d'authentification.
Chaque clé API porte une liste blanche de points de terminaison autorisés. Si /v2/lookup
n'est pas sur la liste de la clé, la requête est rejetée avec 403.
Comment fonctionne lookup#
Une requête exécute une recherche fournisseur puis, seulement si vous le demandez, effectue le rendu des meilleurs résultats.
- Contrôle de quota. Avant toute facturation, le gestionnaire vérifie le
quota mensuel unifié d'ops de votre plan. Un plan désactivé ou un quota
épuisé est rejeté avec
402, de sorte que rien n'est facturé en cas de rejet. - Recherche. La requête part vers le fournisseur de recherche (Serper)
sur le point de terminaison correspondant à votre
category. Récence, pays, locale, localisation, taille de page et autocorrection sont mappés sur les paramètres du fournisseur. - Normalisation. Chaque résultat du fournisseur est aplati en un
LookupResultneutre qui portetitle,url,snippetetposition. Les extras propres à la catégorie atterrissent dansextra, de sorte que le contrat n'ajoute jamais une colonne par particularité de fournisseur. - Facturation et audit. La recherche a réussi, donc une op est
facturée et une ligne d'audit
ch_lookup_queriesest écrite. L'identifiant de la ligne revient souslookup_idpour la corrélation côté support. - Auto-perception (optionnelle). Si
perceive_top > 0, les N premières URL de résultat sont rendues une par une via le singleton headless Chrome partagé, le même pipeline que le point de terminaison perceive. Chaque rendu est une opération/v2/perceivecomplète : sa propre op facturée sur le quota partagé, sa propre ligne d'opération, son propreoperation_id. Par défaut, l'auto-perception ne demande que du Markdown, sans capture d'écran, PDF ni extraction LLM ; envoyez un objetenrichpour élargir les sorties, les exécuter en parallèle, ou ajouter une extraction par schéma et une réponse synthétisée.
L'auto-perception est au mieux. Une URL isolée qui échoue, ou le quota d'ops qui s'épuise en cours de route, se dégrade en avertissement et renvoie tout de même les résultats de recherche. La SERP est ici le produit principal, donc un problème de perception ne fait jamais couler l'appel entier.
Paramètres de requête#
Requête et catégorie#
| Paramètre | Type | Valeur par défaut | Description |
|---|---|---|---|
query |
string |
aucune | La requête de recherche. 1–512 caractères, dépouillée des espaces de début et de fin. Une requête vide après ce nettoyage est rejetée avec 422. Obligatoire. |
category |
string |
"web" |
L'une de web, news, images, scholar, patents, maps. |
Ciblage et récence#
| Paramètre | Type | Valeur par défaut | Description |
|---|---|---|---|
country |
string |
null |
Code pays Google gl, par ex. us, in. 8 caractères maximum. |
locale |
string |
null |
Langue d'interface Google hl, par ex. en. 16 caractères maximum. |
time_filter |
string |
null |
Restreindre aux résultats de la période passée : hour, day, week, month, ou year. |
location |
string |
null |
Chaîne de localisation en texte libre, par ex. "Austin, Texas". 128 caractères maximum. |
autocorrect |
boolean |
true |
Indique si le fournisseur peut autocorriger l'orthographe de la requête. |
Pagination#
| Paramètre | Type | Valeur par défaut | Description |
|---|---|---|---|
num_results |
integer |
10 |
Résultats par page. 1–100. |
page |
integer |
1 |
Numéro de page. 1–10. |
Auto-perception#
| Paramètre | Type | Valeur par défaut | Description |
|---|---|---|---|
perceive_top |
integer |
0 |
Auto-percevoir les N premières URL de résultat qui ont un lien navigable. 0–10. Chacune est un rendu navigateur complet qui facture une op sur votre quota mensuel, ce qui explique le plafond de 10. Pour des ensembles plus grands, prenez les champs url et appelez le point de terminaison de perception par lot. 0 désactive l'auto-perception. |
Enrichissement (enrich)#
Un objet enrich optionnel ajuste la manière dont les N premiers résultats
(perceive_top) sont lus, et peut synthétiser une réponse unique et fondée à
travers eux. Lorsque enrich est omis, perceive_top conserve son
comportement par défaut (Markdown uniquement, un résultat à la fois).
| Paramètre | Type | Valeur par défaut | Description |
|---|---|---|---|
enrich.outputs |
string[] |
["markdown"] |
Les sorties perceive à produire par résultat enrichi, par exemple markdown, html_cleaned, links, screenshot, structured. Voir les sorties de perceive. |
enrich.concurrency |
integer |
3 |
Combien d'URL de résultat enrichir en parallèle. 1–5. Les rendus Markdown/HTML se parallélisent ; les rendus capture d'écran/PDF se sérialisent sur le navigateur partagé. |
enrich.schema |
object |
null |
Exécute une extraction structurée pilotée par schéma sur chaque résultat enrichi. Les données extraites apparaissent sous le perceive.structured de chaque résultat. Objet JSON-Schema ou une correspondance plate {field: description}. |
enrich.synthesize_answer |
boolean |
false |
Synthétise une réponse citée et fondée à la requête à travers les résultats enrichis, renvoyée sous answer (avec answer_sources). Utilise le contenu de page perçu lorsqu'il est disponible, sinon les extraits de résultat. |
enrich.answer_prompt |
string |
null |
Une question à laquelle répondre au lieu de la requête brute. Utilisée uniquement lorsque synthesize_answer vaut true. 1,000 caractères max. |
enrich.schema et enrich.synthesize_answer utilisent le palier d'extraction
LLM. Si cette étape d'extraction ne peut pas s'exécuter, ils se dégradent en
avertissement et le reste de la réponse n'est pas affecté.
{
"query": "best open-source vector databases",
"perceive_top": 3,
"enrich": {
"outputs": ["markdown"],
"concurrency": 3,
"synthesize_answer": true
}
}
Catégories#
Chaque catégorie atteint un point de terminaison fournisseur différent et fait apparaître une
forme de résultat légèrement différente. Les champs universels (title, url,
snippet, position) sont toujours typés ; les champs propres à la catégorie
atterrissent dans extra.
category |
Ce qu'elle recherche | Champs notables renseignés |
|---|---|---|
web |
Résultats web généraux | title, url, snippet, date, position |
news |
Articles d'actualité | ajoute source, image_url |
images |
Résultats d'images | image_url, thumbnail_url, source (souvent pas de snippet) |
scholar |
Résultats académiques | même forme que web ; nombre de citations dans extra |
patents |
Résultats de brevets | même forme que web ; champs de brevet dans extra |
maps |
Lieux locaux | url est le site web du lieu ; snippet porte l'adresse ; note, coordonnées dans extra |
À signaler : pour images et maps, url peut être null pour un résultat donné
lorsque le fournisseur ne renvoie aucun lien navigable. L'auto-perception ignore
tout résultat dont l'url est null, de sorte qu'un perceive_top de 5 sur une
SERP comptant deux résultats sans URL perçoit au plus trois pages.
Réponse#
Le point de terminaison omet les champs null, de sorte qu'un résultat web minimal ne porte
que les champs réellement renseignés.
| Champ | Type | Description |
|---|---|---|
lookup_id |
integer |
L'identifiant de la ligne d'audit ch_lookup_queries. Citez-le au support. null si l'écriture d'audit a échoué, sachant que les résultats restent valides. |
query |
string |
La requête (nettoyée) que vous avez envoyée. |
category |
string |
La catégorie recherchée. |
country |
string |
Écho du country que vous avez envoyé, le cas échéant. |
locale |
string |
Écho du locale que vous avez envoyé, le cas échéant. |
time_filter |
string |
Écho du time_filter que vous avez envoyé, le cas échéant. |
total |
integer |
Nombre de résultats renvoyés. |
results |
LookupResult[] |
La liste de résultats. Voir ci-dessous. |
perceive_top |
integer |
Combien de résultats ont réellement été perçus : au plus la valeur que vous avez demandée, et moins si le quota d'ops s'est épuisé ou si des URL ont échoué. |
perceive_operation_ids |
string[] |
Les identifiants d'opération per_... des résultats perçus, dans l'ordre. |
answer_box |
object |
La boîte de réponse du fournisseur, lorsqu'elle est présente. |
knowledge_graph |
object |
Le panneau knowledge graph du fournisseur, lorsqu'il est présent. |
answer |
string |
La réponse citée synthétisée à travers les résultats enrichis. Présente uniquement lorsque enrich.synthesize_answer vaut true et qu'elle a réussi. |
answer_sources |
string[] |
Les URL utilisées comme fondement pour answer, dans l'ordre de citation. |
credits |
integer |
Crédits fournisseur consommés par cette requête. |
cost_cents |
number |
Coût monétaire de la recherche en cents. Un forfait de 0.06 par requête aujourd'hui. |
warnings |
string[] |
Notes non fatales : un résultat sans URL ignoré, un échec d'auto-perception, le quota d'ops épuisé en cours de boucle. |
LookupResult#
| Champ | Type | Description |
|---|---|---|
title |
string |
Titre du résultat. |
url |
string |
Lien canonique de la page, celui que vous percevriez. null pour les résultats sans URL navigable. |
snippet |
string |
Extrait du résultat. Pour maps, il porte l'adresse. |
position |
integer |
La position du résultat sur la SERP. |
source |
string |
Source/éditeur, pour news et images. |
date |
string |
Date de publication, lorsque le fournisseur en signale une. |
image_url |
string |
URL de l'image, pour images et news. |
thumbnail_url |
string |
URL de la miniature, pour images. |
extra |
object |
Champs propres à la catégorie absents de l'ensemble neutre : notes, coordonnées, nombre de citations, et ainsi de suite. |
perceive |
PerceiveResponse |
Le résultat de perception complet en ligne pour cette URL, présent uniquement pour les N premiers lorsque perceive_top > 0 et que le rendu a réussi. Même forme d'objet que le point de terminaison perceive. |
Lire les résultats d'auto-perception#
Lorsque vous envoyez perceive_top, parcourez les résultats et vérifiez la présence
du champ perceive. Il n'est présent que sur les résultats qui ont été perçus, et
seulement lorsque leur rendu a réussi. Le Markdown de chacun se trouve derrière une
URL de téléchargement pré-signée (un lien signé à courte durée de vie vers le
stockage objet) sous perceive.outputs.markdown.url, comme pour un appel perceive
direct.
{
"lookup_id": 81910,
"query": "react server components data fetching",
"category": "web",
"total": 10,
"results": [
{
"title": "Data fetching with RSC",
"url": "https://example.com/rsc/data",
"snippet": "Fetch on the server, stream to the client...",
"position": 1,
"perceive": {
"operation_id": "per_3f9a2c1b8e7d4a6f90b1c2d3e4f5a6b7",
"status": "completed",
"url": "https://example.com/rsc/data",
"outputs": {
"markdown": {
"url": "https://spaces.example.com/...signed...",
"size_bytes": 7421,
"content_type": "text/markdown; charset=utf-8",
"expires_in": 900
}
},
"cost_cents": 0.0,
"duration_ms": 5840
}
}
],
"perceive_top": 1,
"perceive_operation_ids": [
"per_3f9a2c1b8e7d4a6f90b1c2d3e4f5a6b7"
],
"credits": 1,
"cost_cents": 0.06,
"warnings": []
}
Ces URL signées expirent au bout de 15 minutes. Pour télécharger une page perçue
plus tard, récupérez à nouveau son opération avec GET /v2/perceive/{operation_id}
en utilisant l'identifiant tiré de perceive_operation_ids. Cela re-signe les URL
et n'effectue pas de nouveau rendu, donc cela ne coûte aucune op. Consultez
la section de récupération de perceive
pour les détails.
Exemples de code#
curl : recherche web#
curl -X POST https://api.enconvert.com/v2/lookup \
-H "X-API-Key: sk_your_private_key" \
-H "Content-Type: application/json" \
-d '{
"query": "open source vector database",
"num_results": 20
}'
curl : actualités récentes, localisées#
curl -X POST https://api.enconvert.com/v2/lookup \
-H "X-API-Key: sk_your_private_key" \
-H "Content-Type: application/json" \
-d '{
"query": "rbi monetary policy",
"category": "news",
"country": "in",
"locale": "en",
"time_filter": "week"
}'
curl : recherche plus auto-perception des 3 premiers#
curl -X POST https://api.enconvert.com/v2/lookup \
-H "X-API-Key: sk_your_private_key" \
-H "Content-Type: application/json" \
-d '{
"query": "langchain retrieval augmented generation",
"perceive_top": 3
}'
Python#
import requests
response = requests.post(
"https://api.enconvert.com/v2/lookup",
headers={"X-API-Key": "sk_your_private_key"},
json={
"query": "langchain retrieval augmented generation",
"perceive_top": 3,
},
)
response.raise_for_status()
data = response.json()
# Pull the Markdown of every result that was perceived
for result in data["results"]:
perceived = result.get("perceive")
if not perceived:
continue
markdown_url = perceived["outputs"]["markdown"]["url"]
page_text = requests.get(markdown_url).text
print(result["url"], len(page_text), "chars")
for note in data["warnings"]:
print("warning:", note)
Node.js#
const res = await fetch("https://api.enconvert.com/v2/lookup", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": "sk_your_private_key"
},
body: JSON.stringify({
query: "langchain retrieval augmented generation",
perceive_top: 3
})
});
const data = await res.json();
// Pull the Markdown of every result that was perceived
for (const result of data.results) {
if (!result.perceive) continue;
const markdownUrl = result.perceive.outputs.markdown.url;
const pageText = await fetch(markdownUrl).then(r => r.text());
console.log(result.url, pageText.length, "chars");
}
for (const note of data.warnings) {
console.log("warning:", note);
}
Si vous appelez EnConvert depuis Claude, Cursor, ou un autre client Model Context Protocol (MCP), la capacité de recherche y sera également exposée comme un outil. Voir la page du serveur MCP.
Réponses d'erreur#
Le gestionnaire ne renvoie jamais le texte brut du fournisseur au client. Les détails du fournisseur et de la SSRF restent dans les journaux du serveur, et le client reçoit un message propre et générique.
| Statut | Condition |
|---|---|
401 Unauthorized |
Clé API / jeton JWT manquant ou invalide. |
402 Payment Required |
Lookup ne figure pas dans votre plan actuel, ou votre quota mensuel d'ops est épuisé. |
403 Forbidden |
/v2/lookup ne figure pas dans les points de terminaison autorisés de la clé API. |
422 Unprocessable Entity |
La validation de la requête a échoué : query vide/trop longue, category ou time_filter inconnu, num_results ou page hors plage, perceive_top supérieur à 10. |
502 Bad Gateway |
Le fournisseur de recherche a renvoyé une réponse d'erreur ou une faute de transport non réessayable (SearchUpstreamError). Réessayer peut aider. |
503 Service Unavailable |
Le fournisseur de recherche est mal configuré côté serveur (une clé manquante de notre côté, SearchConfigError), ou il est temporairement indisponible : le disjoncteur est ouvert, ou le fournisseur nous a limités en débit (SearchUnavailableError). Réessayez plus tard. |
500 Internal Server Error |
Un échec inattendu. Le message est générique ; citez l'heure de l'appel au support. |
Une auto-perception qui échoue ne lève jamais d'erreur de son propre fait. Elle
atterrit dans warnings et l'appel répond tout de même 200. La référence complète
des codes de statut figure dans le guide des codes d'erreur.
Limites#
| Limite | Valeur |
|---|---|
Longueur de query |
1–512 caractères (nettoyée) |
Longueur de country |
8 caractères |
Longueur de locale |
16 caractères |
Longueur de location |
128 caractères |
num_results |
1–100 |
page |
1–10 |
perceive_top |
0–10 |
| Ops par appel | 1 pour la requête, plus 1 par résultat auto-perçu |
| Sorties d'auto-perception | Markdown par défaut ; élargies avec enrich.outputs |
| Concurrence d'auto-perception | Séquentielle par défaut ; 1–5 avec enrich.concurrency |
| Coût par recherche | 0.06 cent forfaitaire |
| Expiration de l'URL signée d'une page perçue | 15 minutes |
Questions fréquentes#
Comment lancer une recherche web et récupérer le contenu de page en un seul appel API REST ?#
Envoyez POST /v2/lookup avec une query et définissez perceive_top (0–10). Les URL des N premiers résultats sont rendues dans un vrai navigateur, et chaque résultat perçu porte un objet perceive en ligne dont le Markdown se trouve derrière une URL pré-signée à perceive.outputs.markdown.url.
/v2/lookup est-elle une alternative à une API SERP sans dépendance à un fournisseur ?#
Oui. Serper est le fournisseur de recherche qui l'alimente, mais la requête et la réponse parlent un vocabulaire de recherche neutre (category, country, locale, time_filter), de sorte qu'un futur changement de fournisseur ne modifie pas le contrat sur lequel vous codez.
Quelles catégories de recherche l'API lookup prend-elle en charge ?#
Six : web (par défaut), news, images, scholar, patents et maps. Les champs universels (title, url, snippet, position) sont toujours typés, et les extras propres à la catégorie atterrissent dans extra.
Pourquoi lookup a-t-il perçu moins de pages que ma valeur perceive_top ?#
L'auto-perception ignore les résultats dont url est null, s'arrête si le quota mensuel d'ops s'épuise en cours de boucle, et dégrade un rendu échoué en simple avertissement. Le perceive_top de la réponse indique combien de pages ont réellement été perçues, et warnings explique les écarts.