API de rastreo de sitemaps#

Beta privada. Discover ya se puede llamar hoy con tu clave de API habitual, en cualquier plan incluido Founding, y descuenta de tu cuota mensual de ops igual que cualquier otra llamada. No está anunciado ni disponible de forma general: las formas de la solicitud y de la respuesta pueden cambiar sin avisar, y no hay ningún compromiso de estabilidad ni de soporte, así que todavía no montes nada crítico encima. La hoja de ruta está en Próximamente, y cada versión se anuncia en el changelog.

POST /v2/discover es una API de rastreo de sitemaps que lista las URLs de un sitio web de la forma económica: un rastreo que prioriza HTTP más el análisis del sitemap, con un fallback opcional de renderizado de JavaScript para aplicaciones de una sola página (SPA). No hay captura de pantalla, ni PDF, ni artefacto almacenado. Devuelve una lista plana y sin duplicados de URLs junto con un recuento de la procedencia de cada una, de forma síncrona en una sola llamada. Será la primitiva ligera para "mapear el sitio": apúntala a un dominio, obtén de vuelta las páginas que vale la pena procesar y luego pasa esa lista a el endpoint perceive o a un trabajo de ingesta en modo crawl.

Aquí está la llamada mínima útil. Envía una URL, obtén su mapa de vuelta:

curl -X POST https://api.enconvert.com/v2/discover \
  -H "X-API-Key: sk_your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com"
  }'

La respuesta es una lista plana de URLs con contadores de procedencia: sin URLs firmadas, sin ID de operación, sin sondeo:

{
    "url": "https://example.com",
    "mode": "hybrid",
    "total": 47,
    "urls": [
        "https://example.com/",
        "https://example.com/pricing",
        "https://example.com/docs",
        "https://example.com/blog/launch"
    ],
    "pages_crawled": 12,
    "truncated": false,
    "robots_respected": false,
    "sources": {"sitemap": 42, "crawl": 30},
    "warnings": []
}

Endpoints#

Método Ruta Propósito
POST /v2/discover Mapea las URLs de un sitio solo por HTTP y devuelve una lista plana con recuentos por fuente.

/v2/discover expone una única ruta. No tiene estado: no hay una fila de operación que volver a consultar ni un trabajo que sondear, así que no existe un endpoint GET complementario como sí lo tiene perceive.

Content-Type: application/json en el POST.


Autenticación#

Autentícate con una clave privada en el encabezado X-API-Key para llamadas de servidor a servidor. Este es el método que usan los ejemplos siguientes.

X-API-Key: sk_your_private_key

Las claves públicas con un token JWT bearer también funcionan, usando el mismo flujo que el resto de los endpoints: genera un token con tu clave pk_ y luego envíalo como Authorization: Bearer <token>. El flujo completo, incluido el bloqueo de dominio y la renovación de tokens, está en la guía de autenticación.

Cada clave de API lleva una lista de permitidos de endpoints. Si /v2/discover no está en la lista de la clave, la solicitud se rechaza con 403 y un mensaje que indica la ruta bloqueada.


Cómo funciona discover#

Una solicitud se ejecuta enteramente por HTTP. El Chrome headless singleton que impulsa perceive nunca se toca. La ruta de rastreo usa la estrategia de rastreador HTTP de Crawl4AI (un GET con httpx más un análisis de enlaces con lxml por página), y la ruta del sitemap reutiliza los mismos helpers de sitemap y feeds puramente HTTP que el resto de la plataforma.

  1. Filtra la semilla. La URL que envías se verifica contra SSRF antes de cualquier solicitud: se validan el esquema, las credenciales incrustadas, los hostnames bloqueados y la IP resuelta. Una URL que resuelve a una dirección privada, loopback, link-local o de metadatos de nube se rechaza con 400. La semilla siempre se incluye como la primera entrada en su propio mapa.
  2. Recopila desde sitemaps. En modo sitemap o hybrid, discover lee robots.txt y obtiene las URLs Sitemap: que declara, sondea sitemap.xml (recurriendo en los hijos <sitemapindex>) y extrae páginas de feeds RSS/Atom. Ejecuta estos sondeos tanto contra el host que enviaste como contra el dominio registrable (apex) del sitio, de modo que un sitemap publicado solo en el apex se encuentra igualmente desde una semilla en un subdominio o en una ruta profunda. Un sitemap ausente o roto se convierte en una advertencia, no en un error.
  3. Rastrea por HTTP. En modo crawl o hybrid, discover ejecuta un rastreo en anchura desde la semilla hasta max_depth, recolectando los enlaces <a href> del HTML crudo de cada página obtenida. Cada enlace seguido se filtra contra SSRF antes de solicitarlo.
  4. Normaliza y filtra. La lista combinada en bruto se canonicaliza (se eliminan los fragmentos y los parámetros de seguimiento, se quitan los puertos por defecto, se ordenan las claves de consulta), y luego pasa por la verificación de mismo dominio, tus patrones regex de inclusión y exclusión, el filtro de robots.txt, la deduplicación y finalmente el límite de max_urls.

En la ruta solo por HTTP, una aplicación de una sola página (SPA) renderizada en el cliente devuelve solo su shell HTML en modo crawl, típicamente la semilla más cero o una URL. El fallback opcional render_js (consulta renderizado de JavaScript) cierra esa brecha: en su valor por defecto "auto", discover renderiza la página una vez en el navegador y recolecta los enlaces que esta inyecta en tiempo de ejecución siempre que el rastreo por HTTP devuelve solo un shell. El modo sitemap sigue siendo una ruta rápida y sin navegador para las SPAs con buen SEO, que normalmente publican un sitemap.


Parámetros de la solicitud#

Básicos#

Parámetro Tipo Valor por defecto Descripción
url string ninguno El sitio a mapear. Debe empezar con http:// o https://. Máximo 2,048 caracteres. Obligatorio.
mode string "hybrid" sitemap, crawl o hybrid. Consulta Modos.
max_urls integer 100 Número máximo de URLs devueltas. 1–1,000. La lista se limita aquí y truncated indica si existían más.
max_depth integer 2 Profundidad de rastreo desde la semilla, en modo crawl/hybrid. 1–5.
same_domain_only boolean true Conserva solo las URLs del host de la semilla. Cuando es false, también se conservan los enlaces fuera de ese host descubiertos durante el rastreo.
render_js string "auto" Descubrimiento con renderizado en el navegador para sitios JavaScript/SPA (solo crawl/hybrid). auto renderiza solo cuando el rastreo por HTTP devuelve un shell; always lo fuerza; never se mantiene solo por HTTP. Consulta renderizado de JavaScript.

Filtrado#

Parámetro Tipo Valor por defecto Descripción
include_patterns string[] [] Lista de permitidos con regex de Python (semántica re.search, no glob). Una URL debe coincidir con al menos uno para conservarse. Vacío significa permitir todo. Máximo 50 patrones.
exclude_patterns string[] [] Lista de denegados con regex de Python. Una URL que coincida con cualquier patrón se descarta. Se aplica después de include_patterns. Máximo 50 patrones.
respect_robots boolean false Cuando es true, las URLs no permitidas por el robots.txt del sitio se eliminan de la lista devuelta.

Los patrones son expresiones regulares de Python reales, compiladas en el momento de la validación. Un patrón mal formado da un 422 en el borde, no un 500 a mitad del rastreo. Como la semántica es re.search, una subcadena simple como "/blog/" coincide en cualquier parte de la URL: usa ^/$ como anclas si necesitas una coincidencia posicional.

Vale la pena aclarar esto de entrada. respect_robots se aplica en el momento del filtrado de salida, no en el momento de la solicitud. Crawl4AI 0.8.9 no tiene una validación nativa de robots, así que en modo crawl o hybrid una página no permitida puede igualmente obtenerse por HTTP y descartarse después, antes de llegar a la respuesta. A diferencia de perceive, donde respect_robots=true rechaza una URL no permitida con 403, discover nunca devuelve 403 por una regla de robots: descarta la URL en silencio y no reporta nada.

Modos#

mode Qué hace
sitemap Entradas de sitemap de robots.txt, sondeo de sitemap.xml (con recursión de índice) y páginas de feeds RSS/Atom. Instantáneo, sin rastreo.
crawl Rastreo en anchura solo por HTTP desde la semilla, recolectando enlaces <a href> del markup crudo.
hybrid (por defecto) La unión sin duplicados de sitemap y crawl.

El modo crawl solicita hasta tu max_urls completo (hasta 1,000), así que un sitio grande se enumera en una sola pasada. El modo crawl es solo por HTTP (sin navegador), así que sigue siendo rápido. Los operadores pueden bajar el techo con la variable de entorno DISCOVER_CRAWL_MAX_PAGES si un rastreo muy grande alguna vez necesita acotarse. pages_crawled en la respuesta te indica exactamente cuántos GETs se ejecutaron.

La obtención de sitemaps maneja sitemaps comprimidos con gzip (sitemap.xml.gz y cualquier sitemap servido como application/gzip), y envía encabezados de navegador realistas, de modo que los sitios detrás de un WAF tienen muchas más probabilidades de devolver su sitemap en lugar de un 403/503.

Renderizado de JavaScript#

Los modos crawl y hybrid leen el HTML crudo que devuelve un servidor, así que una aplicación de una sola página (SPA) renderizada en el cliente que construye sus enlaces en el navegador es invisible para ellos. render_js habilita un fallback acotado en el navegador que cierra esa brecha:

render_js Qué hace
auto (por defecto) Ejecuta primero el rastreo por HTTP; renderiza en el navegador solo cuando este devuelve un shell vacío (una URL o ninguna), y luego recolecta los enlaces inyectados por el cliente.
always Ejecuta siempre el rastreo con renderizado en el navegador.
never Se mantiene estrictamente solo por HTTP: el comportamiento preexistente.

El fallback usa el mismo Chrome headless compartido que perceive y está limitado a unas pocas páginas para que la llamada se mantenga dentro del timeout de la solicitud. Los enlaces que encuentra se contabilizan bajo la clave crawl_js en sources. Se aplica solo a los modos crawl y hybrid: el modo sitemap ya es sin navegador y no se ve afectado.


Respuesta#

POST /v2/discover devuelve este objeto directamente: no hay un trabajo asíncrono ni una segunda llamada.

Campo Tipo Descripción
url string La URL semilla que enviaste.
mode string El modo que se ejecutó: sitemap, crawl o hybrid.
total integer Número de URLs en urls (después de la deduplicación, el filtrado y el límite).
urls string[] La lista de URLs sin duplicados, normalizada y limitada. La semilla siempre es el primer candidato.
pages_crawled integer GETs HTTP emitidos por el rastreo. 0 en modo sitemap puro.
truncated boolean true cuando existían más URLs únicas de las que permitía max_urls.
robots_respected boolean Refleja el valor de respect_robots que enviaste.
sources object Recuento de URLs en bruto por fuente antes de la deduplicación/filtrado, p. ej. {"sitemap": 42, "crawl": 30}. Las claves incluyen sitemap, crawl, sitemap_apex (sitemaps encontrados en el dominio apex) y crawl_js (enlaces del fallback de renderizado de JavaScript). Los recuentos se solapan y suman más que total.
warnings string[] Notas no fatales: un sitemap ausente, un rastreo que falló, un robots.txt inaccesible.

Los recuentos de sources son en bruto: son el número de URLs que produjo cada ruta antes de que se ejecutaran la normalización, la verificación de mismo dominio, tus filtros y la deduplicación. Habitualmente sumarán más que total, porque el modo hybrid encuentra las mismas páginas tanto desde el sitemap como desde el rastreo. Úsalos para ver qué ruta está aportando el mapa, no como un recuento posterior al filtrado.


Ejemplos de código#

curl: mapa hybrid por defecto#

curl -X POST https://api.enconvert.com/v2/discover \
  -H "X-API-Key: sk_your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com"
  }'

curl: solo sitemap, páginas de blog, limitado a 500#

curl -X POST https://api.enconvert.com/v2/discover \
  -H "X-API-Key: sk_your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "mode": "sitemap",
    "max_urls": 500,
    "include_patterns": ["/blog/"],
    "exclude_patterns": ["/tag/", "/author/"],
    "respect_robots": true
  }'

Python#

import requests

response = requests.post(
    "https://api.enconvert.com/v2/discover",
    headers={"X-API-Key": "sk_your_private_key"},
    json={
        "url": "https://example.com",
        "mode": "hybrid",
        "max_urls": 200,
        "include_patterns": [r"/docs/"],
    },
)
response.raise_for_status()
data = response.json()

print(f"found {data['total']} URLs from {data['sources']}")
for page_url in data["urls"]:
    print(page_url)

Node.js#

const res = await fetch("https://api.enconvert.com/v2/discover", {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "X-API-Key": "sk_your_private_key"
    },
    body: JSON.stringify({
        url: "https://example.com",
        mode: "hybrid",
        max_urls: 200,
        include_patterns: ["/docs/"]
    })
});

const data = await res.json();

console.log(`found ${data.total} URLs from`, data.sources);
data.urls.forEach((pageUrl) => console.log(pageUrl));

Un patrón común es primero descubrir y luego renderizar: toma data.urls y pásalas al endpoint perceive: llamadas individuales para un puñado de páginas, o su ruta por lotes (batch) para la lista completa.


Respuestas de error#

Estado Condición
400 Bad Request La URL no es http(s), lleva credenciales incrustadas, no tiene hostname, o resuelve a una dirección privada, loopback, link-local o de metadatos de nube (protección SSRF).
401 Unauthorized Falta la clave de API / token JWT o es inválido.
402 Payment Required Discover no está habilitado en tu plan actual, o tu cuota mensual de ops está agotada. Cada llamada a /v2/discover factura una op.
403 Forbidden /v2/discover no está en los endpoints permitidos de la clave de API.
422 Unprocessable Entity Falló la validación de la solicitud: enum mode inválido, max_urls fuera de 1–1,000, max_depth fuera de 1–5, más de 50 patrones de inclusión/exclusión, una regex mal formada, o una url de más de 2,048 caracteres.
500 Internal Server Error El descubrimiento de URLs falló de forma inesperada. El cliente recibe un mensaje genérico; el detalle completo va solo a los logs del servidor.

Ten en cuenta que un fallo al obtener el sitemap o un error de rastreo no producen un estado de error: se degradan a entradas en el arreglo warnings, y la solicitud igual devuelve 200 con lo que se haya encontrado. La referencia completa de códigos de estado está en la guía de códigos de error.


Límites#

Límite Valor
Longitud de la URL 2,048 caracteres
max_urls 1–1,000 (por defecto 100)
max_depth 1–5 (por defecto 2)
include_patterns Máximo 50 patrones
exclude_patterns Máximo 50 patrones
Páginas solicitadas en modo crawl hasta max_urls (máx. 1,000; se baja con DISCOVER_CRAWL_MAX_PAGES)
Timeout de la solicitud 300 segundos
Ops por llamada 1, facturada contra la cuota mensual unificada

Preguntas frecuentes#

¿Cómo listo todas las URLs de un sitio web con una API?#

Envía POST /v2/discover con la URL del sitio. El modo hybrid por defecto combina el análisis del sitemap (entradas de robots.txt, sitemap.xml con recursión de índice, feeds RSS/Atom) con un rastreo en anchura por HTTP, y devuelve hasta max_urls (1–1,000, por defecto 100) URLs sin duplicados en una sola respuesta síncrona.

¿El endpoint discover usa un navegador headless o renderiza JavaScript?#

Por defecto se ejecuta por HTTP y solo renderiza cuando es necesario. La opción render_js controla esto: en el modo por defecto "auto", discover se mantiene solo por HTTP y renderiza una página en el navegador justo cuando el rastreo por HTTP devuelve un shell JavaScript vacío, recolectando los enlaces inyectados por el cliente; "always" fuerza el rastreo en el navegador y "never" lo mantiene estrictamente solo por HTTP. El modo sitemap sigue siendo una opción rápida y sin navegador para las SPAs con buen SEO.

¿Cuántas páginas solicita realmente el modo crawl?#

El modo crawl solicita hasta tu max_urls completo (hasta 1,000). Se mantiene solo por HTTP, así que sigue siendo rápido; los operadores pueden bajar el techo con la variable de entorno DISCOVER_CRAWL_MAX_PAGES. Cada página solicitada aporta además muchos enlaces. El campo pages_crawled de la respuesta indica exactamente cuántos GETs HTTP se ejecutaron.

¿Puedo filtrar qué URLs se devuelven?#

Sí: include_patterns y exclude_patterns aceptan hasta 50 regex de Python cada uno (semántica re.search, no glob), y respect_robots: true elimina de la lista devuelta las URLs no permitidas por el robots.txt del sitio.