---
name: bentho-api
description: Usa la API v1 de Bentho para preguntar a los documentos de un espacio (con fuentes y confianza), subir o quitar documentos, ajustar la configuración, consultar créditos y, con sus módulos, armar fichas con datos de la web (Fuentes) o crear landings desde un brief (Landings). Úsala cuando la tarea mencione Bentho, una clave bth_, bentho.org/api o un «espacio» de Bentho.
---

# Bentho API v1

Documentación completa: https://dev.bentho.org · Texto para modelos: https://dev.bentho.org/llms-full.txt

## Lo básico

- Base: `https://bentho.org/api`
- Autenticación: `Authorization: Bearer bth_<id>.<secreto>`. Léela SIEMPRE de la variable de entorno `BENTHO_KEY`; nunca la escribas en el código ni la muestres.
- JSON salvo la subida de documentos (multipart) y el stream (SSE).
- Llama desde un servidor: la API no admite llamadas desde el navegador (CORS).
- Timeout de cliente: 60 s o más. Una pregunta tarda de 2 a 20 s.

## Qué ruta usar

| Tarea                                     | Ruta                                                                                         | Permiso       |
| ----------------------------------------- | -------------------------------------------------------------------------------------------- | ------------- |
| Saber a qué espacios llega la clave (ids) | `GET /api/companies` → `companies[].id`                                                      | cualquiera    |
| Preguntar                                 | `POST /api/rag/{espacio}/conversations` con `{"question", "session_id"}`                     | lee           |
| Preguntar mostrando el texto en vivo      | `POST /api/rag/{espacio}/conversations/stream` (SSE)                                         | lee           |
| Listar documentos                         | `GET /api/rag/{espacio}/documents`                                                           | lee           |
| Subir documentos (.pdf .docx .txt .md)    | `POST /api/rag/{espacio}/load_documents`, multipart, campo `files` repetible                 | escribe       |
| Saber si lo subido ya está listo          | `GET /api/rag/{espacio}/indexing_status` hasta `status` = `done` o `error`                   | lee           |
| Quitar un documento                       | `DELETE /api/rag/{espacio}/documents/{archivo}`                                              | escribe       |
| Leer / ajustar cómo responde              | `GET` / `PATCH /api/rag/{espacio}/config`                                                    | lee / escribe |
| Límites, cuota diaria, IPs del espacio    | `GET` / `PATCH /api/companies/{espacio}/api-config`                                          | lee / escribe |
| Créditos                                  | `GET /api/companies/{espacio}/cuenta` → `cuenta.id`, luego `GET /api/cuentas/{cuenta}/bolsa` | lee           |
| Armar una ficha con datos de la web       | `POST /api/mod/fuentes/{espacio}/fichas` con `{"tema", "plantilla"}` → 202 con `id`          | escribe       |
| Seguir una ficha                          | `GET /api/mod/fuentes/{espacio}/fichas/{ficha}` hasta `status` = `publicado` o `fallido`     | lee           |
| Leer la ficha armada                      | `GET /api/mod/fuentes/{espacio}/fichas/{ficha}/markdown`                                     | lee           |
| Crear una landing desde un brief          | `POST /api/mod/landing/{espacio}/landings` con `{"prompt", "submitUrl"}` → 202 con `id`      | escribe       |
| Seguir una landing                        | `GET /api/mod/landing/{espacio}/landings/{landing}` hasta que `status` termine               | lee           |
| Bajar el HTML de una landing              | `GET /api/mod/landing/{espacio}/landings/{landing}/html`                                     | lee           |

## Preguntar bien

- `session_id` es OBLIGATORIO en la práctica (sin él: 400 `"session_id es obligatorio."`). Usa uno por conversación y reúsalo en las preguntas de seguimiento.
- Respuesta: `status_code` `"1000"` = respondió con apoyo en los documentos; `"1001"` = no hay información suficiente, `response` trae el mensaje de rechazo y `sources` va vacío. No reintentes un 1001: dará lo mismo.
- `warning: true` = respaldo parcial; dilo al presentar la respuesta. `confidence` va de 0 a 1.
- `sources` son los documentos citados; `response` termina con el pie «Referencia: …».
- Un error interno llega como 200 con `status_code` `"1001"` y el texto «Ocurrió un error interno procesando la consulta. Intenta de nuevo.»: ahí sí puedes reintentar una vez.

## Stream (SSE)

Tramas `data: {json}` separadas por una línea en blanco. Ignora las líneas que empiezan por `:` (keepalive cada 15 s). Eventos: `status`, `chunk` (`content`), `handoff`, `done` (`status_code`, `full_response`, `confidence`, `warning`, `sources`) y `error` (`content`, cierra el stream). Decide con el `status_code` del `done`, no con los `chunk`.

## Fuentes (módulo)

Solo en espacios con el módulo `fuentes` (sale en `GET /api/companies`); si no, 403 `módulo no habilitado para este espacio.`. Guía: https://dev.bentho.org/api/fuentes/

- La plantilla es markdown: `## Sección` y una línea `- Nombre: qué buscar` por campo. Sin secciones con campos: 422.
- Armar responde 202 al momento; la ficha tarda minutos. Consulta el estado cada 10-15 s. Al quedar `publicado`, ya está en los documentos del espacio (`ficha-<tema>.md`) y Bentho la usa al responder. Otra ficha con el mismo tema la reemplaza.
- Cada dato del markdown lleva `Fuente` y `Cita`; los vacíos dicen «sin respaldo en las páginas leídas». No rellenes tú los vacíos.
- Si llenó menos de la mitad, `traza.sugerencia` lo dice: pide a la persona 2-4 URLs del caso y vuelve a armarla con `urls`.
- Armar una ficha y lanzar una fuente gastan créditos (402 sin saldo).

## Landings (módulo)

Solo en espacios con el módulo `landing` (sale en `GET /api/companies`); si no, 403 `módulo no habilitado para este espacio.`. Guía: https://dev.bentho.org/api/landings/

- Crear responde 202 al momento; la landing tarda minutos. Consulta el estado cada 10-15 s. No vuelvas a crearla para «reintentar»: gastarías otra vez.
- `status`: `pendiente`, `generando`, `aplazado` (sigue sola) → espera. `esperando_datos` → enseña a la persona las `pregunta` de `versiones[0].faltantes` y manda sus respuestas a `POST …/landings/{landing}/completar` con `{"respuestas": {clave: texto}, "omitir": [clave]}`. No inventes las respuestas. `aprobado` → lista. `revision` → hay HTML, pero `calidad.motivos` dice qué no pasó. `fallido` / `cancelado` → mira `error`.
- Cambios: `POST …/refinar` con `{"prompt": "qué cambiar"}`. Una sola versión en curso por landing (409). Cancelar: `POST …/cancelar`.
- El formulario envía JSON a `submitUrl` desde el navegador y espera `{"success": true}`: si está en otro dominio, necesita CORS.
- Crear, refinar, validar y completar gastan créditos (402 sin saldo).

## Errores: qué hacer

Siempre `{"detail": "…"}` (422: lista; 402: objeto con `motivo`).

| Status          | Qué hacer                                                                                                                                                                                            |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 401             | Clave ausente, inválida o revocada. No reintentes: pide una clave válida.                                                                                                                            |
| 402             | `motivo` `pago_vencido`/`suspension_comercial` (cuenta) o `bolsa_agotada` (créditos, trae `renueva`). No reintentes.                                                                                 |
| 403             | Espacio fuera de alcance, prueba vencida, API apagada, IP no autorizada, clave `lee` en una escritura, campo que solo cambia Bentho, módulo que el espacio no tiene. Lee el `detail`; no reintentes. |
| 404 / 405 / 422 | Corrige la petición.                                                                                                                                                                                 |
| 413             | Subida > 200 MB, > 20 archivos o un archivo > 50 MB. Divide.                                                                                                                                         |
| 429             | Espera `Retry-After` (segundos) y reintenta. Sin la cabecera: espera creciente.                                                                                                                      |
| 502 / 503       | Reintenta 2-3 veces con espera creciente.                                                                                                                                                            |

## Límites y créditos

- 120 peticiones por minuto por clave (ventana deslizante). Por espacio: 2/s con ráfaga de 120 por defecto y cuota diaria opcional (UTC), configurables en `api-config`.
- Gastan créditos las preguntas, la indexación, las fichas de Fuentes y las landings; sin créditos, 402 en preguntar, subir, armar fichas y crear o refinar landings. `gastados` y `restantes` de la bolsa son TEXTO decimal (`"0.3426"`): conviértelos con un tipo decimal.

## No hagas

- No inventes rutas ni campos: si no está aquí, consulta https://dev.bentho.org/llms-full.txt.
- No cambies `activa` a `false` en `api-config` con la misma clave con la que trabajas: te dejas fuera.
- No uses una clave `escribe` si la tarea solo pregunta o lee.
