API di Ricerca Web per Agenti LLM#
POST /v2/lookup è un'API di ricerca web pensata per agenti LLM: esegue
una ricerca in una di sei categorie e restituisce un elenco di risultati
piatto e neutrale rispetto al provider. Imposta perceive_top e
l'endpoint renderizza anche gli URL dei primi N risultati in un browser
reale, così un agente ottiene la pagina dei risultati del motore di
ricerca (SERP) e il contenuto della pagina dietro ogni risultato in
un'unica chiamata. Come alternativa alle SERP API, comprime lo stack
abituale (interrogare un'API di ricerca, analizzarne i risultati, poi
lanciare uno scraper) in un'unica chiamata. Sarà la risposta di EnConvert
a Firecrawl /search.
È Serper a fornire il backend di ricerca. La richiesta e la risposta
parlano un vocabolario di ricerca neutrale (category, country,
locale, time_filter), così un futuro cambio di provider non modifica
il contratto su cui scrivi il codice.
Ecco la chiamata minima utile. Invia una query e ricevi i migliori risultati 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 risposta è un elenco di risultati piatto più la provenienza per la correlazione con il supporto:
{
"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": []
}
Endpoint#
| Metodo | Percorso | Scopo |
|---|---|---|
POST |
/v2/lookup |
Esegue una ricerca e, opzionalmente, applica l'auto-perceive ai primi N URL dei risultati. |
/v2/lookup è un endpoint a chiamata singola: non esiste un percorso
separato di stato o di recupero. Quando esegui l'auto-perceive, ogni
pagina renderizzata diventa un'operazione perceive
a pieno titolo con un proprio operation_id, che puoi recuperare in
seguito tramite GET /v2/perceive/{operation_id}.
Content-Type: application/json.
Autenticazione#
Autenticati con una chiave privata nell'header X-API-Key per le chiamate
server-to-server. Questo è il percorso usato negli esempi seguenti.
X-API-Key: sk_your_private_key
Funzionano anche le chiavi pubbliche con un token bearer JWT, usando lo
stesso flusso di ogni altro endpoint: genera un token con la tua chiave
pk_, poi invialo come Authorization: Bearer <token>. Il flusso
completo, incluso il domain locking e il refresh del token, si trova
nella guida all'autenticazione.
Ogni chiave API porta con sé un'allowlist di endpoint consentiti. Se /v2/lookup
non è nella lista della chiave, la richiesta viene rifiutata con 403.
Come funziona lookup#
Una richiesta esegue una ricerca sul provider e poi, solo se lo richiedi, renderizza i primi risultati.
- Controllo quota. Prima che venga addebitato qualsiasi costo,
l'handler controlla la quota mensile unificata di ops del tuo piano.
Se il piano è disabilitato o la quota è esaurita, la richiesta
viene rifiutata con
402e non viene addebitato nulla. - Ricerca. La query viene inviata al provider di ricerca (Serper)
sull'endpoint corrispondente alla tua
category. Recency, country, locale, location, dimensione della pagina e autocorrect vengono mappati sui parametri del provider. - Normalizzazione. Ogni risultato del provider viene appiattito in
un
LookupResultneutrale che portatitle,url,snippeteposition. Gli extra specifici della categoria finiscono inextra, così il contratto non cresce di una colonna per ogni stranezza del provider. - Addebito e audit. La ricerca è riuscita, quindi viene addebitata
una op e viene scritta una riga di audit
ch_lookup_queries. L'id della riga torna comelookup_idper la correlazione con il supporto. - Auto-perceive (opzionale). Se
perceive_top > 0, gli URL dei primi N risultati vengono renderizzati uno alla volta tramite il singleton condiviso di Chrome headless, la stessa pipeline dell'endpoint perceive. Ogni render è un'operazione/v2/perceivea pieno titolo: propria op addebitata sulla quota condivisa, propria riga di operazione, propriooperation_id. Per impostazione predefinita l'auto-perceive richiede solo Markdown, senza screenshot, PDF o estrazione LLM; invia un oggettoenrichper ampliare gli output, eseguirli in parallelo, oppure aggiungere l'estrazione guidata da schema e una risposta sintetizzata.
Auto-perceive è best-effort. Un singolo URL che fallisce, o l'esaurimento della quota di ops a metà del processo, degrada a un warning e restituisce comunque i risultati di ricerca. Qui la SERP è il prodotto primario, quindi un problema di auto-perceive non affonda mai l'intera chiamata.
Parametri della richiesta#
Query e categoria#
| Parametro | Tipo | Predefinito | Descrizione |
|---|---|---|---|
query |
string |
nessuno | La query di ricerca. 1–512 caratteri, dopo la rimozione degli spazi bianchi iniziali/finali. Una query vuota dopo il trimming viene rifiutata con 422. Obbligatorio. |
category |
string |
"web" |
Una tra web, news, images, scholar, patents, maps. |
Targeting e recency#
| Parametro | Tipo | Predefinito | Descrizione |
|---|---|---|---|
country |
string |
null |
Codice paese Google gl, ad es. us, in. Massimo 8 caratteri. |
locale |
string |
null |
Lingua dell'interfaccia Google hl, ad es. en. Massimo 16 caratteri. |
time_filter |
string |
null |
Limita ai risultati del periodo passato: hour, day, week, month o year. |
location |
string |
null |
Stringa di località in testo libero, ad es. "Austin, Texas". Massimo 128 caratteri. |
autocorrect |
boolean |
true |
Se il provider può correggere automaticamente l'ortografia della query. |
Paginazione#
| Parametro | Tipo | Predefinito | Descrizione |
|---|---|---|---|
num_results |
integer |
10 |
Risultati per pagina. 1–100. |
page |
integer |
1 |
Numero di pagina. 1–10. |
Auto-perceive#
| Parametro | Tipo | Predefinito | Descrizione |
|---|---|---|---|
perceive_top |
integer |
0 |
Applica l'auto-perceive ai primi N URL dei risultati che hanno un link navigabile. 0–10. Ognuno è un render completo del browser che addebita una op dalla tua quota mensile, ed è per questo che il limite è 10. Per insiemi più grandi, prendi i campi url e chiama l'endpoint perceive batch. 0 disabilita l'auto-perceive. |
Arricchimento (enrich)#
Un oggetto enrich opzionale regola come vengono letti i primi N
risultati (perceive_top), e può sintetizzare un'unica risposta fondata
sulle fonti attraverso di essi. Quando enrich viene omesso,
perceive_top mantiene il suo comportamento predefinito (solo Markdown,
un risultato alla volta).
| Parametro | Tipo | Predefinito | Descrizione |
|---|---|---|---|
enrich.outputs |
string[] |
["markdown"] |
Quali output perceive produrre per ogni risultato arricchito, ad esempio markdown, html_cleaned, links, screenshot, structured. Vedi gli output perceive. |
enrich.concurrency |
integer |
3 |
Quanti URL dei risultati arricchire in parallelo. 1–5. I render Markdown/HTML si parallelizzano; i render screenshot/PDF vengono serializzati sul browser condiviso. |
enrich.schema |
object |
null |
Esegue l'estrazione strutturata guidata da schema su ogni risultato arricchito. I dati estratti compaiono sotto perceive.structured di ciascun risultato. Oggetto JSON-Schema o una mappa piatta {field: description}. |
enrich.synthesize_answer |
boolean |
false |
Sintetizza un'unica risposta citata e fondata alla query attraverso i risultati arricchiti, restituita come answer (con answer_sources). Usa il contenuto della pagina sottoposta a perceive quando disponibile, altrimenti gli snippet dei risultati. |
enrich.answer_prompt |
string |
null |
Una domanda a cui rispondere invece della query grezza. Usato solo quando synthesize_answer è true. Massimo 1,000 caratteri. |
enrich.schema e enrich.synthesize_answer usano il livello di
estrazione LLM. Se quel passaggio di estrazione non può essere eseguito,
degradano a un warning e il resto della risposta non viene toccato.
{
"query": "best open-source vector databases",
"perceive_top": 3,
"enrich": {
"outputs": ["markdown"],
"concurrency": 3,
"synthesize_answer": true
}
}
Categorie#
Ogni categoria interroga un endpoint diverso del provider e restituisce
una forma di risultato leggermente diversa. I campi universali (title,
url, snippet, position) sono sempre tipizzati; i campi specifici
della categoria finiscono in extra.
category |
Cosa cerca | Campi rilevanti popolati |
|---|---|---|
web |
Risultati web generali | title, url, snippet, date, position |
news |
Articoli di notizie | aggiunge source, image_url |
images |
Risultati immagine | image_url, thumbnail_url, source (spesso senza snippet) |
scholar |
Risultati accademici | stessa forma di web; conteggi delle citazioni in extra |
patents |
Risultati brevetti | stessa forma di web; campi brevetto in extra |
maps |
Luoghi locali | url è il sito web del luogo; snippet riporta l'indirizzo; rating, coordinate in extra |
Da notare: per images e maps, url può essere null per un dato
risultato quando il provider non restituisce un link navigabile.
L'auto-perceive salta qualsiasi risultato il cui url è null, quindi un
perceive_top di 5 su una SERP con due risultati privi di URL applica
l'auto-perceive ad al massimo tre pagine.
Risposta#
L'endpoint omette i campi null, quindi un risultato web minimo porta
solo i campi effettivamente popolati.
| Campo | Tipo | Descrizione |
|---|---|---|
lookup_id |
integer |
L'id della riga di audit ch_lookup_queries. Riportalo al supporto. null se la scrittura dell'audit è fallita, anche se i risultati restano comunque validi. |
query |
string |
La query (dopo il trimming) che hai inviato. |
category |
string |
La categoria cercata. |
country |
string |
Eco del country che hai inviato, se presente. |
locale |
string |
Eco del locale che hai inviato, se presente. |
time_filter |
string |
Eco del time_filter che hai inviato, se presente. |
total |
integer |
Numero di risultati restituiti. |
results |
LookupResult[] |
L'elenco dei risultati. Vedi sotto. |
perceive_top |
integer |
Quanti risultati sono stati effettivamente sottoposti a perceive: al massimo il valore richiesto, e meno se la quota di ops è esaurita o gli URL sono falliti. |
perceive_operation_ids |
string[] |
Gli id operazione per_... dei risultati sottoposti a perceive, in ordine. |
answer_box |
object |
L'answer box del provider, quando presente. |
knowledge_graph |
object |
Il pannello knowledge graph del provider, quando presente. |
answer |
string |
La risposta citata sintetizzata attraverso i risultati arricchiti. Presente solo quando enrich.synthesize_answer è true ed è riuscita. |
answer_sources |
string[] |
Gli URL usati come fondamento per answer, in ordine di citazione. |
credits |
integer |
Crediti del provider consumati da questa query. |
cost_cents |
number |
Costo monetario della ricerca in centesimi. Oggi un valore fisso di 0.06 per query. |
warnings |
string[] |
Note non fatali: un risultato privo di URL saltato, un fallimento dell'auto-perceive, l'esaurimento della quota di ops a metà ciclo. |
LookupResult#
| Campo | Tipo | Descrizione |
|---|---|---|
title |
string |
Titolo del risultato. |
url |
string |
Link canonico della pagina, ciò a cui applicheresti perceive. null per i risultati senza URL navigabile. |
snippet |
string |
Snippet del risultato. Per maps, riporta l'indirizzo. |
position |
integer |
La posizione del risultato sulla SERP. |
source |
string |
Fonte/editore, per news e images. |
date |
string |
Data di pubblicazione, quando il provider la riporta. |
image_url |
string |
URL immagine, per images e news. |
thumbnail_url |
string |
URL miniatura, per images. |
extra |
object |
Campi specifici della categoria non presenti nel set neutrale: rating, coordinate, conteggi delle citazioni, e così via. |
perceive |
PerceiveResponse |
Il risultato perceive inline completo per questo URL, presente solo per i primi N quando perceive_top > 0 e il render è riuscito. Stessa forma di oggetto dell'endpoint perceive. |
Lettura dei risultati auto-perceive#
Quando invii perceive_top, scorri i risultati e controlla il campo
perceive. È presente solo nei risultati sottoposti a perceive, e solo
quando il loro render è riuscito. Il Markdown di ciascuno si trova dietro
un URL di download pre-firmato (un link firmato e di breve durata verso
l'object storage) sotto perceive.outputs.markdown.url, come per una
chiamata perceive diretta.
{
"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": []
}
Quegli URL firmati scadono dopo 15 minuti. Per scaricare in seguito una
pagina sottoposta a perceive, recupera di nuovo la sua operazione con
GET /v2/perceive/{operation_id} usando l'id da perceive_operation_ids.
Questo rifirma gli URL e non ri-renderizza, quindi non costa ops. Per
i dettagli vedi
la sezione recupero perceive.
Esempi di codice#
curl: ricerca 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: notizie recenti, localizzate#
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: ricerca più auto-perceive dei primi 3#
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);
}
Se chiami EnConvert da Claude, Cursor o un altro client Model Context Protocol (MCP), la capacità di ricerca sarà esposta come tool anche lì. Vedi la pagina del server MCP.
Risposte di errore#
L'handler non restituisce mai al client il testo grezzo del provider. I dettagli su provider e SSRF restano nei log del server, e il client riceve un messaggio pulito e generico.
| Status | Condizione |
|---|---|
401 Unauthorized |
Chiave API / token JWT mancante o non valido. |
402 Payment Required |
Lookup non è incluso nel tuo piano attuale, oppure la tua quota mensile di ops è esaurita. |
403 Forbidden |
/v2/lookup non è tra gli endpoint consentiti della chiave API. |
422 Unprocessable Entity |
Validazione della richiesta fallita: query vuota/troppo lunga, category o time_filter sconosciuti, num_results o page fuori intervallo, perceive_top superiore a 10. |
502 Bad Gateway |
Il provider di ricerca ha restituito una risposta di errore o un errore di trasporto non ritentabile (SearchUpstreamError). Riprovare potrebbe aiutare. |
503 Service Unavailable |
Il provider di ricerca è configurato in modo errato lato server (una chiave mancante dalla nostra parte, SearchConfigError), oppure è temporaneamente non disponibile: il circuit breaker è aperto, o il provider ci ha applicato un rate limit (SearchUnavailableError). Riprova più tardi. |
500 Internal Server Error |
Un errore imprevisto. Il messaggio è generico; riporta al supporto l'orario della chiamata. |
Un auto-perceive che fallisce non genera mai un proprio errore. Finisce
in warnings e la chiamata risponde comunque 200. Il riferimento
completo dei codici di stato si trova nella
guida ai codici di errore.
Limiti#
| Limite | Valore |
|---|---|
Lunghezza query |
1–512 caratteri (dopo trimming) |
Lunghezza country |
8 caratteri |
Lunghezza locale |
16 caratteri |
Lunghezza location |
128 caratteri |
num_results |
1–100 |
page |
1–10 |
perceive_top |
0–10 |
| Ops per chiamata | 1 per la query, più 1 per ogni risultato auto-percepito |
| Output auto-perceive | Markdown per impostazione predefinita; ampliabili con enrich.outputs |
| Concorrenza auto-perceive | Sequenziale per impostazione predefinita; 1–5 con enrich.concurrency |
| Costo per ricerca | 0.06 centesimi fisso |
| Scadenza URL firmato pagina perceive | 15 minuti |
Domande frequenti#
Come eseguo una ricerca web e ottengo il contenuto della pagina in un'unica chiamata REST API?#
Invia POST /v2/lookup con una query e imposta perceive_top (0–10). Gli URL dei primi N risultati vengono renderizzati in un browser reale, e ogni risultato sottoposto a perceive porta un oggetto perceive inline il cui Markdown si trova dietro un URL pre-firmato in perceive.outputs.markdown.url.
/v2/lookup è un'alternativa alle SERP API che posso adottare senza provider lock-in?#
Sì. È Serper a fornire il backend di ricerca, ma la richiesta e la risposta parlano un vocabolario di ricerca neutrale (category, country, locale, time_filter), così un futuro cambio di provider non modifica il contratto su cui scrivi il codice.
Quali categorie di ricerca supporta l'API lookup?#
Sei: web (predefinita), news, images, scholar, patents e maps. I campi universali (title, url, snippet, position) sono sempre tipizzati, e gli extra specifici della categoria finiscono in extra.
Perché lookup applica il perceive a meno pagine rispetto al mio perceive_top?#
L'auto-perceive salta i risultati il cui url è null, si ferma se la quota mensile di ops si esaurisce a metà ciclo, e riduce un render fallito a un warning. Il perceive_top della risposta riporta quante pagine sono state effettivamente sottoposte a perceive, e warnings spiega le lacune.