API di Ricerca Web per Agenti LLM#

Beta privata. Lookup è già chiamabile oggi con la tua normale chiave API, su qualsiasi piano compreso Founding, e scala dalla tua quota mensile di ops come ogni altra chiamata. Non è annunciato né disponibile in generale: le forme di richiesta e risposta possono cambiare senza preavviso e non c'è alcun impegno di stabilità o di supporto, quindi non costruirci ancora sopra nulla di critico. La roadmap è su In arrivo, e ogni rilascio viene annunciato nel changelog.

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.

  1. 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 402 e non viene addebitato nulla.
  2. 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.
  3. Normalizzazione. Ogni risultato del provider viene appiattito in un LookupResult neutrale che porta title, url, snippet e position. Gli extra specifici della categoria finiscono in extra, così il contratto non cresce di una colonna per ogni stranezza del provider.
  4. 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 come lookup_id per la correlazione con il supporto.
  5. 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/perceive a pieno titolo: propria op addebitata sulla quota condivisa, propria riga di operazione, proprio operation_id. Per impostazione predefinita l'auto-perceive richiede solo Markdown, senza screenshot, PDF o estrazione LLM; invia un oggetto enrich per 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.