Fuentes
Indexar, sincronizar y consultar el estado de tus documentos
Una fuente (source) es un documento, sitio web o conector que Kelova indexa como conocimiento consultable. Todos los endpoints de esta página requieren JWT; la creación, edición y borrado requieren rol admin — la lectura acepta admin o member.
Listar fuentes
curl https://api.kelova.app/ingest/sources \
-H "Authorization: Bearer <token>"[
{
"source_id": "3f2e1a...",
"name": "Catálogo 2026",
"source_type": "file",
"sync_status": "synced",
"last_synced_at": "2026-07-08T10:15:00Z",
"created_at": "2026-06-01T09:00:00Z",
"chunks_count": 214
}
]sync_status es uno de: pending (nunca sincronizada), syncing (en curso), synced (última sync exitosa), error (falló — revisa error_message), reauth_required (credenciales OAuth expiradas).
Crear una fuente
Para fuentes sin archivo (web, y conectores en modo referencia) — source_type acepta: file, gdrive, onedrive, notion, web, whatsapp, sap_b1, dynamics, api, audio.
curl -X POST https://api.kelova.app/ingest/sources \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"name": "Sitio corporativo",
"source_type": "web",
"source_url": "https://tuempresa.com"
}'Respuesta (201):
{
"source_id": "3f2e1a...",
"name": "Sitio corporativo",
"sync_status": "pending"
}La fuente queda en pending — dispara el primer sync con POST /ingest/sources/{id}/sync.
Para sitios web, corre POST /ingest/sources/preflight antes de crear la fuente — verifica en segundos si la URL es indexable (no es SPA, no está detrás de Cloudflare, tiene suficiente texto) sin gastar cupo de fuentes. Body: {"source_type": "web", "source_url": "..."}. Respuesta: {"indexable": true, "pages_found": 12, "max_pages": 50, "sample_title": "..."} o {"indexable": false, "error": "..."}.
Subir un archivo
POST /ingest/sources/upload es multipart/form-data, no JSON. Acepta PDF, DOCX, XLSX, PPTX, CSV, TXT, Markdown, imágenes (PNG/JPEG/TIFF/WebP/BMP, vía OCR) y audio (WAV/MP3/OGG/M4A/FLAC/WebM, vía transcripción). Máximo 50 MB (20 MB para imágenes).
curl -X POST https://api.kelova.app/ingest/sources/upload \
-H "Authorization: Bearer <token>" \
-F "name=Manual de producto" \
-F "file=@./manual.pdf"Respuesta (201) — indexado sincrónicamente, sin necesidad de disparar un sync aparte:
{
"source_id": "3f2e1a...",
"name": "Manual de producto",
"sync_status": "synced",
"chunks_count": 87
}Si el chunking o el embedding fallan, la respuesta sigue siendo 201 (la fuente se crea) pero con sync_status: "error" y error_message con la causa — no hace falta pollear /status para saberlo.
La estrategia de chunking (paragraph, section, row) se detecta automáticamente por MIME type — no es configurable.
Sincronizar manualmente
curl -X POST https://api.kelova.app/ingest/sources/{id}/sync \
-H "Authorization: Bearer <token>"Respuesta (202) — el sync corre en background:
{
"source_id": "3f2e1a...",
"message": "sync started"
}Responde 409 SYNC_IN_PROGRESS si ya hay un sync activo para esa fuente (salvo que el lock tenga más de 30 minutos, en cuyo caso se considera stale y se sobreescribe). El sync reemplaza todos los chunks de la fuente en una única transacción — nunca deja estados parciales visibles a las queries.
Consultar el estado (polling)
curl https://api.kelova.app/ingest/sources/{id}/status \
-H "Authorization: Bearer <token>"{
"source_id": "3f2e1a...",
"sync_status": "synced",
"last_synced_at": "2026-07-10T08:00:00Z",
"chunks_count": 214
}Preview de chunks indexados
Devuelve los primeros 3 chunks (contenido truncado a 200 caracteres) — útil para verificar visualmente que el contenido se indexó bien.
curl https://api.kelova.app/ingest/sources/{id}/preview \
-H "Authorization: Bearer <token>"[
{
"content": "Kelova indexa el conocimiento interno de tu empresa...",
"chunk_level": "child",
"location": "1"
}
]Historial de syncs
curl "https://api.kelova.app/ingest/sources/{id}/history?limit=20" \
-H "Authorization: Bearer <token>"[
{
"id": "a1b2c3...",
"action": "sync_completed",
"details": { "chunks_written": 214, "provider": "voyage" },
"created_at": "2026-07-10T08:00:00Z"
}
]Sync automático (schedule)
curl -X PUT https://api.kelova.app/ingest/sources/{id}/schedule \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"frequency": "24h"}'frequency acepta manual, 1h, 6h, 24h, weekly — las frecuencias disponibles dependen del plan (ver Límites de uso). Responde 402 si tu plan no incluye la frecuencia pedida.
{
"source_id": "3f2e1a...",
"frequency": "24h",
"next_sync_at": "2026-07-11T08:00:00Z",
"enabled": true
}GET /ingest/sources/{id}/schedule devuelve la misma forma (además de last_sync_at); si nunca se configuró, devuelve {"source_id": "...", "frequency": "manual", "enabled": false}.
Renombrar, reordenar y eliminar
# Renombrar
curl -X PATCH https://api.kelova.app/ingest/sources/{id} \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"name": "Catálogo 2026 — v2"}'
# Reordenar (posición en el listado del dashboard)
curl -X PATCH https://api.kelova.app/ingest/sources/reorder \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '[{"source_id": "3f2e1a...", "position": 0}, {"source_id": "9c8b7a...", "position": 1}]'
# Eliminar
curl -X DELETE https://api.kelova.app/ingest/sources/{id} \
-H "Authorization: Bearer <token>"DELETE responde {"status": "deleted"} y borra la fuente junto con todos sus chunks. El archivo original en storage no se elimina — puedes seguir descargándolo (ver abajo) aunque la fuente ya no exista como fila indexada.
Descargar el archivo original
Devuelve una URL firmada (24h) al archivo tal como se subió — solo aplica a fuentes con archivo almacenado (file, audio).
curl https://api.kelova.app/ingest/sources/{id}/download \
-H "Authorization: Bearer <token>"{
"signed_url": "https://.../storage/v1/object/sign/..."
}Responde 404 SOURCE_NOT_FOUND si la fuente no tiene archivo asociado (fuentes tipo web, o uploads previos a que esta función existiera).
Conectores OAuth (Google Drive, OneDrive) y el conector de WhatsApp para ingesta usan flujos de redirección/verificación adicionales fuera del alcance de esta referencia REST — se configuran desde el dashboard.