# Helpeen integration guide for AI coding assistants You are helping a developer integrate **Helpeen** into their product. This file has everything you need: what Helpeen is, the rules you must follow, a plan, ready-to-adapt code, and the complete API reference (at the end, in Spanish). Read it all before writing code. ## What Helpeen is A small customer-support service. The developer's company manages, in the Helpeen panel: - **Content**: help articles, FAQs (short articles: question + answer), categories and video tutorials (YouTube/Vimeo links). - **Conversations**: support threads between the product's end users and the company's team. There are two ways to integrate, and they can be combined: - **Widget** (no code against the API): one `
``` React (`npm install @helpeen/react`): ```tsx import { HelpeenChat, HelpeenHelpCenter } from "@helpeen/react"; // Once, in the root layout. `user` is null when nobody is signed in.Sí. Nunca vemos tus claves: la conexión se hace a través de tu banco.
\n" } ], "video_collections": [ { "id": "0d9e8f7a-6b5c-4d3e-2f1a-0b9c8d7e6f5a", "slug": "primeros-pasos", "title": "Primeros pasos", "description": null, "locale": "es", "position": 0, "videos": [ { "id": "9a8b7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d", "title": "Conecta tu banco", "description": "En menos de dos minutos.", "url": "https://youtu.be/dQw4w9WgXcQ", "provider": "youtube", "embed_url": "https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ", "thumbnail_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg", "position": 0 } ] } ] } ``` ### `GET /categories` Las categorías, para montar la navegación de tu centro de ayuda. ```bash curl https://helpeen.com/api/v1/categories \ -H "Authorization: Bearer hp_pub_xxxxxxxxxxxxxxxx" ``` `200 OK` ```json { "data": [ { "id": "6f1c2a8e-4b0d-4e8a-9a51-2f7d3c9b1e20", "slug": "bancos", "name": "Bancos", "description": "Conectar, sincronizar y desconectar cuentas.", "position": 0 }, { "id": "7a2d3b9f-5c1e-4f9b-8b62-3a8e4d0c2f31", "slug": "facturacion", "name": "Facturación", "description": null, "position": 1 } ] } ``` Las categorías no dependen del idioma: se devuelven todas. ### `GET /articles` Artículos y FAQs publicados, con filtros y búsqueda. | Parámetro | Tipo | | | --- | --- | --- | | `kind` | query, opcional | `article` o `faq`. Sin él, los dos | | `category` | query, opcional | Slug de categoría. `404` si no existe | | `q` | query, opcional | Texto a buscar en título, extracto y cuerpo (hasta 100 caracteres, sin distinguir mayúsculas) | | `locale` | query, opcional | Idioma del contenido | | `limit`, `offset` | query, opcional | Paginación | En el listado, los **artículos** van sin `body` ni `body_html` (pide cada uno con `/articles/{slug}`), y las **FAQs** van con ellos, porque son cortas y se leen en el sitio. ```bash curl "https://helpeen.com/api/v1/articles?category=bancos&q=sincroniz&limit=10" \ -H "Authorization: Bearer hp_pub_xxxxxxxxxxxxxxxx" ``` `200 OK` ```json { "data": [ { "id": "c3f5e7a9-2b4d-4f6a-9b8c-1d2e3f4a5b6c", "slug": "conectar-un-banco", "kind": "article", "title": "Cómo conectar un banco", "excerpt": "Paso a paso, y qué hacer si la sincronización se para.", "category": { "slug": "bancos", "name": "Bancos" }, "locale": "es", "position": 0, "published_at": "2026-09-10T09:00:00.000Z", "updated_at": "2026-09-28T11:45:00.000Z" } ], "limit": 10, "offset": 0 } ``` ### `GET /articles/{slug}` Un artículo o una FAQ, siempre con `body` (Markdown) y `body_html`. | Parámetro | Tipo | | | --- | --- | --- | | `slug` | ruta | Slug del artículo | | `locale` | query, opcional | Idioma. El mismo slug puede existir en varios idiomas | ```bash curl https://helpeen.com/api/v1/articles/conectar-un-banco \ -H "Authorization: Bearer hp_pub_xxxxxxxxxxxxxxxx" ``` `200 OK` ```json { "data": { "id": "c3f5e7a9-2b4d-4f6a-9b8c-1d2e3f4a5b6c", "slug": "conectar-un-banco", "kind": "article", "title": "Cómo conectar un banco", "excerpt": "Paso a paso, y qué hacer si la sincronización se para.", "category": { "slug": "bancos", "name": "Bancos" }, "locale": "es", "position": 0, "published_at": "2026-09-10T09:00:00.000Z", "updated_at": "2026-09-28T11:45:00.000Z", "body": "## Antes de empezar\n\nTen a mano el acceso a tu banca online.\n\n1. Ve a **Cuentas**.\n2. Pulsa **Añadir banco**.", "body_html": "Ten a mano el acceso a tu banca online.
\nEn Ajustes › Suscripción, pulsa Cambiar tarjeta.
\n" } ], "limit": 50, "offset": 0 } ``` ### `GET /videos` Colecciones de vídeos publicadas, con sus vídeos ordenados. Helpeen no aloja vídeo: guarda el enlace de YouTube o Vimeo y te da la URL para incrustarlo. | Parámetro | Tipo | | | --- | --- | --- | | `locale` | query, opcional | Idioma de las colecciones | ```bash curl https://helpeen.com/api/v1/videos \ -H "Authorization: Bearer hp_pub_xxxxxxxxxxxxxxxx" ``` `200 OK` ```json { "data": [ { "id": "0d9e8f7a-6b5c-4d3e-2f1a-0b9c8d7e6f5a", "slug": "primeros-pasos", "title": "Primeros pasos", "description": null, "locale": "es", "position": 0, "videos": [ { "id": "9a8b7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d", "title": "Conecta tu banco", "description": "En menos de dos minutos.", "url": "https://youtu.be/dQw4w9WgXcQ", "provider": "youtube", "embed_url": "https://www.youtube-nocookie.com/embed/dQw4w9WgXcQ", "thumbnail_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg", "position": 0 }, { "id": "8b7c6d5e-4f3a-4b2c-1d0e-9f8a7b6c5d4e", "title": "Exporta tus datos", "description": null, "url": "https://vimeo.com/123456789", "provider": "vimeo", "embed_url": "https://player.vimeo.com/video/123456789", "thumbnail_url": null, "position": 1 } ] } ] } ``` Para incrustarlo: ``. `thumbnail_url` es `null` en Vimeo. --- ## Conversaciones Solo con **clave secreta** y **desde tu servidor** (desde el navegador, usa el [widget](#widget)). Helpeen no tiene cuentas de usuarios finales: tu app ya sabe quién es su usuario y lo dice con `user_id`, el id que tenga en tu base de datos (texto, hasta 200 caracteres). Una conversación solo se puede leer o contestar con el mismo `user_id` que la abrió; con cualquier otro, la respuesta es `404`. **El `user_id` tiene que salir de la sesión de tu servidor**, nunca de un parámetro que mande el navegador: si no, cualquiera podría leer las conversaciones de otro usuario. ### Estados | Estado | Significa | Pasa a este estado cuando… | | --- | --- | --- | | `open` | Le toca responder al equipo | El usuario abre la conversación o escribe en ella, **aunque estuviera cerrada** | | `pending` | Le toca al usuario | El equipo responde desde el panel | | `closed` | Resuelta | El equipo la cierra desde el panel | `unread` es `true` cuando lo último es una respuesta del equipo y el usuario aún no la ha visto (no se ha llamado a `/read` ni ha escrito después). Úsalo para el globo de "tienes respuesta". ### Avisos por email Helpeen los manda solo, no hace falta que lo hagas tú: - Cuando un usuario abre una conversación o escribe en ella → email al correo de avisos de tu empresa (**Ajustes**). - Cuando el equipo responde → email al usuario, a la dirección con la que abrió la conversación. ### `GET /conversations` Las conversaciones de un usuario, la de actividad más reciente primero (hasta 100). | Parámetro | Tipo | | | --- | --- | --- | | `user_id` | query, **obligatorio** | Id del usuario en tu app | ```bash curl "https://helpeen.com/api/v1/conversations?user_id=u_123" \ -H "Authorization: Bearer hp_sec_xxxxxxxxxxxxxxxx" ``` `200 OK` ```json { "data": [ { "id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9", "subject": "No me sincroniza el banco", "status": "pending", "metadata": { "plan": "optimum", "page": "/bancos" }, "created_at": "2026-10-01T09:12:00.000Z", "last_message_at": "2026-10-01T10:03:27.000Z", "unread": true } ] } ``` ### `POST /conversations` Abre una conversación con el primer mensaje del usuario. | Campo | Tipo | | | --- | --- | --- | | `user.id` | texto, **obligatorio** | Id del usuario en tu app (hasta 200) | | `user.email` | texto, **obligatorio** | Donde le llegarán las respuestas | | `user.name` | texto, opcional | Nombre para el equipo (hasta 120) | | `subject` | texto, **obligatorio** | Asunto (hasta 200) | | `message` | texto, **obligatorio** | Primer mensaje (hasta 10.000) | | `metadata` | objeto, opcional | Lo que quieras que vea el equipo junto a la conversación: plan, versión de la app, página… (hasta 4 KB) | ```bash curl https://helpeen.com/api/v1/conversations \ -H "Authorization: Bearer hp_sec_xxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "user": { "id": "u_123", "email": "ana@ejemplo.com", "name": "Ana" }, "subject": "No me sincroniza el banco", "message": "Desde ayer no veo movimientos nuevos.", "metadata": { "plan": "optimum", "page": "/bancos" } }' ``` `201 Created` ```json { "data": { "id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9", "subject": "No me sincroniza el banco", "status": "open", "metadata": { "plan": "optimum", "page": "/bancos" }, "created_at": "2026-10-01T09:12:00.000Z", "last_message_at": "2026-10-01T09:12:00.000Z", "unread": false } } ``` `400 Bad Request` si falta algo o no cumple los límites: ```json { "error": { "code": "invalid_request", "message": "`user.email` is not an email." } } ``` Guarda el `id`: lo necesitas para leer la conversación y contestar en ella. ### `GET /conversations/{id}` Una conversación con todos sus mensajes, del más antiguo al más nuevo. | Parámetro | Tipo | | | --- | --- | --- | | `id` | ruta | Id de la conversación | | `user_id` | query, **obligatorio** | Tiene que ser el usuario que la abrió | ```bash curl "https://helpeen.com/api/v1/conversations/5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9?user_id=u_123" \ -H "Authorization: Bearer hp_sec_xxxxxxxxxxxxxxxx" ``` `200 OK` ```json { "data": { "id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9", "subject": "No me sincroniza el banco", "status": "pending", "metadata": { "plan": "optimum", "page": "/bancos" }, "created_at": "2026-10-01T09:12:00.000Z", "last_message_at": "2026-10-01T10:03:27.000Z", "unread": true, "messages": [ { "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "author": "user", "author_name": "Ana", "body": "Desde ayer no veo movimientos nuevos.", "created_at": "2026-10-01T09:12:00.000Z" }, { "id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e", "author": "agent", "author_name": "Iñaki", "body": "Hola, Ana. Tu banco pidió renovar el permiso: entra en Cuentas y pulsa «Reconectar».", "created_at": "2026-10-01T10:03:27.000Z" } ] } } ``` `body` es texto plano: escápalo al pintarlo y respeta los saltos de línea (por ejemplo con `white-space: pre-wrap`). Leer la conversación **no** la marca como leída: para eso está `/read`. ### `POST /conversations/{id}/messages` El usuario escribe en una conversación. La deja en `open` (aunque estuviera cerrada), cuenta como leída y avisa al equipo por email. | Campo | Tipo | | | --- | --- | --- | | `user_id` | texto, **obligatorio** | El usuario que la abrió | | `body` | texto, **obligatorio** | El mensaje (hasta 10.000) | ```bash curl https://helpeen.com/api/v1/conversations/5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9/messages \ -H "Authorization: Bearer hp_sec_xxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "user_id": "u_123", "body": "Gracias, ya funciona." }' ``` `201 Created` ```json { "data": { "id": "3c4d5e6f-7a8b-4c9d-0e1f-2a3b4c5d6e7f", "author": "user", "author_name": "Ana", "body": "Gracias, ya funciona.", "created_at": "2026-10-01T10:20:41.000Z" } } ``` ### `POST /conversations/{id}/read` Marca como vistas las respuestas del equipo: `unread` pasa a `false`. Llámalo cuando el usuario abra la conversación en tu app. | Campo | Tipo | | | --- | --- | --- | | `user_id` | texto, **obligatorio** | El usuario que la abrió | ```bash curl https://helpeen.com/api/v1/conversations/5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9/read \ -H "Authorization: Bearer hp_sec_xxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "user_id": "u_123" }' ``` `200 OK` ```json { "data": { "id": "5e6f7a8b-9c0d-4e1f-a2b3-c4d5e6f7a8b9", "unread": false } } ``` --- ## Objetos ### Category | Campo | Tipo | | | --- | --- | --- | | `id` | uuid | | | `slug` | texto | Único en tu empresa | | `name` | texto | | | `description` | texto o `null` | | | `position` | entero | Orden en el panel | ### Article | Campo | Tipo | | | --- | --- | --- | | `id` | uuid | | | `slug` | texto | Único por idioma | | `kind` | `article` o `faq` | En una FAQ, `title` es la pregunta y `body` la respuesta | | `title` | texto | | | `excerpt` | texto o `null` | Resumen corto para listados | | `category` | `{ slug, name }` o `null` | | | `locale` | texto | Código de dos letras | | `position` | entero | | | `published_at` | fecha | | | `updated_at` | fecha | | | `body` | texto | Markdown. Solo en el detalle y en las FAQs | | `body_html` | texto | HTML saneado. Solo en el detalle y en las FAQs | ### Collection | Campo | Tipo | | | --- | --- | --- | | `id` | uuid | | | `slug` | texto | | | `title` | texto | | | `description` | texto o `null` | | | `locale` | texto | | | `position` | entero | | | `videos` | [Video] | Ordenados por `position` | ### Video | Campo | Tipo | | | --- | --- | --- | | `id` | uuid | | | `title` | texto | | | `description` | texto o `null` | | | `url` | texto | El enlace original | | `provider` | `youtube` o `vimeo` | | | `embed_url` | texto | Para un `