Ingest
POST /v2/ingest convierte un sitio — o una lista explícita de URLs — en
fragmentos listos para RAG y emite un único archivo JSONL que se carga
directamente en JSONLoader de LangChain, SimpleDirectoryReader de
LlamaIndex o una importación masiva a una base de datos vectorial. Reemplaza
la pila de dos pasos que de otro modo tendrías que construir: Firecrawl
/crawl para descubrir y extraer, más tu propio fragmentador para trocear el
Markdown. EnConvert hace el descubrimiento, el renderizado en Chrome headless,
el fragmentado consciente de encabezados y el ensamblado del JSONL en un solo
trabajo.
Esta es la llamada útil más pequeña. Rastrea un sitio y fragmenta cada página que descubre:
curl -X POST https://api.enconvert.com/v2/ingest \
-H "X-API-Key: sk_live_your_private_key" \
-H "Content-Type: application/json" \
-d '{
"mode": "crawl",
"url": "https://example.com/docs"
}'
La respuesta es el registro del trabajo, devuelto con 202 Accepted. Observa
que el estado es queued, y output_url está ausente hasta que el trabajo se
completa:
{
"job_id": "ing_3f9a2c1b8e7d4a6f90b1c2d3e4f5a6b7",
"status": "queued",
"mode": "crawl",
"pages_discovered": 0,
"pages_processed": 0,
"pages_failed": 0,
"total_chunks": 0,
"webhook_delivered": false,
"created_at": "2026-06-24T09:14:02.118Z"
}
Ingest es siempre asíncrono. Cada página se renderiza en un navegador
real, lo que tarda entre 10 y 30 segundos por URL — muy por encima de la
ventana de petición de 300 segundos para cualquier trabajo no trivial. Por eso
POST responde 202 con un job_id, y un worker local del droplet drena el
trabajo fuera de banda. Sondeas GET /v2/ingest/{job_id} para ver el
progreso, o registras un webhook_url para que te avisen cuando termine.
Vale la pena señalarlo de entrada.
/v2/ingestes un endpoint V2 con su propio contador de cuota,ingest_pages. Los planes de conversión V1 no incluyen ninguna asignación de ingest — necesitas un plan que incluya V2 para llamarlo. Se factura una página por cada URL cuya etapa de renderizado, fragmentado y JSONL se complete; las páginas que fallan o se omiten no se facturan. Consulta la página de precios para ver las asignaciones por nivel, y la visión general de V2 para saber en qué se diferencian los contadores de V2 de las conversiones V1.
Endpoints
| Method | Path | Purpose |
|---|---|---|
POST |
/v2/ingest |
Crea un trabajo de ingest. Responde 202 con un job_id. |
GET |
/v2/ingest |
Lista de los trabajos de este proyecto, del más nuevo al más antiguo, con paginación skip/limit. |
GET |
/v2/ingest/{job_id} |
Estado del ciclo de vida de un trabajo, con un output_url recién firmado una vez completado. |
DELETE |
/v2/ingest/{job_id} |
Cancela un trabajo. El worker ve el estado cancelado y se detiene entre páginas. |
POST |
/v2/ingest/{job_id}/retry-webhook |
Vuelve a firmar y reenvía por POST el webhook de finalización de un trabajo completado. |
GET |
/v2/ingest/webhook-secret |
Revela el secreto de firma de webhook del proyecto (canal del dashboard). |
POST |
/v2/ingest/webhook-secret/rotate |
Rota el secreto de firma. Las firmas antiguas dejan de verificarse de inmediato. |
Content-Type: application/json en cada POST.
Authentication
Autentícate con una clave privada en el encabezado X-API-Key para las
llamadas servidor a servidor. Esta es la vía que usan los ejemplos de abajo.
X-API-Key: sk_live_your_private_key
Las claves públicas con un token bearer JWT también funcionan, usando el mismo
flujo que cualquier otro endpoint — genera un token con tu clave pk_, luego
envíalo como Authorization: Bearer <token>. El flujo completo, incluido el
bloqueo de dominio y la renovación del token, está en la guía de
autenticación.
Cada clave de API lleva una lista de permitidos de endpoints autorizados. Si
/v2/ingest no está en la lista de la clave, la petición se rechaza con
403. Una clave restringida a /v2/ingest aún alcanza los trabajos que creó
— GET y DELETE /v2/ingest/{job_id} y POST
/v2/ingest/{job_id}/retry-webhook siempre se permiten para un job_id (la
forma ing_… se compara explícitamente). El endpoint de lista estático y las
dos rutas de gestión de webhook-secret no heredan esa excepción;
requieren un token de alcance más amplio o de dashboard.
How ingest works
Un trabajo recorre cinco fases, todas duraderas y a prueba de reinicios. Si el proceso del worker se reinicia a mitad de un trabajo, el trabajo se vuelve a encolar al arrancar y se reanuda desde la página en la que se detuvo — las páginas ya completadas conservan su salida preparada y nunca se vuelven a renderizar ni a facturar.
- Queue.
POSTvalida la petición, ejecuta una comprobación rápida de cuotaunits=1(el plan tiene ingest habilitado y algo de margen mensual), inserta la fila del trabajo y responde202. No se persiste nada si la compuerta de cuota falla — un402no deja ninguna fila atrás. - Discover. Para los modos
sitemapycrawlel worker ejecuta el mismo pase de descubrimiento que el endpoint discover, limitado amax_pages, y aplica un filtro SSRF a la URL semilla. Para el modourlsla lista explícita se deduplica en orden; no se ejecuta ningún descubrimiento. - Render and chunk. Cada URL se renderiza a través del singleton compartido de Chrome headless — la misma canalización de renderizado detrás de el endpoint perceive — luego el HTML renderizado se convierte a fit-Markdown y se trocea con el fragmentador consciente de encabezados. Los renderizados se ejecutan secuencialmente, una página a la vez.
- Stage. Los fragmentos de cada página se escriben en un objeto JSONL por
página en el almacenamiento, indexado de forma determinista por
(project, job, url). Esto es lo que hace barato un reinicio: un trabajo reanudado reutiliza las páginas preparadas en lugar de volver a renderizarlas. - Assemble. Una vez que todas las páginas están listas, los objetos por
página se concatenan en el
v2-ingest/{job_id}.jsonlfinal, los objetos de preparación se eliminan, el trabajo pasa acompletedy — si se estableció unwebhook_url— se dispara el webhook de finalización firmado.
El contador de cuota se vuelve a comprobar por página dentro del worker,
no solo en el momento del envío. Un trabajo crawl cuyo número de páginas se
desconoce de antemano se detiene limpiamente en tu tope mensual: las páginas
ya renderizadas se facturan y se conservan, y las páginas restantes se marcan
como skipped en lugar de gastar de más.
Los renderizados de ingest son sin credenciales por diseño. A diferencia
de /v2/perceive, no acepta auth, cookies ni headers personalizados —
no se persiste nada secreto para la reanudación duradera, por lo que el estado
del trabajo en disco nunca lleva credenciales.
Request parameters
Source and mode
| Parameter | Type | Default | Description |
|---|---|---|---|
mode |
string |
"urls" |
urls, sitemap o crawl. Selecciona cómo se construye el conjunto de URLs. |
url |
string |
null |
URL semilla para el modo sitemap/crawl. Debe empezar por http:// o https://. Máximo 2.048 caracteres. Obligatoria para esos modos; rechazada en el modo urls. |
urls |
string[] |
null |
URLs explícitas a ingerir en el modo urls. No vacía, máximo 1.000 entradas, cada una http(s) y ≤ 2.048 caracteres. Obligatoria para el modo urls; rechazada en el modo sitemap/crawl. |
url y urls son mutuamente excluyentes — exactamente una fuente. El modo
urls requiere urls; sitemap y crawl requieren una url semilla.
Enviar la incorrecta para el modo es un 422.
Discovery (sitemap / crawl modes)
Estos se reenvían al pase de descubrimiento y se ignoran en el modo urls.
| Parameter | Type | Default | Description |
|---|---|---|---|
max_pages |
integer |
50 |
Tope sobre las URLs descubiertas e ingeridas. 1–1.000. |
max_depth |
integer |
2 |
Profundidad de enlaces del rastreo desde la semilla. 1–5. |
same_domain_only |
boolean |
true |
Restringe el descubrimiento al dominio de la semilla. |
include_patterns |
string[] |
[] |
Patrones regex que una URL debe coincidir para conservarse. Máximo 50. Cada uno se compila en el envío; un patrón inválido es un 422. |
exclude_patterns |
string[] |
[] |
Patrones regex que descartan una URL coincidente. Máximo 50. |
respect_robots |
boolean |
false |
Cuando es true, una URL no permitida por el robots.txt del sitio se omite. |
Rendering
| Parameter | Type | Default | Description |
|---|---|---|---|
wait_for |
string |
null |
Espera tras la navegación a un selector CSS o una expresión JS antes de capturar. Máximo 1.024 caracteres. |
wait_timeout_ms |
integer |
30000 |
Cuánto tiempo puede esperar wait_for, en milisegundos. 0–60.000. |
Nota. Ingest no acepta
auth,cookiesniheaders. Si una página necesita credenciales para renderizarse, ingest es la herramienta equivocada — usa el endpoint perceive, que lleva toda la superficie de petición autenticada, para esa única página.
Chunking (chunk object)
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
max_words |
integer |
512 |
32–4,000 | Tope flexible de palabras por fragmento. Consciente de encabezados. Los bloques de código y las tablas de pipe permanecen atómicos y pueden superarlo. |
sentence_overlap |
integer |
1 |
0–10 | Oraciones repetidas entre fragmentos de prosa consecutivos de la misma sección. 0 desactiva el solapamiento. El solapamiento nunca cruza un límite de encabezado. |
El fragmentador divide en los encabezados #, ## y ### — cada fragmento
pertenece a exactamente una sección y lleva su ruta de encabezados completa.
Los encabezados más profundos (####–######) permanecen en línea como
contenido. Los bloques de código entre vallas y las tablas de Markdown nunca
se dividen, incluso cuando un solo bloque supera max_words; los elementos de
lista se dividen entre elementos, nunca a mitad de un elemento.
Webhook
| Parameter | Type | Default | Description |
|---|---|---|---|
webhook_url |
string |
null |
Endpoint que recibe el callback de finalización firmado con HMAC. Máximo 2.048 caracteres. Se verifica el esquema en el envío; se aplica el filtro SSRF en el momento de la entrega, no en el del envío. |
Response
POST, GET /v2/ingest/{job_id} y DELETE devuelven todos el mismo objeto
IngestJobResponse.
| Field | Type | Description |
|---|---|---|
job_id |
string |
ID opaco (ing_…). Úsalo con los endpoints GET/DELETE y cítalo al soporte. |
status |
string |
queued, discovering, processing, completed, failed o canceled. |
mode |
string |
El modo que enviaste: urls, sitemap o crawl. |
pages_discovered |
integer |
URLs que el trabajo ingerirá (la lista explícita, o el resultado del descubrimiento). |
pages_processed |
integer |
URLs cuyo render → chunk → stage se completó. |
pages_failed |
integer |
URLs que fallaron al renderizar o se omitieron (p. ej. cuota agotada). |
total_chunks |
integer |
Total de fragmentos escritos en todas las páginas completadas — coincide con el número de líneas del JSONL. |
output_url |
string |
URL de descarga prefirmada para el JSONL final. Presente solo una vez que status es completed; expira a los 15 minutos. |
error_message |
string |
Se establece cuando status es failed (p. ej. descubrimiento rechazado, todas las páginas fallaron). |
webhook_url |
string |
El destino del webhook de finalización registrado para este trabajo, si lo hay. |
webhook_delivered |
boolean |
true una vez que el webhook de finalización firmado recibió un 2xx. |
created_at |
string |
Cuándo se creó el trabajo (UTC). |
completed_at |
string |
Cuándo el trabajo alcanzó un estado terminal (UTC). |
warnings |
string[] |
Notas no fatales. |
Nota.
POSTy elGET/DELETEpor trabajo usanresponse_model_exclude_none, por lo que los campos que aún sonnull(comooutput_urlantes de completarse) se omiten del JSON en lugar de enviarse comonull.
The JSONL record shape
El archivo final es JSON delimitado por saltos de línea. Cada línea es un fragmento:
{"id":"9f2b8c1ad4e5-0000","content":"Pricing is usage-based...","metadata":{"source_url":"https://example.com/pricing","title":"Pricing","headings_path":["Pricing","Plans"],"section":"Plans","word_count":118,"chunk_index":0}}
| Field | Type | Description |
|---|---|---|
id |
string |
Determinista por (source_url, chunk_index): <md5(url)[:12]>-<index:04d>. Una nueva ejecución produce ids idénticos. |
content |
string |
El texto recuperable del fragmento. Se mapea a Document.page_content en LangChain. |
metadata.source_url |
string |
La página de la que provino el fragmento. |
metadata.title |
string |
El <title> de la página, recurriendo al primer <h1>, limitado a 512 caracteres. |
metadata.headings_path |
string[] |
La ruta h1 → h2 → h3 bajo la que se sitúa el fragmento. |
metadata.section |
string |
El texto del encabezado más interno (la última entrada de headings_path). |
metadata.word_count |
integer |
Número de palabras de content delimitadas por espacios en blanco. |
metadata.chunk_index |
integer |
El índice del fragmento dentro de su página. |
El archivo es UTF-8, escrito con ensure_ascii=false, por lo que el unicode
se mantiene legible. Como content es una cadena de nivel superior y
metadata es un objeto hermano, el mismo archivo se carga con JSONLoader(content_key="content", json_lines=True) de LangChain,
SimpleDirectoryReader de LlamaIndex y cualquier importación a base de datos
vectorial orientada a líneas sin reestructurarse.
Job lifecycle and polling
Un trabajo se mueve a través de estos estados:
queued → discovering → processing → completed | failed | canceled
| Status | Meaning |
|---|---|
queued |
Aceptado y esperando al worker. |
discovering |
Ejecutando el pase de descubrimiento de sitemap/crawl (solo sitemap/crawl). |
processing |
Renderizando y fragmentando páginas. pages_processed y total_chunks suben en vivo. |
completed |
El JSONL final está ensamblado; output_url está firmado y listo. |
failed |
El descubrimiento fue rechazado, o todas las páginas fallaron o se omitieron. error_message lo explica. |
canceled |
Un DELETE alcanzó el trabajo antes de que terminara. |
Sondea el estado con el GET por trabajo. Es de solo lectura — no consume
cuota y vuelve a firmar el output_url a partir de la clave de objeto
almacenada en cada llamada:
curl https://api.enconvert.com/v2/ingest/ing_3f9a2c1b8e7d4a6f90b1c2d3e4f5a6b7 \
-H "X-API-Key: sk_live_your_private_key"
Un job_id desconocido, o uno que pertenece a otro proyecto, devuelve 404 —
la existencia nunca se filtra entre proyectos.
Listing jobs
GET /v2/ingest devuelve los trabajos de este proyecto del más nuevo al más
antiguo, con los parámetros de consulta skip y limit. limit tiene un
valor predeterminado de 20 y un tope de 100. La respuesta lleva una
bandera has_more en lugar de un recuento total:
curl "https://api.enconvert.com/v2/ingest?skip=0&limit=20" \
-H "X-API-Key: sk_live_your_private_key"
{
"jobs": [
{
"job_id": "ing_3f9a...",
"status": "completed",
"mode": "crawl",
"pages_discovered": 42,
"pages_processed": 41,
"pages_failed": 1,
"total_chunks": 1187,
"output_url": "https://spaces.example.com/...signed...",
"webhook_configured": true,
"webhook_delivered": true,
"created_at": "2026-06-24T09:14:02.118Z",
"completed_at": "2026-06-24T09:31:55.402Z"
}
],
"skip": 0,
"limit": 20,
"has_more": false
}
Las filas de la lista reducen webhook_url a un booleano
webhook_configured — la lista nunca devuelve el endpoint en bruto a la
tabla.
Canceling a job
DELETE /v2/ingest/{job_id} establece el estado del trabajo a canceled. El
worker lee ese estado entre páginas y se detiene sin ensamblar la salida. La
cancelación es idempotente y a prueba de carreras: si el ensamblado ya se
confirmó, el DELETE no coincide con nada y el trabajo se devuelve sin
cambios como completed — un trabajo terminado nunca se revierte a
canceled.
curl -X DELETE \
https://api.enconvert.com/v2/ingest/ing_3f9a2c1b8e7d4a6f90b1c2d3e4f5a6b7 \
-H "X-API-Key: sk_live_your_private_key"
Completion webhooks
Establece webhook_url en el POST y EnConvert envía un único POST firmado
con HMAC cuando el trabajo se completa. La carga útil es JSON compacto y
ordenado por clave:
{"job_id":"ing_3f9a...","output_url":"https://spaces.example.com/...signed...","pages_processed":41,"status":"completed","total_chunks":1187}
La entrega se reintenta hasta tres veces después del primer intento, con
retardos de back-off de 1, 4 y 16 segundos — cuatro POST en el peor caso.
Cada intento se vuelve a firmar con una marca de tiempo nueva, por lo que una
cadena de reintentos lenta nunca se desfasa más allá de la ventana de
frescura del consumidor. Una respuesta 2xx es éxito; un endpoint muerto se
registra como una no entrega (y genera una alerta en el dashboard), nunca
hunde un trabajo que por lo demás está completado.
El webhook_url recibe el filtro SSRF en el momento de la entrega, no en
el del envío. Una URL que resuelve a una dirección privada, de loopback o de
metadatos se almacena de forma inerte y solo se rechaza cuando EnConvert
intenta hacer POST a ella.
Verifying the signature
Cada entrega lleva dos encabezados:
| Header | Value |
|---|---|
X-Enconvert-Signature |
sha256=<hex> — el HMAC-SHA256 de <timestamp>.<raw body>. |
X-Enconvert-Timestamp |
La marca de tiempo en segundos unix vinculada a la firma. |
La entrada de firma es la marca de tiempo, un . literal, y luego el cuerpo
en bruto de la petición. Vincular la marca de tiempo al MAC significa que un
consumidor que rechaza marcas de tiempo obsoletas obtiene protección contra
repetición gratis — la ventana de frescura predeterminada es de 300
segundos. Verifica en tu handler:
import hashlib
import hmac
import time
SECRET = "whsec_your_signing_secret" # from GET /v2/ingest/webhook-secret
TOLERANCE_SECONDS = 300
def verify(raw_body: bytes, signature_header: str, timestamp_header: str) -> bool:
if not signature_header or not timestamp_header:
return False
try:
ts = int(timestamp_header)
except ValueError:
return False
if abs(time.time() - ts) > TOLERANCE_SECONDS:
return False # replayed or badly skewed clock
provided = signature_header.removeprefix("sha256=")
expected = hmac.new(
SECRET.encode("utf-8"),
f"{ts}.".encode("utf-8") + raw_body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, provided)
Managing the signing secret
GET /v2/ingest/webhook-secret revela el secreto del proyecto (creándolo en
la primera llamada) junto con los nombres de encabezado y la tolerancia que
necesita tu consumidor. Es sensible y se expone solo a través del canal
autenticado del dashboard:
{
"secret": "whsec_...",
"signature_header": "X-Enconvert-Signature",
"timestamp_header": "X-Enconvert-Timestamp",
"signature_scheme": "sha256",
"replay_tolerance_seconds": 300,
"rotated": false
}
POST /v2/ingest/webhook-secret/rotate emite un nuevo secreto y establece
rotated a true. Toda firma calculada con el secreto anterior deja de
verificarse en el momento en que la rotación se confirma — rota tras una fuga
sospechada, luego actualiza tu consumidor.
Re-delivering a webhook
Si tu endpoint estaba caído cuando el trabajo terminó,
POST /v2/ingest/{job_id}/retry-webhook vuelve a firmar y reenvía por POST
con la misma política de reintentos:
curl -X POST \
https://api.enconvert.com/v2/ingest/ing_3f9a.../retry-webhook \
-H "X-API-Key: sk_live_your_private_key"
{
"job_id": "ing_3f9a...",
"delivered": true,
"attempts": 1,
"status_code": 200,
"detail": "Delivered (HTTP 200)."
}
Devuelve 404 para un job_id desconocido o ajeno, 400 cuando no hay
webhook_url configurado (o la URL almacenada ahora resuelve a una dirección
privada/interna), y 409 cuando el trabajo no ha alcanzado completed.
Code examples
curl — explicit URL list
curl -X POST https://api.enconvert.com/v2/ingest \
-H "X-API-Key: sk_live_your_private_key" \
-H "Content-Type: application/json" \
-d '{
"mode": "urls",
"urls": [
"https://example.com/docs/intro",
"https://example.com/docs/quickstart",
"https://example.com/docs/api"
]
}'
curl — crawl with chunking and a webhook
curl -X POST https://api.enconvert.com/v2/ingest \
-H "X-API-Key: sk_live_your_private_key" \
-H "Content-Type: application/json" \
-d '{
"mode": "crawl",
"url": "https://example.com/docs",
"max_pages": 200,
"max_depth": 3,
"include_patterns": ["/docs/"],
"chunk": {"max_words": 700, "sentence_overlap": 2},
"webhook_url": "https://your-app.example.com/hooks/ingest"
}'
Python — submit, poll, download
import time
import requests
BASE = "https://api.enconvert.com"
HEADERS = {"X-API-Key": "sk_live_your_private_key"}
# 1. Submit (always 202).
job = requests.post(
f"{BASE}/v2/ingest",
headers=HEADERS,
json={"mode": "crawl", "url": "https://example.com/docs", "max_pages": 100},
).json()
job_id = job["job_id"]
# 2. Poll until terminal.
while True:
job = requests.get(f"{BASE}/v2/ingest/{job_id}", headers=HEADERS).json()
if job["status"] in ("completed", "failed", "canceled"):
break
time.sleep(5)
# 3. Download the JSONL from its signed URL.
if job["status"] == "completed":
jsonl = requests.get(job["output_url"]).text
print(f"{job['total_chunks']} chunks across "
f"{job['pages_processed']} pages")
print(jsonl.splitlines()[0])
Node.js — submit and poll
const BASE = "https://api.enconvert.com";
const HEADERS = {
"Content-Type": "application/json",
"X-API-Key": "sk_live_your_private_key"
};
// 1. Submit.
const submit = await fetch(`${BASE}/v2/ingest`, {
method: "POST",
headers: HEADERS,
body: JSON.stringify({
mode: "crawl",
url: "https://example.com/docs",
max_pages: 100
})
});
let job = await submit.json();
// 2. Poll until terminal.
while (!["completed", "failed", "canceled"].includes(job.status)) {
await new Promise((r) => setTimeout(r, 5000));
const poll = await fetch(`${BASE}/v2/ingest/${job.job_id}`, {
headers: { "X-API-Key": HEADERS["X-API-Key"] }
});
job = await poll.json();
}
// 3. Download the JSONL.
if (job.status === "completed") {
const jsonl = await fetch(job.output_url).then((r) => r.text());
console.log(`${job.total_chunks} chunks`);
console.log(jsonl.split("\n")[0]);
}
Plan gating
El ingest de V2 se mide con su propio contador, ingest_pages — separado de
las conversiones V1 y de los demás contadores de V2. Se factura una página por
cada URL cuya etapa de renderizado, fragmentado y JSONL se completa; las
páginas que fallan o se omiten no se facturan.
La comprobación en el momento del envío es una compuerta rápida units=1: tu
plan debe tener ingest habilitado, con algo de margen mensual. El verdadero
limitador del gasto es la comprobación por página dentro del worker — un
trabajo crawl se detiene limpiamente en tu tope mensual y marca las páginas
restantes como skipped en lugar de excederlo.
| Gate | Behaviour |
|---|---|
| Plan sin ingest habilitado | 402 en el envío — actualiza a un plan que incluya V2. |
Cuota mensual de ingest_pages agotada |
402 en el envío; o, si se agota a mitad del trabajo, las páginas restantes se marcan como skipped. |
| Ilimitado (enterprise / admin) | Un límite de 0 con la bandera habilitada significa que no hay tope mensual. |
MAX_PAGES_PER_JOB (1.000) es un techo por petición que acota un solo
trabajo; no es tu asignación mensual. La cuota mensual de ingest_pages es el
verdadero limitador del gasto. Las cifras actuales por nivel están en la
página de precios; consulta también cómo se miden las
operaciones de perceive para el contador
hermano de V2.
Error responses
| Status | Condition |
|---|---|
202 Accepted |
El trabajo se creó y se encoló. Este es el resultado normal de un POST. |
401 Unauthorized |
Clave de API / token JWT faltante o inválido. |
402 Payment Required |
Ingest no está en tu plan actual, o tu cuota mensual de ingest_pages está agotada. |
403 Forbidden |
/v2/ingest no está en los endpoints permitidos de la clave de API. |
404 Not Found |
job_id desconocido, o uno propiedad de otro proyecto. |
409 Conflict |
Se llamó a retry-webhook en un trabajo que no ha alcanzado completed. |
400 Bad Request |
Se llamó a retry-webhook sin un webhook_url configurado, o su URL almacenada ahora resuelve a una dirección privada/interna. |
422 Unprocessable Entity |
La fuente no coincide con el modo (urls sin urls, o una url semilla en el modo urls); un parámetro está fuera de rango; o un regex de include_patterns/exclude_patterns no compila. |
500 Internal Server Error |
El trabajo no pudo crearse. El mensaje incluye el job_id para citarlo al soporte. |
Un fallo de renderizado a nivel de página no hace fallar la petición ni el
trabajo — incrementa pages_failed, deja el error de la página en su propia
fila, y el trabajo continúa. Un trabajo solo falla cuando se rechaza el
descubrimiento o cuando todas las páginas fallan o se omiten. La referencia
completa de códigos de estado está en la guía de códigos de
error.
Limits
| Limit | Value |
|---|---|
URLs por petición en modo urls |
1,000 |
Longitud de url / cada entrada de urls |
2,048 caracteres |
max_pages (tope de descubrimiento) |
1–1,000 |
max_depth |
1–5 |
include_patterns / exclude_patterns |
50 cada uno |
Longitud de wait_for |
1,024 caracteres |
wait_timeout_ms |
0–60,000 ms |
chunk.max_words |
32–4,000 (predeterminado 512) |
chunk.sentence_overlap |
0–10 (predeterminado 1) |
Longitud de webhook_url |
2,048 caracteres |
Techo de páginas por trabajo (MAX_PAGES_PER_JOB) |
1,000 |
limit de la lista GET /v2/ingest |
1–100 (predeterminado 20) |
Expiración del output_url firmado |
15 minutos |
| Intentos de entrega del webhook | 4 (inicial + 3 reintentos) |
| Tolerancia de repetición del webhook | 300 segundos |
ingest_pages mensual |
Depende del plan — consulta precios |