# La API REST > Envía contenido desde tu propio código con una clave de API, y comprueba qué pasó. Source: https://welcomeai.dev/es/docs/rest-ingest Category: Integraciones Updated: 2026-09-11 --- ## Qué hace Envía documentos a una base de conocimiento desde tu propio código. Una petición por documento, o hasta veinticinco a la vez. Es la opción correcta cuando controlas quién hace la petición: un script, un proceso del backend, un paso del build. Si quien la hace es una herramienta sin código, usa el webhook de sincronización: los mismos documentos, la misma forma de endpoint, una firma en lugar de una clave para que la herramienta no tenga credenciales que guardar. ## A qué puede acceder Exactamente a lo que permiten sus permisos, en el espacio al que pertenece la clave, y a nada de fuera. Una clave fijada a una base de conocimiento no puede escribir en otra. ## Qué necesitas antes de empezar - Un espacio de WelcomeAI en plan **Pro** o superior. - Una clave de API con el permiso `ingest:write`. - El id de una base de conocimiento, que sale de su URL. ## Autenticación `Authorization: Bearer wai_live_…`, por HTTPS. La clave se muestra una sola vez al crearla: guardamos solo un hash, así que no hay nada que consultar si se pierde. Ponla en tu gestor de contraseñas o en los secretos de tu despliegue enseguida, y dale el conjunto de permisos más pequeño que funcione. ## Configurarlo ```bash curl -X POST 'https://app.welcomeai.dev/api/v1/ingest' \ -H "Authorization: Bearer $WELCOMEAI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "kb_id": "kb_…", "external_id": "faq-reembolsos", "title": "Reembolsos", "url": "https://acme.com/ayuda/reembolsos", "content_md": "# Reembolsos\n\nDentro de 14 días, escribe a billing@acme.com." }' ``` `external_id` es tu identificador del documento. Volver a enviar el mismo lo actualiza en vez de crear una copia, que es lo que hace seguros los reintentos y baratas las repeticiones. Acertar con él es la decisión más importante de aquí. Envía `{"external_id": "…", "action": "delete"}` para eliminar uno. La lista completa de campos, la forma del lote, la respuesta, cada código de error y las reglas de reintento están en la guía del webhook de sincronización: el cuerpo es idéntico y solo cambia la autenticación. ## Cómo funciona la sincronización No hay horario: envías cuando tienes algo. Nada sondea y nada se ejecuta de nuestro lado si no llamas. Envía `content_hash` con cada elemento si puedes. Un hash sin cambios se salta la reindexación entera, así que reenviar cada noche un corpus grande no cuesta casi nada. ### Por qué no hay una "API REST" que añadir No la vas a encontrar en **Añadir fuente**, y no es un olvido. La fuente aparece sola en Fuentes conectadas la primera vez que llega algo: no hay nada que añadir, porque la iniciativa es enteramente tuya. Por lo mismo casi no tiene ajustes. Un rastreo guarda una dirección, una periodicidad y un límite de páginas, y los tres responden a "¿qué vamos a leer?", una pregunta que una fuente de tipo push no hace nunca. Eso es cosa de tu código. Aquí puedes cambiar su nombre, ahí mismo en la lista, y una cosa en **Ajustes**: la dirección del sitio. ### Dirección del sitio Opcional, y solo se usa cuando un elemento llega con una `url` relativa como `/help/refunds`. Esa página se enlaza entonces bajo la dirección que indiques, para que una respuesta que la cite abra la página correcta. Sin ella, una `url` relativa se guarda como si no hubiera URL: el documento se indexa igual y se responde con él, pero la cita lleva título y no lleva enlace. No adivinamos un origen, porque una cita que va a la página equivocada es peor que una que no es un enlace: el widget corre en la página de **tu** visitante, así que un enlace relativo abriría una ruta del sitio que esa persona esté leyendo. Una `url` absoluta se guarda siempre tal cual, diga lo que diga la dirección del sitio. Enviar URLs absolutas sigue siendo la mejor costumbre; esto es lo que salva el caso en que no puedes. Las **ejecuciones** de sincronización también se quedan vacías. Una ejecución registra que fuimos a buscar algo, y nunca vamos. El **registro** de sincronización es el que hay que mirar: recibe una fila por cada elemento que empujas, creado, cambiado o borrado, y ahí es donde aparece un elemento rechazado. Borrar la fuente pregunta si conservar sus documentos. Vuelve a aparecer la próxima vez que empujes algo, así que borrarla sirve para desvincular los documentos, no para apagar el endpoint: para eso, revoca la clave de API. ## Qué se importa Lo que envíes: `content_md` (preferido) o `content_html`, que se convierte. Hasta 2 MB por documento. `title` es la etiqueta de la cita y `url` su enlace; los dos son opcionales y los dos vale la pena ponerlos, porque un "Sin título" en una cita hace que una respuesta correcta parezca poco fiable. ## Cómo se gestionan las actualizaciones Por `external_id`. Mismo id, mismo documento. Un documento que dejas de enviar **no** se elimina solo: no tenemos forma de saber si querías borrarlo o simplemente no lo mencionaste esta vez. Envía un borrado explícito. ## Para qué se usa Sincronizar desde un CMS del que no tenemos conector. Enviar contenido generado -- notas de versión, un changelog, una página de estado -- como parte de un build. Mantener una base al día desde un sistema interno que ya sabe cuándo cambian sus registros. ## Cómo comprobar que funciona La respuesta te dice por elemento: `created`, `updated`, `unchanged`, `deleted`, `missing` o `failed`. Mira `unchanged`: en una sincronización completa repetida casi todo debería decirlo. Si todo dice `updated`, algo en tu proceso reescribe el contenido en cada pasada y estás pagando por volver a incrustar el mismo texto. Todo queda también en el Registro de sincronización con los recuentos por ejecución, y los documentos aparecen en la base con su título. ## Errores habituales **401**: la clave está mal, revocada, o le falta el prefijo `Bearer `. **403**: la clave no tiene `ingest:write`, o está fijada a otra base de conocimiento distinta de la de `kb_id`. **400 `invalid_input`**: falta un campo o tiene la forma equivocada; el mensaje lo nombra. La causa habitual es que un elemento que no es un borrado no lleva ni `content_md` ni `content_html`. **402**: un límite del plan. Documentos o almacenamiento, y el mensaje dice cuál. **413**: el cuerpo pasa de 4 MB, o un elemento de 2 MB. Divide el lote. ## Reconectar Revoca la clave vieja, crea otra y vuelve a desplegar con ella. Nada de lo ya enviado se ve afectado: los documentos pertenecen a la base de conocimiento, no a la clave que los creó. ## Desconectar Deja de llamar, y revoca la clave para que no pueda usarla algo que hayas olvidado. Los documentos se quedan y siguen respondiendo. Para eliminarlos, borra la fuente en Fuentes conectadas.