{
  "formatVersion": 1,
  "language": "es",
  "instructions": [
    "Elige el idioma del lector, lee el flujo y el endpoint pertinentes y consulta su contrato OpenAPI exacto. Cita las fuentes utilizadas. Estos exports no autorizan solicitudes de negocio reales.",
    "Conserva los hosts, métodos, rutas, autenticación, nombres de campos, tipos, campos obligatorios y anulables, enums, valores predeterminados, límites y códigos de respuesta publicados. Las traducciones describen la misma API."
  ],
  "schemaScope": "Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.",
  "specs": [
    {
      "title": "Bridge API",
      "url": "https://docs.bridge.new/es/api-reference/openapi.yaml",
      "source": "es/api-reference/openapi.yaml"
    },
    {
      "title": "Bridge Campaign Leads API",
      "url": "https://docs.bridge.new/es/api-reference/campaign-leads.openapi.yaml",
      "source": "es/api-reference/campaign-leads.openapi.yaml"
    }
  ],
  "format": "bridge-documentation-collection",
  "title": "Bridge Documentación recopilada — Español",
  "description": "Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.",
  "indexUrl": "https://docs.bridge.new/llms-es.json",
  "pages": [
    {
      "title": "Integra tus sistemas con Bridge",
      "source": "https://docs.bridge.new/es/index",
      "markdownUrl": "https://docs.bridge.new/es/index.md",
      "description": "Conecta tu CRM, automatizaciones o landing page mediante la API REST, los webhooks y Custom Connections.",
      "kind": "page",
      "contentMarkdown": "Implementa con tu herramienta de programación preferida\n\n## Conecta tu asistente de programación con IA\n\nDale a tu herramienta de programación la documentación actual de Bridge. Elígela abajo para ver la configuración, un ejemplo de prompt y la prueba de conexión.\n\n  [Codex →](https://docs.bridge.new/es/connect-your-agent.md#codex)\n  [Claude Code →](https://docs.bridge.new/es/connect-your-agent.md#claude-code)\n  [Cursor →](https://docs.bridge.new/es/connect-your-agent.md#cursor)\n  [GitHub Copilot →](https://docs.bridge.new/es/connect-your-agent.md#github-copilot)\n\nLeer la documentación no requiere una clave de API de Bridge. El acceso al espacio de trabajo se configura por separado.\n\n## Elige tu integración\n\n  \n\n    \n\n### [API REST](https://docs.bridge.new/es/credentials.md)\n\n      Crea contactos, conversaciones y mensajes desde tu servidor.\n\n      **Acceso:** `x-api-key` desde el servidor.\n    \n\n    \n\n### [Webhooks](https://docs.bridge.new/es/webhooks.md)\n\n      Recibe eventos de Bridge en tu endpoint HTTPS.\n\n      **Acceso:** verifica las credenciales del webhook y su vigencia.\n    \n\n    \n\n### [Custom Connections](https://docs.bridge.new/es/lead-capture/index.md)\n\n      Captura leads de landing pages y encola un mensaje inicial de WhatsApp.\n\n      **Acceso:** `captureKey` y reCAPTCHA; sin clave de la API REST.\n    \n\n  \n\n## Haz tu primera solicitud a la API REST\n\n  \n\n### Obtén tus credenciales de API\n\n    Sigue la guía de [autenticación](https://docs.bridge.new/es/credentials.md) para generar una clave de API en la consola de administración de Bridge. Si necesitas acceso, pídeselo al administrador de Bridge. Guarda la clave en tu servidor.\n  \n\n  \n\n### Comprueba la conexión\n\n    Usa el encabezado `x-api-key` para llamar a la [comprobación de estado](https://docs.bridge.new/es/api-reference/health/comprobar-estado.md) autenticada en `https://api-connect-us.bridge.new/bridge/api/health`.\n\n    Continúa en la pestaña **API REST**. Cada endpoint detalla sus campos, respuestas y ejemplos.\n  \n\n**Nota**\n\n  Custom Connections usa otro endpoint y una `captureKey` pública. Sigue su [guía de integración](https://docs.bridge.new/es/lead-capture/integration.md). Un `202` confirma la aceptación de la solicitud, no la entrega del mensaje de WhatsApp.\n\n## Implementa a partir del contrato publicado\n\n- [Crea un contacto y envía un mensaje](https://docs.bridge.new/es/guides/first-conversation.md): sigue el flujo completo de contacto → conversación → mensaje.\n- [Envía un PDF u otro adjunto](https://docs.bridge.new/es/guides/send-attachments.md): checksum, URL de carga, carga del archivo y mensaje.\n- [Envía una plantilla de WhatsApp](https://docs.bridge.new/es/guides/send-template.md): consulta las variables y proporciona los valores que debe aportar quien hace la solicitud.\n- [Inicia una conversación saliente con un agente y transfiérela](https://docs.bridge.new/es/guides/agent-outbound.md): elige un agente y entiende `forceSend`, la reutilización y la recuperación.\n- [Consulta los identificadores](https://docs.bridge.new/es/guides/identifiers.md) y [recorre los resultados paginados](https://docs.bridge.new/es/guides/pagination.md): usa los IDs y cursores correctos.\n- [Límites de solicitudes](https://docs.bridge.new/es/rate-limits.md): administra el presupuesto compartido y maneja respuestas `429`.\n- [Códigos de error](https://docs.bridge.new/es/error-codes.md): interpreta los errores de la API REST. Custom Connections tiene su propia [referencia de errores](https://docs.bridge.new/es/lead-capture/errors.md).\n- [Parámetros de plantillas de WhatsApp](https://docs.bridge.new/es/templates-and-parameters.md): abre conversaciones con plantillas y proporciona sus variables.\n- [Registro de cambios](https://docs.bridge.new/es/changelog.md): revisa los cambios que afectan las integraciones.\n\nLee sin MCP mediante el [índice trilingüe](https://docs.bridge.new/llms.txt), el [índice en español](https://docs.bridge.new/llms-es.json), la [documentación reunida en español](https://docs.bridge.new/llms-full-es.json) o la [guía para agentes de IA](https://docs.bridge.new/skill.md). Consulta los esquemas exactos en el [OpenAPI de integraciones REST](https://docs.bridge.new/es/api-reference/openapi.yaml) o el [OpenAPI de Custom Connections](https://docs.bridge.new/es/api-reference/campaign-leads.openapi.yaml).\n\nSi necesitas ayuda para usar la aplicación Bridge, visita el [Centro de ayuda](https://help.bridge.new).\n"
    },
    {
      "title": "Conecta tu asistente de programación con IA",
      "source": "https://docs.bridge.new/es/connect-your-agent",
      "markdownUrl": "https://docs.bridge.new/es/connect-your-agent.md",
      "description": "Conecta Codex, Claude Code, Cursor o GitHub Copilot a la documentación actual de Bridge e implementa a partir del contrato exacto de la API.",
      "kind": "page",
      "contentMarkdown": "Dale a tu asistente acceso a la documentación actual de Bridge antes de pedirle que construya tu integración. Elige tu herramienta, agrega el endpoint público MCP y comprueba la conexión.\n\n| Configuración | Valor |\n| --- | --- |\n| URL del servidor | `https://docs.bridge.new/mcp` |\n| Conexión | HTTP remoto / Streamable HTTP |\n| Nombre local sugerido | `bridgeDocs` |\n| Credenciales de Bridge | No se necesitan para este servidor de documentación |\n\n**Nota**\n\n  Esto conecta tu asistente a la **documentación de Bridge**. No lo conecta a tu espacio de trabajo ni le da permiso para crear contactos o enviar mensajes. Tu integración usa por separado las [credenciales de la API REST](https://docs.bridge.new/es/credentials.md) o la configuración pública de [Custom Connections](https://docs.bridge.new/es/lead-capture/index.md). El servidor de documentación también ofrece una herramienta opcional para enviar comentarios sobre la documentación a Bridge.\n\n## Elige tu asistente de programación\n\n  \n\n### [Codex](https://docs.bridge.new/es/connect-your-agent.md#codex)\n\nConfiguración de CLI y del IDE local.\n\n  \n\n### [Claude Code](https://docs.bridge.new/es/connect-your-agent.md#claude-code)\n\nAgrega un comando y comprueba la conexión.\n\n  \n\n### [Cursor](https://docs.bridge.new/es/connect-your-agent.md#cursor)\n\nAgrega el servidor al archivo MCP de tu proyecto.\n\n  \n\n### [GitHub Copilot](https://docs.bridge.new/es/connect-your-agent.md#github-copilot)\n\nConfiguración guiada en VS Code o configuración portátil del proyecto.\n\n## Codex\n\n**Antes de comenzar:** debes tener instalado Codex CLI o la extensión de Codex para tu IDE. Para la CLI, agrega el servidor desde la terminal:\n\n```bash\ncodex mcp add bridgeDocs --url https://docs.bridge.new/mcp\ncodex mcp list\n```\n\nLa lista debe incluir `bridgeDocs` con la URL de documentación de Bridge. Que aparezca confirma la configuración; usa [la comprobación de conexión](https://docs.bridge.new/es/connect-your-agent.md#check-the-connection) para confirmar que realmente puede leer la documentación.\n\nSi prefieres editar la configuración, agrega esta entrada a `~/.codex/config.toml`. Conserva las demás opciones y los otros servidores:\n\n```toml\n[mcp_servers.bridgeDocs]\nurl = \"https://docs.bridge.new/mcp\"\n```\n\nReinicia el cliente o la extensión después de cambiar su configuración. En la interfaz de terminal de Codex, `/mcp` muestra los servidores activos. Los clientes locales de Codex pueden compartir la configuración en el mismo equipo; los entornos remotos pueden tener configuraciones y políticas independientes.\n\n**Ejemplo de prompt:**\n\n> Usa bridgeDocs para leer el contrato REST de Bridge y la guía de primera conversación. Prepara una integración en Node.js que cree un contacto, inicie una conversación y cree un mensaje. Enumera primero los identificadores y la configuración necesarios. Conserva todos los campos y tipos de la API, cita tus fuentes y no hagas solicitudes reales a la API.\n\n[Guía oficial de MCP para Codex](https://learn.chatgpt.com/docs/extend/mcp?surface=cli).\n\n## Claude Code\n\n**Antes de comenzar:** debes tener instalado Claude Code. Agrega el servidor a tu configuración personal para usarlo en distintos proyectos:\n\n```bash\nclaude mcp add --transport http bridgeDocs --scope user https://docs.bridge.new/mcp\nclaude mcp list\n```\n\nSi prefieres una configuración compartida del proyecto, usa `--scope project` en lugar de `--scope user`. Revisa la configuración resultante antes de guardarla en el repositorio.\n\nInicia Claude Code y usa `/mcp` para inspeccionar `bridgeDocs`. Después ejecuta [la comprobación de conexión](https://docs.bridge.new/es/connect-your-agent.md#check-the-connection). El endpoint de documentación de Bridge no necesita una clave de API de Bridge ni iniciar sesión con OAuth.\n\n**Ejemplo de prompt:**\n\n> Usa bridgeDocs para leer las guías actuales de verificación y recepción de webhooks de Bridge. Implementa un receptor en Python con la representación HMAC documentada y aceptación duradera antes de confirmar la recepción. Agrega pruebas sin conexión usando el vector de firma publicado. Explica la limitación de la marca de tiempo y el manejo de duplicados, y cita las páginas utilizadas.\n\n[Guía oficial de MCP para Claude Code](https://code.claude.com/docs/en/mcp).\n\n## Cursor\n\n**Antes de comenzar:** abre tu proyecto de integración en Cursor. Crea o actualiza `.cursor/mcp.json` en ese proyecto. Combina la entrada con los servidores existentes:\n\n```json\n{\n  \"mcpServers\": {\n    \"bridgeDocs\": {\n      \"url\": \"https://docs.bridge.new/mcp\"\n    }\n  }\n}\n```\n\nPara una configuración personal entre proyectos, usa `~/.cursor/mcp.json`. En la barra lateral **Customize** de Cursor, comprueba que el servidor esté habilitado. Abre una conversación de Agent y ejecuta [la comprobación de conexión](https://docs.bridge.new/es/connect-your-agent.md#check-the-connection); las herramientas MCP pertinentes aparecen en **Available Tools**. Revisa las solicitudes de uso de herramientas cuando Cursor te lo pida.\n\n**Ejemplo de prompt:**\n\n> Usa bridgeDocs para encontrar el flujo completo de adjuntos PDF. Implementa una carga desde el servidor que calcule el SHA-256 en Base64 de los bytes exactos del archivo, solicite una carga prefirmada, ejecute el PUT obligatorio y cree un mensaje con el mediaId devuelto. Conserva los campos documentados y explica cómo manejar los fallos de cada etapa. No envíes una clave de API de Bridge a la URL de carga.\n\n[Guía oficial de MCP para Cursor](https://cursor.com/docs/mcp).\n\n## GitHub Copilot\n\n**Antes de comenzar:** habilita GitHub Copilot en VS Code y abre la carpeta de tu proyecto. Selecciona **Copilot** como destino de la sesión.\n\n1. Abre la paleta de comandos con `Command` + `Shift` + `P` en macOS o `Ctrl` + `Shift` + `P` en Windows/Linux.\n2. Ejecuta **MCP: Add Server** y elige **HTTP (HTTP or Server-Sent Events)**.\n3. Introduce `https://docs.bridge.new/mcp` y llama al servidor `bridgeDocs`.\n4. Elige **Global → Copilot Global** para tu configuración personal, cuando esté disponible. Revisa el destino que muestra tu versión de VS Code y cualquier solicitud de confianza del servidor.\n5. Abre una conversación de Copilot, habilita las herramientas de documentación de Bridge para esa sesión y ejecuta [la comprobación de conexión](https://docs.bridge.new/es/connect-your-agent.md#check-the-connection).\n\nPara un proyecto compartido con la configuración portátil actual de Copilot, crea o combina esta entrada en `.mcp.json`, en la raíz del espacio de trabajo:\n\n```json\n{\n  \"mcpServers\": {\n    \"bridgeDocs\": {\n      \"type\": \"http\",\n      \"url\": \"https://docs.bridge.new/mcp\",\n      \"tools\": [\"*\"]\n    }\n  }\n}\n```\n\nEl formato portátil de Copilot anterior difiere de `.vscode/mcp.json`, administrado por el editor, que usa un objeto `servers`. Usa el archivo correspondiente a la conexión elegida; no mezcles ambos formatos. Si el destino portátil no está disponible en tu versión, usa la configuración guiada y el archivo que seleccione.\n\n**Ejemplo de prompt:**\n\n> Usa bridgeDocs para leer la guía de Custom Connections y su contrato OpenAPI independiente. Prepara un formulario de landing page que registre el consentimiento, obtenga un token CAPTCHA nuevo en cada intento y presente un 202 como aceptado con su requestId. Conserva captureKey, los campos de solicitud y la acción CAPTCHA configurada. No uses una clave de la API REST en la página.\n\n[Configuración oficial de VS Code](https://code.visualstudio.com/docs/agent-customization/mcp-servers) · [Referencia de configuración de Copilot](https://code.visualstudio.com/docs/agents/reference/mcp-configuration).\n\n## Comprueba la conexión\n\nDespués de configurar cualquiera de los cuatro clientes, pregunta lo siguiente:\n\n> Usa el servidor MCP de documentación de Bridge para buscar cómo crear un mensaje. Lee el esquema MessageRequest en el OpenAPI REST publicado. ¿Qué tres campos son obligatorios y un 201 exitoso demuestra la entrega por WhatsApp? Cita la fuente exacta de Bridge que leíste. No llames a la API de negocio.\n\nUna comprobación exitosa usa una herramienta de documentación y cita una página o esquema de Bridge. Debe identificar `conversationId`, `messageBody` y `enableExternalBroadcast` como obligatorios y distinguir un mensaje creado de una confirmación de entrega del proveedor. Una respuesta plausible sin uso de herramientas ni fuente no es una prueba de conexión.\n\n## Lee la documentación con cualquier IA, sin MCP\n\nNo necesitas conectar MCP para leer la documentación de Bridge. Dale a un asistente que pueda abrir URLs el [índice trilingüe de documentación](https://docs.bridge.new/llms.txt) y elige las fuentes para tu tarea e idioma:\n\n| Idioma | Índice de páginas | Documentación reunida |\n| --- | --- | --- |\n| English | [English index](https://docs.bridge.new/llms-en.json) | [English collection](https://docs.bridge.new/llms-full-en.json) |\n| Español | [Índice en español](https://docs.bridge.new/llms-es.json) | [Documentación en español](https://docs.bridge.new/llms-full-es.json) |\n| Português do Brasil | [Índice em português](https://docs.bridge.new/llms-pt-br.json) | [Documentação em português](https://docs.bridge.new/llms-full-pt-br.json) |\n\nEl índice enlaza a las páginas `.md` individuales y a los archivos OpenAPI exactos. La [colección completa](https://docs.bridge.new/llms-full.txt) incluye los tres idiomas; la colección de un solo idioma es más pequeña. Las descripciones de endpoints reunidas no sustituyen los esquemas completos de OpenAPI.\n\nLos archivos por idioma usan JSON: el índice enumera las URLs y cada colección contiene el texto de las páginas como Markdown en su campo `contentMarkdown`. Los archivos generales `llms.txt` y `llms-full.txt` mantienen el formato Markdown.\n\n**Ejemplo de prompt:**\n\n> Lee https://docs.bridge.new/llms.txt y elige las fuentes en español para enviar un PDF. Lee la guía completa de adjuntos y el OpenAPI REST enlazado antes de escribir código. Explica la secuencia de carga, los campos obligatorios y las limitaciones de entrega. Conserva las firmas publicadas de la API y cita las URLs que leíste. Prepara solo el código; no hagas solicitudes reales.\n\nSi buscas mediante MCP, especifica `language: \"es\"` para español, `language: \"pt-BR\"` para portugués o `language: \"en\"` para inglés. Las páginas públicas usan `.md`; las lecturas de páginas en el filesystem MCP usan `.mdx`. Consulta también la [guía de capacidades y fuentes de Bridge](https://docs.bridge.new/skill.md).\n\n## Implementa con el contrato correcto\n\nEl servidor permite buscar documentación, leer páginas y esquemas completos en un sistema de archivos virtual de documentación y, opcionalmente, enviar comentarios. La herramienta de archivos no ejecuta comandos en tu equipo. Los comentarios son una función separada de la búsqueda y lectura: úsala solo cuando realmente quieras enviar un comentario sobre la documentación.\n\nIndica al asistente la tarea y el flujo correspondiente:\n\n- [Primera conversación](https://docs.bridge.new/es/guides/first-conversation.md): contacto → conversación → mensaje.\n- [Adjuntos](https://docs.bridge.new/es/guides/send-attachments.md): bytes del archivo → checksum → PUT prefirmado → mensaje.\n- [Plantillas](https://docs.bridge.new/es/guides/send-template.md): consulta las variables antes de enviar.\n- [Conversaciones salientes de agentes](https://docs.bridge.new/es/guides/agent-outbound.md): selecciona un agente y entiende `forceSend`, la reutilización y la recuperación.\n- [Receptor de webhooks](https://docs.bridge.new/es/webhooks/receive-events.md): verifica, guarda, confirma y procesa.\n\nEl [índice de documentación](https://docs.bridge.new/llms.txt) permite encontrar las páginas. La [documentación reunida](https://docs.bridge.new/llms-full.txt) agrupa guías y descripciones de endpoints, pero no incluye todos los esquemas. Antes de generar código, lee el Markdown del endpoint individual o el [OpenAPI REST](https://docs.bridge.new/es/api-reference/openapi.yaml) o [OpenAPI de Custom Connections](https://docs.bridge.new/es/api-reference/campaign-leads.openapi.yaml) que corresponda.\n\nPídele al asistente que conserve hosts, métodos, rutas, autenticación, identificadores, nombres de campos, tipos, campos obligatorios y que admiten null, enums, valores predeterminados, límites y códigos de respuesta. Si las fuentes publicadas se contradicen, identifica los fragmentos y confirma el comportamiento actual antes de basarte en ellos.\n\n## Si no aparece el servidor\n\n| Síntoma | Qué revisar |\n| --- | --- |\n| Falta el servidor | Confirma la ubicación del archivo o el alcance de la configuración, el nombre del servidor y el cliente o entorno que usas. Conserva la configuración existente al agregar la entrada. |\n| Está configurado, pero no hay herramientas | Reinicia o recarga el cliente, habilita el servidor y revisa su estado MCP o sus registros. La organización puede restringir los servidores personalizados. |\n| Solicita autenticación | El servidor público de documentación de Bridge no necesita una clave de API de Bridge. Comprueba la URL y las políticas del cliente o de tu organización. No pegues credenciales del espacio de trabajo en el chat. |\n| Responde sin citas | Pide explícitamente usar `bridgeDocs`, buscar y leer el esquema del endpoint. Ejecuta nuevamente la comprobación de conexión. |\n| MCP no está disponible temporalmente | Lee directamente el [índice](https://docs.bridge.new/llms.txt), el Markdown del endpoint y el OpenAPI. El servidor de documentación no tiene un compromiso de disponibilidad separado. |\n\nLas interfaces de los clientes cambian con el tiempo. Las opciones pueden variar según la versión y las políticas de la organización; consulta la documentación del proveedor enlazada si tus menús son distintos. Instrucciones de proveedores verificadas por última vez: **14 de noviembre de 2026**.\n"
    },
    {
      "title": "Autenticación de la API REST",
      "source": "https://docs.bridge.new/es/credentials",
      "markdownUrl": "https://docs.bridge.new/es/credentials.md",
      "description": "Genera y usa una clave de API desde tu servidor para la API REST de integraciones, sin confundirla con las credenciales de webhooks o Custom Connections.",
      "kind": "page",
      "contentMarkdown": "## Descripción general\n\nToda solicitud a la **API REST de integraciones** en `https://api-connect-us.bridge.new` usa una **clave de API** en el encabezado `x-api-key`. Esta clave identifica tu aplicación y la autoriza a acceder a los recursos de Bridge en nombre de tu organización.\n\n| Tipo de integración | Manejo de credenciales |\n| --- | --- |\n| API REST de integraciones | `x-api-key` desde el servidor, enviada a `https://api-connect-us.bridge.new`. |\n| Webhooks | Tu receptor comprueba la clave de API del webhook configurada, la firma HMAC y la política de vigencia. Sigue la guía para [verificar firmas](https://docs.bridge.new/es/webhooks/verifying-signatures.md). |\n| Custom Connections | `captureKey` pública y reCAPTCHA desde el navegador; sin encabezado de autenticación. Sigue su [guía de integración](https://docs.bridge.new/es/lead-capture/integration.md). |\n\n**Nota**\n\n  Necesitas acceso a la consola de administración de Bridge en https://admin.bridge.new.\n\n  Si no tienes una cuenta, pídele al administrador de Bridge que te cree un usuario.\n\n---\n\n## Genera una clave de API\n\n  \n\n### Abre la consola de administración\n\n    Ve al [panel de Bridge](https://admin.bridge.new) e inicia sesión con tus credenciales.\n  \n\n  \n\n### Ve a la administración de claves\n\n    En el panel izquierdo, abre **Developers → API Keys Management**.\n  \n\n  \n\n### Crea una clave\n\n    Haz clic en **Generate New Key**. Puedes asignarle un nombre descriptivo y una fecha de vencimiento.\n\n    \n\n**Advertencia**\n\n      **Importante:**\\\n      Tu clave de API se muestra una sola vez al crearla. Cópiala de inmediato y guárdala en un lugar seguro; no podrás volver a consultarla.\n    \n\n  \n\n---\n\n## Usa tu clave de API\n\nIncluye tu clave de la API REST en el encabezado `x-api-key` de cada solicitud al host de integraciones REST:\n\n```bash\ncurl -X GET \"https://api-connect-us.bridge.new/bridge/api/health\" \\\n  -H \"x-api-key: YOUR_API_KEY\"\n```\n\n```javascript\nconst response = await fetch(\"https://api-connect-us.bridge.new/bridge/api/health\", {\n  method: \"GET\",\n  headers: {\n    \"x-api-key\": \"YOUR_API_KEY\",\n  },\n});\n\nconst data = await response.json();\nconsole.log(data);\n```\n\n```python\nimport requests\n\nresponse = requests.get(\n    \"https://api-connect-us.bridge.new/bridge/api/health\",\n    headers={\"x-api-key\": \"YOUR_API_KEY\"}\n)\n\nprint(response.json())\n```\n\n\n**Nota**\n\n  Usa el endpoint `GET /bridge/api/health` para comprobar que la clave de API es válida y que la conexión funciona.\n\n---\n\n## Buenas prácticas de seguridad\n\n- **Usa variables de entorno:** guarda la clave en una variable de entorno, por ejemplo `BRIDGE_API_KEY`, en lugar de escribirla directamente en el código fuente.\n- **Nunca expongas las claves en código del cliente:** las claves de API solo deben usarse en aplicaciones del servidor. Nunca las incluyas en código frontend, aplicaciones móviles ni repositorios públicos.\n- **Configura un vencimiento:** establece siempre una fecha de vencimiento al crear la clave. Evita usar claves sin vencimiento definido.\n- **Una clave por aplicación:** usa una clave de API distinta para cada servicio o aplicación que se conecte a Bridge. Así limitas el impacto si una clave se filtra.\n- **Rota las claves periódicamente:** crea una nueva clave y actualiza tus aplicaciones antes de desactivar la anterior. Esto evita interrupciones durante la rotación.\n\n---\n\n## Solución de problemas\n\n| Error | Posible causa | Solución |\n| ----- | -------------- | -------- |\n| `401 Unauthorized` | La clave de API es inválida, venció o no se envió | Comprueba que la clave sea correcta, esté activa y se incluya en el encabezado `x-api-key` |\n| `403 Forbidden` | La clave de API no tiene acceso al recurso solicitado | Comprueba que tenga los permisos necesarios para este endpoint |\n| No puedes volver a consultar la clave de API | La clave se muestra una sola vez al crearla | Genera una nueva clave en la consola de administración |\n\nConsulta la lista completa en la referencia de [códigos de error](https://docs.bridge.new/es/error-codes.md).\n\n---\n\n## Temas relacionados\n\n- [Códigos de error](https://docs.bridge.new/es/error-codes.md): referencia completa de errores de la API de Bridge.\n- [Referencia de la API REST](https://docs.bridge.new/es/api-reference/health/comprobar-estado.md): consulta todos los endpoints disponibles.\n- [Webhooks](https://docs.bridge.new/es/webhooks.md): configura notificaciones de eventos en tiempo real.\n"
    },
    {
      "title": "Glosario e identificadores",
      "source": "https://docs.bridge.new/es/guides/identifiers",
      "markdownUrl": "https://docs.bridge.new/es/guides/identifiers.md",
      "description": "Encuentra los identificadores correctos de espacios de trabajo, contactos, usuarios de Bridge, agentes, conversaciones, plantillas, líneas y archivos sin confundirlos.",
      "kind": "page",
      "contentMarkdown": "## Empieza con la integración correcta\n\nLa **API REST de integraciones** lee o modifica recursos del espacio de trabajo desde tu servidor mediante `x-api-key`. Los **webhooks** envían eventos de Bridge a tu receptor. **Custom Connections** registra leads desde una landing page con su endpoint público independiente, `captureKey` y reCAPTCHA.\n\nUna clave de API es un secreto que se guarda en el servidor. La `captureKey` de Custom Connections está diseñada para aparecer en la landing page. Estos valores no son intercambiables. Consulta [Autenticación](https://docs.bridge.new/es/credentials.md) y [Custom Connections](https://docs.bridge.new/es/lead-capture/index.md).\n\n## Personas, agentes y líneas\n\n- Un **contacto** es la persona externa con la que se comunica tu negocio. Los endpoints de contactos y los participantes externos de las conversaciones se refieren a esa persona.\n- Un **usuario de Bridge** es un usuario humano interno. Las consultas de usuarios internos y los destinatarios de una transferencia se refieren a estos usuarios.\n- Un **agente** es un agente automatizado expuesto por la API de agentes. Su tipo es `LEADSCOUT` o `SERVICE_AGENT`; tiene su propio identificador, disponibilidad y líneas.\n- Un **proveedor** es un tipo de canal, como `WHATSAPP`. Una **línea** es un canal específico usado para una conversación. El tipo de proveedor, el teléfono y el `providerChannelId` son valores distintos.\n- Un **espacio de trabajo** delimita el alcance de la solicitud. Una **marca** es otro identificador usado cuando la operación lo exige o lo admite; no es un espacio de trabajo ni una línea.\n\nEl `ownerId` de un contacto se refiere a un usuario de Bridge, no a un agente automatizado. Puedes resolverlo con el [endpoint de consulta de un usuario interno](https://docs.bridge.new/es/api-reference/internal-users-api/obtener-usuario-interno-por-id.md).\n\n## De dónde sale cada identificador\n\nUsa identificadores del espacio de trabajo correcto. No reutilices un identificador solo porque el mismo teléfono, correo o nombre aparece en otro espacio de trabajo.\n\n| Valor que necesitas | Dónde obtenerlo o verificarlo | Qué debes enviar |\n| --- | --- | --- |\n| `workspaceId` | Usa el identificador proporcionado para tu integración. Si no lo tienes, pídeselo al administrador de Bridge. El contrato REST publicado no ofrece un endpoint global para listar espacios de trabajo. | El ID del espacio de trabajo en la ruta de la operación. Custom Connections también lo exige en el cuerpo y, para solicitudes desde un navegador, en la cadena de consulta. |\n| ID de contacto | [Consulta un contacto](https://docs.bridge.new/es/api-reference/contacts-api/obtener-contacto-por-un-identificador.md) por `PHONE`, `EMAIL` o `ID`; las respuestas de listado, creación y upsert también devuelven el `id` del contacto. | El `id` devuelto para `{contactId}` o un objeto identificador con `identifierType: \"ID\"`, cuando la operación lo admita. |\n| ID de usuario de Bridge | [Consulta un usuario interno](https://docs.bridge.new/es/api-reference/internal-users-api/obtener-usuario-interno-por-un-identificador.md) por `EMAIL` o `ID`, o usa el listado de usuarios internos. | El `id` devuelto para `{userId}` o un objeto identificador interno. La consulta de usuarios internos no admite `PHONE`. |\n| ID de agente | [Lista los agentes](https://docs.bridge.new/es/api-reference/agents-api/listar-los-agents-de-un-workspace.md). Lee `agents[].id`, `type` y `available`. | `agents[].id` para `{agentId}` en la operación de conversación saliente de agentes. `available` indica si el agente puede iniciar conversaciones. |\n| ID de línea del agente | En la misma respuesta de agentes, lee `lines[].providerChannelId` de ese agente. | Un ID de línea perteneciente al agente cuando la operación admite `contact.providerChannelId`. Consulta las reglas de selección de línea en la referencia de conversaciones salientes. |\n| Canal de proveedor general | [Lista los canales de proveedor](https://docs.bridge.new/es/api-reference/provider-channels-api/obtener-canales-de-proveedores-por-workspace.md). Esta respuesta publica `provider` e `identifier`, no el UUID del canal. | Usa estos campos únicamente para las finalidades documentadas por la operación que los consume. No sustituyas `providerChannelId` por el `identifier` que representa un teléfono. |\n| `brandId` | La respuesta de un agente puede incluir su `brandId`. Para otro flujo, obtén el ID de marca correcto de la configuración de integración o del administrador; el contrato publicado no ofrece un endpoint general de listado de marcas. | El ID de marca que acepta la operación. Un ID de marca no es un ID de línea. |\n| `teamId` | Obtén del administrador de Bridge o de la configuración de integración el ID del equipo interno correcto. El contrato REST publicado no ofrece un endpoint de listado de equipos. | La opción documentada de asignación a un equipo al crear una conversación; no envíes también `participants.internals`. |\n| ID de conversación | Crea o consulta una conversación y conserva el `id` devuelto. Las respuestas de conversaciones salientes incluyen `conversation.id`. | `{conversationId}` o `conversationId`, exactamente donde lo exija la operación. |\n| Plantilla | [Consulta una plantilla](https://docs.bridge.new/es/api-reference/templates-api/descubrir-las-variables-agn%C3%B3sticas-de-una-plantilla.md) por ID o nombre. La respuesta devuelve `id`, `name` y las claves de sus variables. | Usa el selector que espera la operación de envío; consulta la sección siguiente. |\n| `mediaId` | [Solicita las cargas prefirmadas](https://docs.bridge.new/es/api-reference/files-api/crear-cargas-prefirmadas-de-archivos.md). Cada elemento del array de respuesta contiene `mediaId` y `presignUrl`. Completa la carga PUT requerida. | El `mediaId` devuelto en `mediaIds` o en el campo de medios que admita esa operación. No envíes la URL prefirmada como ID de medios. |\n\n**Nota**\n\n  Los listados de agentes exponen IDs de línea en el contexto de cada agente. No son un mecanismo general para descubrir todas las líneas del espacio de trabajo. Si otro flujo requiere un `providerChannelId` que no puedes obtener de la respuesta publicada, pide al administrador de Bridge o a [soporte](mailto:support@sainapsis.com) el ID de línea correcto. No lo generes ni lo deduzcas de un teléfono.\n\n## Nombres parecidos pueden exigir campos distintos\n\nLa **consulta de contactos por identificador** usa parámetros de consulta llamados `type` y `value`. Un participante externo de una conversación usa `identifier` e `identifierType`, además de los otros campos que exija esa operación. No copies los parámetros de una consulta directamente al cuerpo de un participante.\n\nLa **consulta de plantillas** acepta un ID o nombre en el parámetro de ruta `{templateId}`. Las **plantillas de inicio de conversación** usan `onboardingTemplates[].templateId`. La **selección de plantilla para conversaciones salientes** usa `id` o `name` dentro del objeto `template`; lee el esquema del endpoint en lugar de renombrar todos los selectores como `templateId`.\n\nUsa la `key` devuelta de cada variable en los `parameters` de la plantilla. Las claves de variables no son índices de posiciones de Meta. La [guía de parámetros de plantillas](https://docs.bridge.new/es/templates-and-parameters.md) explica los valores obligatorios, los predeterminados y la diferencia entre omitir un valor y enviarlo en blanco.\n\n## Mantén separados los identificadores de resultado\n\n| Valor devuelto | Qué identifica | Qué no demuestra por sí solo |\n| --- | --- | --- |\n| `messageId` | Un mensaje creado mediante el endpoint de mensajes | Una confirmación de entrega del proveedor |\n| `trackingId` | Una solicitud aceptada de transferencia de LeadScout | Que haya terminado la asignación de los usuarios solicitados |\n| `requestId` | Un envío aceptado de Custom Connections | Que se haya entregado el mensaje inicial de WhatsApp |\n| `eventId` | Un identificador proporcionado con un evento de webhook; algunas familias de eventos usan valores derivados de la entidad | Una clave de deduplicación globalmente única o una garantía del orden de entrega |\n\nSigue [Recepción de eventos](https://docs.bridge.new/es/webhooks/receive-events.md) para la identidad de eventos y el manejo de duplicados. Consulta [Respuestas y errores](https://docs.bridge.new/es/guides/responses.md) para los estados HTTP, resultados asíncronos y decisiones de reintento. Para un flujo completo, sigue [Primera conversación](https://docs.bridge.new/es/guides/first-conversation.md) o [Envío de adjuntos](https://docs.bridge.new/es/guides/send-attachments.md).\n"
    },
    {
      "title": "Crea un contacto y envía un mensaje",
      "source": "https://docs.bridge.new/es/guides/first-conversation",
      "markdownUrl": "https://docs.bridge.new/es/guides/first-conversation.md",
      "description": "Sigue un flujo completo desde el servidor: contacto, conversación y mensaje, conservando los identificadores devueltos.",
      "kind": "page",
      "contentMarkdown": "Esta guía crea un contacto, inicia una conversación con un usuario interno de Bridge y crea un mensaje. Ejecútala en tu servidor.\n\n**Advertencia**\n\n  Usa un contacto de prueba al que tengas autorización para escribir. Crear una conversación puede ejecutar las plantillas de inicio del espacio de trabajo antes de la solicitud independiente que crea el mensaje. Revisa primero esa configuración: establecer en false el indicador de envío externo del mensaje posterior no desactiva las plantillas de inicio de la conversación.\n\n## Antes de comenzar\n\n- Obtén una clave de API para usar desde el servidor en [Autenticación](https://docs.bridge.new/es/credentials.md).\n- Consigue el ID del espacio de trabajo, el `providerChannelId` de una línea activa de WhatsApp y el correo de un usuario interno de Bridge. Consulta [Identificadores y conceptos](https://docs.bridge.new/es/guides/identifiers.md).\n- Usa un número nuevo de prueba en formato internacional. Si el contacto ya existe, usa la [consulta de contactos por identificador](https://docs.bridge.new/es/api-reference/contacts-api/obtener-contacto-por-un-identificador.md) en lugar de crearlo otra vez.\n- Revisa los atributos personalizados obligatorios y la secuencia de plantillas de inicio del espacio de trabajo. Este ejemplo mínimo no proporciona atributos personalizados ni reemplaza las plantillas.\n- Elige `enableExternalBroadcast` explícitamente: `true` solicita el envío externo cuando lo permiten las reglas de la conversación y del destinatario; `false` crea el mensaje, pero omite ese envío externo. Ningún valor confirma la entrega por parte del proveedor. Este indicador no anula reglas de visibilidad ni permisos.\n\n## La secuencia\n\n| Paso | Solicitud | Valor que debes conservar |\n| --- | --- | --- |\n| Comprueba el acceso | `GET /bridge/api/health` | Respuesta HTTP exitosa |\n| Crea el contacto | `POST /bridge/api/v1/workspaces/{workspaceId}/contacts` | `id` del contacto |\n| Inicia la conversación | `POST /bridge/api/v1/workspaces/{workspaceId}/conversations` | `id` de la conversación |\n| Crea el mensaje | `POST /bridge/api/v1/workspaces/{workspaceId}/messages` | `messageId` |\n\nEl `id` del contacto se convierte en el `identifier` del participante externo, con `identifierType: \"ID\"`. El `id` de la conversación se convierte en el `conversationId` del mensaje.\n\n## Ejecuta el ejemplo\n\nUsa Node.js con `fetch` integrado. Guarda el ejemplo como `first-conversation.mjs`. Proporciona estas variables de entorno mediante la configuración y el sistema de secretos de tu servidor:\n\n| Variable | Valor |\n| --- | --- |\n| `BRIDGE_API_KEY` | Tu clave de API secreta |\n| `BRIDGE_WORKSPACE_ID` | ID del espacio de trabajo correcto |\n| `BRIDGE_PROVIDER_CHANNEL_ID` | ID de la línea de WhatsApp autorizada, no su teléfono |\n| `BRIDGE_USER_EMAIL` | Usuario interno de Bridge del mismo espacio de trabajo |\n| `TEST_CONTACT_PHONE` | Teléfono de un contacto nuevo de prueba al que tienes autorización para escribir |\n| `ENABLE_EXTERNAL_BROADCAST` | Exactamente `true` o `false`; no se asume un valor predeterminado |\n\nLos nombres y el mensaje que aparecen abajo son ejemplos. Reemplázalos con el contenido previsto para tu prueba antes de ejecutarla.\n\n```javascript\nconst BASE = \"https://api-connect-us.bridge.new\";\n\nfunction required(name) {\n  const value = process.env[name];\n  if (!value) throw new Error(`Set ${name} before running this example.`);\n  return value;\n}\n\nconst apiKey = required(\"BRIDGE_API_KEY\");\nconst workspaceId = required(\"BRIDGE_WORKSPACE_ID\");\nconst providerChannelId = required(\"BRIDGE_PROVIDER_CHANNEL_ID\");\nconst internalEmail = required(\"BRIDGE_USER_EMAIL\");\nconst cellphone = required(\"TEST_CONTACT_PHONE\");\nconst broadcast = required(\"ENABLE_EXTERNAL_BROADCAST\");\nif (![\"true\", \"false\"].includes(broadcast)) {\n  throw new Error(\"ENABLE_EXTERNAL_BROADCAST must be true or false.\");\n}\nconst workspacePath = `/bridge/api/v1/workspaces/${encodeURIComponent(workspaceId)}`;\n\nasync function request(method, path, body, expectedStatus) {\n  const response = await fetch(`${BASE}${path}`, {\n    method,\n    headers: {\n      \"x-api-key\": apiKey,\n      ...(body === undefined ? {} : { \"Content-Type\": \"application/json\" }),\n    },\n    ...(body === undefined ? {} : { body: JSON.stringify(body) }),\n  });\n  const result = await response.json().catch(() => null);\n  if (response.status !== expectedStatus) {\n    const code = result?.code ? ` (${result.code})` : \"\";\n    throw new Error(`${method} ${path}: HTTP ${response.status}${code}`);\n  }\n  return result;\n}\n\nawait request(\"GET\", \"/bridge/api/health\", undefined, 200);\n\nconst contact = await request(\"POST\", `${workspacePath}/contacts`, {\n  firstName: \"Alex\",\n  lastName: \"Example\",\n  languageCode: \"EN\",\n  cellphone,\n}, 201);\nif (!contact?.id || contact.workspaceId !== workspaceId) {\n  throw new Error(\"The Contact response does not identify the intended workspace.\");\n}\n\nconst conversation = await request(\"POST\", `${workspacePath}/conversations`, {\n  participants: {\n    externals: [{\n      identifier: contact.id,\n      identifierType: \"ID\",\n      messageProviderType: \"WHATSAPP\",\n      providerChannelId,\n    }],\n    internals: [{ identifier: internalEmail, identifierType: \"EMAIL\" }],\n  },\n  name: \"Integration test\",\n  status: \"ACTIVE\",\n}, 201);\nif (!conversation?.id || conversation.workspaceId !== workspaceId) {\n  throw new Error(\"The Conversation response does not identify the intended workspace.\");\n}\n\nconst message = await request(\"POST\", `${workspacePath}/messages`, {\n  conversationId: conversation.id,\n  messageBody: \"Hello from our authorized Bridge integration test.\",\n  enableExternalBroadcast: broadcast === \"true\",\n}, 201);\nif (!message?.messageId) throw new Error(\"The Message response has no messageId.\");\n\nconsole.log({\n  contactId: contact.id,\n  conversationId: conversation.id,\n  messageId: message.messageId,\n});\n```\n\n```bash\nnode first-conversation.mjs\n```\n\n\n## Entiende el resultado\n\n- Una respuesta `201` al crear el contacto proporciona su identidad y espacio de trabajo. Lee `type` para conocer su clasificación real: `NORMAL` o `PARTIAL`.\n- Una respuesta `201` de conversación proporciona el ID que debes usar en el siguiente paso. Cuando no hay líneas libres, Bridge puede recuperar una conversación liberada que tenga exactamente los participantes solicitados. Se conservan su ID e historial; en ese caso de recuperación no se aplican el `name` ni el `status` solicitados.\n- Una respuesta `201` de mensaje proporciona `messageId`. Por sí sola, no demuestra que WhatsApp haya entregado el mensaje al contacto.\n\nEsta guía asigna explícitamente un usuario interno de Bridge. Para asignar mediante un equipo, usa la opción documentada `teamId` en lugar de `participants.internals`: son mutuamente excluyentes.\n\n## Si falla un paso\n\nEl ejemplo se detiene en la solicitud que falla y nunca reintenta automáticamente una escritura. Un fallo de red puede dejar el resultado incierto. Comprueba el recurso correspondiente antes de repetir una operación de creación o envío.\n\n| Situación | Qué hacer |\n| --- | --- |\n| El contacto ya existe | Consúltalo por identificador y usa el `id` devuelto; no sigas intentando crear el mismo contacto. |\n| Error de marca o línea | Confirma con el administrador cuál es la línea o marca autorizada; el teléfono de una línea no es su ID. |\n| Plantilla `0604`–`0608` | Sigue [Parámetros de plantillas de WhatsApp](https://docs.bridge.new/es/templates-and-parameters.md), incluidos los errores de configuración del espacio de trabajo. |\n| El mensaje se rechaza porque la conversación está liberada | Revisa el estado de la conversación y la referencia de errores de la operación antes de actuar. |\n| `429` | Sigue [Límites de solicitudes](https://docs.bridge.new/es/rate-limits.md), incluido `Retry-After`. |\n\nConsulta [Respuestas y errores](https://docs.bridge.new/es/guides/responses.md) para conocer los formatos de respuesta y las decisiones de recuperación.\n\n## Próximos pasos\n\n- [Carga y envía un adjunto](https://docs.bridge.new/es/guides/send-attachments.md).\n- [Elige y completa una plantilla de WhatsApp](https://docs.bridge.new/es/guides/send-template.md).\n- Consulta los contratos completos de solicitud y respuesta de [crear un contacto](https://docs.bridge.new/es/api-reference/contacts-api/crear-contacto.md), [crear una conversación](https://docs.bridge.new/es/api-reference/conversations-api/crear-conversaci%C3%B3n-con-identificaci%C3%B3n-flexible-de-usuarios.md) y [crear un mensaje](https://docs.bridge.new/es/api-reference/messages-api/crear-mensaje.md).\n"
    },
    {
      "title": "Enviar PDF y otros adjuntos",
      "source": "https://docs.bridge.new/es/guides/send-attachments",
      "markdownUrl": "https://docs.bridge.new/es/guides/send-attachments.md",
      "description": "Envía un PDF u otro archivo compatible en una conversación: calcula su checksum, súbelo a la URL prefirmada y adjunta su ID de medios al mensaje.",
      "kind": "page",
      "contentMarkdown": "Para enviar un PDF u otro adjunto compatible, solicita la carga a Bridge, sube los bytes del archivo a la URL devuelta y crea un mensaje que incluya el `mediaId` recibido. El ejemplo completo desde el servidor que aparece más abajo envía un PDF.\n\n## Antes de comenzar\n\n- Debes tener una conversación existente en el espacio de trabajo correcto. Consulta [Primera conversación](https://docs.bridge.new/es/guides/first-conversation.md).\n- Elige un PDF que tengas autorización para compartir y comprueba que cumpla los límites de la [API de archivos](https://docs.bridge.new/es/api-reference/files-api/crear-cargas-prefirmadas-de-archivos.md).\n- Guarda la clave de API de Bridge en tu servidor. No la agregues a la solicitud de carga prefirmada.\n- Elige explícitamente el indicador `enableExternalBroadcast` del mensaje.\n\n## Valida el archivo antes de solicitar una carga\n\nComprueba el archivo real en tu servidor: su extensión, tipo MIME y longitud en bytes deben cumplir las reglas publicadas de la [API de archivos](https://docs.bridge.new/es/api-reference/files-api/crear-cargas-prefirmadas-de-archivos.md). La solicitud de URL prefirmada contiene metadatos y una suma de comprobación, no los bytes del archivo ni un campo de tamaño. Una respuesta `201` prepara una carga; no demuestra que se hayan inspeccionado los bytes reales, que el tamaño cargado cumpla los límites publicados ni que un proveedor de mensajería vaya a aceptar el archivo.\n\nSi omites `contentType`, copia igualmente `presignUrl.headers` en la solicitud PUT: Bridge puede deducir `Content-Type` a partir del nombre del archivo. Si lo proporcionas, usa el tipo MIME del archivo real y mantenlo coherente con `fileType` y la extensión. Cambiar el nombre de un archivo no convierte su contenido.\n\nDespués de un PUT exitoso, el procesamiento de la carga puede seguir pendiente. Si una solicitud de Message devuelve un [error de carga de archivos](https://docs.bridge.new/es/error-codes.md#file-upload-errors), conserva el error completo y comprueba qué etapa falló antes de decidir si es seguro realizar otra escritura.\n\n## Secuencia de carga\n\n| Etapa | Qué ocurre | Qué no confirma |\n| --- | --- | --- |\n| `POST .../files` | Bridge devuelve `mediaId` y los datos de `presignUrl`. | Los bytes todavía no se han cargado. |\n| `PUT` prefirmado | Tu servidor envía los bytes exactos con la URL de carga y los encabezados devueltos. | Este paso no crea ningún mensaje. |\n| `POST .../messages` | Adjuntas el `mediaId` cargado mediante `mediaIds`. | La respuesta de la API por sí sola no demuestra la entrega por parte del proveedor. |\n\nEl checksum es el **resumen SHA-256 de todos los bytes del archivo, codificado en Base64**. No es un resumen hexadecimal ni un hash del nombre del archivo.\n\n## Ejemplo completo desde el servidor\n\nUsa Node.js con `fetch` integrado. Guarda el ejemplo como `send-attachment.mjs`. Configura `BRIDGE_API_KEY`, `BRIDGE_WORKSPACE_ID`, `BRIDGE_CONVERSATION_ID`, `ATTACHMENT_PATH` y `ENABLE_EXTERNAL_BROADCAST` (`true` o `false`).\n\n```javascript\nimport { readFile } from \"node:fs/promises\";\nimport { basename } from \"node:path\";\nimport { createHash } from \"node:crypto\";\n\nconst BASE = \"https://api-connect-us.bridge.new\";\nfunction required(name) {\n  const value = process.env[name];\n  if (!value) throw new Error(`Set ${name} before running this example.`);\n  return value;\n}\nconst apiKey = required(\"BRIDGE_API_KEY\");\nconst workspaceId = required(\"BRIDGE_WORKSPACE_ID\");\nconst conversationId = required(\"BRIDGE_CONVERSATION_ID\");\nconst filePath = required(\"ATTACHMENT_PATH\");\nconst broadcast = required(\"ENABLE_EXTERNAL_BROADCAST\");\nif (![\"true\", \"false\"].includes(broadcast)) {\n  throw new Error(\"ENABLE_EXTERNAL_BROADCAST must be true or false.\");\n}\nif (!filePath.toLowerCase().endsWith(\".pdf\")) {\n  throw new Error(\"This example is configured for a PDF document.\");\n}\nconst workspacePath = `/bridge/api/v1/workspaces/${encodeURIComponent(workspaceId)}`;\nconst bytes = await readFile(filePath);\nconst checksumBase64 = createHash(\"sha256\").update(bytes).digest(\"base64\");\n\nasync function bridgePost(path, body) {\n  const response = await fetch(`${BASE}${workspacePath}${path}`, {\n    method: \"POST\",\n    headers: { \"x-api-key\": apiKey, \"Content-Type\": \"application/json\" },\n    body: JSON.stringify(body),\n  });\n  const result = await response.json().catch(() => null);\n  if (response.status !== 201) {\n    const code = result?.code ? ` (${result.code})` : \"\";\n    throw new Error(`Bridge ${path}: HTTP ${response.status}${code}`);\n  }\n  return result;\n}\n\nconst uploads = await bridgePost(\"/files\", [{\n  name: basename(filePath),\n  fileType: \"DOCUMENT\",\n  contentType: \"application/pdf\",\n  checksumBase64,\n}]);\nconst upload = uploads?.[0];\nif (!upload?.mediaId || !upload.presignUrl?.url) {\n  throw new Error(\"The upload response is missing its mediaId or URL.\");\n}\nconst method = upload.presignUrl.method ?? \"PUT\";\nif (method !== \"PUT\") throw new Error(\"Expected a presigned PUT upload.\");\nconst uploadHeaders = new Headers(upload.presignUrl.headers ?? {});\nconst returnedChecksum = uploadHeaders.get(\"x-amz-checksum-sha256\");\nif (returnedChecksum !== null && returnedChecksum !== checksumBase64) {\n  throw new Error(\"The returned checksum differs from the file checksum.\");\n}\nif (returnedChecksum === null) {\n  uploadHeaders.set(\"x-amz-checksum-sha256\", checksumBase64);\n}\n\nconst uploaded = await fetch(upload.presignUrl.url, {\n  method,\n  headers: uploadHeaders,\n  body: bytes,\n});\nif (!uploaded.ok) {\n  throw new Error(`File upload failed: HTTP ${uploaded.status}; no Message was created.`);\n}\n\nconst message = await bridgePost(\"/messages\", {\n  conversationId,\n  messageBody: \"Here is the document you requested.\",\n  enableExternalBroadcast: broadcast === \"true\",\n  mediaIds: [upload.mediaId],\n});\nif (!message?.messageId) throw new Error(\"The Message response has no messageId.\");\nconsole.log({ mediaId: upload.mediaId, messageId: message.messageId });\n```\n\n```bash\nnode send-attachment.mjs\n```\n\n\n## Conserva intacta la solicitud de carga\n\nUsa `presignUrl.url` sin reconstruir su host, ruta ni cadena de consulta. Usa el método devuelto y los encabezados obligatorios. El contrato establece `PUT` como método predeterminado cuando se omite, y la API de archivos exige `x-amz-checksum-sha256` con el mismo checksum enviado a Bridge.\n\nLa carga envía los mismos `bytes` con los que se calculó el checksum. No conviertas el PDF a texto, no lo envuelvas en JSON ni envíes otra copia del archivo después de calcular el hash.\n\nSi cargas varios archivos, conserva la relación entre cada `mediaId` devuelto, sus datos prefirmados y el archivo correspondiente. Completa todas las cargas necesarias antes de adjuntar esos IDs a un mensaje.\n\nAlgunos medios necesitan más preparación después de la carga: copiar el archivo, generar una vista previa, convertirlo o cargarlo al proveedor de mensajería. Estas etapas pueden fallar por separado. Un PUT correcto o una respuesta 201 al crear el mensaje no demuestran que el procesamiento ni la entrega del proveedor hayan terminado. Conserva el archivo original y los identificadores recibidos para correlacionar el resultado antes de repetir una solicitud de mensaje.\n\n## Maneja una etapa fallida\n\n- **Bridge rechaza la solicitud del archivo:** comprueba la extensión, `fileType`, el tipo de contenido, el tamaño y el checksum contra la referencia.\n- **La carga falla:** detente antes de crear el mensaje. Comprueba la URL exacta, el método, los encabezados, el checksum y los bytes. No asumas una vigencia de carga ni una política de reintentos que la respuesta no indique.\n- **La solicitud de mensaje falla o agota el tiempo de espera:** que el archivo se haya cargado no demuestra que exista un mensaje. Comprueba el resultado antes de repetir la solicitud que lo crea.\n\n`STICKER` y `WEBSITE` aparecen en el enum `FileType`, pero la tabla de carga publicada no especifica sus reglas de extensión, MIME y tamaño. Confirma esas reglas antes de usarlos en una integración.\n\nConsulta la [API de archivos](https://docs.bridge.new/es/api-reference/files-api/crear-cargas-prefirmadas-de-archivos.md), la [API de mensajes](https://docs.bridge.new/es/api-reference/messages-api/crear-mensaje.md) y [Respuestas y errores](https://docs.bridge.new/es/guides/responses.md).\n"
    },
    {
      "title": "Elige y completa una plantilla de WhatsApp",
      "source": "https://docs.bridge.new/es/guides/send-template",
      "markdownUrl": "https://docs.bridge.new/es/guides/send-template.md",
      "description": "Consulta una plantilla por ID o nombre, proporciona sus claves de variables independientes del proveedor y usa el ID devuelto en una solicitud de conversación.",
      "kind": "page",
      "contentMarkdown": "Usa esta guía cuando quieras abrir una conversación con una plantilla específica de WhatsApp. La [referencia detallada de plantillas](https://docs.bridge.new/es/templates-and-parameters.md) explica las reglas de validación y todos los errores de plantilla documentados.\n\n## Antes de comenzar\n\n- Debes conocer el **ID o nombre** de la plantilla. `GET .../templates/{templateId}` acepta ambos.\n- Confirma que la plantilla esté aprobada para la cuenta de WhatsApp Business asociada a la línea que usarás.\n- Debes tener el ID de un contacto de prueba existente, el `providerChannelId` de la línea autorizada de WhatsApp y el correo de un usuario interno de Bridge. Consulta [Identificadores y conceptos](https://docs.bridge.new/es/guides/identifiers.md).\n- Revisa la secuencia de plantillas de inicio del espacio de trabajo: según su configuración, tu reemplazo puede sustituir toda la secuencia o solo la primera plantilla.\n\n**Advertencia**\n\n  La solicitud final inicia una conversación y puede enviar plantillas de inicio. Usa un contacto de prueba autorizado y el contenido previsto.\n\n## 1. Consulta las variables\n\n```http\nGET /bridge/api/v1/workspaces/{workspaceId}/templates/{templateId}\nx-api-key: YOUR_API_KEY\n```\n\nCodifica para URL el ID o nombre proporcionado. Lee `id`, `name`, `variables` y `driftWarning` en la respuesta.\n\n| Variable | Qué hacer |\n| --- | --- |\n| `callerMustSupply: true` | Proporciona una cadena que no esté en blanco bajo la `key` de esa variable. |\n| `callerMustSupply: false`, no personalizada | Omítela para conservar el valor que Bridge obtiene para cada contacto. Un valor enviado reemplaza ese valor para todos los contactos. |\n| `isCustom: true` | Proporciona tu valor, omítelo o envíalo en blanco para usar su `default`. |\n\nUsa la `key` independiente del proveedor, nunca el `label` visible, una posición de Meta ni un nombre de variable inventado. `driftWarning` es informativo y por sí solo no bloquea el envío.\n\n## 2. Prepara los valores\n\nCrea en tu servidor un archivo JSON que contenga únicamente claves devueltas por la consulta. Si la plantilla realmente declara `order_number` y `delivery_date`, podría contener lo siguiente:\n\n```json\n{\n  \"order_number\": \"A-10492\",\n  \"delivery_date\": \"October 3\"\n}\n```\n\nEsos dos nombres son ejemplos, no campos universales de Bridge. Consulta tu propia plantilla antes de usarlos. Respeta las [reglas de valores de WhatsApp](https://docs.bridge.new/es/templates-and-parameters.md#whatsapp-value-rules); omite los valores no personalizados que quieras que Bridge complete, en lugar de enviar cadenas en blanco.\n\n## 3. Consulta, comprueba y crea la conversación\n\nUsa Node.js con `fetch` integrado. Guarda el ejemplo como `send-template.mjs` y configura `BRIDGE_API_KEY`, `BRIDGE_WORKSPACE_ID`, `BRIDGE_TEMPLATE_ID_OR_NAME`, `TEMPLATE_VALUES_PATH`, `BRIDGE_CONTACT_ID`, `BRIDGE_PROVIDER_CHANNEL_ID` y `BRIDGE_USER_EMAIL`.\n\n```javascript\nimport { readFile } from \"node:fs/promises\";\n\nconst BASE = \"https://api-connect-us.bridge.new\";\nfunction required(name) {\n  const value = process.env[name];\n  if (!value) throw new Error(`Set ${name} before running this example.`);\n  return value;\n}\nconst apiKey = required(\"BRIDGE_API_KEY\");\nconst workspaceId = required(\"BRIDGE_WORKSPACE_ID\");\nconst templateRef = required(\"BRIDGE_TEMPLATE_ID_OR_NAME\");\nconst contactId = required(\"BRIDGE_CONTACT_ID\");\nconst providerChannelId = required(\"BRIDGE_PROVIDER_CHANNEL_ID\");\nconst internalEmail = required(\"BRIDGE_USER_EMAIL\");\nconst parameters = JSON.parse(await readFile(required(\"TEMPLATE_VALUES_PATH\"), \"utf8\"));\nif (parameters === null || Array.isArray(parameters) || typeof parameters !== \"object\") {\n  throw new Error(\"The template values file must contain a JSON object.\");\n}\nif (Object.entries(parameters).some(([key, value]) =>\n  Array.from(key).length > 128 || typeof value !== \"string\" || Array.from(value).length > 1024\n)) {\n  throw new Error(\"Parameter keys and values must respect the published string limits.\");\n}\nif (Object.keys(parameters).length > 50) throw new Error(\"At most 50 parameters are allowed.\");\nconst workspacePath = `/bridge/api/v1/workspaces/${encodeURIComponent(workspaceId)}`;\n\nasync function request(method, path, body, expectedStatus) {\n  const response = await fetch(`${BASE}${workspacePath}${path}`, {\n    method,\n    headers: {\n      \"x-api-key\": apiKey,\n      ...(body === undefined ? {} : { \"Content-Type\": \"application/json\" }),\n    },\n    ...(body === undefined ? {} : { body: JSON.stringify(body) }),\n  });\n  const result = await response.json().catch(() => null);\n  if (response.status !== expectedStatus) {\n    const code = result?.code ? ` (${result.code})` : \"\";\n    throw new Error(`${method} ${path}: HTTP ${response.status}${code}`);\n  }\n  return result;\n}\n\nconst template = await request(\n  \"GET\", `/templates/${encodeURIComponent(templateRef)}`, undefined, 200,\n);\nif (!template?.id) throw new Error(\"Template discovery returned no id.\");\nconst variables = template.variables ?? [];\nconst known = new Set(variables.map((variable) => variable.key));\nconst unknown = Object.keys(parameters).filter((key) => !known.has(key));\nconst missing = variables.filter((variable) =>\n  variable.callerMustSupply &&\n  (typeof parameters[variable.key] !== \"string\" || !parameters[variable.key].trim())\n);\nif (unknown.length || missing.length) {\n  throw new Error(`Check template keys: ${unknown.length} unknown, ${missing.length} missing.`);\n}\n\nconst conversation = await request(\"POST\", \"/conversations\", {\n  participants: {\n    externals: [{\n      identifier: contactId,\n      identifierType: \"ID\",\n      messageProviderType: \"WHATSAPP\",\n      providerChannelId,\n    }],\n    internals: [{ identifier: internalEmail, identifierType: \"EMAIL\" }],\n  },\n  onboardingTemplates: [{ templateId: template.id, parameters }],\n}, 201);\nif (!conversation?.id || conversation.workspaceId !== workspaceId) {\n  throw new Error(\"The Conversation response does not identify the intended workspace.\");\n}\nconsole.log({ templateId: template.id, conversationId: conversation.id });\n```\n\n```bash\nnode send-template.mjs\n```\n\nEl ejemplo usa el ID devuelto por la consulta en `onboardingTemplates[].templateId`. Las dos operaciones de conversaciones salientes también aceptan el ID o nombre de una plantilla; si envías ambos, el ID tiene prioridad. Sus cuerpos de solicitud son distintos de `onboardingTemplates`: lee el contrato de la operación antes de reutilizar este cuerpo en otra.\n\nLas comprobaciones locales detectan claves desconocidas o faltantes. Bridge realiza igualmente su propia validación, incluida la aprobación para la línea elegida y las reglas finales de valores de WhatsApp. La validación local no equivale a aprobación ni garantiza la entrega.\n\n## Cómo corregir una solicitud rechazada\n\n| Error | Qué hacer |\n| --- | --- |\n| Consulta `BRIDGE_TEMPLATE_0001` | Comprueba el ID o nombre y el espacio de trabajo. Esta respuesta no revela si el identificador pertenece a otro espacio de trabajo. |\n| `BRIDGE_CONVERSATION_0604` | Proporciona valores que no estén en blanco para las variables de `extra.missingVariables`. |\n| `BRIDGE_CONVERSATION_0605` | Quita las claves de `extra.unknownKeys`; usa las claves independientes del proveedor devueltas por la consulta. |\n| `BRIDGE_CONVERSATION_0607` | Corrige los valores de `extra.invalidVariables` según su `reason`. |\n| `BRIDGE_CONVERSATION_0608` | Pídele a un administrador que cambie la secuencia de plantillas de inicio del espacio de trabajo. Cambiar los valores de tu plantilla no resuelve este error de configuración. |\n\nConsulta la [referencia completa de errores de plantillas](https://docs.bridge.new/es/templates-and-parameters.md#errors) para los errores de aprobación, pertenencia, parámetros no admitidos y solicitudes mal formadas. No reintentes automáticamente una solicitud de conversación que agotó el tiempo de espera: primero determina su resultado.\n"
    },
    {
      "title": "Inicia una conversación saliente con un agente",
      "source": "https://docs.bridge.new/es/guides/agent-outbound",
      "markdownUrl": "https://docs.bridge.new/es/guides/agent-outbound.md",
      "description": "Elige un agente, envía una plantilla inicial, entiende forceSend y la recuperación, y solicita una transferencia de LeadScout.",
      "kind": "page",
      "contentMarkdown": "Usa las operaciones de conversaciones salientes cuando un contacto existente deba recibir una plantilla aprobada de WhatsApp y continuar con un agente de IA. Para el flujo general, consulta [Crear una conversación](https://docs.bridge.new/es/guides/first-conversation.md).\n\n## Elige la operación\n\n| Objetivo | Operación | Cómo se elige el agente |\n| --- | --- | --- |\n| Iniciar con un LeadScout o Service Agent específico | `POST /bridge/api/v1/workspaces/{workspaceId}/agents/{agentId}/outbound` | Proporcionas el ID de agente obtenido de `GET /agents`. |\n| Iniciar con un LeadScout seleccionado mediante las líneas elegibles del espacio de trabajo | `POST /bridge/api/v1/workspaces/{workspaceId}/leadscout/outbound` | Bridge determina el agente de prospección de la línea. |\n\nAmbas usan el host de la API REST `https://api-connect-us.bridge.new` y una `x-api-key` desde el servidor. Sus esquemas de solicitud son distintos. Lee la [referencia de conversaciones salientes de agentes](https://docs.bridge.new/es/api-reference/agents-api/iniciar-conversaci%C3%B3n-saliente-con-un-contact-como-agent-espec%C3%ADfico.md) o la [referencia de LeadScout](https://docs.bridge.new/es/api-reference/leadscout-api/iniciar-conversaci%C3%B3n-saliente-de-leadscout-con-un-lead-conocido.md) según la operación que uses.\n\n## Antes de enviar\n\n1. [Consulta el contacto](https://docs.bridge.new/es/api-reference/contacts-api/obtener-contacto-por-un-identificador.md) o [créalo](https://docs.bridge.new/es/api-reference/contacts-api/crear-contacto.md) si no existe. Estas operaciones exigen que el contacto ya exista en el espacio de trabajo; no necesitas crear antes una conversación o un mensaje independiente.\n2. [Lista los agentes](https://docs.bridge.new/es/api-reference/agents-api/listar-los-agents-de-un-workspace.md). Elige uno disponible y lee su `lines[].providerChannelId`. El ID de un agente de IA no es el de un usuario humano de Bridge.\n3. Elige una plantilla aprobada. [Consulta sus variables](https://docs.bridge.new/es/guides/send-template.md#1-discover-the-variables), proporciona los valores que debe aportar quien hace la solicitud y comprueba que esté aprobada para la línea de destino. Para este requisito solo necesitas el paso de consulta; no ejecutes el paso de creación de conversación de esa guía antes de una operación de conversación saliente.\n4. Confirma que tu negocio tenga la autorización necesaria. Si envías `consent.status: \"GRANTED\"`, incluye `capturedAt`: así registras tu declaración de consentimiento.\n\nEn la operación de agentes, `contact.providerChannelId` debe pertenecer al agente elegido si lo envías. Es una preferencia: se puede seleccionar otra línea elegible de ese agente. En LeadScout se respeta la línea explícita. [Identificadores y sus fuentes](https://docs.bridge.new/es/guides/identifiers.md) explica qué valores usar.\n\n## Envía una solicitud mínima de agente\n\nReemplaza todos los valores de ejemplo. Este caso asume que la plantilla elegida no tiene variables obligatorias pendientes que solo puedas proporcionar tú. Define `forceSend` deliberadamente; el ejemplo mantiene explícito el comportamiento predeterminado.\n\n```bash\ncurl --fail-with-body --request POST \\\n  \"https://api-connect-us.bridge.new/bridge/api/v1/workspaces/$WORKSPACE_ID/agents/$AGENT_ID/outbound\" \\\n  --header \"x-api-key: $BRIDGE_API_KEY\" \\\n  --header \"Content-Type: application/json\" \\\n  --data '{\n    \"contact\": {\n      \"identifier\": \"f0000001-0000-4000-8000-000000000001\",\n      \"identifierType\": \"ID\",\n      \"messageProviderType\": \"WHATSAPP\"\n    },\n    \"template\": {\n      \"id\": \"f0000040-0000-4000-8000-000000000040\"\n    },\n    \"forceSend\": false\n  }'\n```\n\nUna solicitud exitosa devuelve `201`. Conserva `conversation.id` e interpreta estos campos de respuesta:\n\n| Campo | Significado |\n| --- | --- |\n| `alreadyInitiated: true` | Se reutilizó una conversación activa existente. La solicitud exitosa igualmente agrega su nueva plantilla y sus mensajes de seguimiento. |\n| `recovered: true` | Se recuperó una conversación liberada y recuperable, conservando su ID. Se reemplazan su contexto saliente anterior y su `agentContext`. |\n| `additionalMessagesPersisted` | Cantidad de mensajes de seguimiento almacenados. No es una confirmación de entrega. |\n| `templateSent` | Resumen de la plantilla inicial almacenada para enviarla. El nombre del campo no demuestra que el destinatario la haya recibido. |\n\nEn una creación nueva, ni reutilización ni recuperación se establecen en true. Puede haber recuperación con `forceSend: false`. Los mensajes adicionales se guardan en el orden de la solicitud: no asumas que esperan la respuesta del contacto. El flujo compartido almacena seguimientos de texto y no adjunta sus `mediaIds`. Usa la opción documentada `template.media` para medios en la plantilla inicial o el [flujo de adjuntos de mensajes](https://docs.bridge.new/es/guides/send-attachments.md) para un mensaje separado.\n\n## Qué hace forceSend\n\nLa disponibilidad se evalúa para **la conversación de este contacto en cada línea**. Que una línea esté ocupada en este contexto no significa que la línea corporativa de WhatsApp esté reservada globalmente para un solo contacto.\n\nLas reglas siguientes siguen sujetas a la disponibilidad del agente y a las validaciones de plantilla, consentimiento y sesión.\n\nEn pantallas estrechas, desplázate horizontalmente para comparar las cuatro opciones. Si usas teclado, puedes enfocar esta comparación y recorrerla con las flechas.\n\n| Situación | LeadScout: false | LeadScout: true | Agentes: false | Agentes: true |\n| --- | --- | --- | --- | --- |\n| La línea elegida está libre | Crea | Crea | Crea | Crea |\n| La línea elegida contiene una conversación liberada marcada como recuperable | Recupera el mismo ID | Recupera el mismo ID | Recupera el mismo ID | Recupera el mismo ID |\n| La selección automática solo encuentra conversaciones activas ocupadas | `409 …0008` | Reutiliza la primera conversación ocupada elegible | `409 …0008` | Prefiere una controlada por el agente solicitado y aplica la comprobación de controlador indicada abajo |\n| La línea explícita está ocupada | `409 …0007` | Reutiliza esa conversación | Busca otras líneas libres o recuperables del agente; si no hay, `409 …0008` | Busca otras líneas libres o recuperables; si no hay, prefiere una ocupada que controle el agente |\n| La conversación ocupada elegida está controlada por una persona u otro agente | No reutiliza conversaciones activas | La ruta heredada permite reutilizarla, sujeto a otras comprobaciones; esto no promete por sí solo transferir su control | No reutiliza conversaciones activas | `409 BRIDGE_AI_AGENT_OUTBOUND_0006`; este rechazo no escribe nada |\n| Solo hay conversaciones bloqueadas o liberadas no recuperables | `409 …0008` | `409 …0008` | `409 …0008` | `409 …0008` |\n\nEn la tabla, `…0007` es `BRIDGE_AI_LEADSCOUT_0007` y `…0008` es `BRIDGE_AI_LEADSCOUT_0008`. Una conversación liberada solo se puede recuperar si lo permite su indicador de recuperación almacenado; `forceSend` no la convierte en recuperable.\n\nEn ambas rutas, una sesión de LeadScout abierta y sin vencer bloquea una nueva solicitud de conversación saliente con `409 BRIDGE_AI_LEADSCOUT_0017`. Si no se puede finalizar una sesión vencida, se devuelve `409 BRIDGE_AI_LEADSCOUT_0018`. Un Service Agent puede continuar su sesión de servicio abierta y vigente; una sesión vencida se cierra antes de abrir otra.\n\n**Advertencia**\n\n  `forceSend` no es una clave de idempotencia. Repetir una solicitud exitosa puede agregar otra plantilla y más mensajes. No omite conversaciones bloqueadas, comprobaciones de sesión, reglas de aprobación ni validaciones. Si se agota el tiempo de espera, el resultado queda incierto: inspecciona la conversación antes de decidir si vuelves a enviar la solicitud.\n\n## Maneja conflictos y efectos parciales\n\n| Resultado | Qué hacer |\n| --- | --- |\n| `BRIDGE_AI_LEADSCOUT_0007` / `0008` | Revisa la conversación existente del contacto y sus líneas elegibles. Decide si corresponde reutilizarla antes de habilitar `forceSend`. |\n| `BRIDGE_AI_AGENT_OUTBOUND_0006` | Revisa `extra.conversationId` y quién controla esa conversación. Coordina su control antes de liberarla deliberadamente. No interrumpas automáticamente una conversación humana. |\n| `BRIDGE_AI_LEADSCOUT_0017` / `0018` | Resuelve la sesión existente o contacta a soporte. Cambiar `forceSend` a true no corrige el problema de sesión. |\n| `BRIDGE_AI_LEADSCOUT_0019` / `0020` / `0021` | Usa la consulta de variables para corregir valores faltantes, superpuestos o claves desconocidas. |\n| `400 BRIDGE_AI_LEADSCOUT_0016` por un `mediaId` de plantilla desconocido en la operación de agentes | La conversación puede haberse creado o recuperado antes del error. Revísala antes de reintentar. |\n\n[Liberar una conversación](https://docs.bridge.new/es/api-reference/conversations-api/liberar-conversaci%C3%B3n.md) es una operación independiente con efectos de negocio. Un `204` no tiene cuerpo de respuesta. Libera una conversación solo cuando realmente quieras terminarla.\n\n## Solicita una transferencia de LeadScout a una persona\n\nPara una conversación de LeadScout, obtén el [ID o correo del usuario humano de Bridge](https://docs.bridge.new/es/guides/identifiers.md) y llama al [endpoint de transferencia manual](https://docs.bridge.new/es/api-reference/leadscout-api/solicitar-transferencia-manual-de-leadscout-a-usuarios-internos.md). Esta operación es específica de LeadScout: no asumas que aplica a un Service Agent.\n\n```bash\ncurl --fail-with-body --request POST \\\n  \"https://api-connect-us.bridge.new/bridge/api/v1/workspaces/$WORKSPACE_ID/leadscout/conversations/$CONVERSATION_ID/handoff\" \\\n  --header \"x-api-key: $BRIDGE_API_KEY\" \\\n  --header \"Content-Type: application/json\" \\\n  --data '{\n    \"assignees\": [\n      {\"identifier\": \"f0000002-0000-4000-8000-000000000002\", \"identifierType\": \"ID\"}\n    ]\n  }'\n```\n\nUn `202` confirma la aceptación de la solicitud. Conserva `trackingId` y `conversationId`; la aceptación no demuestra que haya terminado la asignación ni que una persona haya leído o respondido la conversación. La referencia no publica un endpoint de seguimiento de transferencias: no construyas uno a partir de `trackingId`.\n\nContinúa con el [manejo de errores](https://docs.bridge.new/es/error-codes.md) y la [recepción de webhooks](https://docs.bridge.new/es/webhooks/receive-events.md) para conectar este flujo a tu sistema.\n"
    },
    {
      "title": "Lee todas las páginas de resultados",
      "source": "https://docs.bridge.new/es/guides/pagination",
      "markdownUrl": "https://docs.bridge.new/es/guides/pagination.md",
      "description": "Recorre los cursores opacos de contactos, conversaciones, usuarios de Bridge y agentes sin detenerte en una página corta.",
      "kind": "page",
      "contentMarkdown": "Los endpoints de listado devuelven una colección y un `cursor` opcional. Envía ese cursor sin modificar para leer la siguiente página. Continúa hasta que sea null o no aparezca.\n\n## Elige la colección\n\nLos cuatro endpoints siguientes aceptan un `limit` de **1 a 100**, con un valor predeterminado de **20**.\n\n| Recurso | Ruta después del espacio de trabajo | Campo de la colección |\n| --- | --- | --- |\n| Contactos | `/contacts` | `contacts` |\n| Conversaciones | `/conversations` | `conversations` |\n| Usuarios de Bridge | `/users` | `users` |\n| Agentes | `/agents` | `agents` |\n\nUsa la [consulta de contactos por identificador](https://docs.bridge.new/es/api-reference/contacts-api/obtener-contacto-por-un-identificador.md) o la [consulta de usuarios de Bridge por identificador](https://docs.bridge.new/es/api-reference/internal-users-api/obtener-usuario-interno-por-un-identificador.md) cuando necesites encontrar a una persona conocida. Recorrer toda una lista es una tarea distinta.\n\n## Ejemplo desde el servidor\n\nEste ejemplo lee contactos. Guárdalo como `list-contacts.mjs` y configura `BRIDGE_API_KEY` y `BRIDGE_WORKSPACE_ID` en tu servidor.\n\nLa protección local `maxPages` evita una ejecución ilimitada por accidente; no es un límite de la API de Bridge. La protección contra cursores repetidos detiene el proceso e informa el problema, en lugar de devolver silenciosamente una lista incompleta.\n\n```javascript\nconst BASE = \"https://api-connect-us.bridge.new\";\nconst apiKey = process.env.BRIDGE_API_KEY;\nconst workspaceId = process.env.BRIDGE_WORKSPACE_ID;\nif (!apiKey || !workspaceId) {\n  throw new Error(\"Set BRIDGE_API_KEY and BRIDGE_WORKSPACE_ID.\");\n}\n\nasync function* pages(resource, collection, filters = {}) {\n  let cursor;\n  const seen = new Set();\n  const maxPages = 10000;\n\n  for (let pageNumber = 0; pageNumber < maxPages; pageNumber += 1) {\n    const url = new URL(\n      `/bridge/api/v1/workspaces/${encodeURIComponent(workspaceId)}/${resource}`,\n      BASE,\n    );\n    for (const [key, value] of Object.entries(filters)) {\n      url.searchParams.set(key, String(value));\n    }\n    url.searchParams.set(\"limit\", \"100\");\n    if (cursor !== undefined) url.searchParams.set(\"cursor\", cursor);\n\n    const response = await fetch(url, { headers: { \"x-api-key\": apiKey } });\n    const body = await response.json().catch(() => null);\n    if (response.status !== 200) {\n      const code = body?.code ? ` (${body.code})` : \"\";\n      throw new Error(`List ${resource}: HTTP ${response.status}${code}`);\n    }\n    if (!Array.isArray(body?.[collection])) {\n      throw new Error(`Expected the ${collection} collection.`);\n    }\n\n    yield body[collection];\n    if (body.cursor === null || body.cursor === undefined) return;\n    if (typeof body.cursor !== \"string\" || seen.has(body.cursor)) {\n      throw new Error(\"Invalid or repeated cursor; stopped without claiming completion.\");\n    }\n    seen.add(body.cursor);\n    cursor = body.cursor;\n  }\n  throw new Error(\"Local page guard reached; the sweep is incomplete.\");\n}\n\nlet count = 0;\nfor await (const contacts of pages(\"contacts\", \"contacts\")) {\n  // Process or store this page before continuing. Avoid logging personal data.\n  count += contacts.length;\n}\nconsole.log({ contactsRead: count });\n```\n\n```bash\nnode list-contacts.mjs\n```\n\nUsa `pages(\"conversations\", \"conversations\", { status: \"ACTIVE\" })`, `pages(\"users\", \"users\")` o `pages(\"agents\", \"agents\")` con el contrato correspondiente. Conserva los mismos filtros durante todo un recorrido.\n\n## No te detengas en una página corta\n\nUna página con menos registros que `limit` puede tener una página siguiente. El endpoint de agentes documenta expresamente este comportamiento. El cursor devuelto indica si debes continuar; la cantidad de elementos de la colección no lo indica.\n\nTrata el cursor como un valor opaco. No lo decodifiques, no lo incrementes ni construyas uno por tu cuenta. En el ejemplo, `URL.searchParams` conserva su valor mediante la codificación de URL.\n\n## Filtros y límites de solicitudes\n\n- Los filtros `ownerEmail` y `search` del listado de contactos están obsoletos. Para buscar un correo o teléfono conocido, usa la consulta por identificador. Para filtrar un inventario por `ownerId`, lee ese campo en las filas devueltas y filtra en tu código.\n- Los filtros `email` y `status` del listado de usuarios de Bridge están obsoletos. Usa la consulta por identificador para un correo conocido o revisa el `status` de cada usuario devuelto.\n- Cada solicitud de página consume el presupuesto compartido del espacio de trabajo. Sigue [Límites de solicitudes](https://docs.bridge.new/es/rate-limits.md), incluido `Retry-After` ante un `429`. Este ejemplo mínimo se detiene si recibe una respuesta distinta de 200, en lugar de reintentar automáticamente.\n\nLos contratos publicados no prometen una instantánea transaccional del listado mientras cambian los registros. No presentes este recorrido como una exportación cuya consistencia esté garantizada ni deduzcas una vigencia del cursor que no esté documentada.\n\n## Referencias\n\n- [Lista de contactos](https://docs.bridge.new/es/api-reference/contacts-api/listar-contactos.md)\n- [Lista de conversaciones](https://docs.bridge.new/es/api-reference/conversations-api/consultar-conversaciones-con-filtros-flexibles.md)\n- [Lista de usuarios de Bridge](https://docs.bridge.new/es/api-reference/internal-users-api/listar-usuarios-internos.md)\n- [Lista de agentes](https://docs.bridge.new/es/api-reference/agents-api/listar-los-agents-de-un-workspace.md)\n- [Respuestas y errores](https://docs.bridge.new/es/guides/responses.md)\n"
    },
    {
      "title": "Respuestas, errores y reintentos",
      "source": "https://docs.bridge.new/es/guides/responses",
      "markdownUrl": "https://docs.bridge.new/es/guides/responses.md",
      "description": "Interpreta creación, aceptación, respuestas vacías, validación y señales de reintento sin confundir los contratos REST y de Custom Connections.",
      "kind": "page",
      "contentMarkdown": "## Interpreta el resultado de la operación que llamaste\n\nEl estado HTTP y el cuerpo de respuesta describen la operación solicitada. No todos significan que una persona recibió un mensaje.\n\n| Operación | Éxito publicado | Cómo interpretarlo |\n| --- | --- | --- |\n| Crear un mensaje | `201`, con `messageId` | Conserva el ID del mensaje. La respuesta publicada no incluye una confirmación de entrega del proveedor; no lo marques como entregado basándote solo en ella. |\n| Liberar una conversación | `204`, sin cuerpo de respuesta | Trátalo como éxito y no intentes interpretar el cuerpo vacío como JSON. |\n| Solicitar una transferencia de LeadScout | `202`, con `trackingId`, `conversationId`, `status` y `assignees` | Conserva el ID de correlación. La asignación es asíncrona: los destinatarios reflejan la solicitud y no demuestran que haya terminado su resolución o asignación posterior. |\n| Enviar un lead de Custom Connections | `202`, con `requestId` | Conserva el ID de solicitud. Muestra que el lead fue aceptado; otro servicio envía el mensaje inicial de WhatsApp después. |\n\nLa referencia de cada operación sigue siendo la autoridad: [mensajes](https://docs.bridge.new/es/api-reference/messages-api/crear-mensaje.md), [liberación](https://docs.bridge.new/es/api-reference/conversations-api/liberar-conversaci%C3%B3n.md), [transferencia](https://docs.bridge.new/es/api-reference/leadscout-api/solicitar-transferencia-manual-de-leadscout-a-usuarios-internos.md) y [Custom Connections](https://docs.bridge.new/es/api-reference/campaign-leads/registrar-un-lead-de-campa%C3%B1a.md).\n\n**Nota**\n\n  Un ID de correlación no es una URL de estado. El contrato publicado no define un endpoint de consulta periódica para `trackingId` ni `requestId`. Consérvalo para correlación y soporte; no construyas un endpoint nuevo a partir de él.\n\n## Interpreta el formato de error publicado por el endpoint\n\nLas integraciones REST y Custom Connections tienen contratos de error separados.\n\n### Integraciones REST\n\nMuchas respuestas usan `Problem`: `title` y `status` son obligatorios; `code`, `detail`, `errors`, `traceId`, `instance` y `extra` son opcionales. Cuando haya un `code`, úsalo para elegir un manejador de error documentado en lugar de comparar el `title` legible para personas. Conserva `traceId` para soporte cuando se incluya.\n\nAlgunas respuestas de validación publicadas declaran `HTTPValidationError`, cuyo `detail` es un array de elementos con `loc`, `msg` y `type`. El manejador compartido de errores de la API revisado para esta documentación devuelve esos detalles en `Problem.errors[]`. Las definiciones de respuesta publicadas se conservan; aún está pendiente confirmar el comportamiento contra la API desplegada. Consulta la [nota de compatibilidad de validación](https://docs.bridge.new/es/error-codes.md#parse-validation-errors-defensively).\n\nAcepta errores JSON con `application/json` o `application/problem+json`. Revisa `code` cuando aparezca y después un array `errors` o `detail` para los errores de campos. Un `detail` de tipo cadena es una explicación, no un array. El estado `422` por sí solo no identifica un formato universal de cuerpo. Prevé un caso alternativo para errores sin `code` y usa la referencia del endpoint junto con los [códigos de error](https://docs.bridge.new/es/error-codes.md) para decidir qué hacer.\n\n### Custom Connections\n\nSu cuerpo de error exige `type`, `title` y `status`, y puede incluir `detail`. Aquí **`type` es el identificador de error para el código que procesa la respuesta**. No es el campo REST `code`. La [referencia de errores de Custom Connections](https://docs.bridge.new/es/lead-capture/errors.md) detalla estas respuestas.\n\nLas respuestas de error no incluyen el `requestId` del envío; solo aparece en una respuesta `202` exitosa. Para pedir soporte por un error, conserva la URL de la página y la hora aproximada, como indica esa referencia.\n\n## Decide si reintentar según la operación y la causa\n\n| Resultado | Qué hacer |\n| --- | --- |\n| REST `429` | Respeta `Retry-After` en segundos. La guía de límites indica que la solicitud rechazada no se procesó. El presupuesto del espacio de trabajo se comparte entre las claves de API. |\n| REST `401` o `403` | Corrige la clave, los permisos o el espacio de trabajo incorrecto. Un reintento programado no corrige esas causas. |\n| Error de validación o configuración | Corrige primero la causa documentada. No envíes repetidamente la misma solicitud inválida. |\n| Custom Connections `422` | La causa documentada es la indisponibilidad del proveedor de CAPTCHA. Su guía de errores indica que reintentar es seguro; genera un token nuevo para el siguiente intento. |\n| Rechazo de CAPTCHA en Custom Connections | Comprueba que el token exista, esté vigente y se haya generado para este intento. El mismo error también cubre una puntuación baja; por eso un intento nuevo no demuestra por sí solo la causa original. |\n| Tiempo de espera agotado, pérdida de conexión o `5xx` sin clasificar durante una modificación | No asumas que no ocurrió nada. Revisa los efectos documentados de la operación y los identificadores que ya obtuviste antes de decidir si repetirla. No asumas una garantía general de idempotencia. |\n\nConsulta [Límites de solicitudes](https://docs.bridge.new/es/rate-limits.md) para controlar el ritmo y [Errores de Custom Connections](https://docs.bridge.new/es/lead-capture/errors.md) para sus reglas de reintento específicas.\n\n## Algunos fallos pueden ocurrir después de una escritura\n\nLa [referencia de conversaciones salientes de agentes](https://docs.bridge.new/es/api-reference/agents-api/iniciar-conversaci%C3%B3n-saliente-con-un-contact-como-agent-espec%C3%ADfico.md) documenta que un `template.media.mediaId` desconocido puede producir `BRIDGE_AI_LEADSCOUT_0016` después de crear o recuperar la conversación. Por eso un reintento puede producir un resultado distinto.\n\nUn estado de error no garantiza de forma universal que se hayan revertido todos los efectos. Sigue las instrucciones de efectos y recuperación de la operación específica. Si no están claras o se contradicen, identifica la incertidumbre y contacta a [soporte de Bridge](mailto:support@sainapsis.com) antes de repetir una acción con efectos externos.\n"
    },
    {
      "title": "Parámetros de plantillas de WhatsApp",
      "source": "https://docs.bridge.new/es/templates-and-parameters",
      "markdownUrl": "https://docs.bridge.new/es/templates-and-parameters.md",
      "description": "Abre una conversación con tus plantillas de WhatsApp, completa sus variables y maneja todos los errores que puede devolver la solicitud.",
      "kind": "page",
      "contentMarkdown": "## Descripción general\n\nAl crear una conversación, `onboardingTemplates` permite elegir las plantillas de WhatsApp que la abren y su orden. Una plantilla puede contener variables, como un número de pedido, una fecha de entrega o el nombre del contacto. Bridge completa algunas por su cuenta para cada contacto; otras solo las puedes proporcionar tú y las envías en los `parameters` de la entrada.\n\nEl flujo tiene tres pasos:\n\n1. Consulta las variables de la plantilla.\n2. Decide qué valores enviar.\n3. Envíalos con `POST .../conversations`.\n\n**Nota**\n\n  Todas las comprobaciones de esta página se ejecutan antes de crear recursos. Si la solicitud se rechaza, **no se crea una conversación ni se envía un mensaje**, de modo que puedes corregirla y enviarla nuevamente.\n\n---\n\n## 1. Consulta las variables de la plantilla\n\n```http\nGET /bridge/api/v1/workspaces/{workspaceId}/templates/{templateId}\nx-api-key: YOUR_API_KEY\n```\n\n`templateId` acepta el `id` o el `name` de la plantilla. La respuesta enumera sus variables:\n\n```json\n{\n  \"id\": \"f0000040-0000-4000-8000-000000000040\",\n  \"name\": \"order_shipped_promo\",\n  \"language\": \"es\",\n  \"driftWarning\": { \"hasDrift\": false, \"stale\": [], \"missingLabels\": [] },\n  \"variables\": [\n    { \"key\": \"first_name\", \"label\": \"Contact first name\", \"callerMustSupply\": false, \"isCustom\": false, \"default\": null },\n    { \"key\": \"order_number\", \"label\": \"Order number\", \"callerMustSupply\": true, \"isCustom\": false, \"default\": null },\n    { \"key\": \"delivery_date\", \"label\": \"Delivery date\", \"callerMustSupply\": true, \"isCustom\": false, \"default\": null },\n    { \"key\": \"tracking_code\", \"label\": \"Tracking code\", \"callerMustSupply\": false, \"isCustom\": true, \"default\": \"pending\" }\n  ]\n}\n```\n\n`driftWarning` es solo informativo: señala diferencias entre las variables declaradas y la instantánea de la plantilla de Meta y nunca bloquea un envío. La tabla siguiente describe cada elemento de `variables`.\n\n| Campo | Significado |\n| --- | --- |\n| `key` | Nombre que debes usar en `parameters` |\n| `label` | Descripción de la variable legible para personas |\n| `callerMustSupply` | `true` cuando debes proporcionar un valor que no esté en blanco porque Bridge no tiene una fuente para él; `false` en los demás casos |\n| `isCustom` | Indica si es una variable personalizada: un valor que solo tú conoces y que tiene un texto predeterminado |\n| `default` | Para una variable personalizada, texto enviado si no proporcionas un valor; `null` en los demás casos |\n\nUna plantilla que no está en tu espacio de trabajo devuelve `404` con `BRIDGE_TEMPLATE_0001`.\n\n---\n\n## 2. Decide qué valores enviar\n\n| Variable | Qué significa | Qué hacer |\n| --- | --- | --- |\n| `callerMustSupply: true` | Bridge no tiene una fuente para ese valor | **Obligatorio.** Envía un valor que no esté en blanco para su `key` |\n| `callerMustSupply: false`, `isCustom: false` | Bridge lo completa para cada contacto, por ejemplo con su nombre | **Opcional.** Omítelo para conservar el valor de Bridge |\n| `isCustom: true` | Un valor que solo tú conoces, con un `default` | **Opcional.** Envía tu valor, omítelo o envíalo en blanco para que se envíe su `default` |\n\nEl valor que envíes para una variable `callerMustSupply: false` reemplaza el valor de Bridge y se usa **para todos los contactos** de la conversación.\n\n**Advertencia**\n\n  Para conservar el valor de Bridge en una variable no personalizada, **omite la clave**. Un valor en blanco no significa «usar el predeterminado»: se envía tal como lo escribiste. Una variable obligatoria cuyo valor esté vacío o contenga solo espacios se rechaza como faltante. Solo las variables personalizadas (`isCustom: true`) tratan el valor en blanco como no enviado y recurren a su `default`.\n\n---\n\n## 3. Envía los parámetros\n\nCada entrada de `onboardingTemplates` recibe el `id` de la plantilla devuelto en el paso 1 y sus `parameters`, usando la `key` de cada variable. La posición en la lista determina el orden de envío.\n\n```http\nPOST /bridge/api/v1/workspaces/{workspaceId}/conversations\nx-api-key: YOUR_API_KEY\nContent-Type: application/json\n```\n\n```json\n{\n  \"participants\": {\n    \"externals\": [\n      {\n        \"identifier\": \"+13802098869\",\n        \"identifierType\": \"PHONE\",\n        \"messageProviderType\": \"WHATSAPP\",\n        \"brandId\": \"YOUR_BRAND_ID\"\n      }\n    ]\n  },\n  \"onboardingTemplates\": [\n    {\n      \"templateId\": \"f0000040-0000-4000-8000-000000000040\",\n      \"parameters\": {\n        \"order_number\": \"A-10492\",\n        \"delivery_date\": \"3 de octubre\"\n      }\n    }\n  ]\n}\n```\n\nEn este ejemplo se omiten `first_name` y `tracking_code`, por lo que cada contacto recibe su propio nombre y `tracking_code` se envía con su valor predeterminado, `pending`.\n\nLímites por plantilla: como máximo **50** parámetros, claves de hasta **128** caracteres y valores de hasta **1024** caracteres. Las solicitudes que superan esos límites se rechazan por formato incorrecto; consulta [Errores](https://docs.bridge.new/es/templates-and-parameters.md#errors).\n\nSegún la configuración del espacio de trabajo, tus plantillas reemplazan toda la secuencia de inicio o solo su primera plantilla. En el segundo caso, el resto de la secuencia configurada se envía después de las tuyas.\n\n---\n\n## Reglas de valores de WhatsApp\n\nWhatsApp rechaza algunos valores al enviar el mensaje. Bridge los comprueba de antemano para que la solicitud falle mientras aún puedes corregirla:\n\n| Regla | Límite |\n| --- | --- |\n| Saltos de línea y tabulaciones | No se permiten `\\n`, `\\r` ni `\\t` |\n| Espacios consecutivos | Como máximo 4 seguidos |\n| Encabezado | El texto del encabezado con tu valor debe caber en **60** caracteres |\n| Botón de URL | El enlace del botón con tu valor debe caber en **2000** caracteres |\n| Cuerpo | El texto del cuerpo más todos sus valores debe caber en **1024** caracteres |\n\n**Advertencia**\n\n  El límite del cuerpo incluye los valores que Bridge completa para cada contacto, como su nombre. Bridge solo puede comprobar los valores que conoce al recibir la solicitud: deja espacio para los demás.\n\nBridge nunca recorta ni reescribe tus valores: lo que envías es lo que recibe el contacto.\n\n---\n\n## Errores\n\nTodos los errores usan el formato `application/problem+json` descrito en [Códigos de error](https://docs.bridge.new/es/error-codes.md). Decide qué hacer según `code`, nunca según `title`.\n\n| Código | Estado | Cuándo ocurre | `extra` |\n| --- | --- | --- | --- |\n| `BRIDGE_CONVERSATION_0601` | 404 | La plantilla no existe | `templateId`, `workspaceId` |\n| `BRIDGE_CONVERSATION_0602` | 400 | La plantilla pertenece a otro espacio de trabajo | `templateId`, `workspaceId` |\n| `BRIDGE_CONVERSATION_0603` | 400 | La plantilla no está aprobada para la línea usada para contactar a un participante | `templateId`, `workspaceId`, `userIds` —contactos para cuya línea no está aprobada, cuando se conocen— |\n| `BRIDGE_CONVERSATION_0604` | 422 | Falta una variable obligatoria o está en blanco | `templateId`, `missingVariables: [{key, label}]` |\n| `BRIDGE_CONVERSATION_0605` | 422 | Una clave de `parameters` no pertenece a las variables de la plantilla | `templateId`, `unknownKeys: [key]` |\n| `BRIDGE_CONVERSATION_0606` | 422 | Se enviaron `parameters` para una plantilla que no es de WhatsApp | `templateId` |\n| `BRIDGE_CONVERSATION_0607` | 422 | Un valor infringe una [regla de WhatsApp](https://docs.bridge.new/es/templates-and-parameters.md#whatsapp-value-rules) | `templateId`, `invalidVariables: [{key, label, reason}]` |\n| `BRIDGE_CONVERSATION_0608` | 422 | Una plantilla que el espacio de trabajo envía después de las tuyas necesita valores que solo puede proporcionar quien llama a la API | `templateId`, `origin: \"WORKSPACE_CONFIGURATION\"` |\n\n### Valores faltantes: `0604`\n\n```json\n{\n  \"title\": \"A template named in the onboarding override is missing values only the caller can provide\",\n  \"status\": 422,\n  \"detail\": \"A template named in the onboarding override is missing values only the caller can provide\",\n  \"code\": \"BRIDGE_CONVERSATION_0604\",\n  \"extra\": {\n    \"templateId\": \"f0000040-0000-4000-8000-000000000040\",\n    \"missingVariables\": [\n      { \"key\": \"delivery_date\", \"label\": \"Delivery date\" }\n    ]\n  }\n}\n```\n\n\n### Valores inválidos: `0607`\n\n```json\n{\n  \"title\": \"Parameter values for an onboarding template break a WhatsApp rule and would be rejected when sent\",\n  \"status\": 422,\n  \"detail\": \"Parameter values for an onboarding template break a WhatsApp rule and would be rejected when sent\",\n  \"code\": \"BRIDGE_CONVERSATION_0607\",\n  \"extra\": {\n    \"templateId\": \"f0000040-0000-4000-8000-000000000040\",\n    \"invalidVariables\": [\n      { \"key\": \"order_number\", \"label\": \"Order number\", \"reason\": \"NEWLINE\" }\n    ]\n  }\n}\n```\n\n`reason` indica la primera regla que infringe el valor:\n\n| `reason` | Significado |\n| --- | --- |\n| `NEWLINE` | El valor contiene `\\n` o `\\r` |\n| `TAB` | El valor contiene `\\t` |\n| `CONSECUTIVE_SPACES` | El valor tiene más de 4 espacios consecutivos |\n| `TOO_LONG` | El encabezado o botón de URL supera su límite al insertar el valor |\n| `BODY_TOO_LONG` | El cuerpo supera los 1024 caracteres; se enumeran todos los valores de cuerpo que enviaste |\n\n### `0608` no se resuelve cambiando la solicitud\n\n`BRIDGE_CONVERSATION_0608` solo ocurre en espacios de trabajo donde tus plantillas reemplazan únicamente la primera de la secuencia de inicio. Significa que una plantilla enviada después de las tuyas necesita valores que solo puedes proporcionar tú y que la API no puede aportar. Pídele a un administrador que cambie la secuencia de inicio.\n\n### Solicitudes mal formadas\n\nUna solicitud que no cumpla el esquema —más de 50 parámetros, una clave de más de 128 caracteres, un valor de más de 1024 o un campo desconocido— se rechaza con `422` **sin `code`**. En su lugar, incluye una lista `errors` que indica cada problema:\n\n```json\n{\n  \"title\": \"Unprocessable content\",\n  \"status\": 422,\n  \"errors\": [\n    {\n      \"loc\": [\"body\", \"onboardingTemplates\", 0, \"parameters\", \"order_number\"],\n      \"msg\": \"String should have at most 1024 characters\",\n      \"type\": \"string_too_long\"\n    }\n  ]\n}\n```\n\n\n### Orden de evaluación\n\nLas comprobaciones se ejecutan en este orden y **solo se devuelve el primer error**:\n\n1. Límite de solicitudes: `429`.\n2. Formato de la solicitud: `422` sin `code`.\n3. Participantes, marca y línea: `400` / `409`, por ejemplo `BRIDGE_BRAND_0101` o `BRIDGE_PROVIDER_CHANNEL_0001`.\n4. Cada plantilla, en el orden de la lista: `0601` / `0602` → `0603` → `0606` → `0605` → `0604` → `0607`.\n5. `0608`, solo si tus plantillas reemplazan únicamente la primera de la secuencia del espacio de trabajo.\n\nPor eso corregir un error puede revelar el siguiente. Los valores de una plantilla posterior no se revisan hasta que pasen todas las anteriores.\n\n---\n\n## Temas relacionados\n\n- [Crear una conversación](https://docs.bridge.new/es/api-reference/conversations-api/crear-conversaci%C3%B3n-con-identificaci%C3%B3n-flexible-de-usuarios.md): referencia completa de solicitud y respuesta.\n- [Códigos de error](https://docs.bridge.new/es/error-codes.md): todos los códigos, incluidos los de marcas y líneas.\n- [Límites de solicitudes](https://docs.bridge.new/es/rate-limits.md): manejo de `429`.\n"
    },
    {
      "title": "Límites de solicitudes",
      "source": "https://docs.bridge.new/es/rate-limits",
      "markdownUrl": "https://docs.bridge.new/es/rate-limits.md",
      "description": "Cuántas solicitudes acepta la API de Bridge, qué encabezados indican el presupuesto disponible y cómo manejar correctamente un 429.",
      "kind": "page",
      "contentMarkdown": "## Descripción general\n\nLa API de Bridge acepta **50 solicitudes cada 5 segundos**. El límite se aplica a todos los endpoints, está habilitado por defecto y no requiere configuración.\n\n**Nota**\n\n  El presupuesto pertenece al **espacio de trabajo**, no a la clave de API. Si creas varias claves para el mismo espacio de trabajo —una por aplicación, como se recomienda— todas consumen las mismas 50 solicitudes.\n\n---\n\n## Comprueba el presupuesto disponible\n\nToda respuesta a una solicitud autenticada incluye dos encabezados para que no tengas que adivinar cuánto presupuesto queda:\n\n```http\nRateLimit-Policy: \"default\";q=50;w=5\nRateLimit: \"default\";r=43;t=3\n```\n\n| Campo | Significado |\n| --- | --- |\n| `q` | Solicitudes permitidas por ventana |\n| `w` | Duración de la ventana, en segundos |\n| `r` | Solicitudes **restantes** en la ventana actual |\n| `t` | Segundos hasta que la ventana se reinicie y `r` vuelva a `q` |\n\nUn cliente que observa `r` y hace una pausa cuando se acerca a cero evita los rechazos por este límite.\n\n**Nota**\n\n  Una solicitud rechazada **antes** de la autenticación, porque falta la clave de API o es inválida, no incluye ninguno de esos encabezados. Consulta esas respuestas en [Autenticación](https://docs.bridge.new/es/credentials.md).\n\n---\n\n## Si superas el límite\n\nLas solicitudes que exceden el presupuesto reciben `429 Too Many Requests`. No se procesa nada, por lo que es seguro repetir la solicitud.\n\n```http\nHTTP/1.1 429 Too Many Requests\nContent-Type: application/problem+json\nRetry-After: 3\nRateLimit-Policy: \"default\";q=50;w=5\nRateLimit: \"default\";r=0;t=3\n```\n\n```json\n{\n  \"title\": \"Too Many Requests\",\n  \"status\": 429,\n  \"detail\": \"The workspace has exhausted its request budget for the current window\",\n  \"code\": \"BRIDGE_RATE_LIMIT_0001\"\n}\n```\n\n`Retry-After` se expresa en **segundos a partir de ahora**, no como fecha. Espera ese tiempo antes de que se atienda la siguiente solicitud.\n\n**Advertencia**\n\n  **Un `429` no es un problema de autenticación.** `401` y `403` indican que falta la clave, es inválida, venció o no está autorizada, y **reintentarlos de forma programada no resolverá el problema**: solo consume tu presupuesto. Solo se debe reintentar automáticamente un `429`, y únicamente después de la espera que indica.\n\n---\n\n## Qué consume presupuesto\n\nCada solicitud HTTP cuenta como una, incluidas las que terminan en un error de validación o un `404`. Lo que importa es cuántas llamadas hace el cliente, no cuántos datos devuelve la API.\n\nLa diferencia se ve al leer:\n\n- **Un recurso por ID**, con `GET .../contacts/{contactId}`, cuesta **una solicitud**, sin importar el tamaño de la respuesta.\n- **Un listado**, con `GET .../contacts`, cuesta **una solicitud por página**. Leerlo completo consume tantas solicitudes como páginas tenga.\n\nPor eso el tamaño de página determina el costo de recorrer todo el listado. Leer 500 contactos cuesta 5 solicitudes con páginas de 100 y 25 solicitudes con páginas de 20: los mismos datos consumen cinco veces más presupuesto.\n\n**Nota**\n\n  Prefiere el mayor tamaño de página que admita el endpoint al leer una lista completa. Cuando ya sabes qué recurso necesitas, consúltalo directamente por ID.\n\n---\n\n## Controla la espera en la práctica\n\nUn cliente que regula su ritmo con `RateLimit` y respeta `Retry-After` cuando ocasionalmente supera el límite no necesita más lógica para este control:\n\n```python\nimport time\n\nimport requests\n\nBASE = \"https://api-connect-us.bridge.new\"\nHEADERS = {\"x-api-key\": \"YOUR_API_KEY\"}\n\n\ndef rate_limit_state(response):\n    header = response.headers.get(\"RateLimit\", \"\")\n    fields = dict(part.split(\"=\", 1) for part in header.split(\";\") if \"=\" in part)\n    return int(fields.get(\"r\", 1)), int(fields.get(\"t\", 1))\n\n\ndef get(path):\n    while True:\n        response = requests.get(f\"{BASE}{path}\", headers=HEADERS)\n\n        if response.status_code == 429:\n            time.sleep(int(response.headers[\"Retry-After\"]))\n            continue\n\n        remaining, reset_in = rate_limit_state(response)\n        if remaining == 0:\n            time.sleep(reset_in)\n\n        return response\n```\n\n```javascript\nconst BASE = \"https://api-connect-us.bridge.new\";\nconst HEADERS = { \"x-api-key\": \"YOUR_API_KEY\" };\n\nconst sleep = (seconds) => new Promise((done) => setTimeout(done, seconds * 1000));\n\nfunction rateLimitState(response) {\n  const fields = Object.fromEntries(\n    (response.headers.get(\"RateLimit\") ?? \"\")\n      .split(\";\")\n      .filter((part) => part.includes(\"=\"))\n      .map((part) => part.split(\"=\"))\n  );\n  return { remaining: Number(fields.r ?? 1), resetIn: Number(fields.t ?? 1) };\n}\n\nasync function get(path) {\n  while (true) {\n    const response = await fetch(`${BASE}${path}`, { headers: HEADERS });\n\n    if (response.status === 429) {\n      await sleep(Number(response.headers.get(\"Retry-After\")));\n      continue;\n    }\n\n    const { remaining, resetIn } = rateLimitState(response);\n    if (remaining === 0) await sleep(resetIn);\n\n    return response;\n  }\n}\n```\n\n\n**Advertencia**\n\n  No reintentes un `429` de inmediato ni con un intervalo fijo elegido por tu cuenta. Si reintentas antes de que transcurra `Retry-After`, la solicitud vuelve a rechazarse. Un bucle de reintentos demasiado rápido mantiene en cero el presupuesto del espacio de trabajo para todas las demás aplicaciones que lo comparten.\n\n---\n\n## Estándares\n\nEstos campos no son exclusivos de Bridge: `RateLimit-Policy` y `RateLimit` siguen la especificación IETF de [campos de límites de solicitudes](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/), `Retry-After` corresponde a [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html#field.retry-after) y el cuerpo de `429` sigue [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457.html). Si ya manejas encabezados `X-RateLimit-*` de otra API, estos son sus equivalentes estandarizados.\n\nSi los valores difieren, **prevalece `Retry-After`**: es la señal que determina cuándo reintentar, mientras que `RateLimit` informa cómo regular el ritmo.\n\n---\n\n## Temas relacionados\n\n- [Autenticación](https://docs.bridge.new/es/credentials.md): claves de API y respuestas `401`/`403` que no deben reintentarse.\n- [Códigos de error](https://docs.bridge.new/es/error-codes.md): referencia completa, incluido `BRIDGE_RATE_LIMIT_0001`.\n- [Referencia de la API REST](https://docs.bridge.new/es/api-reference/health/comprobar-estado.md): todos los endpoints documentan su respuesta `429`.\n"
    },
    {
      "title": "Códigos de error",
      "source": "https://docs.bridge.new/es/error-codes",
      "markdownUrl": "https://docs.bridge.new/es/error-codes.md",
      "description": "Interpreta los códigos de error REST, las respuestas de validación y los resultados de escritura inciertos para decidir qué hacer.",
      "kind": "page",
      "contentMarkdown": "## Formato de respuesta\n\nEjemplo de respuesta `Problem`. Consulta la referencia del endpoint para conocer su estado HTTP, tipo de contenido y esquema de respuesta:\n\n```json\n{\n  \"title\": \"A template named in the onboarding override is missing values only the caller can provide\",\n  \"status\": 422,\n  \"detail\": \"A template named in the onboarding override is missing values only the caller can provide\",\n  \"code\": \"BRIDGE_CONVERSATION_0604\",\n  \"extra\": {\n    \"templateId\": \"f0000040-0000-4000-8000-000000000040\",\n    \"missingVariables\": [{ \"key\": \"delivery_date\", \"label\": \"Delivery date\" }]\n  },\n  \"instance\": \"https://api-connect-us.bridge.new/bridge/api/v1/workspaces/{workspaceId}/conversations\",\n  \"traceId\": \"Root=1-6702b8c4-3f1a2b4c5d6e7f8091a2b3c4\"\n}\n```\n\n| Campo | Significado |\n| --- | --- |\n| `code` | Cuando aparece, código estable de error incluido en esta página. **Decide qué hacer según este campo, no según el título.** Los errores de validación y del servidor pueden omitirlo. |\n| `title` | Mensaje legible para personas. Puede ser más largo que el título de las tablas siguientes: nunca lo uses para identificar el error |\n| `status` | Código de estado HTTP |\n| `detail` | Más información sobre este caso, cuando está disponible |\n| `extra` | Contexto estructurado para procesar el error, como los IDs o claves involucrados, cuando está disponible |\n| `instance` | URL de la solicitud |\n| `traceId` | Inclúyelo cuando contactes a soporte |\n\n**Nota**\n\n  Lee el esquema de respuesta de la operación que llamas. Cuando sea `HTTPValidationError`, los detalles están en un array `detail`; cada entrada contiene `loc` —dónde—, `msg` —qué— y `type`. Otras respuestas `422` documentadas usan `Problem` y pueden incluir `code` y `extra`. No asumas que todas las respuestas `422` tienen el mismo formato.\n\n### Interpreta los errores de validación de forma defensiva\n\nAcepta cuerpos de error JSON con `application/json` o `application/problem+json`. Comprueba primero el estado HTTP y después revisa el cuerpo:\n\n1. Si aparece `code`, usa la entrada correspondiente de esta página para decidir qué hacer.\n2. Si `errors` es un array, lee sus entradas `loc`, `msg` y `type` como detalles de validación.\n3. Si `detail` es un array, interprétalo como el formato `HTTPValidationError`. Un `detail` de tipo cadena es una explicación, no una lista de errores de campos.\n4. Conserva `traceId`, el estado y la URL de solicitud para soporte. No exijas la presencia de `code` o `extra` ni uses mensajes legibles como identificadores.\n\nUn campo inválido y una regla que relaciona varios campos no tienen por qué compartir el mismo estado. Las reglas del cuerpo saliente revisadas generan `400` con `BRIDGE_CORE_0103` cuando `consent.status` es `GRANTED` y no se incluye `capturedAt`, o cuando `template.media` proporciona ambos o ninguno de `mediaId` y `url`. Los tipos de campo o UUID inválidos pueden producir, en cambio, detalles de validación de solicitud con `422`. Interpreta juntos el estado y el cuerpo de error; no exijas un array `errors` para toda solicitud inválida.\n\n### Códigos heredados con sufijo\n\nAlgunos manejadores de errores heredados añaden un nombre simbólico a `code`, por ejemplo, `BRIDGE_PRELOAD_FILE_0002 | PRELOAD_FILE_IS_PENDING`. Conserva el valor recibido completo para registros y soporte. Para consultar el catálogo, acepta un código simple conocido o su forma heredada reconocida explícitamente; no compares `title` o `detail`, no inventes un código desconocido ni reescribas el cuerpo de la respuesta. Esta revisión del código fuente no ha confirmado de forma independiente qué versión del manejador está desplegada.\n\n**Advertencia**\n\n  **Compatibilidad de validación:** algunas respuestas OpenAPI publicadas declaran `HTTPValidationError.detail[]` y `application/json`, mientras que el manejador compartido de errores de la API revisado para esta documentación devuelve detalles de validación en `Problem.errors[]` con `application/problem+json`. Esta actualización editorial conserva las definiciones de respuesta publicadas. Maneja ambos formatos; sigue pendiente la confirmación contra la API desplegada antes de admitir solo uno en un cliente generado estricto.\n\n### Decide si debes reintentar\n\n| Resultado | Acción |\n| --- | --- |\n| `400` o `422` | Corrige la solicitud según el código y los errores de campos. Repetir la misma entrada no corrige la validación. |\n| `401` o `403` | Revisa las credenciales, el espacio de trabajo y los permisos del tipo de integración correcto. Guarda las claves REST en el servidor. |\n| `404` | Confirma el identificador y el espacio de trabajo. Una consulta sin contacto coincidente es distinta de una entrada mal formada. |\n| `409` | Lee el código de la operación: una conversación existente, un agente no disponible o una sesión pendiente requieren soluciones distintas. No habilites `forceSend` automáticamente. |\n| `429` | Sigue la [guía de encabezados y espera por límite de solicitudes](https://docs.bridge.new/es/rate-limits.md). |\n| Tiempo de espera agotado, respuesta desconectada o `5xx` después de una escritura | Trata el resultado como incierto. Revisa el recurso afectado antes de reenviar: un error no demuestra que no se haya guardado ningún cambio. |\n\nEsta guía general de reintentos no agrega idempotencia a un endpoint. Para reutilización, recuperación y escrituras parciales, consulta [Conversaciones salientes y transferencias de agentes](https://docs.bridge.new/es/guides/agent-outbound.md). Custom Connections tiene su propia [referencia de errores](https://docs.bridge.new/es/lead-capture/errors.md) y no usa una clave de la API REST.\n\n## Errores al responder a un mensaje\n\nPara `POST .../messages`, las comprobaciones revisadas del mensaje al que respondes definen estas formas heredadas adicionales:\n\n- `BRIDGE_MESSAGE_0001 | MESSAGE_NOT_FOUND` (`404`): no se encontró el Message indicado en `replyToMessageId`.\n- `BRIDGE_MESSAGE_0002 | MESSAGE_IS_NOT_ON_CONVERSATION` (`403`): el mensaje al que respondes pertenece a otra Conversation. Usa uno de la Conversation en la que vas a enviar el mensaje.\n\nConserva `code` completo, incluido su sufijo simbólico. Estas comprobaciones se refieren al mensaje al que respondes, no al `mediaId` del archivo adjunto.\n\n## Errores de carga de archivos\n\nEl flujo de carga revisado define estos códigos heredados. El sufijo forma parte del `code` recibido, no es un campo de la solicitud. Consulta el contrato de respuesta de la operación y conserva la interpretación compatible anterior.\n\nLa operación determina qué errores de archivo corresponden: `POST .../files` comprueba los metadatos y puede devolver los códigos `0003` o `0004` de abajo. `POST .../messages` puede devolver `0001` o `0002` cuando el `mediaId` de un adjunto no existe o sigue pendiente. Los archivos de las plantillas salientes tienen su propio manejo de errores; no sustituyas `BRIDGE_AI_LEADSCOUT_0016` por estos códigos.\n\n| `code` heredado | Estado | Acción |\n| --- | --- | --- |\n| `BRIDGE_PRELOAD_FILE_0001 \\| PRELOAD_FILE_NOT_FOUND` | 404 | Comprueba el `mediaId` devuelto y la carga a la que hace referencia. |\n| `BRIDGE_PRELOAD_FILE_0002 \\| PRELOAD_FILE_IS_PENDING` | 400 | El archivo sigue pendiente. Confirma que el PUT terminó y permite que se procese la carga; no deduzcas que una solicitud de Message fallida no guardó ningún cambio. |\n| `BRIDGE_PRELOAD_FILE_0003 \\| PRELOAD_FILE_INVALID_MIME_TYPE` | 400 | Corrige la combinación del tipo MIME y el `fileType` lógico. |\n| `BRIDGE_PRELOAD_FILE_0004 \\| PRELOAD_FILE_INVALID_NAME` | 400 | Proporciona un nombre con una extensión admitida para ese `fileType` lógico. |\n\n## Códigos de error de agentes\n\nErrores de las operaciones de agentes.\n\n| Código | Referencia en inglés | Mensaje |\n| --- | --- | --- |\n| `BRIDGE_AI_AGENT_OUTBOUND_0001` | Agent Not Found | No se encontró el agente en el espacio de trabajo |\n| `BRIDGE_AI_AGENT_OUTBOUND_0002` | Agent Not Available | El agente no está disponible para conversaciones salientes |\n| `BRIDGE_AI_AGENT_OUTBOUND_0003` | Agent Type Not Supported | El tipo de agente no admite conversaciones salientes |\n| `BRIDGE_AI_AGENT_OUTBOUND_0004` | No Channels For Agent | El agente no tiene una línea activa de mensajería vinculada |\n| `BRIDGE_AI_AGENT_OUTBOUND_0005` | Agent Not Assigned To Channel | El agente no está asignado al canal solicitado |\n| `BRIDGE_AI_AGENT_OUTBOUND_0006` | Conversation Controlled By Other Agent | Otro agente controla la conversación activa |\n| `BRIDGE_AI_AGENT_OUTBOUND_0007` | Invalid Cursor | El cursor de paginación está mal formado o pertenece a otro espacio de trabajo |\n\n`POST .../agents/{agentId}/outbound` devuelve `0001` y `0004` como `404`, `0002` y `0006` como `409`, y `0003` y `0005` como `422`.\n\n- `0002`: el agente está en borrador o no tiene una línea. `extra.reason` indica la causa; esa misma causa aparece en `unavailableReason` en `GET .../agents`.\n- `0006`: la conversación del contacto en la línea seleccionada por la solicitud está controlada por otro agente o por un usuario de Bridge. No se envió nada. Libérala con `POST .../conversations/{conversationId}/release`, usando `extra.conversationId`, y vuelve a intentar. `extra` también incluye `channelId` y, solo si la controla un agente, `controllingAgentId`, que identifica a ese agente. Cuando la controla un usuario de Bridge, la clave no aparece; no se devuelve `null`.\n\n`GET .../agents` devuelve `0007` como `400` cuando el `cursor` está mal formado o se emitió para otro espacio de trabajo. Empieza otra vez sin cursor. Conserva el mismo filtro `type` durante la paginación: un cursor emitido con un filtro `type` se rechaza si la solicitud usa otro `type`.\n\n### Otros códigos de `POST .../agents/{agentId}/outbound`\n\n| Código | Estado | Significado |\n| --- | --- | --- |\n| `BRIDGE_CORE_0103` | 400 | La solicitud es inválida: `consent.status` es `GRANTED` sin `capturedAt`, `template` no incluye `id` ni `name`, o `template.media` no incluye exactamente uno de `mediaId` o `url` |\n| `BRIDGE_CORE_0301` | 403 | El espacio de trabajo de la ruta no coincide con el de la clave de API |\n| `BRIDGE_AI_LEADSCOUT_0001` | 404 | El contacto no existe en el espacio de trabajo |\n| `BRIDGE_AI_LEADSCOUT_0002` | 404 | El usuario de Bridge de `handoffOverride` no existe en el espacio de trabajo |\n| `BRIDGE_AI_LEADSCOUT_0003` | 409 | Se eliminó al usuario de Bridge de `handoffOverride` |\n| `BRIDGE_AI_LEADSCOUT_0004` | 404 | Ninguna plantilla del espacio de trabajo coincide con `template.id`, o con `template.name` cuando no se envía un ID |\n| `BRIDGE_AI_LEADSCOUT_0005` | 409 | La plantilla no está aprobada |\n| `BRIDGE_AI_LEADSCOUT_0006` | 400 | No coinciden los parámetros ordenados de la plantilla |\n| `BRIDGE_AI_LEADSCOUT_0007` | 409 | Ya existe una conversación activa: otra solicitud obtuvo primero la conversación liberada. Reintenta |\n| `BRIDGE_AI_LEADSCOUT_0008` | 409 | Ninguna línea del agente está libre o es recuperable para este contacto; consulta `forceSend` |\n| `BRIDGE_AI_LEADSCOUT_0009` | 404 | No hay una línea configurada para el `brandId` solicitado |\n| `BRIDGE_AI_LEADSCOUT_0016` | 400 | Error de validación de conversación saliente |\n| `BRIDGE_AI_LEADSCOUT_0017` | 409 | La sesión más reciente no está finalizada |\n| `BRIDGE_AI_LEADSCOUT_0018` | 409 | No se pudo finalizar la sesión vencida antes de iniciar otra |\n| `BRIDGE_AI_LEADSCOUT_0019` | 422 | Faltan una o más variables obligatorias de la plantilla |\n| `BRIDGE_AI_LEADSCOUT_0020` | 422 | Hay fuentes de parámetros de plantilla superpuestas para la misma posición |\n| `BRIDGE_AI_LEADSCOUT_0021` | 422 | Clave de parámetro de plantilla desconocida |\n\nEn `POST .../agents/{agentId}/outbound`, los errores `5xx` no incluyen `code` ni `extra`.\n\n## Códigos de error de LeadScout\n\nCódigos adicionales documentados para [iniciar una conversación saliente de LeadScout](https://docs.bridge.new/es/api-reference/leadscout-api/iniciar-conversaci%C3%B3n-saliente-de-leadscout-con-un-lead-conocido.md) mediante `POST .../leadscout/outbound`:\n\n| Código | Estado | Referencia en inglés | Significado |\n| --- | --- | --- | --- |\n| `BRIDGE_AI_LEADSCOUT_0010` | 404 | Channel Not In Workspace | El canal de proveedor no pertenece al espacio de trabajo |\n| `BRIDGE_AI_LEADSCOUT_0011` | 404 | No Provider Channels | El espacio de trabajo no tiene canales de proveedor |\n| `BRIDGE_AI_LEADSCOUT_0012` | 404 | No Agent For Channel | No hay un agente de prospección para el canal |\n| `BRIDGE_AI_LEADSCOUT_0013` | 409 | Multiple Agents For Brand | Hay varios agentes de prospección para la marca |\n| `BRIDGE_AI_LEADSCOUT_0014` | 409 | Multiple Agents For Channel | Hay varios agentes de prospección para el canal |\n| `BRIDGE_AI_LEADSCOUT_0015` | 500 | Conversation Operation Failed | Falló la operación de conversación |\n\n## Códigos de error de marcas\n\nErrores de comprobación de marcas al crear una conversación.\n\n| Código | Referencia en inglés | Mensaje |\n| --- | --- | --- |\n| `BRIDGE_BRAND_0101` | Brand Required | El espacio de trabajo tiene marcas habilitadas; cada participante externo debe corresponder a una marca o línea |\n\nSe devuelve como `400`. Envía `brandId` o `providerChannelId` para cada participante externo; `extra.resources` enumera los participantes que no tenían ninguno de los dos.\n\n## Códigos de error de conversaciones\n\nErrores de las operaciones de conversaciones.\n\n| Código | Referencia en inglés | Mensaje |\n| --- | --- | --- |\n| `BRIDGE_CONVERSATION_0001` | Conversation Not Found | No se encontró la conversación solicitada |\n| `BRIDGE_CONVERSATION_0002` | Conversation Not In Workspace | La conversación no pertenece al espacio de trabajo especificado |\n| `BRIDGE_CONVERSATION_0003` | Conversation With Same Participants Already Exists | Ya existe una conversación activa con los mismos participantes |\n| `BRIDGE_CONVERSATION_0004` | Conversation Not Active | La conversación está inactiva y no se pueden hacer operaciones sobre ella |\n| `BRIDGE_CONVERSATION_0005` | Conversation Operation Failed | Ocurrió un error al operar sobre la conversación |\n| `BRIDGE_CONVERSATION_0006` | Conversation With Inconsistent State | La conversación tiene un estado inconsistente; contacta a soporte para resolverlo |\n| `BRIDGE_CONVERSATION_0007` | Conversation Is Released | La conversación está liberada: `409` en `POST .../messages` |\n| `BRIDGE_CONVERSATION_0101` | Internal User Already In Conversation | El usuario interno ya participa en la conversación |\n| `BRIDGE_CONVERSATION_0102` | Internal User Not In Conversation | El usuario interno no participa en la conversación |\n| `BRIDGE_CONVERSATION_0103` | External User Already In Conversation | El usuario externo ya participa en la conversación |\n| `BRIDGE_CONVERSATION_0104` | External User Not In Conversation | El usuario externo no participa en la conversación |\n| `BRIDGE_CONVERSATION_0105` | External User Already Use This Channel | El usuario externo ya usa este canal de mensajería en otra conversación |\n| `BRIDGE_CONVERSATION_0201` | External Participants Required | Se requiere al menos un participante externo para operar en una conversación |\n| `BRIDGE_CONVERSATION_0202` | Internal Participants Required | Se requiere al menos un participante interno para operar en una conversación |\n| `BRIDGE_CONVERSATION_0203` | User Is Not Admin | El usuario no es administrador de esta conversación |\n| `BRIDGE_CONVERSATION_0204` | Last Admin Removal Forbidden | La conversación debe tener al menos un administrador |\n| `BRIDGE_CONVERSATION_0205` | Min Internal Users Required | La conversación debe tener una cantidad mínima de participantes internos |\n| `BRIDGE_CONVERSATION_0206` | Max Internal Participants Exceeded | Se superó el máximo de participantes internos de la conversación |\n| `BRIDGE_CONVERSATION_0207` | Min External Participants Required | La conversación debe tener una cantidad mínima de participantes externos |\n| `BRIDGE_CONVERSATION_0208` | Max External Participants Exceeded | Se superó el máximo de participantes externos de la conversación |\n| `BRIDGE_CONVERSATION_0210` | Min Participants Required | La conversación debe tener una cantidad mínima de participantes |\n| `BRIDGE_CONVERSATION_0211` | Max Participants Exceeded | La conversación debe respetar una cantidad máxima de participantes |\n| `BRIDGE_CONVERSATION_0212` | Max Initial Messages Exceeded | Se superó el máximo de mensajes iniciales |\n| `BRIDGE_CONVERSATION_0213` | Messages Not In Conversation | Los mensajes deben pertenecer a la misma conversación |\n| `BRIDGE_CONVERSATION_0601` | Onboarding Template Not Found | No existe una plantilla indicada en el reemplazo de plantillas de inicio |\n| `BRIDGE_CONVERSATION_0602` | Onboarding Template Not In Workspace | Una plantilla indicada en el reemplazo de inicio pertenece a otro espacio de trabajo |\n| `BRIDGE_CONVERSATION_0603` | Onboarding Template Not Approved | Una plantilla indicada en el reemplazo de inicio no está aprobada para la línea usada para contactar a un participante |\n| `BRIDGE_CONVERSATION_0604` | Onboarding Template Missing Parameters | Faltan en una plantilla de inicio valores que solo puede proporcionar quien hace la solicitud |\n| `BRIDGE_CONVERSATION_0605` | Onboarding Template Unknown Parameters | El reemplazo de inicio nombra parámetros que la plantilla no declara |\n| `BRIDGE_CONVERSATION_0606` | Onboarding Template Parameters Not Supported | Se enviaron parámetros para una plantilla de inicio que no es una plantilla de proveedor de WhatsApp |\n| `BRIDGE_CONVERSATION_0607` | Onboarding Template Invalid Parameter Values | Los valores de parámetros de una plantilla de inicio infringen una regla de WhatsApp y se rechazarían al enviarse |\n| `BRIDGE_CONVERSATION_0608` | Onboarding Configured Template Requires Caller Input | Una plantilla de la secuencia de inicio del espacio de trabajo necesita valores que solo puede proporcionar quien hace la solicitud; un administrador debe cambiar la secuencia |\n\nAl crear una conversación, `BRIDGE_CONVERSATION_0105` devuelve `409` con `extra.reason` igual a `PARTICIPANTS_MISMATCH`: una conversación liberada ocupa la línea del contacto con otros contactos o líneas. Solicita los mismos contactos y líneas o usa otra línea.\n\n`BRIDGE_CONVERSATION_0601` devuelve `404`, `0602` y `0603` devuelven `400`, y `0604` a `0608` devuelven `422`. Consulta [Parámetros de plantillas de inicio](https://docs.bridge.new/es/templates-and-parameters.md) para saber qué incluye cada uno en `extra` y cómo corregirlo.\n\n## Códigos de error de usuarios externos\n\nErrores de las operaciones de usuarios externos o contactos.\n\n| Código | Referencia en inglés | Mensaje |\n| --- | --- | --- |\n| `BRIDGE_EXTERNAL_0001` | External User Not Found | No se encontró el usuario externo solicitado |\n| `BRIDGE_EXTERNAL_0002` | External User Already Exists | Ya existe un usuario externo con los mismos datos de identificación |\n| `BRIDGE_EXTERNAL_0004` | External User Not In Workspace | Uno o más usuarios externos no pertenecen al espacio de trabajo especificado |\n| `BRIDGE_EXTERNAL_0005` | External User Without Configured Field | El usuario externo no tiene un campo configurado; revisa la configuración del espacio de trabajo o de información externa |\n| `BRIDGE_EXTERNAL_0007` | Cellphone Owned By Another Contact | El teléfono ya es una identidad activa de otro usuario externo |\n| `BRIDGE_EXTERNAL_0013` | Email Owned By Another Contact | El correo ya es una identidad activa de otro usuario externo |\n| `BRIDGE_EXTERNAL_0101` | External User Operation Failed | Ocurrió un error al operar sobre el usuario externo |\n\n## Códigos de error de usuarios internos\n\nErrores de las operaciones de usuarios internos.\n\n| Código | Referencia en inglés | Mensaje |\n| --- | --- | --- |\n| `BRIDGE_INTERNAL_0001` | Internal User Not Found | No se encontró el usuario interno |\n| `BRIDGE_INTERNAL_0002` | Internal Users Not In Workspace | Los usuarios internos proporcionados no pertenecen al espacio de trabajo especificado |\n| `BRIDGE_INTERNAL_0003` | Inactive Internal User | Uno o más usuarios internos están inactivos en el espacio de trabajo; revisa su estado en la configuración |\n| `BRIDGE_INTERNAL_0004` | Internal User Without Configured Field | El usuario interno no tiene un campo configurado; revisa la configuración del espacio de trabajo o de información interna |\n| `BRIDGE_INTERNAL_0101` | Internal User Does Not Support Operation | El usuario interno no admite esta operación |\n\n## Códigos de error de canales de proveedor\n\nErrores de las operaciones de canales de proveedor.\n\n| Código | Referencia en inglés | Mensaje |\n| --- | --- | --- |\n| `BRIDGE_PROVIDER_CHANNEL_0001` | Provider Channel Not Found | No se encontró el canal de proveedor; verifica que el espacio de trabajo tenga canales configurados |\n\nAl crear una conversación, este código se devuelve como `409` cuando no hay una línea de WhatsApp libre para un contacto ni una conversación liberada que recuperar, o cuando el `providerChannelId` indicado no está disponible para ese contacto.\n\n## Códigos de error de límites de solicitudes\n\nErrores devueltos cuando un espacio de trabajo supera su presupuesto de solicitudes. Consulta el presupuesto, los encabezados y un cliente que regula su ritmo en [Límites de solicitudes](https://docs.bridge.new/es/rate-limits.md).\n\n| Código | Referencia en inglés | Mensaje |\n| --- | --- | --- |\n| `BRIDGE_RATE_LIMIT_0001` | Too Many Requests | El espacio de trabajo agotó el presupuesto de solicitudes de la ventana actual |\n\nEste es el único código que debe reintentarse automáticamente, y solo después de la espera indicada por `Retry-After`. Los fallos de autenticación no son errores de límite de solicitudes y reintentarlos de forma programada no los resolverá.\n\n## Códigos de error de solicitudes\n\nErrores devueltos antes de ejecutar una operación cuando la propia solicitud no se puede procesar. Consulta en el [Registro de cambios](https://docs.bridge.new/es/changelog.md) los parámetros que un endpoint dejará de aceptar.\n\n| Código | Referencia en inglés | Mensaje |\n| --- | --- | --- |\n| `BRIDGE_CORE_0101` | Invalid Field Format | El formato del campo es inválido; proporciona un valor válido |\n| `BRIDGE_CORE_0102` | Missing Required Field | Faltan campos obligatorios; revisa la operación |\n| `BRIDGE_CORE_0103` | Bad Request | La solicitud es inválida; revisa el cuerpo y los parámetros |\n| `BRIDGE_CORE_0104` | Invalid Cursor | El cursor es inválido; usa uno obtenido de una respuesta anterior |\n\nNo reintentes ninguno de estos casos sin hacer cambios. `detail` describe el problema y, cuando es posible, indica el campo o parámetro incorrecto; la misma solicitud fallará igual hasta que la modifiques.\n\n## Códigos de error de plantillas\n\nErrores de las operaciones de plantillas.\n\n| Código | Referencia en inglés | Mensaje |\n| --- | --- | --- |\n| `BRIDGE_TEMPLATE_0001` | Provider Template Not Found | No se encontró una plantilla de proveedor para el espacio de trabajo y nombre indicados |\n\n`GET .../templates/{templateId}` lo devuelve como `404` cuando el ID o nombre no coincide con una plantilla de WhatsApp de tu espacio de trabajo.\n\n## Códigos de error de espacios de trabajo\n\nErrores de las operaciones de espacios de trabajo.\n\n| Código | Referencia en inglés | Mensaje |\n| --- | --- | --- |\n| `BRIDGE_WORKSPACE_0001` | Workspace Not Found | No se encontró el espacio de trabajo solicitado |\n| `BRIDGE_WORKSPACE_0002` | Workspace Not In Organization | El espacio de trabajo no pertenece a la organización especificada |\n| `BRIDGE_WORKSPACE_0003` | Workspace Without Available Provider Channels | El espacio de trabajo no tiene canales de proveedor disponibles |\n| `BRIDGE_WORKSPACE_0004` | Workspace Without Configured Field | El espacio de trabajo no tiene un campo configurado: `409` en `POST .../conversations/{conversationId}/release` |\n"
    },
    {
      "title": "Registro de cambios",
      "source": "https://docs.bridge.new/es/changelog",
      "markdownUrl": "https://docs.bridge.new/es/changelog.md",
      "description": "Cambios de la API de Bridge que afectan tu integración, del más reciente al más antiguo.",
      "kind": "page",
      "contentMarkdown": "## Descripción general\n\nAquí se muestran los cambios que afectan las llamadas que ya haces, del más reciente al más antiguo. Los cambios aditivos —un endpoint nuevo o un campo opcional nuevo— no se incluyen salvo que reemplacen algo que se retirará; aparecen en la [referencia de la API REST](https://docs.bridge.new/es/api-reference/health/comprobar-estado.md) cuando se publican.\n\n**Nota**\n\n  Las entradas anteriores de abajo no registraron fechas de entrada en vigor. No se han verificado sus fechas de despliegue y su orden no establece una fecha de lanzamiento. **Aún no se ha anunciado** la fecha de retirada de los filtros de listado obsoletos. Sigue usando el contrato actual documentado hasta que se publique un cambio efectivo y usa los endpoints de consulta por identificador disponibles para integraciones nuevas.\n\n## Mejoras de documentación\n\nEsta revisión aclara el contrato existente de la API e incorpora guías de integración por tarea. Renombra la función de landing pages como **Custom Connections**, explica la reutilización y recuperación de conversaciones salientes y mejora las guías de errores y webhooks. Se conservan las firmas actuales de la API y las URLs de documentación `/lead-capture`. La fecha de una revisión documental no es una fecha de despliegue de la API ni de retirada de funciones.\n\n---\n\n## Crear una conversación puede recuperar una liberada\n\n`POST /conversations` antes devolvía `409 BRIDGE_PROVIDER_CHANNEL_0001` cuando no había una línea libre. Ahora, si los contactos solicitados tienen una conversación liberada con recuperación habilitada, se recupera y se devuelve con `201` y su `id` existente. Por eso puedes recibir un `id` que ya tenías guardado. Si esa conversación incluye otros contactos o líneas, la solicitud devuelve `409 BRIDGE_CONVERSATION_0105`. Consulta los detalles en la [referencia de la API REST](https://docs.bridge.new/es/api-reference/health/comprobar-estado.md).\n\n---\n\n## Buscar un contacto o usuario por identificador\n\n**Advertencia**\n\n  **Se retirarán parámetros de consulta que existen hoy.** Todavía funcionan y están marcados como obsoletos en la [referencia de la API REST](https://docs.bridge.new/es/api-reference/health/comprobar-estado.md). Antes de que dejen de aceptarse publicaremos aquí la fecha. Los endpoints de consulta por identificador que los reemplazan ya están disponibles.\n\n### Qué cambia\n\n**Disponibles ahora:** `GET /contacts/lookup` y `GET /users/lookup` devuelven un contacto o un usuario de Bridge —usuario interno en la referencia de la API— a partir de un identificador.\n\n**Obsoletos, pendientes de retirada:** los endpoints de listado dejarán de filtrar. `GET /contacts` y `GET /users` conservarán únicamente `limit` y `cursor`.\n\n| Obsoleto | Reemplazo |\n| --- | --- |\n| `GET /contacts?search=`: teléfono | `GET /contacts/lookup?type=PHONE&value=…` |\n| `GET /contacts?search=`: correo | `GET /contacts/lookup?type=EMAIL&value=…` |\n| `GET /contacts?search=`: nombre | **Ninguno** |\n| `GET /contacts?ownerEmail=` | **Ninguno** |\n| `GET /users?email=` | `GET /users/lookup?type=EMAIL&value=…` |\n| `GET /users?status=` | **Ninguno**: cada fila ya incluye `status` |\n\nDespués de retirarse, el parámetro se **rechazará**, no se ignorará. Enviarlo devolverá `400` con `BRIDGE_CORE_0103` y la respuesta nombrará el parámetro. Es deliberado: si se ignorara el filtro silenciosamente, la llamada entregaría la primera página de todo el espacio de trabajo y podrías tratarla como una coincidencia.\n\n### Qué debes hacer\n\n**Si buscas por teléfono o correo**, migra al endpoint de consulta correspondiente. Devuelve el mismo objeto que el listado entrega en cada fila, o `404` cuando no hay coincidencia.\n\n`type` acepta los tipos de identificador que la API usa en otros lugares: los mismos valores de `identifierType` de un participante de conversación. Los contactos admiten `ID`, `EMAIL` y `PHONE`; los usuarios de Bridge admiten `ID` y `EMAIL`, porque su teléfono no funciona como identificador de consulta en Bridge.\n\nSe admite `ID` por la misma razón: el código que ya maneja un par `{identifierType, identifier}` no debería tener que separar uno de sus valores para construir una URL distinta. Devuelve exactamente lo mismo que `GET /contacts/{contactId}`, que sigue siendo la URL canónica de un contacto: prefiérela cuando ya tengas el ID.\n\n```bash\n# Before\ncurl \"https://api-connect-us.bridge.new/bridge/api/v1/workspaces/$WORKSPACE/contacts?search=%2B14084029292\" \\\n  -H \"x-api-key: $BRIDGE_API_KEY\"\n\n# After\ncurl \"https://api-connect-us.bridge.new/bridge/api/v1/workspaces/$WORKSPACE/contacts/lookup?type=PHONE&value=%2B14084029292\" \\\n  -H \"x-api-key: $BRIDGE_API_KEY\"\n```\n\nUn `PHONE` se interpreta igual que el teléfono que envías al crear un contacto: si no incluye código de país, se interpreta según el país predeterminado del espacio de trabajo, y se ignoran espacios y separadores. En un `EMAIL`, el dominio se convierte a minúsculas, pero la parte local debe coincidir exactamente con lo enviado.\n\n**Nota**\n\n  Un teléfono en formato internacional comienza con `+`, que debe codificarse como `%2B` en la cadena de consulta. La mayoría de los clientes HTTP lo hacen automáticamente si proporcionas los parámetros como un mapa en lugar de construir la URL a mano.\n\nUn `value` que no corresponda a su `type` —correo, teléfono o UUID con formato incorrecto— se rechaza con `422` y `BRIDGE_CORE_0101` antes de hacer la búsqueda. Si pasas entradas del usuario directamente, maneja ese caso por separado de `404`: uno indica *enviaste algo que no es un identificador* y el otro, *nadie en este espacio de trabajo tiene ese identificador*.\n\n**Si filtras usuarios de Bridge por estado**, lee el `status` de cada fila. Es un valor calculado, no almacenado, y ya aparece en todas las respuestas. Hoy el listado devuelve solo usuarios activos si no envías `status`; cuando se retire ese parámetro, devolverá tanto activos como deshabilitados.\n\nLo mismo aplica a `GET /users/lookup`: devuelve al usuario de Bridge esté activo o deshabilitado y prefiere el activo cuando el correo coincide con ambos. Hoy `GET /users?email=` no devuelve un usuario deshabilitado; por eso debes revisar el `status` de la respuesta si solo quieres actuar sobre usuarios activos.\n\n**Si buscas contactos por nombre**, no habrá reemplazo. Conviene entender qué se pierde: el parámetro solo coincide con el **nombre completo exacto**, formado por nombre, un espacio y apellido. Nunca coincide con un prefijo, una parte del nombre o solo el apellido. Si hoy te funciona, ya estás enviando el nombre completo.\n\n**Si filtras contactos por propietario**, no habrá reemplazo. Obtén la página y filtra por `ownerId` en tu código. `ownerId` es el ID del usuario de Bridge propietario, no su correo: consúltalo una vez con `GET /users/lookup?type=EMAIL&value=…` y compáralo con su `id`.\n\n### Por qué cambia\n\nFiltrar con esos parámetros hace que el costo de la llamada dependa del tamaño del espacio de trabajo en lugar del tamaño de la respuesta. Buscar un contacto por teléfono en un espacio de trabajo grande lee decenas de miles de registros para devolver uno; pedir una página mayor lo hace más lento, no más rápido. Los endpoints de consulta solo leen los registros que tienen ese identificador.\n\nPor eso se retiran esos filtros en lugar de ajustarlos: cuando existe un reemplazo, es mejor; y la búsqueda por nombre, que no tiene reemplazo, nunca encontró algo distinto del nombre completo exacto.\n\n---\n\n## Temas relacionados\n\n- [Códigos de error](https://docs.bridge.new/es/error-codes.md): referencia completa, incluidos `BRIDGE_CORE_0103` y `BRIDGE_CORE_0101`.\n- [Referencia de la API REST](https://docs.bridge.new/es/api-reference/health/comprobar-estado.md): endpoints de consulta, sus parámetros y sus respuestas.\n- [Límites de solicitudes](https://docs.bridge.new/es/rate-limits.md): qué acepta la API por espacio de trabajo y cómo esperar correctamente antes de reintentar.\n"
    },
    {
      "title": "Recibe webhooks de Bridge",
      "source": "https://docs.bridge.new/es/webhooks",
      "markdownUrl": "https://docs.bridge.new/es/webhooks.md",
      "description": "Conecta un receptor HTTPS a los eventos de Bridge y entiende la autenticación, la confirmación de recepción y el procesamiento asíncrono.",
      "kind": "page",
      "contentMarkdown": "Los webhooks envían eventos **desde Bridge hacia tu sistema**. Configura una URL de recepción HTTPS y suscríbete a las familias de eventos que necesita tu integración. Bridge envía JSON mediante `POST`; tu receptor autentica y almacena el evento antes de devolver `2xx`.\n\nUsa la [API REST de integraciones](https://docs.bridge.new/es/credentials.md) cuando tu sistema necesite leer o modificar un recurso de Bridge. Una suscripción de webhook no crea por sí sola una integración bidireccional completa con un CRM: tu receptor debe relacionar los identificadores, procesar el evento e implementar las escrituras de vuelta que necesites mediante la operación REST documentada.\n\n## Construye el receptor\n\n  \n\n### Elige los eventos\n\n    Lee la [referencia de eventos](https://docs.bridge.new/es/webhooks/events.md) y elige la familia y la versión de suscripción adecuadas para tu flujo.\n  \n\n  \n\n### Verifica y almacena cada solicitud\n\n    Sigue [Verificar firmas](https://docs.bridge.new/es/webhooks/verifying-signatures.md) para la serialización HMAC exacta y [Recepción de eventos](https://docs.bridge.new/es/webhooks/receive-events.md) para un ejemplo de almacenamiento duradero.\n  \n\n  \n\n### Configura y prueba la recepción\n\n    Introduce la URL, la clave de API del webhook y el secreto de cliente en la [consola de administración de Bridge](https://docs.bridge.new/es/webhooks/configuration.md). Comprueba el webhook de prueba antes de habilitar el flujo de negocio.\n  \n\n```mermaid\nsequenceDiagram\n    participant B as Bridge\n    participant R as Tu receptor\n    participant I as Bandeja de entrada duradera\n    participant W as Tu proceso de trabajo\n    B->>R: POST de un evento JSON y encabezados de autenticación\n    R->>R: Verifica la clave de API, el HMAC y la política de vigencia\n    R->>I: Guarda el evento verificado o confirma el duplicado exacto\n    I-->>R: Aceptación duradera\n    R-->>B: Confirmación 2xx\n    W->>I: Lee los eventos pendientes\n    W->>W: Aplica la acción de negocio de forma idempotente\n```\n\n\n## Mantén separadas las credenciales\n\n| Encabezado | Finalidad |\n| --- | --- |\n| `X-Bridge-API-Key` | Clave de API del webhook configurada para esta URL de recepción. Compárala con el valor esperado. |\n| `X-Bridge-Signature` | `sha256=` seguido del HMAC-SHA256 de la representación canónica del evento de Bridge, calculado con tu secreto de cliente del webhook. |\n| `X-Bridge-Timestamp` | Segundos Unix para comprobar la vigencia en el receptor. El HMAC **no** incluye este encabezado. |\n\nEstas credenciales de webhook son distintas de la `x-api-key` de la API REST y de la `captureKey` de Custom Connections usada en el navegador. Guarda el secreto de cliente del webhook en tu servidor.\n\n## Qué significa la confirmación de recepción\n\nUna respuesta `2xx` significa que tu receptor aceptó el evento. No demuestra que haya terminado la actualización del CRM u otra acción de negocio. Guarda primero el evento y procésalo fuera de la solicitud para que un servicio lento posterior no retrase la confirmación.\n\nEl emisor HTTP actual hace tres intentos por operación de entrega, con esperas de uno y dos segundos y un tiempo de espera de socket predeterminado de diez segundos. Esto no promete un total de tres intentos para toda la cadena de procesamiento del evento. Lee el [comportamiento de reintentos, duplicados y orden](https://docs.bridge.new/es/webhooks/receive-events.md) antes de elegir tu política de recuperación.\n\nNo asumas entrega exactamente una vez, un orden global de eventos ni un endpoint público de reenvío. La [referencia de eventos](https://docs.bridge.new/es/webhooks/events.md) describe los cuerpos de los eventos; la [guía del receptor](https://docs.bridge.new/es/webhooks/receive-events.md) explica cómo manejarlos de forma confiable.\n"
    },
    {
      "title": "Verifica las solicitudes de webhook",
      "source": "https://docs.bridge.new/es/webhooks/verifying-signatures",
      "markdownUrl": "https://docs.bridge.new/es/webhooks/verifying-signatures.md",
      "description": "Verifica la clave de API del webhook y la representación HMAC exacta que usa Bridge; luego deduplica los eventos aceptados.",
      "kind": "page",
      "contentMarkdown": "Verifica cada solicitud antes de aceptarla en tu sistema. Usa la clave de API del **webhook** y el secreto de cliente configurados para esta URL de recepción: son distintos de la clave de la API REST de integraciones.\n\n## Encabezados de autenticación\n\n| Encabezado | Comprobación |\n| --- | --- |\n| `X-Bridge-API-Key` | Comparación en tiempo constante con la clave de API del webhook que configuraste |\n| `X-Bridge-Signature` | `sha256=` seguido del resumen hexadecimal HMAC-SHA256 en minúsculas |\n| `X-Bridge-Timestamp` | Segundos Unix dentro de la ventana de vigencia aceptada; el ejemplo admite cinco minutos en ambas direcciones |\n\nLos nombres de los encabezados no distinguen mayúsculas y minúsculas.\n\n## Qué se firma exactamente\n\nBridge construye la entrada del HMAC a partir del evento JSON con esta expresión de Python y luego codifica la cadena en UTF-8:\n\n```python\njson.dumps(event, sort_keys=True).encode(\"utf-8\")\n```\n\nEsto ordena recursivamente las claves de los objetos, conserva el orden de los arrays, escapa los caracteres no ASCII y usa los espacios predeterminados de Python después de comas y dos puntos. No agrega un salto de línea final. La clave es el secreto de cliente codificado en UTF-8. Es una convención de serialización JSON de Python, no RFC 8785 / JCS.\n\nNo la reemplaces por un resumen de los bytes crudos arbitrarios de la solicitud, JSON compacto, un `JSON.stringify` genérico de JavaScript ni una cadena con una marca de tiempo como prefijo. Los espacios, los escapes Unicode y el formato de números pueden cambiar la entrada HMAC aunque el objeto interpretado parezca equivalente. Usa el verificador de Python de abajo o prueba otra implementación contra el vector antes de conectarla.\n\n**Advertencia**\n\n  La entrada HMAC actual contiene únicamente el JSON del evento. **`X-Bridge-Timestamp` no está incluido en la firma.** Comprueba la vigencia, pero no consideres que la marca de tiempo por sí sola ofrece protección criptográfica contra reenvíos: un cuerpo y una firma válidos anteriores pueden presentarse con otra marca de tiempo. Autentica la clave de API del webhook y usa una bandeja de entrada duradera y procesamiento idempotente, como explica [Recepción de eventos](https://docs.bridge.new/es/webhooks/receive-events.md).\n\n## Verificador de Python\n\nGuárdalo como `bridge_webhooks.py`. Devuelve el objeto interpretado y verificado para que el código posterior use la misma interpretación que se autenticó. Obtén los secretos de variables de entorno del servidor o de tu almacén de secretos.\n\n```python\nimport hashlib\nimport hmac\nimport json\nimport re\nimport sqlite3\nimport time\n\n\nclass VerificationError(ValueError):\n    pass\n\n\ndef canonical_payload(event):\n    # Match Bridge's Python json.dumps defaults: sort recursively, ASCII escapes,\n    # a space after commas and colons, then UTF-8. This is not RFC 8785 / JCS.\n    return json.dumps(event, sort_keys=True).encode(\"utf-8\")\n\n\ndef _unique_object(pairs):\n    result = {}\n    for key, value in pairs:\n        if key in result:\n            raise VerificationError(\"Duplicate JSON object key\")\n        result[key] = value\n    return result\n\n\ndef verify_webhook(raw_body, headers, webhook_api_key, client_secret, *, now=None, tolerance=300):\n    headers = {key.lower(): value for key, value in headers.items()}\n    received_key = headers.get(\"x-bridge-api-key\", \"\")\n    if not received_key or not webhook_api_key or not client_secret:\n        raise VerificationError(\"Missing webhook credentials\")\n    if not hmac.compare_digest(received_key.encode(\"utf-8\"), webhook_api_key.encode(\"utf-8\")):\n        raise VerificationError(\"Invalid webhook API key\")\n\n    received_signature = headers.get(\"x-bridge-signature\", \"\")\n    if not re.fullmatch(r\"sha256=[0-9a-f]{64}\", received_signature):\n        raise VerificationError(\"Invalid signature format\")\n    timestamp = headers.get(\"x-bridge-timestamp\", \"\")\n    if not re.fullmatch(r\"[0-9]+\", timestamp):\n        raise VerificationError(\"Invalid timestamp\")\n    current_time = time.time() if now is None else now\n    if abs(current_time - int(timestamp)) > tolerance:\n        raise VerificationError(\"Timestamp outside the permitted window\")\n\n    try:\n        event = json.loads(raw_body.decode(\"utf-8\"), object_pairs_hook=_unique_object)\n    except (UnicodeDecodeError, json.JSONDecodeError) as exc:\n        raise VerificationError(\"Invalid JSON body\") from exc\n    if not isinstance(event, dict):\n        raise VerificationError(\"Expected a JSON object\")\n    expected = \"sha256=\" + hmac.new(\n        client_secret.encode(\"utf-8\"), canonical_payload(event), hashlib.sha256\n    ).hexdigest()\n    if not hmac.compare_digest(expected, received_signature):\n        raise VerificationError(\"Invalid webhook signature\")\n    return event\n\n```\n\nLa ventana de cinco minutos es una política del receptor; mantén sincronizado el reloj de tu servidor. El verificador también rechaza claves JSON duplicadas y ambiguas. No desactives la autenticación para depurar una discrepancia: revisa las credenciales configuradas y compara la entrada canónica con los datos de prueba siguientes.\n\n## Vector de firma reproducible\n\nEstos valores son datos sintéticos de prueba, no credenciales reales ni un evento para enviar a Bridge. Al probar las comprobaciones de vigencia, fija el argumento `now` del verificador en `1800000000`.\n\n| Valor | Dato de prueba |\n| --- | --- |\n| Secreto de cliente | `bridge-docs-test-secret` |\n| Clave de API del webhook | `bridge-docs-test-key` |\n| Encabezado de marca de tiempo | `1800000000` |\n| Firma esperada | `sha256=5536c29fd98baab6ffe46dd9517adb185b32202864cbb5a76146172fc0b39423` |\n\nObjeto de evento:\n\n```json\n{\n  \"eventId\": \"evt_docs_001\",\n  \"eventType\": \"contact.updated\",\n  \"entity\": \"contact\",\n  \"workspaceId\": \"ws_docs\",\n  \"timestamp\": \"2026-01-01T00:00:00Z\",\n  \"payload\": {\n    \"name\": \"José\",\n    \"tags\": [\n      \"café\",\n      \"one\"\n    ],\n    \"active\": true,\n    \"count\": 2\n  }\n}\n```\n\nCadena JSON exacta que se firma: las secuencias `\\u` siguientes contienen barras invertidas ASCII literales, no caracteres decodificados.\n\n```text\n{\"entity\": \"contact\", \"eventId\": \"evt_docs_001\", \"eventType\": \"contact.updated\", \"payload\": {\"active\": true, \"count\": 2, \"name\": \"Jos\\u00e9\", \"tags\": [\"caf\\u00e9\", \"one\"]}, \"timestamp\": \"2026-01-01T00:00:00Z\", \"workspaceId\": \"ws_docs\"}\n```\n\nCambiar un campo debe hacer fallar la verificación. Cambiar solo el orden de las claves de entrada o enviar Unicode literal en lugar de escapes Unicode JSON debe seguir verificando después de interpretar el JSON y reconstruir la misma representación canónica.\n\n## Después de verificar\n\nGuarda el evento de forma duradera antes de confirmar su recepción. Un HMAC válido confirma la representación autenticada del evento; no demuestra que se haya ejecutado tu acción de negocio, que el evento sea nuevo ni que represente el estado más reciente del recurso. Continúa con [entrega, duplicados y orden](https://docs.bridge.new/es/webhooks/receive-events.md).\n"
    },
    {
      "title": "Recibe eventos de forma confiable",
      "source": "https://docs.bridge.new/es/webhooks/receive-events",
      "markdownUrl": "https://docs.bridge.new/es/webhooks/receive-events.md",
      "description": "Verifica, guarda y confirma los webhooks; después procesa de forma segura los duplicados y los eventos fuera de orden.",
      "kind": "page",
      "contentMarkdown": "Un receptor de webhooks tiene dos tareas: aceptar rápidamente un evento autenticado y procesarlo de forma confiable después. Ejecuta las llamadas lentas al CRM, el enriquecimiento y otras tareas de negocio fuera de la solicitud HTTP.\n\n## Recibe → verifica → guarda → confirma\n\n1. Lee el cuerpo y los encabezados de la solicitud.\n2. Verifica la clave de API del webhook, el HMAC canónico y la política de marcas de tiempo con [el verificador](https://docs.bridge.new/es/webhooks/verifying-signatures.md).\n3. Guarda atómicamente el evento verificado en una bandeja de entrada duradera o confirma que ese evento exacto ya esté almacenado.\n4. Devuelve una respuesta `2xx` rápidamente. Procesa los eventos almacenados en un proceso de trabajo y haz que cada acción de negocio sea idempotente.\n\nDevuelve éxito solo después de la aceptación duradera. Si el almacenamiento no está disponible, devuelve una respuesta distinta de `2xx` para no confirmar el intento de entrega. Un duplicado que ya está guardado debe recibir `2xx` nuevamente.\n\n## Comportamiento de reintentos\n\nEl emisor actual hace hasta **tres intentos HTTP** para una operación de entrega. Espera **un segundo** y luego **dos segundos** antes de los intentos restantes. Cualquier respuesta `2xx` detiene esos intentos. Una respuesta distinta de `2xx`, un fallo de conexión o una excepción de solicitud pueden activar el siguiente intento. El tiempo de espera de socket predeterminado es de **10 segundos** por intento: confirma la recepción en pocos segundos en lugar de depender de un margen de 30 segundos.\n\nEl cuerpo y los encabezados de firma y marca de tiempo se reutilizan dentro de esa operación de entrega. Esos tres intentos limitan una operación de envío, **no el total de entregas de un evento de extremo a extremo**. Si un evento vuelve a entregarse en una etapa anterior, puede invocar de nuevo al emisor. Aquí no se promete un número total de reintentos ni un plazo máximo de reenvío. No dependas de un encabezado de respuesta `Retry-After` para establecer los tiempos de reintento de Bridge.\n\nSi fallan todos los intentos, la entrega se considera fallida. No asumas reintentos automáticos indefinidos ni un endpoint público de reenvío. Para investigar, conserva el espacio de trabajo, el tipo, el ID y la hora aproximada del evento, y contacta a soporte de Bridge. No incluyas las credenciales del webhook en mensajes a soporte ni en registros de la aplicación.\n\n## Duplicados e identidad del evento\n\nTu servicio puede haber guardado un evento aunque Bridge no haya recibido tu respuesta `2xx`. Reintentarlo no debe crear una segunda actualización del CRM, factura, mensaje u otro efecto de negocio.\n\nDelimita cada registro de la bandeja mediante `workspaceId`, `eventType` y `eventId`. Guarda también un resumen del evento verificado. No asumas que `eventId` es globalmente único en todas las familias de notificaciones: algunas usan un ID derivado de la entidad. Conserva los cuerpos distintos que compartan un ID y aplica después idempotencia de negocio a la operación que ejecuta tu proceso de trabajo.\n\nEl ejemplo siguiente deduplica eventos repetidos exactos usando los tres identificadores y la huella SHA-256 del evento canónico. Es una clave de bandeja para este ejemplo, no un campo nuevo de solicitud de Bridge.\n\nNo hagas vencer un registro de deduplicación solo porque transcurrió la ventana de cinco minutos de la marca de tiempo. Ese encabezado no está firmado, por lo que la ventana no establece un vencimiento seguro de protección contra reenvíos. Elige la retención según las necesidades de conciliación de tu negocio y mantén idempotentes las acciones del sistema de destino. El ejemplo no elimina automáticamente los registros de la bandeja.\n\n## Receptor duradero mínimo\n\nAgrega estas definiciones al módulo `bridge_webhooks.py` de [Verificar solicitudes de webhook](https://docs.bridge.new/es/webhooks/verifying-signatures.md). El módulo del verificador ya incluye las importaciones usadas aquí.\n\n```python\nclass SQLiteInbox:\n    \"\"\"Single-service example inbox. Use a shared durable store for multiple replicas.\"\"\"\n    def __init__(self, path):\n        self.path = str(path)\n        with sqlite3.connect(self.path) as db:\n            db.execute(\"\"\"CREATE TABLE IF NOT EXISTS webhook_inbox (\n                workspace_id TEXT NOT NULL, event_type TEXT NOT NULL,\n                event_id TEXT NOT NULL, fingerprint TEXT NOT NULL,\n                body TEXT NOT NULL, received_at REAL NOT NULL,\n                processed INTEGER NOT NULL DEFAULT 0,\n                PRIMARY KEY(workspace_id, event_type, event_id, fingerprint)\n            )\"\"\")\n\n    def accept(self, event):\n        identifiers = [event.get(key) for key in (\"workspaceId\", \"eventType\", \"eventId\")]\n        if not all(isinstance(value, str) and value for value in identifiers):\n            raise VerificationError(\"Missing event envelope identifiers\")\n        body = canonical_payload(event)\n        fingerprint = hashlib.sha256(body).hexdigest()\n        with sqlite3.connect(self.path, timeout=3) as db:\n            cursor = db.execute(\n                \"\"\"INSERT OR IGNORE INTO webhook_inbox\n                (workspace_id, event_type, event_id, fingerprint, body, received_at)\n                VALUES (?, ?, ?, ?, ?, ?)\"\"\",\n                (*identifiers, fingerprint, body.decode(\"utf-8\"), time.time()),\n            )\n            inserted = cursor.rowcount == 1\n        # Context manager commits before the request can be acknowledged.\n        return inserted\n\n\ndef make_wsgi_app(inbox, webhook_api_key, client_secret):\n    \"\"\"Verify, commit an inbox record, then acknowledge; workers process it later.\"\"\"\n    def app(environ, start_response):\n        if environ.get(\"REQUEST_METHOD\") != \"POST\":\n            start_response(\"405 Method Not Allowed\", [(\"Allow\", \"POST\")])\n            return [b\"\"]\n        try:\n            length = int(environ.get(\"CONTENT_LENGTH\") or \"0\")\n            if length < 1:\n                raise VerificationError(\"Missing JSON body\")\n            raw_body = environ[\"wsgi.input\"].read(length)\n            headers = {\n                \"x-bridge-api-key\": environ.get(\"HTTP_X_BRIDGE_API_KEY\", \"\"),\n                \"x-bridge-signature\": environ.get(\"HTTP_X_BRIDGE_SIGNATURE\", \"\"),\n                \"x-bridge-timestamp\": environ.get(\"HTTP_X_BRIDGE_TIMESTAMP\", \"\"),\n            }\n            event = verify_webhook(raw_body, headers, webhook_api_key, client_secret)\n            inbox.accept(event)  # A duplicate exact event is also acknowledged.\n        except (VerificationError, ValueError):\n            status, body = \"400 Bad Request\", b'{\"accepted\":false}'\n        except sqlite3.Error:\n            status, body = \"503 Service Unavailable\", b'{\"accepted\":false}'\n        else:\n            status, body = \"200 OK\", b'{\"accepted\":true}'\n        start_response(status, [(\"Content-Type\", \"application/json\"), (\"Content-Length\", str(len(body)))])\n        return [body]\n    return app\n\n```\n\nCrea la aplicación WSGI en la configuración de tu servidor:\n\n```python\nimport os\n\nfrom bridge_webhooks import SQLiteInbox, make_wsgi_app\n\napplication = make_wsgi_app(\n    SQLiteInbox(os.environ[\"WEBHOOK_INBOX_PATH\"]),\n    os.environ[\"BRIDGE_WEBHOOK_API_KEY\"],\n    os.environ[\"BRIDGE_WEBHOOK_CLIENT_SECRET\"],\n)\n```\n\nUsa una ruta de base de datos duradera para este ejemplo de un solo servicio. Si ejecutas varias réplicas del receptor, usa almacenamiento compartido con una restricción equivalente de unicidad atómica. Aplica los límites de tamaño de solicitud y las políticas de red de tu servicio en el servidor HTTP, y termina allí la conexión HTTPS.\n\nEste ejemplo llega hasta la aceptación duradera. Un proceso de trabajo debe leer las filas con `processed=0`, ejecutar la acción de negocio de manera idempotente y marcarlas como procesadas solo después del éxito. Una confirmación local no demuestra que la acción de negocio haya terminado.\n\n## Orden y conciliación\n\nNo dependas de un orden global de entrega. Distintas familias de recursos e intentos independientes de entrega pueden intercalarse. Dirige cada evento según el `eventType` publicado y usa el esquema de esa suscripción.\n\nCuando un cuerpo incluya `sequence`, trátalo como una indicación de orden del recurso o flujo, no como un contador global compartido por todos los espacios de trabajo o familias de eventos. No lo inventes para eventos cuyo esquema no tenga secuencia. Conserva las marcas de tiempo y los identificadores de origen, y evita reemplazar un estado nuevo por una notificación anterior. Si la API REST permite leer el recurso, consulta su estado actual cuando el evento deje el resultado incierto; de lo contrario, sigue la guía de la familia de eventos o contacta a soporte.\n\nNo exijas un campo `version` universal en todos los sobres de evento. Para las familias admitidas por este servicio de webhooks, la versión de suscripción configurada selecciona el transformador registrado y el esquema de esa familia. Sigue el esquema documentado de esa familia y suscripción; no deduzcas una propiedad de versión que el sobre no publica.\n\n## Comprueba el receptor antes de pasar a producción\n\nPrueba el vector de firma proporcionado, un cuerpo modificado, una clave de API incorrecta, marcas de tiempo vencidas y futuras, una entrega duplicada después de reiniciar el proceso, un fallo de almacenamiento y dos cuerpos distintos con el mismo ID. Reenviar un cuerpo firmado anteriormente con una nueva marca de tiempo demuestra por qué necesitas una bandeja duradera además de la comprobación de vigencia.\n\nUsa el webhook de prueba de la consola de Bridge para validar la conexión y las credenciales configuradas después de desplegar el receptor. Una prueba exitosa demuestra que funciona la ruta de recepción; no establece garantías de entrega u orden para todos los eventos de negocio.\n"
    },
    {
      "title": "Configura los webhooks",
      "source": "https://docs.bridge.new/es/webhooks/configuration",
      "markdownUrl": "https://docs.bridge.new/es/webhooks/configuration.md",
      "description": "Configura una URL de recepción, las credenciales del webhook y las suscripciones de eventos en la consola de administración de Bridge.",
      "kind": "page",
      "contentMarkdown": "Puedes administrar toda la configuración de webhooks desde la [consola de administración de Bridge](https://admin.bridge.new). Esto incluye el endpoint receptor, las claves de autenticación y los tipos de eventos a los que quieres suscribirte.\n\n---\n\n## Configura los webhooks\n\nSigue estos pasos en la consola de administración de Bridge:\n\n1. **Inicia sesión** en la consola de administración de Bridge.\n2. Ve a **Developers → Webhooks**.\n3. Proporciona estos datos:\n   - **Webhook URL:** URL HTTPS completa de tu endpoint.\n   - **API Key:** clave que identifica tu espacio de trabajo.\n   - **Client Secret:** secreto usado para generar y verificar firmas HMAC-SHA256 de los webhooks.\n4. Selecciona en **Select Event Types** los eventos a los que quieres suscribirte.\n\n---\n\n## Conectores nativos de CRM y webhooks personalizados\n\nUn conector nativo de CRM y un webhook personalizado son vías de entrega separadas. Si tienes un CRM conectado, comprueba la configuración activa del conector y las funciones que muestra la consola. Esta página no establece que se sincronicen todos los eventos, que no se requiera configuración ni que las actualizaciones tengan un plazo fijo en tiempo real.\n\nConfigura un webhook personalizado cuando tu servicio necesite recibir un evento y procesarlo por su cuenta. Puedes suscribirte a una familia de eventos que también use un conector nativo. Si tu receptor escribe en el mismo CRM, coordina las dos vías para no aplicar dos veces la misma acción de negocio.\n\nLa confirmación de un webhook personalizado solo indica que tu receptor lo aceptó. Usa [aceptación duradera y procesamiento idempotente](https://docs.bridge.new/es/webhooks/receive-events.md); no asumas que dos vías de entrega garantizan actualizaciones del CRM exactamente una vez.\n\n---\n\n## Opciones de suscripción de eventos\n\nBridge admite actualmente las siguientes categorías:\n\n### Notificaciones de resúmenes de conversación\n\nv1\n\nRecibe una notificación diaria por conversación cuando Bridge AI genera el resumen del día.\n\n- `conversation_summary.created`\n\n### Notificaciones de tareas\n\nv1\n\nRecibe notificaciones cuando se crean tareas o cambia su estado.\n\n- `task.created`\n- `task.status_changed`\n- `task.assigned`\n- `task.unassigned`\n- `task.remove_reminder`\n- `task.field_updated`\n\n### Actualizaciones de contactos\n\nv1\n\nRecibe notificaciones cuando se crean, actualizan o eliminan contactos.\n\n- `contact.created`\n- `contact.updated`\n- `contact.deleted`\n\n### Notificaciones de llamadas\n\nv1\n\nRecibe un webhook por cada fase del ciclo de vida de una llamada —creada, sonando, iniciada y finalizada— y la transcripción de IA cuando esté lista. Las llamadas no se eliminan.\n\n- `call.created`\n- `call.updated`\n- `call.transcription.created`\n\n### Notificaciones de reuniones\n\nv1\n\nRecibe una notificación cuando una reunión alcanza el estado CREATED. Las reuniones no se eliminan, por lo que solo se emite `meeting.updated`.\n\n- `meeting.updated`\n\n### Notificaciones de correo electrónico\n\nv1\n\nRecibe una notificación cuando se ha procesado un correo y está disponible su resumen de IA. Los correos no se eliminan, por lo que solo se emite `email.updated`.\n\n- `email.updated`\n\n---\n\n## Verifica la configuración\n\nAl guardar la configuración, Bridge envía automáticamente un **webhook de prueba** a tu endpoint para comprobar que sea accesible y responda correctamente.\n\nTu endpoint debe responder con:\n\n- **Código de estado HTTP:** `200–299`.\n- **Content-Type:** `application/json` (opcional).\n- **Tiempo de respuesta:** confirma rápidamente después de guardar el evento de forma duradera. El emisor usa un tiempo de espera de socket predeterminado de 10 segundos por intento HTTP; no dependas de un margen de 30 segundos. Consulta el [comportamiento de reintentos](https://docs.bridge.new/es/webhooks/receive-events.md#retry-behavior).\n\n---\n\n## Administra los webhooks\n\nPuedes administrar su configuración en cualquier momento desde la consola:\n\n| Acción | Descripción |\n| --- | --- |\n| **Edit** | Actualiza la URL, la clave de API o los eventos suscritos |\n| **Disable Events** | Pausa temporalmente tipos específicos de eventos sin eliminar el webhook |\n| **Delete** | Elimina permanentemente una configuración de webhook |\n\n---\n\n## Temas relacionados\n\n- [Descripción general](https://docs.bridge.new/es/webhooks.md)\n- [Verificar firmas](https://docs.bridge.new/es/webhooks/verifying-signatures.md)\n- [Tipos de eventos](https://docs.bridge.new/es/webhooks/events.md)\n"
    },
    {
      "title": "Eventos de webhook",
      "source": "https://docs.bridge.new/es/webhooks/events",
      "markdownUrl": "https://docs.bridge.new/es/webhooks/events.md",
      "description": "Familias de eventos, ejemplos de cuerpos y versiones de suscripción de los webhooks de Bridge.",
      "kind": "page",
      "contentMarkdown": "Los webhooks de Bridge entregan cuerpos de eventos estructurados en JSON cuando ocurren acciones específicas en tu espacio de trabajo. Cada evento sigue un esquema consistente para facilitar su interpretación y validación.\n\n---\n\n## Estructura común de los eventos\n\nEl ejemplo siguiente ilustra el sobre común: `\"string\"` representa un tipo, no un valor de evento para enviar. Lee los ejemplos de cada familia más abajo. No asumas que `eventId` sea globalmente único entre familias de notificaciones.\n\n```json\n{\n  \"eventId\": \"string\",\n  \"eventType\": \"string\",\n  \"entity\": \"string\",\n  \"workspaceId\": \"string\",\n  \"timestamp\": \"string\",\n  \"payload\": {}\n}\n```\n\n---\n\n## Notificaciones de resúmenes de conversación\n\nv1\n\nSe activan una vez al día por conversación cuando Bridge AI genera el resumen diario. El resumen recoge los puntos principales del intercambio y los participantes internos y externos involucrados.\n\n  \n\n### Tipos de eventos\n\n    | Tipo de evento | Descripción |\n    | --- | --- |\n    | `conversation_summary.created` | Se generó el resumen diario de una conversación |\n  \n\n  \n\n### Ejemplo de cuerpo\n\n    ```json\n    {\n      \"eventId\": \"evt_summary_001\",\n      \"eventType\": \"conversation_summary.created\",\n      \"entity\": \"conversation_summary\",\n      \"workspaceId\": \"ws_123\",\n      \"timestamp\": \"2026-05-19T05:03:15.910Z\",\n      \"payload\": {\n        \"conversationId\": \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n        \"summaryDate\": \"2026-05-19\",\n        \"summary\": \"- Advisor asked the customer about their preferred schedule and offered to book a product demo.\\n- Customer replied they are unavailable on Monday morning.\\n- Advisor offered alternative slots later in the week and is waiting for confirmation.\",\n        \"externalUsers\": [\n          { \"id\": \"c1d2e3f4-a5b6-7890-cdef-012345678901\", \"first_name\": \"Ana\", \"last_name\": \"Garcia\", \"cellphone\": \"+57300000000\" }\n        ],\n        \"internalUsers\": [\n          { \"id\": \"d4e5f6a7-b8c9-0123-defa-234567890123\", \"first_name\": \"Bob\", \"last_name\": \"Smith\", \"cellphone\": \"+57301000000\", \"email\": \"bob.smith@example.com\" }\n        ],\n        \"initMessageId\": \"f1e2d3c4-b5a6-7890-fedc-ba0987654321\",\n        \"endMessageId\": \"a9b8c7d6-e5f4-3210-abcd-ef9876543210\",\n        \"createdAt\": \"2026-05-19T05:03:15.910Z\",\n        \"updatedAt\": \"2026-05-19T05:03:15.910Z\"\n      }\n    }\n    ```\n  \n\n---\n\n## Actualizaciones de tareas\n\nv1\n\nSe activan cuando se crean tareas o cambian su estado, asignación o recordatorios.\n\nLos cuerpos varían según el tipo de evento. El campo `details` explica qué cambió en ese evento específico.\n\n  \n\n### Tipos de eventos\n\n    | Tipo de evento | Descripción |\n    | --- | --- |\n    | `task.created` | Se creó una tarea |\n    | `task.status_changed` | Cambió el estado de la tarea, por ejemplo, de OPEN a CLOSED |\n    | `task.assigned` | Se asignó un usuario a la tarea |\n    | `task.unassigned` | Se quitó la asignación de un usuario a la tarea |\n    | `task.remove_reminder` | Se eliminó un recordatorio de la tarea |\n    | `task.field_updated` | Se actualizó un campo de la tarea |\n  \n\n  \n\n### Ejemplos de cuerpos\n\n    \n\n    ```json Created\n    {\n      \"eventId\": \"evt_123456789\",\n      \"eventType\": \"task.created\",\n      \"entity\": \"task\",\n      \"workspaceId\": \"ws_123\",\n      \"timestamp\": \"2026-01-15T10:30:00.000Z\",\n      \"payload\": {\n        \"taskId\": \"task_123\",\n        \"actorType\": \"USER\",\n        \"actorId\": \"user_123\",\n        \"task\": {\n          \"title\": \"Sample task\",\n          \"description\": \"Example task description\",\n          \"type\": \"TASK\",\n          \"priority\": \"NORMAL\",\n          \"status\": \"OPEN\",\n          \"sourceType\": \"MANUAL\",\n          \"dueDate\": \"2026-01-20T00:00:00.000Z\",\n          \"recurrenceEnded\": false,\n          \"createdAt\": \"2026-01-15T10:30:00.000Z\",\n          \"updatedAt\": \"2026-01-15T10:30:00.000Z\"\n        },\n        \"assignees\": [\n          { \"assigneeId\": \"user_456\", \"assigneeType\": \"USER\" }\n        ],\n        \"conversations\": [\n          {\n            \"id\": \"conv_123\",\n            \"status\": \"ACTIVE\",\n            \"createdAt\": \"2026-01-14T09:10:00.000Z\",\n            \"updatedAt\": \"2026-01-14T09:10:00.000Z\"\n          }\n        ]\n      }\n    }\n    ```\n\n    ```json Assigned\n    {\n      \"eventId\": \"evt_123456790\",\n      \"eventType\": \"task.assigned\",\n      \"entity\": \"task\",\n      \"workspaceId\": \"ws_123\",\n      \"timestamp\": \"2026-01-15T10:31:00.000Z\",\n      \"payload\": {\n        \"taskId\": \"task_123\",\n        \"actorType\": \"USER\",\n        \"actorId\": \"user_123\",\n        \"details\": { \"assignee\": { \"assigneeId\": \"user_456\" } }\n      }\n    }\n    ```\n\n    ```json Unassigned\n    {\n      \"eventId\": \"evt_123456791\",\n      \"eventType\": \"task.unassigned\",\n      \"entity\": \"task\",\n      \"workspaceId\": \"ws_123\",\n      \"timestamp\": \"2026-01-15T10:32:00.000Z\",\n      \"payload\": {\n        \"taskId\": \"task_123\",\n        \"actorType\": \"USER\",\n        \"actorId\": \"user_123\",\n        \"details\": { \"assignee\": { \"assigneeId\": \"user_456\" } }\n      }\n    }\n    ```\n\n    ```json Status changed (open → closed)\n    {\n      \"eventId\": \"evt_123456792\",\n      \"eventType\": \"task.status_changed\",\n      \"entity\": \"task\",\n      \"workspaceId\": \"ws_123\",\n      \"timestamp\": \"2026-01-15T10:33:00.000Z\",\n      \"payload\": {\n        \"taskId\": \"task_123\",\n        \"actorType\": \"USER\",\n        \"actorId\": \"user_123\",\n        \"details\": {\n          \"statusChange\": { \"fromStatus\": \"OPEN\", \"toStatus\": \"CLOSED\" }\n        }\n      }\n    }\n    ```\n\n    ```json Status changed (closed → open)\n    {\n      \"eventId\": \"evt_123456793\",\n      \"eventType\": \"task.status_changed\",\n      \"entity\": \"task\",\n      \"workspaceId\": \"ws_123\",\n      \"timestamp\": \"2026-01-15T10:34:00.000Z\",\n      \"payload\": {\n        \"taskId\": \"task_123\",\n        \"actorType\": \"USER\",\n        \"actorId\": \"user_123\",\n        \"task\": {\n          \"title\": \"Sample task\",\n          \"description\": \"Example task description\",\n          \"type\": \"TASK\",\n          \"priority\": \"NORMAL\",\n          \"status\": \"OPEN\",\n          \"sourceType\": \"MANUAL\",\n          \"dueDate\": \"2026-01-20T00:00:00.000Z\",\n          \"recurrenceEnded\": false,\n          \"createdAt\": \"2026-01-15T10:30:00.000Z\",\n          \"updatedAt\": \"2026-01-15T10:34:00.000Z\"\n        },\n        \"conversations\": [\n          {\n            \"id\": \"conv_123\",\n            \"status\": \"ACTIVE\",\n            \"createdAt\": \"2026-01-14T09:10:00.000Z\",\n            \"updatedAt\": \"2026-01-14T09:10:00.000Z\"\n          }\n        ],\n        \"details\": {\n          \"statusChange\": { \"fromStatus\": \"CLOSED\", \"toStatus\": \"OPEN\" }\n        }\n      }\n    }\n    ```\n\n    ```json Reminder removed\n    {\n      \"eventId\": \"evt_123456794\",\n      \"eventType\": \"task.remove_reminder\",\n      \"entity\": \"task\",\n      \"workspaceId\": \"ws_123\",\n      \"timestamp\": \"2026-01-15T10:35:00.000Z\",\n      \"payload\": {\n        \"taskId\": \"task_456\",\n        \"actorType\": \"USER\",\n        \"actorId\": \"user_123\",\n        \"details\": { \"reminder\": { \"reminderId\": \"rem_123\" } }\n      }\n    }\n    ```\n\n    ```json Field updated\n    {\n      \"eventId\": \"evt_123456795\",\n      \"eventType\": \"task.field_updated\",\n      \"entity\": \"task\",\n      \"workspaceId\": \"ws_123\",\n      \"timestamp\": \"2026-01-15T10:36:00.000Z\",\n      \"payload\": {\n        \"taskId\": \"task_123\",\n        \"actorType\": \"USER\",\n        \"actorId\": \"user_123\",\n        \"task\": {\n          \"title\": \"Sample task\",\n          \"description\": \"Example updated description\",\n          \"type\": \"TASK\",\n          \"priority\": \"NORMAL\",\n          \"status\": \"OPEN\",\n          \"sourceType\": \"MANUAL\",\n          \"dueDate\": \"2026-01-20T00:00:00.000Z\",\n          \"recurrenceEnded\": false,\n          \"createdAt\": \"2026-01-15T10:30:00.000Z\",\n          \"updatedAt\": \"2026-01-15T10:36:00.000Z\"\n        },\n        \"details\": {\n          \"fieldUpdate\": { \"changedFields\": [\"description\"] }\n        }\n      }\n    }\n    ```\n\n    \n\n  \n\n---\n\n## Actualizaciones de contactos\n\nv1\n\nSe activan cuando se crean, actualizan o eliminan registros de contactos.\n\n  \n\n### Tipos de eventos\n\n    | Tipo de evento | Descripción |\n    | --- | --- |\n    | `contact.created` | Se creó un contacto |\n    | `contact.updated` | Se actualizó un registro de contacto |\n    | `contact.deleted` | Se eliminó un contacto |\n  \n\n  \n\n### Ejemplos de cuerpos\n\n    Los campos de propiedad dependen de si el contacto está vinculado a un CRM externo:\n\n    - Los **contactos sincronizados con un CRM** incluyen `crmContactId` y `crmLastSyncedAt`: la identidad del contacto la controla el CRM, no un usuario interno de Bridge.\n    - Los **contactos nativos de Bridge**, sin vínculo a un CRM, incluyen en cambio `internalUserOwnerId`, que identifica al usuario de Bridge propietario del registro.\n\n    Estos grupos son mutuamente excluyentes: un contacto sincronizado no incluye `internalUserOwnerId`, y uno no sincronizado no incluye `crmContactId` ni `crmLastSyncedAt`.\n\n    Cada entrada de `openAttributes` y `closedAttributes` incluye un `name` legible junto a `customAttributeId`. Para atributos cerrados, `closedCustomAttributeIds` es un array de objetos `{ id, content }`, donde `content` es la etiqueta visible de la opción elegida.\n\n    \n\n    ```json CRM-synced\n    {\n      \"eventId\": \"evt_contact_001\",\n      \"eventType\": \"contact.updated\",\n      \"entity\": \"contact\",\n      \"workspaceId\": \"ws_123\",\n      \"timestamp\": \"2026-01-15T10:30:00.000Z\",\n      \"payload\": {\n        \"id\": \"contact_123\",\n        \"firstName\": \"John\",\n        \"lastName\": \"Doe\",\n        \"email\": \"john@example.com\",\n        \"cellphone\": \"+1234567890\",\n        \"languageCode\": \"EN\",\n        \"openAttributes\": [\n          {\n            \"customAttributeId\": \"attr_open_1\",\n            \"name\": \"Account Number\",\n            \"content\": \"14\"\n          }\n        ],\n        \"closedAttributes\": [\n          {\n            \"customAttributeId\": \"attr_closed_1\",\n            \"name\": \"Preferred Language\",\n            \"closedCustomAttributeIds\": [\n              { \"id\": \"opt_1\", \"content\": \"ENGLISH\" }\n            ]\n          },\n          {\n            \"customAttributeId\": \"attr_closed_2\",\n            \"name\": \"Software Tools\",\n            \"closedCustomAttributeIds\": [\n              { \"id\": \"opt_2\", \"content\": \"Go\" },\n              { \"id\": \"opt_3\", \"content\": \"Postgres\" }\n            ]\n          }\n        ],\n        \"crmContactId\": \"crm_456\",\n        \"crmLastSyncedAt\": \"2026-01-10T09:00:00.000Z\",\n        \"createdAt\": \"2026-01-01T00:00:00.000Z\",\n        \"updatedAt\": \"2026-01-15T10:30:00.000Z\"\n      }\n    }\n    ```\n\n    ```json Bridge-native (no CRM)\n    {\n      \"eventId\": \"evt_contact_002\",\n      \"eventType\": \"contact.updated\",\n      \"entity\": \"contact\",\n      \"workspaceId\": \"ws_123\",\n      \"timestamp\": \"2026-01-15T10:32:00.000Z\",\n      \"payload\": {\n        \"id\": \"contact_456\",\n        \"firstName\": \"Jane\",\n        \"lastName\": \"Smith\",\n        \"email\": \"jane@example.com\",\n        \"cellphone\": \"+1987654321\",\n        \"languageCode\": \"EN\",\n        \"openAttributes\": [\n          {\n            \"customAttributeId\": \"attr_open_2\",\n            \"name\": \"Education level\",\n            \"content\": \"Secondary\"\n          }\n        ],\n        \"closedAttributes\": [\n          {\n            \"customAttributeId\": \"attr_closed_1\",\n            \"name\": \"Preferred Language\",\n            \"closedCustomAttributeIds\": [\n              { \"id\": \"opt_1\", \"content\": \"ENGLISH\" }\n            ]\n          },\n          {\n            \"customAttributeId\": \"attr_closed_3\",\n            \"name\": \"Gender\",\n            \"closedCustomAttributeIds\": [\n              { \"id\": \"opt_4\", \"content\": \"FEMALE\" }\n            ]\n          }\n        ],\n        \"internalUserOwnerId\": \"user_789\",\n        \"createdAt\": \"2026-01-05T15:47:49.000Z\",\n        \"updatedAt\": \"2026-01-15T10:32:00.000Z\"\n      }\n    }\n    ```\n\n    \n\n  \n\n---\n\n## Notificaciones de llamadas\n\nv1\n\nSe activan cuando una llamada avanza por su ciclo de vida. Bridge emite como máximo un webhook por fase y llamada. Tu integración recibe una secuencia clara de cuatro fases —creada, sonando, iniciada y finalizada— en lugar de cada transición intermedia que Bridge registra internamente.\n\nLa fase actual se puede deducir del estado de la llamada y de los estados de sus participantes:\n\n| Fase | Cómo detectarla |\n| --- | --- |\n| created | El estado es CREATED y ningún participante se ha unido ni está sonando |\n| ringing | Un participante tiene estado RINGING y nadie se ha unido todavía |\n| started | El estado es STARTED y dos participantes están JOINED |\n| finished | El estado es FINISHED |\n\nLas llamadas perdidas, en las que nadie responde, omiten la fase started: la integración recibe únicamente created, ringing y finished.\n\nCuando termina la llamada, Bridge procesa la grabación mediante un flujo asíncrono de transcripción con IA. Cuando está lista, la integración recibe un evento adicional `call.transcription.created` con la transcripción completa dividida en segmentos por hablante y con marcas de tiempo. Este evento llega **después** de `call.updated (finished)`, normalmente entre varios segundos y unos minutos más tarde según la duración de la llamada. La diarización —identificación de distintos hablantes— depende de la calidad del audio de origen: una grabación mono puede producir una sola etiqueta de hablante para toda la transcripción.\n\n  \n\n### Tipos de eventos\n\n    | Tipo de evento | Descripción |\n    | --- | --- |\n    | `call.created` | Se aprovisionó una llamada |\n    | `call.updated` | Cambió una fase del ciclo de vida de la llamada: sonando, iniciada o finalizada |\n    | `call.transcription.created` | Está lista la transcripción de IA de una llamada finalizada |\n  \n\n  \n\n### Ejemplos de cuerpos\n\n    \n\n    ```json Created\n    {\n      \"eventId\": \"evt_call_001\",\n      \"eventType\": \"call.created\",\n      \"entity\": \"call\",\n      \"workspaceId\": \"ws_123\",\n      \"timestamp\": \"2026-05-04T00:48:05.815Z\",\n      \"payload\": {\n        \"callId\": \"call_abc123\",\n        \"conversationId\": \"conv_xyz\",\n        \"messageId\": \"msg_xyz\",\n        \"callType\": \"ONE_TO_ONE\",\n        \"channelProvider\": \"WHATSAPP\",\n        \"state\": \"CREATED\",\n        \"createdAt\": \"2026-05-04T00:48:05.815Z\",\n        \"updatedAt\": \"2026-05-04T00:48:05.815Z\",\n        \"participants\": {\n          \"internal\": [\n            { \"userId\": \"user_internal_1\", \"name\": \"Jane Doe\", \"email\": \"jane@example.com\", \"status\": \"INITIALIZED\" }\n          ],\n          \"external\": [\n            { \"userId\": \"user_external_1\", \"name\": \"John Smith\", \"email\": \"john@example.com\", \"status\": \"INITIALIZED\" }\n          ]\n        }\n      }\n    }\n    ```\n\n    ```json Ringing\n    {\n      \"eventId\": \"evt_call_002\",\n      \"eventType\": \"call.updated\",\n      \"entity\": \"call\",\n      \"workspaceId\": \"ws_123\",\n      \"timestamp\": \"2026-05-04T00:48:06.243Z\",\n      \"payload\": {\n        \"callId\": \"call_abc123\",\n        \"conversationId\": \"conv_xyz\",\n        \"messageId\": \"msg_xyz\",\n        \"callType\": \"ONE_TO_ONE\",\n        \"channelProvider\": \"WHATSAPP\",\n        \"state\": \"CREATED\",\n        \"createdAt\": \"2026-05-04T00:48:05.815Z\",\n        \"updatedAt\": \"2026-05-04T00:48:06.243Z\",\n        \"participants\": {\n          \"internal\": [\n            { \"userId\": \"user_internal_1\", \"name\": \"Jane Doe\", \"email\": \"jane@example.com\", \"status\": \"INITIALIZED\" }\n          ],\n          \"external\": [\n            { \"userId\": \"user_external_1\", \"name\": \"John Smith\", \"email\": \"john@example.com\", \"status\": \"RINGING\" }\n          ]\n        }\n      }\n    }\n    ```\n\n    ```json Started\n    {\n      \"eventId\": \"evt_call_003\",\n      \"eventType\": \"call.updated\",\n      \"entity\": \"call\",\n      \"workspaceId\": \"ws_123\",\n      \"timestamp\": \"2026-05-04T00:48:12.771Z\",\n      \"payload\": {\n        \"callId\": \"call_abc123\",\n        \"conversationId\": \"conv_xyz\",\n        \"messageId\": \"msg_xyz\",\n        \"callType\": \"ONE_TO_ONE\",\n        \"channelProvider\": \"WHATSAPP\",\n        \"state\": \"STARTED\",\n        \"startedAt\": \"2026-05-04T00:48:12.125Z\",\n        \"createdAt\": \"2026-05-04T00:48:05.815Z\",\n        \"updatedAt\": \"2026-05-04T00:48:12.771Z\",\n        \"participants\": {\n          \"internal\": [\n            { \"userId\": \"user_internal_1\", \"name\": \"Jane Doe\", \"email\": \"jane@example.com\", \"status\": \"JOINED\", \"joinedAt\": \"2026-05-04T00:48:12.125Z\" }\n          ],\n          \"external\": [\n            { \"userId\": \"user_external_1\", \"name\": \"John Smith\", \"email\": \"john@example.com\", \"status\": \"JOINED\", \"joinedAt\": \"2026-05-04T00:48:12.124Z\" }\n          ]\n        }\n      }\n    }\n    ```\n\n    ```json Finished\n    {\n      \"eventId\": \"evt_call_004\",\n      \"eventType\": \"call.updated\",\n      \"entity\": \"call\",\n      \"workspaceId\": \"ws_123\",\n      \"timestamp\": \"2026-05-04T00:48:20.113Z\",\n      \"payload\": {\n        \"callId\": \"call_abc123\",\n        \"conversationId\": \"conv_xyz\",\n        \"messageId\": \"msg_xyz\",\n        \"callType\": \"ONE_TO_ONE\",\n        \"channelProvider\": \"WHATSAPP\",\n        \"state\": \"FINISHED\",\n        \"startedAt\": \"2026-05-04T00:48:12.125Z\",\n        \"finishedAt\": \"2026-05-04T00:48:19.389Z\",\n        \"createdAt\": \"2026-05-04T00:48:05.815Z\",\n        \"updatedAt\": \"2026-05-04T00:48:20.113Z\",\n        \"participants\": {\n          \"internal\": [\n            { \"userId\": \"user_internal_1\", \"name\": \"Jane Doe\", \"email\": \"jane@example.com\", \"status\": \"LEFT\", \"joinedAt\": \"2026-05-04T00:48:12.125Z\", \"leftAt\": \"2026-05-04T00:48:19.388Z\" }\n          ],\n          \"external\": [\n            { \"userId\": \"user_external_1\", \"name\": \"John Smith\", \"email\": \"john@example.com\", \"status\": \"LEFT\", \"joinedAt\": \"2026-05-04T00:48:12.124Z\", \"leftAt\": \"2026-05-04T00:48:19.387Z\" }\n          ]\n        }\n      }\n    }\n    ```\n\n    ```json Transcription created\n    {\n      \"eventId\": \"evt_call_005\",\n      \"eventType\": \"call.transcription.created\",\n      \"entity\": \"call\",\n      \"workspaceId\": \"ws_123\",\n      \"timestamp\": \"2026-05-04T00:50:14.231Z\",\n      \"payload\": {\n        \"callId\": \"call_abc123\",\n        \"transcriptionId\": \"txn_xyz789\",\n        \"conversationId\": \"conv_xyz\",\n        \"duration\": \"27\",\n        \"startedAt\": \"2026-05-04T00:48:12.125Z\",\n        \"finishedAt\": \"2026-05-04T00:48:19.389Z\",\n        \"transcript\": [\n          { \"speaker\": \"0\", \"text\": \"Hi, how can I help you today?\", \"start\": 1.44, \"end\": 5.2 },\n          { \"speaker\": \"1\", \"text\": \"I have a question about your product.\", \"start\": 5.5, \"end\": 12.3 }\n        ]\n      }\n    }\n    ```\n\n    \n\n    Cada segmento de transcripción incluye la etiqueta de hablante `speaker`, normalmente `\"0\"`, `\"1\"`, etc., el `text` y los desplazamientos `start`/`end` en segundos desde el inicio de la llamada.\n  \n\n---\n\n## Notificaciones de reuniones\n\nv1\n\nSe activan cuando una reunión alcanza el estado CREATED. Las cancelaciones se comunican mediante la notificación de correo correspondiente.\n\n  \n\n### Tipos de eventos\n\n    | Tipo de evento | Descripción |\n    | --- | --- |\n    | `meeting.updated` | Una reunión alcanzó el estado `CREATED` |\n  \n\n  \n\n### Ejemplo de cuerpo\n\n    ```json\n    {\n      \"eventId\": \"evt_meeting_001\",\n      \"eventType\": \"meeting.updated\",\n      \"entity\": \"meeting\",\n      \"workspaceId\": \"ws_123\",\n      \"timestamp\": \"2026-05-04T00:46:40.954Z\",\n      \"payload\": {\n        \"meetingId\": \"meeting_abc123\",\n        \"conversationId\": \"conv_xyz\",\n        \"messageId\": \"msg_xyz\",\n        \"subject\": \"Meeting with John Smith\",\n        \"providerType\": \"TEAMS\",\n        \"status\": \"CREATED\",\n        \"organizerInternalUserId\": \"user_internal_1\",\n        \"internalParticipants\": [\"user_internal_1\"],\n        \"externalParticipants\": [\"user_external_1\"],\n        \"startDateTime\": \"2026-05-04T01:00:00.000Z\",\n        \"endDateTime\": \"2026-05-04T01:15:00.000Z\",\n        \"createdAt\": \"2026-05-04T00:46:29.944Z\",\n        \"updatedAt\": \"2026-05-04T00:46:40.954Z\",\n        \"provider\": {\n          \"joinUrl\": \"https://teams.microsoft.com/l/meetup-join/...\",\n          \"calendarEventId\": \"AAMkADhlMWVlMWJhLWUyZTMtNDllOC...\",\n          \"chatId\": \"MWM1Zjg4MmUtZjk0Mi00YjJkLTgyNTItNmRiODNiZmM1NWEw\",\n          \"providerMeetingId\": \"MSowODJkZmFjYy1iNDZmLTRiNDItOGYzOS0xMzI0NDcyMzUwMWUq...\"\n        }\n      }\n    }\n    ```\n  \n\n---\n\n## Notificaciones de correo electrónico\n\nv1\n\nSe activan cuando se ha procesado un correo y está disponible su resumen de IA.\n\nEl campo `sentFromBridge` indica la dirección: true para correos salientes enviados desde el espacio de trabajo y false para correos entrantes recibidos.\n\n  \n\n### Tipos de eventos\n\n    | Tipo de evento | Descripción |\n    | --- | --- |\n    | `email.updated` | Un correo alcanzó el estado con resumen disponible |\n  \n\n  \n\n### Ejemplo de cuerpo\n\n    ```json\n    {\n      \"eventId\": \"evt_email_001\",\n      \"eventType\": \"email.updated\",\n      \"entity\": \"email\",\n      \"workspaceId\": \"ws_123\",\n      \"timestamp\": \"2026-05-04T00:45:31.261Z\",\n      \"payload\": {\n        \"emailId\": \"email_abc123\",\n        \"conversationId\": \"conv_xyz\",\n        \"threadId\": \"AAQkADhlMWVlMWJhLWUyZTMtNDllOC05MDg2LWMzNjFkMTI5MjM4MA...\",\n        \"providerType\": \"OUTLOOK\",\n        \"status\": \"PROCESSED\",\n        \"subject\": \"Project update\",\n        \"sender\": \"jane@example.com\",\n        \"recipients\": [\n          { \"recipientEmail\": \"john@example.com\" }\n        ],\n        \"summary\": \"Jane confirms the project is on track and shares next steps.\",\n        \"importance\": \"NORMAL\",\n        \"sentFromBridge\": true,\n        \"hasAttachments\": false,\n        \"sentAt\": \"2026-05-04T00:45:09.000Z\",\n        \"createdAt\": \"2026-05-04T00:45:09.000Z\",\n        \"updatedAt\": \"2026-05-04T00:45:31.261Z\"\n      }\n    }\n    ```\n  \n\n---\n\n## Notas\n\n- Bridge puede agregar nuevas categorías de eventos en el futuro.\n- Revisa siempre el campo de tipo de evento para determinar qué manejador ejecutar.\n- Configura y admite la versión seleccionada para cada suscripción. El sobre común no declara un campo `version` universal: no lo exijas ni lo inventes. Consulta [Recepción de eventos](https://docs.bridge.new/es/webhooks/receive-events.md) para los duplicados y el orden.\n\n---\n\n## Temas relacionados\n\n- [Descripción general](https://docs.bridge.new/es/webhooks.md)\n- [Verificar firmas](https://docs.bridge.new/es/webhooks/verifying-signatures.md)\n- [Configuración en la consola](https://docs.bridge.new/es/webhooks/configuration.md)\n"
    },
    {
      "title": "Custom Connections",
      "source": "https://docs.bridge.new/es/lead-capture/index",
      "markdownUrl": "https://docs.bridge.new/es/lead-capture/index.md",
      "description": "Usa Custom Connections para registrar leads desde tu landing page y encolar un mensaje inicial de WhatsApp.",
      "kind": "page",
      "contentMarkdown": "## Qué hace esta integración\n\nTu landing page envía un lead a Bridge. Luego Bridge abre la conversación de WhatsApp por ti con una plantilla aprobada. Tú no envías ese mensaje: lo enviamos nosotros.\n\n**Advertencia**\n\n  **Una respuesta `202` significa que el lead fue aceptado, no que se haya enviado un mensaje.** Otro servicio transmite el primer mensaje de WhatsApp después. El texto de confirmación de tu página debe decir algo como «te escribiremos pronto», nunca «ya te enviamos un mensaje».\n\n## Qué necesitas y de dónde lo obtienes\n\nCuatro valores: la URL del endpoint, tu `captureKey`, la clave de sitio de reCAPTCHA y el nombre de la acción de reCAPTCHA.\n\nNo debes armarlos manualmente. En la consola de administración de Bridge, en **LeadScout → Capture snippet**, un administrador de tu espacio de trabajo genera un ejemplo de integración que ya contiene esos cuatro valores. Luego se lo entrega a quien construye la página; esa persona no necesita acceso a la consola.\n\n**Nota**\n\n  El ejemplo es un punto de partida, no un script listo para usar sin ajustes. Tú defines el marcado del formulario y el texto del consentimiento; consulta los [requisitos de consentimiento](https://docs.bridge.new/es/lead-capture/consent.md).\n\n## Continúa con estas guías\n\n  \n\n### [Requisitos de consentimiento](https://docs.bridge.new/es/lead-capture/consent.md)\n\n    Qué debe decir la autorización y qué estás declarando al enviarla.\n  \n\n  \n\n### [Requisitos de plantillas](https://docs.bridge.new/es/lead-capture/templates.md)\n\n    Elige una plantilla Utility o Marketing admitida y conoce los requisitos de su categoría.\n  \n\n  \n\n### [Guía de integración](https://docs.bridge.new/es/lead-capture/integration.md)\n\n    Agrega la integración al formulario y maneja CAPTCHA, consentimiento, respuestas y errores.\n  \n\n  \n\n### [Referencia de errores](https://docs.bridge.new/es/lead-capture/errors.md)\n\n    Todas las respuestas que puede devolver el endpoint y cuáles puedes corregir.\n"
    },
    {
      "title": "Requisitos de consentimiento",
      "source": "https://docs.bridge.new/es/lead-capture/consent",
      "markdownUrl": "https://docs.bridge.new/es/lead-capture/consent.md",
      "description": "Qué debe decir la autorización y qué declaras cuando envías consent.status GRANTED.",
      "kind": "page",
      "contentMarkdown": "## Qué debe incluir tu formulario\n\nTu landing page debe pedir una autorización explícita antes de enviar un lead. Tú redactas el texto, pero debe cumplir dos requisitos de Meta:\n\n- **Nombrar tu negocio.** No basta con «nosotros» o «nuestros aliados»: debe identificar al negocio que le escribirá a la persona.\n- **Indicar que la persona recibirá comunicaciones de ese negocio por WhatsApp.** No basta con «podemos contactarte»: debes nombrar el canal.\n\nMeta reconoce los formularios de sitios web como un medio válido para obtener esta autorización. Por eso, una casilla en tu landing page es suficiente, siempre que su texto incluya ambos puntos.\n\n**Advertencia**\n\n  Una casilla marcada de antemano no es una autorización. Tampoco lo es una línea en letra pequeña debajo del botón de envío con la que la persona nunca interactúa. La persona debe realizar la acción.\n\n## Qué estás declarando\n\n**Nota**\n\n  Enviar `consent.status: \"GRANTED\"` es una declaración que haces **tú**. No verificamos ni podemos verificar que la persona haya marcado una casilla: registramos que nos dijiste que lo hizo y cuándo. Si alguna vez se restringen tus envíos de WhatsApp, ese registro se presenta en tu nombre.\n\nPor eso `capturedAt` importa más de lo que parece. Debe corresponder al momento en que la persona realmente dio su consentimiento, no al momento en que tu servidor terminó enviando la solicitud ni a una marca de tiempo generada en un proceso nocturno por lotes. Si alguna vez hay que justificar ambos momentos, la diferencia entre ellos será uno de los primeros aspectos que se revisen.\n\nEnvíalo como una marca de tiempo ISO 8601:\n\n```json\n{\n  \"consent\": {\n    \"status\": \"GRANTED\",\n    \"capturedAt\": \"2026-08-26T14:32:07.184Z\"\n  }\n}\n```\n\nSi no hubo consentimiento, no envíes el lead. Toda solicitud con un estado distinto de `GRANTED` se rechaza con `BRIDGE.CAMPAIGN_LEADS.CONSENT_NOT_GRANTED`.\n\n## Un ejemplo para adaptar\n\nEste texto es ilustrativo, no una fórmula para copiar sin revisar. Solo tú sabes qué enviarás y con qué finalidad; la autorización debe reflejarlo.\n\n> ☐ Acepto recibir mensajes de WhatsApp de **Acme Motors** sobre la cotización que acabo de solicitar.\n\nEl ejemplo funciona porque nombra al negocio, identifica el canal y explica de qué tratarán los mensajes. Dejaría de cumplir esas condiciones si quitaras el nombre del negocio, dijeras «mensajes» sin especificar WhatsApp o combinaras esta autorización con una casilla general de términos y condiciones que también abarque asuntos no relacionados.\n"
    },
    {
      "title": "Requisitos de plantillas",
      "source": "https://docs.bridge.new/es/lead-capture/templates",
      "markdownUrl": "https://docs.bridge.new/es/lead-capture/templates.md",
      "description": "Categorías de plantillas admitidas y recomendaciones para abrir conversaciones mediante Custom Connections.",
      "kind": "page",
      "contentMarkdown": "## Categorías de plantillas admitidas\n\nLa plantilla que abre la conversación puede ser de **utilidad** o de **marketing**:\n\n- **Plantillas Utility:** son estrictamente transaccionales y responden a lo que la persona acaba de enviar, por ejemplo, confirmando la recepción de una consulta. Acceden a tarifas de conversación de WhatsApp más bajas.\n- **Plantillas Marketing:** pueden incluir promociones, descuentos, ofertas especiales o mensajes de venta directos. Se facturan con las tarifas estándar de conversaciones de marketing de WhatsApp.\n\n**Nota**\n\n  Las plantillas **Authentication** no se pueden usar con Custom Connections. Se rechaza cualquier plantilla configurada con la categoría `AUTHENTICATION`.\n\nConfiguras y envías tus plantillas a aprobación directamente en Meta WhatsApp Manager. Deben estar aprobadas antes de pasar a producción.\n\n## Clasificación de Meta y entrega\n\n**Advertencia**\n\n  Meta clasifica las plantillas según su contenido, no solo según la categoría que elijas al enviarlas a aprobación. Si una plantilla enviada como UTILITY contiene texto promocional, Meta puede reclasificarla como MARKETING o rechazarla.\n\nElegir la categoría correcta desde el inicio evita problemas de clasificación inesperados y permite anticipar la entrega y la facturación.\n\n## Ejemplos por categoría\n\n**Utility (transaccional):** confirma una consulta sin incluir ofertas promocionales:\n\n```text\nHi {{1}}, thanks for your enquiry about the {{2}}. A member of our team will follow up here shortly.\n```\n\n**Marketing (promocional):** incluye texto promocional, descuentos u ofertas:\n\n```text\nHi {{1}}, thanks for your enquiry about the {{2}}. Book this week and get 15% off — reply YES to claim.\n```\n\n\n## Recomendaciones prácticas\n\n- **Elige Utility** cuando tu objetivo principal sea confirmar rápidamente la solicitud de la persona con un mensaje transaccional. Limítalo a lo que acaba de enviar y evita recursos promocionales para mantener la categoría de utilidad y su menor tarifa.\n- **Elige Marketing** cuando quieras ofrecer de inmediato descuentos de bienvenida, incentivos promocionales u ofertas del catálogo tras la captura.\n- **Evita las plantillas Authentication:** están destinadas exclusivamente a contraseñas de un solo uso y códigos de verificación; se rechazan en los envíos a leads de campañas.\n- Cuando la persona responde, comienza una sesión de conversación normal y las restricciones de categoría de plantilla dejan de aplicarse a los mensajes entrantes o a las respuestas del agente.\n"
    },
    {
      "title": "Guía de integración",
      "source": "https://docs.bridge.new/es/lead-capture/integration",
      "markdownUrl": "https://docs.bridge.new/es/lead-capture/integration.md",
      "description": "Conecta un formulario de landing page con Bridge: ejemplo, CAPTCHA, consentimiento, respuestas y manejo de errores.",
      "kind": "page",
      "contentMarkdown": "## El ejemplo\n\nLa consola de administración de Bridge proporciona un ejemplo generado con la configuración de tu espacio de trabajo. El ejemplo ampliado de abajo agrega validación y mensajes sobre el estado del envío. Antes de ejecutarlo, reemplaza los valores de ejemplo con los de la configuración generada para ti.\n\nReemplaza el marcado del formulario y el texto del consentimiento con los tuyos. **Acme Motors es un negocio ficticio usado en este ejemplo.** Sustitúyelo por el negocio que le escribirá a la persona y describe los mensajes de WhatsApp que acepta recibir. Consulta los [requisitos de consentimiento](https://docs.bridge.new/es/lead-capture/consent.md). El script muestra validación, estado del envío y manejo de errores. Conserva los campos de solicitud y la acción de reCAPTCHA de tu configuración generada.\n\n```html\n<!--\n  Campaign leads integration example.\n  This is a starting point, not a drop-in script: replace the form fields, labels and\n  consent copy below with your own. Keep the existing field ids, or update the matching selectors. The API fields and\n  reCAPTCHA action remain the values from your generated configuration.\n  What this does: collects a phone number (and optionally a name), mints a reCAPTCHA v3\n  token, and POSTs the lead to the campaign-leads endpoint. A 202 response means the lead\n  was accepted and queued -- a separate service sends the first WhatsApp message later, so\n  do not tell the visitor \"message sent\"; something like \"we'll message you shortly\" is\n  accurate.\n-->\n<script>\n  window.__CAMPAIGN_LEADS__ = {\"workspaceId\":\"YOUR_WORKSPACE_ID\",\"captureKey\":\"YOUR_CAPTURE_KEY\",\"endpoint\":\"https://integrations-us.app.bridge.new/api/v1/leadscout/campaign-leads\",\"brandId\":null,\"recaptchaSiteKey\":\"YOUR_RECAPTCHA_SITE_KEY\",\"recaptchaAction\":\"submit_campaign_lead\",\"trackedParams\":[]};\n</script>\n<!-- ============================================================\n     EXAMPLE FORM -- replace with your own markup and consent copy.\n     Keep the element ids (or update the selectors in the script below to match yours).\n     ============================================================ -->\n<form id=\"lead-form\" novalidate>\n  <label>\n    <span>Name (optional)</span>\n    <input id=\"lead-name\" type=\"text\" autocomplete=\"name\" />\n  </label>\n  <label>\n    <span>WhatsApp number</span>\n    <input id=\"lead-phone\" type=\"tel\" autocomplete=\"tel\" required />\n  </label>\n  <!-- The wording of this consent statement is yours to write: it is what the visitor is\n       agreeing to, and only you know what you will message them and why. -->\n  <label>\n    <input id=\"lead-consent\" type=\"checkbox\" required />\n    <span>I agree to receive WhatsApp messages from Acme Motors about the quote I just requested.</span>\n  </label>\n  <button type=\"submit\">Submit</button>\n  <p id=\"lead-result\" role=\"status\" aria-live=\"polite\"></p>\n</form>\n<script>\n  (function (config) {\n    \"use strict\";\n    var form = document.getElementById(\"lead-form\");\n    var consentBox = document.getElementById(\"lead-consent\");\n    var submitButton = form.querySelector(\"button[type=submit]\");\n    var result = document.getElementById(\"lead-result\");\n    var consentCapturedAt = null;\n    var inFlight = false;\n    var accepted = false;\n    var submissionStarted = false;\n    var responseReceived = false;\n    consentBox.addEventListener(\"change\", function () {\n      consentCapturedAt = consentBox.checked ? new Date().toISOString() : null;\n    });\n    function showResult(message) {\n      result.textContent = message;\n    }\n    function loadRecaptcha() {\n      return new Promise(function (resolve, reject) {\n        if (window.grecaptcha) {\n          resolve();\n          return;\n        }\n        var tag = document.createElement(\"script\");\n        tag.src = \"https://www.google.com/recaptcha/api.js?render=\" + config.recaptchaSiteKey;\n        tag.onload = function () {\n          resolve();\n        };\n        tag.onerror = function () {\n          reject(new Error(\"Could not load reCAPTCHA. Check the site key and the network.\"));\n        };\n        document.head.appendChild(tag);\n      });\n    }\n    // Mint the token on submit, not on page load: a reCAPTCHA v3 token is only valid for\n    // ~2 minutes, so minting it earlier means it can already be expired by the time the\n    // visitor actually submits the form.\n    function mintToken() {\n      return loadRecaptcha().then(function () {\n        return new Promise(function (resolve, reject) {\n          window.grecaptcha.ready(function () {\n            window.grecaptcha\n              .execute(config.recaptchaSiteKey, { action: config.recaptchaAction })\n              .then(resolve, reject);\n          });\n        });\n      });\n    }\n    // Allowlist, not a denylist: only utm_* params and the names you seeded in\n    // trackedParams are collected. The rest of the query string can carry ad-network\n    // click ids or session tokens that were never meant to be stored -- over-collection\n    // here is irreversible, so when in doubt leave a param out.\n    function readCampaignParams() {\n      var params = new URLSearchParams(window.location.search);\n      var collected = {};\n      params.forEach(function (value, key) {\n        if (key.indexOf(\"utm_\") === 0 || config.trackedParams.indexOf(key) !== -1) {\n          collected[key] = value;\n        }\n      });\n      return collected;\n    }\n    function buildPayload(token) {\n      return {\n        workspaceId: config.workspaceId,\n        captureKey: config.captureKey,\n        cellphone: document.getElementById(\"lead-phone\").value.trim(),\n        name: document.getElementById(\"lead-name\").value.trim() || null,\n        brandId: config.brandId,\n        // origin + pathname only, never the full URL: the query string can carry\n        // click ids or session tokens, and UTMs already travel separately in \"utm\" above.\n        landingUri: window.location.origin + window.location.pathname,\n        utm: readCampaignParams(),\n        consent: { status: \"GRANTED\", capturedAt: consentCapturedAt },\n        recaptchaToken: token,\n      };\n    }\n    form.addEventListener(\"submit\", function (event) {\n      event.preventDefault();\n      if (inFlight || accepted || !form.reportValidity()) return;\n      if (!consentBox.checked || !consentCapturedAt) {\n        // A browser can restore a previously checked control without firing change.\n        // Ask for a new explicit action instead of inventing its consent timestamp.\n        consentBox.checked = false;\n        showResult(\"Please select the WhatsApp consent checkbox before submitting.\");\n        consentBox.focus();\n        return;\n      }\n      inFlight = true;\n      submissionStarted = false;\n      responseReceived = false;\n      submitButton.disabled = true;\n      showResult(\"Submitting your request...\");\n      // A token verifies once. Every manual attempt, including a retry after a\n      // rejected request, obtains a new token. This example never retries a POST.\n      mintToken()\n        .then(function (token) {\n          var payload = buildPayload(token);\n          // The URL must identify the workspace for the browser's CORS preflight.\n          var url = config.endpoint + \"?workspaceId=\" + encodeURIComponent(config.workspaceId);\n          submissionStarted = true;\n          return fetch(url, {\n            method: \"POST\",\n            headers: { \"Content-Type\": \"application/json\" },\n            body: JSON.stringify(payload),\n          });\n        })\n        .then(function (response) {\n          responseReceived = true;\n          return response.json().catch(function () { return null; }).then(function (body) {\n            if (response.status === 202) {\n              accepted = true;\n              var reference = body && typeof body.requestId === \"string\"\n                ? \" Reference: \" + body.requestId\n                : \"\";\n              showResult(\"Request accepted. The business will process your request.\" + reference);\n              return;\n            }\n            var code = body && body.type ? body.type : \"HTTP \" + response.status;\n            if (response.status === 422 && code === \"BRIDGE.CAMPAIGN_LEADS.CAPTCHA_PROVIDER_UNAVAILABLE\") {\n              throw new Error(\"Verification is temporarily unavailable. You can try again; a new CAPTCHA token will be created.\");\n            }\n            if (response.status === 403 && code === \"BRIDGE.CAMPAIGN_LEADS.CAPTCHA_REJECTED\") {\n              throw new Error(\"The verification was rejected. You can try again with a new CAPTCHA token.\");\n            }\n            var detail = body && (body.detail || body.title);\n            throw new Error(code + (detail ? \": \" + detail : \". Check the form configuration.\"));\n          });\n        })\n        .catch(function (error) {\n          if (submissionStarted && !responseReceived) {\n            showResult(\"We could not confirm whether your request was accepted. Check with the business before submitting it again.\");\n            return;\n          }\n          showResult(error.message || \"The request could not be completed.\");\n        })\n        .finally(function () {\n          inFlight = false;\n          submitButton.disabled = accepted;\n        });\n    });\n  })(window.__CAMPAIGN_LEADS__);\n</script>\n```\n\n\n## Qué hace el ejemplo\n\n- Comprueba los campos obligatorios antes de obtener un token de CAPTCHA.\n- Registra `consent.capturedAt` cuando la persona marca la casilla. Si el navegador restaura una casilla marcada anteriormente, pide una nueva acción de consentimiento.\n- Permite un solo envío a la vez y mantiene el botón deshabilitado después de la aceptación para evitar otro envío desde esa instancia del formulario.\n- Presenta un `202` como aceptación y puesta en cola, y muestra el `requestId` devuelto como referencia para soporte. Nunca afirma que se haya entregado un mensaje de WhatsApp.\n- Muestra los fallos de CAPTCHA que permiten un nuevo intento y genera un token nuevo en cada intento manual. No reintenta automáticamente un POST.\n- Trata un fallo de red posterior al envío como un resultado incierto: no afirma que el lead se haya rechazado ni que sea seguro reenviarlo.\n\nSon mensajes del lado del cliente, no una garantía de deduplicación del backend. Adapta los mensajes visibles a tu página y conserva la [referencia de errores](https://docs.bridge.new/es/lead-capture/errors.md) para el diagnóstico.\n\n## Tu clave de captura no es una clave de API\n\n**Nota**\n\n  La guía de [autenticación](https://docs.bridge.new/es/credentials.md) indica que nunca debes colocar una clave en código frontend. Esa regla se refiere a la clave de la API de integraciones y sigue vigente. Tu `captureKey` es otro tipo de valor.\n\nA diferencia de la `x-api-key` de la API de integraciones, tu `captureKey` está diseñada para aparecer en el HTML de tu página, donde cualquiera puede leerla. No permite leer ningún dato: solo identifica a qué espacio de trabajo pertenece un envío. El abuso se limita mediante otras dos comprobaciones: el token de reCAPTCHA y la aceptación de envíos únicamente desde los dominios registrados para tu espacio de trabajo.\n\nNunca uses aquí tu clave de la API de integraciones ni la coloques en una página.\n\n## Incluye el ID del espacio de trabajo en la URL\n\nEl ID del espacio de trabajo debe ir en el cuerpo de la solicitud **y** en la URL como `?workspaceId=...`. Debe estar en ambos lugares: antes de la solicitud real, el navegador envía una solicitud de comprobación CORS sin cuerpo. Sin el ID en la URL no podemos identificar el espacio de trabajo ni devolver el encabezado que autoriza tu dominio, por lo que el navegador bloquea la solicitud antes de enviarla.\n\nEste fallo puede confundir: verás un error de CORS en la consola del navegador, pero no habrá una solicitud en nuestros registros porque la solicitud real nunca salió de la página. Por eso conviene configurarlo bien desde el inicio.\n\n## Genera el token de CAPTCHA al enviar el formulario\n\nUn token de reCAPTCHA v3 dura aproximadamente dos minutos. Si lo generas al cargar la página, puede haber vencido cuando la persona termina de completar el formulario. Se rechazará con un `403`, que puede parecer un problema de permisos en lugar de uno de vigencia.\n\n## Genera un token nuevo para cada intento\n\nUn token se verifica exactamente una vez. Si falla el envío y reintentas con el mismo token, su reutilización no se puede distinguir de un ataque y devuelve el mismo error que recibiría un bot. Vuelve a llamar siempre a `grecaptcha.execute` antes de reintentar.\n\n## Qué debes enviar\n\nLa [referencia del endpoint](https://docs.bridge.new/es/api-reference/campaign-leads/registrar-un-lead-de-campa%C3%B1a.md) contiene el contrato completo. Estos son los campos cuyo significado no resulta evidente solo con el esquema:\n\n### `brandId` (`string`)\n\n  La marca que vende tu landing page, no el ID de una línea, canal o teléfono. Solo es obligatorio si tu espacio de trabajo tiene marcas habilitadas. **Nunca se exige el ID de una línea.**\n\n### `landingUri` (`string`)\n\n  El origen y la ruta de la página, sin la cadena de consulta. Los parámetros UTM se envían por separado en `utm`; una cadena de consulta sin filtrar puede contener identificadores de clic o tokens de sesión que no deben almacenarse. Envía `https://example.com/offer`, no `https://example.com/offer?gclid=...`.\n\n### `consent` (`object`)\n\n  Tu declaración de que la persona aceptó y de cuándo lo hizo. Consulta los [requisitos de consentimiento](https://docs.bridge.new/es/lead-capture/consent.md): el texto de autorización del formulario no es opcional.\n\n### `utm` (`object`)\n\n  Se recopilan de la cadena de consulta mediante una lista de permitidos: los parámetros `utm_*` y cualquier nombre adicional que configures en la consola. Se usa una lista de permitidos, no una lista de exclusiones, porque recopilar datos de más no es reversible.\n\n## Después del envío\n\nUn `202` significa que el lead fue aceptado y puesto en cola. **No** significa que se haya enviado un mensaje: eso ocurre después, en otro servicio. Indícale a la persona que le escribirás pronto.\n\nCualquier otra respuesta es un error. Consulta la [referencia de errores](https://docs.bridge.new/es/lead-capture/errors.md) para saber qué significa cada uno y si puedes corregirlo.\n"
    },
    {
      "title": "Referencia de errores",
      "source": "https://docs.bridge.new/es/lead-capture/errors",
      "markdownUrl": "https://docs.bridge.new/es/lead-capture/errors.md",
      "description": "Todas las respuestas que puede devolver el endpoint de Custom Connections y cuáles puedes corregir.",
      "kind": "page",
      "contentMarkdown": "Las respuestas de error usan el formato de detalles de problemas de [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457): `type`, `title`, `status` y, en algunos casos, `detail`.\n\n**Nota**\n\n  **Las respuestas de error no incluyen un identificador de solicitud.** Solo lo incluye una respuesta `202` exitosa. Si necesitas ayuda de soporte, informa la URL de la página y la hora aproximada.\n\n## Todas las respuestas\n\n| Estado | `type` | Qué ocurrió | ¿Puedes corregirlo? |\n| --- | --- | --- | --- |\n| `400` | `invalid_payload` | Falta un campo o su formato es incorrecto. | Sí |\n| `400` | `BRIDGE.CAMPAIGN_LEADS.INVALID_PHONE` | El teléfono no se pudo interpretar como un número válido. | Sí: valídalo antes de enviar |\n| `400` | `BRIDGE.CAMPAIGN_LEADS.CONSENT_NOT_GRANTED` | `consent.status` no era `GRANTED`. | Sí |\n| `400` | `BRIDGE.CAMPAIGN_LEADS.BRAND_OR_LINE_REQUIRED` | El espacio de trabajo tiene marcas habilitadas y no se envió `brandId`. | Sí |\n| `403` | `BRIDGE.CAMPAIGN_LEADS.CAPTURE_DISABLED` | Custom Connections no está habilitado para este espacio de trabajo. | No: contacta a Bridge |\n| `403` | `BRIDGE.CAMPAIGN_LEADS.CAPTURE_KEY_MISMATCH` | No se envió la clave de captura o es incorrecta. | Sí |\n| `403` | `BRIDGE.CAMPAIGN_LEADS.CAPTCHA_REJECTED` | El token de CAPTCHA no se envió, venció, ya se usó o recibió una puntuación demasiado baja. | A veces: consulta la explicación siguiente |\n| `403` | `BRIDGE.CAMPAIGN_LEADS.ORIGIN_NOT_ALLOWED` | El dominio de la página no está registrado para este espacio de trabajo. | No: contacta a Bridge |\n| `422` | `BRIDGE.CAMPAIGN_LEADS.CAPTCHA_PROVIDER_UNAVAILABLE` | No pudimos comunicarnos con el proveedor de CAPTCHA. | Es seguro reintentar |\n| `500` | `unexpected_error` | Ocurrió un fallo de nuestro lado. | No |\n\nSolo se informa el primer fallo. Las comprobaciones se ejecutan en este orden: espacio de trabajo y clave de captura, teléfono, consentimiento, marca, CAPTCHA y, por último, dominio. Corregir un error puede dejar al descubierto el siguiente.\n\n## Sobre el rechazo de CAPTCHA\n\n`CAPTCHA_REJECTED` cubre cuatro situaciones distintas. Revisa cómo maneja los tokens tu integración antes de atribuir el rechazo a la puntuación:\n\n- **El token venció.** Se generó demasiado pronto. Un token de reCAPTCHA v3 dura alrededor de dos minutos: genéralo al enviar el formulario, no al cargar la página.\n- **El token ya se usó.** Un token se verifica una sola vez. Si reintentas una solicitud fallida sin generar un token nuevo, se rechaza su reutilización.\n- **No se envió ningún token.** Asegúrate de que el cliente obtenga un token y lo incluya en `recaptchaToken` en cada envío.\n- **La puntuación fue demasiado baja.** La comprobación contra bots rechazó este intento. No la omitas.\n\nLas cuatro situaciones devuelven el mismo código, por lo que la respuesta por sí sola no identifica la causa. Primero comprueba que se incluya un token, que se genere al enviar el formulario y que sea nuevo para cada intento.\n\n## Sobre el 422\n\nEs un fallo transitorio de nuestro lado: no pudimos comunicarnos con el proveedor de CAPTCHA y, por tanto, no pudimos determinar si el envío era legítimo.\n\n**Es seguro reintentar.** El lead se conserva cuando esto ocurre y el reintento no puede generar un mensaje duplicado. Genera un token de CAPTCHA nuevo para ese reintento, como en cualquier otro intento.\n\n## Sobre el error de dominio\n\nEl orden de estas comprobaciones puede resultar poco intuitivo, por eso conviene explicarlo.\n\nComprobamos que el dominio de tu página esté registrado para tu espacio de trabajo, pero el dominio evaluado es el que **informa el proveedor de CAPTCHA**, no el que aparece en los encabezados de la solicitud. Esta comprobación ocurre *después* de verificar el token.\n\nEn consecuencia, una página alojada en un dominio no registrado falla en la etapa de CAPTCHA con `ORIGIN_NOT_ALLOWED`, no con un error de CORS. Si esto ocurre y el resto de tu integración funciona, falta registrar el dominio en la configuración del espacio de trabajo: contacta a Bridge para agregarlo.\n"
    },
    {
      "title": "Comprobar estado",
      "source": "https://docs.bridge.new/es/api-reference/health/comprobar-estado",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/health/comprobar-estado.md",
      "description": "Endpoint de comprobación de estado para verificar que la API esté en funcionamiento.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `get /bridge/api/health`\n\n**operationId:** `health_bridge_api_health_get`\n\nEndpoint de comprobación de estado para verificar que la API esté en funcionamiento.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Obtener conversación por id",
      "source": "https://docs.bridge.new/es/api-reference/conversations-api/obtener-conversaci%C3%B3n-por-id",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/conversations-api/obtener-conversaci%C3%B3n-por-id.md",
      "description": "Obtiene una conversación específica por su identificador único dentro del workspace.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/conversations/{conversationId}`\n\n**operationId:** `get_conversation_by_id_bridge_api_v1_workspaces__workspaceId__conversations__conversationId__get`\n\nObtiene una conversación específica por su identificador único dentro del workspace.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Actualizar conversación",
      "source": "https://docs.bridge.new/es/api-reference/conversations-api/actualizar-conversaci%C3%B3n",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/conversations-api/actualizar-conversaci%C3%B3n.md",
      "description": "Actualiza los detalles de la conversación, incluidos los participantes, el estado y el nombre.\n\nAdmite actualizaciones parciales: incluye solo los campos que quieras cambiar.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `patch /bridge/api/v1/workspaces/{workspaceId}/conversations/{conversationId}`\n\n**operationId:** `update_conversation_bridge_api_v1_workspaces__workspaceId__conversations__conversationId__patch`\n\nActualiza los detalles de la conversación, incluidos los participantes, el estado y el nombre.\n\nAdmite actualizaciones parciales: incluye solo los campos que quieras cambiar.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Consultar conversaciones con filtros flexibles",
      "source": "https://docs.bridge.new/es/api-reference/conversations-api/consultar-conversaciones-con-filtros-flexibles",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/conversations-api/consultar-conversaciones-con-filtros-flexibles.md",
      "description": "Consulta conversaciones con opciones de filtrado flexibles.\n\nPermite buscar por identificadores de usuarios externos (ID, correo electrónico o teléfono) o por participantes internos, con paginación y filtrado por estado.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/conversations`\n\n**operationId:** `get_conversations_bridge_api_v1_workspaces__workspaceId__conversations_get`\n\nConsulta conversaciones con opciones de filtrado flexibles.\n\nPermite buscar por identificadores de usuarios externos (ID, correo electrónico o teléfono) o por participantes internos, con paginación y filtrado por estado.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Crear conversación con identificación flexible de usuarios",
      "source": "https://docs.bridge.new/es/api-reference/conversations-api/crear-conversaci%C3%B3n-con-identificaci%C3%B3n-flexible-de-usuarios",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/conversations-api/crear-conversaci%C3%B3n-con-identificaci%C3%B3n-flexible-de-usuarios.md",
      "description": "Crea una conversación con identificación flexible de usuarios.\n\nLos usuarios externos pueden identificarse por ID, correo electrónico o teléfono. Los usuarios internos solo se asignan cuando se indican explícitamente; de lo contrario, las conversaciones se asignan por turnos mediante un equipo o quedan abiertas para cualquier usuario interno disponible.\n\nCuando no hay una línea libre y los Contacts tienen una conversación liberada con exactamente los participantes solicitados, se recupera y devuelve esa conversación, conservando su `id` e historial. No se le aplican el `name` ni el `status` de la solicitud.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `post /bridge/api/v1/workspaces/{workspaceId}/conversations`\n\n**operationId:** `create_conversation_bridge_api_v1_workspaces__workspaceId__conversations_post`\n\nCrea una conversación con identificación flexible de usuarios.\n\nLos usuarios externos pueden identificarse por ID, correo electrónico o teléfono. Los usuarios internos solo se asignan cuando se indican explícitamente; de lo contrario, las conversaciones se asignan por turnos mediante un equipo o quedan abiertas para cualquier usuario interno disponible.\n\nCuando no hay una línea libre y los Contacts tienen una conversación liberada con exactamente los participantes solicitados, se recupera y devuelve esa conversación, conservando su `id` e historial. No se le aplican el `name` ni el `status` de la solicitud.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Liberar conversación",
      "source": "https://docs.bridge.new/es/api-reference/conversations-api/liberar-conversaci%C3%B3n",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/conversations-api/liberar-conversaci%C3%B3n.md",
      "description": "Libera una conversación: la marca como liberada, elimina los participantes externos y la mueve a la sección RELEASED.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `post /bridge/api/v1/workspaces/{workspaceId}/conversations/{conversationId}/release`\n\n**operationId:** `release_conversation_bridge_api_v1_workspaces__workspaceId__conversations__conversationId__release_post`\n\nLibera una conversación: la marca como liberada, elimina los participantes externos y la mueve a la sección RELEASED.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Crear mensaje",
      "source": "https://docs.bridge.new/es/api-reference/messages-api/crear-mensaje",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/messages-api/crear-mensaje.md",
      "description": "Crea un mensaje en una conversación específica.\n\nPara un mensaje de texto o un adjunto cargado, incluye todos los campos obligatorios: `conversationId`, `messageBody` y `enableExternalBroadcast`. Adjunta los archivos cargados mediante los identificadores recibidos en `mediaIds`; consulta [Enviar un adjunto](/es/guides/send-attachments). Una respuesta satisfactoria devuelve `messageId`; no contiene un comprobante de entrega del proveedor. Consulta [Respuestas y reintentos](/es/guides/responses).",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `post /bridge/api/v1/workspaces/{workspaceId}/messages`\n\n**operationId:** `create_message_bridge_api_v1_workspaces__workspaceId__messages_post`\n\nCrea un mensaje en una conversación específica.\n\nPara un mensaje de texto o un adjunto cargado, incluye todos los campos obligatorios: `conversationId`, `messageBody` y `enableExternalBroadcast`. Adjunta los archivos cargados mediante los identificadores recibidos en `mediaIds`; consulta [Enviar un adjunto](https://docs.bridge.new/es/guides/send-attachments.md). Una respuesta satisfactoria devuelve `messageId`; no contiene un comprobante de entrega del proveedor. Consulta [Respuestas y reintentos](https://docs.bridge.new/es/guides/responses.md).\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Obtener contacto por un identificador",
      "source": "https://docs.bridge.new/es/api-reference/contacts-api/obtener-contacto-por-un-identificador",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/contacts-api/obtener-contacto-por-un-identificador.md",
      "description": "Obtiene un contacto específico por cualquiera de sus identificadores dentro del workspace.\n\n`type=ID` devuelve el mismo contacto que GET /contacts/{contactId}, la URL canónica de un contacto y la opción preferida cuando ya tienes su ID.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/contacts/lookup`\n\n**operationId:** `retrieve_contact_by_identifier_bridge_api_v1_workspaces__workspaceId__contacts_lookup_get`\n\nObtiene un contacto específico por cualquiera de sus identificadores dentro del workspace.\n\n`type=ID` devuelve el mismo contacto que GET /contacts/{contactId}, la URL canónica de un contacto y la opción preferida cuando ya tienes su ID.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Obtener contacto por id",
      "source": "https://docs.bridge.new/es/api-reference/contacts-api/obtener-contacto-por-id",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/contacts-api/obtener-contacto-por-id.md",
      "description": "Obtiene un contacto específico por su identificador único dentro del workspace.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/contacts/{contactId}`\n\n**operationId:** `retrieve_contact_by_id_bridge_api_v1_workspaces__workspaceId__contacts__contactId__get`\n\nObtiene un contacto específico por su identificador único dentro del workspace.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Actualizar contacto",
      "source": "https://docs.bridge.new/es/api-reference/contacts-api/actualizar-contacto",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/contacts-api/actualizar-contacto.md",
      "description": "Actualiza un contacto en el workspace indicado.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `patch /bridge/api/v1/workspaces/{workspaceId}/contacts/{contactId}`\n\n**operationId:** `update_contact_bridge_api_v1_workspaces__workspaceId__contacts__contactId__patch`\n\nActualiza un contacto en el workspace indicado.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Listar contactos",
      "source": "https://docs.bridge.new/es/api-reference/contacts-api/listar-contactos",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/contacts-api/listar-contactos.md",
      "description": "Consulta una lista paginada de contactos del workspace.\n\nSe ordena por fecha de creación. Los filtros `ownerEmail` y `search` están obsoletos y se eliminarán; para encontrar un contacto por un identificador, usa /contacts/lookup.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/contacts`\n\n**operationId:** `get_contacts_bridge_api_v1_workspaces__workspaceId__contacts_get`\n\nConsulta una lista paginada de contactos del workspace.\n\nSe ordena por fecha de creación. Los filtros `ownerEmail` y `search` están obsoletos y se eliminarán; para encontrar un contacto por un identificador, usa /contacts/lookup.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Crear contacto",
      "source": "https://docs.bridge.new/es/api-reference/contacts-api/crear-contacto",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/contacts-api/crear-contacto.md",
      "description": "Crea un contacto en el workspace indicado.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `post /bridge/api/v1/workspaces/{workspaceId}/contacts`\n\n**operationId:** `create_contact_bridge_api_v1_workspaces__workspaceId__contacts_post`\n\nCrea un contacto en el workspace indicado.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Crear o actualizar contacto",
      "source": "https://docs.bridge.new/es/api-reference/contacts-api/crear-o-actualizar-contacto",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/contacts-api/crear-o-actualizar-contacto.md",
      "description": "Crea o actualiza un contacto usando solo el celular. Lo clasifica como NORMAL o PARTIAL.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `post /bridge/api/v1/workspaces/{workspaceId}/contacts/partial`\n\n**operationId:** `create_partial_contact_bridge_api_v1_workspaces__workspaceId__contacts_partial_post`\n\nCrea o actualiza un contacto usando solo el celular. Lo clasifica como NORMAL o PARTIAL.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Crear cargas prefirmadas de archivos",
      "source": "https://docs.bridge.new/es/api-reference/files-api/crear-cargas-prefirmadas-de-archivos",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/files-api/crear-cargas-prefirmadas-de-archivos.md",
      "description": "Carga un archivo adjunto, como un PDF, una imagen o un documento, antes de crear un mensaje. Esta operación devuelve los datos de un PUT prefirmado; los bytes del archivo se cargan por separado. Cuando la carga termine correctamente, utiliza el `mediaId` devuelto en la operación de envío. Sigue [Enviar un archivo adjunto](/es/guides/send-attachments) para los pasos de suma de comprobación, carga y mensaje.\n\nGenera URL prefirmadas para cargar archivos (Presigned PUT). Valida la extensión, contentType y los límites por tipo. La suma de comprobación es obligatoria: envía el resumen SHA-256 en checksumBase64 (Base64). La carga debe incluir la cabecera x-amz-checksum-sha256 con el mismo valor.\n\n---\nPara cargar los archivos, DEBES utilizar la URL prefirmada devuelta con el método HTTP PUT. Carga el archivo exactamente en la URL indicada, sin modificaciones, tal como exige AWS S3 para un PUT con URL prefirmada. Consulta la documentación oficial de AWS S3: [Documentación de AWS S3 sobre Presigned PUT](https://docs.aws.amazon.com/AmazonS3/latest/userguide/PresignedUrlUploadObject.html).\nIncluye todas las cabeceras obligatorias indicadas en la respuesta, por ejemplo, 'x-amz-checksum-sha256' con el valor SHA-256 correcto. AWS rechazará la carga si no utilizas el método HTTP o las cabeceras correctos.\n\n<table><tr><th>Tipo</th><th>Extensión</th><th>Tipo de contenido</th><th>Tamaño máximo</th></tr><tr><td rowspan=\"4\">Imagen</td><td>.jpeg</td><td>image/jpeg</td><td rowspan=\"4\">16 MB</td></tr><tr><td>.jpg</td><td>image/jpeg</td></tr><tr><td>.png</td><td>image/png</td></tr><tr><td>.webp</td><td>image/webp</td></tr><tr><td rowspan=\"2\">GIF</td><td>.gif</td><td>image/gif</td><td rowspan=\"2\">3 MB</td></tr><tr><td>.mp4</td><td>video/mp4</td></tr><tr><td rowspan=\"3\">Vídeo</td><td>.avi</td><td>video/x-msvideo</td><td rowspan=\"3\">64 MB</td></tr><tr><td>.mov</td><td>video/quicktime</td></tr><tr><td>.mp4</td><td>video/mp4</td></tr><tr><td rowspan=\"4\">Audio</td><td>.m4a</td><td>audio/mp4</td><td rowspan=\"4\">16 MB</td></tr><tr><td>.mp3</td><td>audio/mpeg</td></tr><tr><td>.ogg</td><td>audio/ogg</td></tr><tr><td>.wav</td><td>audio/wav</td></tr><tr><td rowspan=\"8\">Documento</td><td>.doc</td><td>application/msword</td><td rowspan=\"8\">100 MB</td></tr><tr><td>.docx</td><td>application/vnd.openxmlformats-officedocument.wordprocessingml.document</td></tr><tr><td>.pdf</td><td>application/pdf</td></tr><tr><td>.ppt</td><td>application/vnd.ms-powerpoint</td></tr><tr><td>.pptx</td><td>application/vnd.openxmlformats-officedocument.presentationml.presentation</td></tr><tr><td>.txt</td><td>text/plain</td></tr><tr><td>.xls</td><td>application/vnd.ms-excel</td></tr><tr><td>.xlsx</td><td>application/vnd.openxmlformats-officedocument.spreadsheetml.sheet</td></tr></table>",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `post /bridge/api/v1/workspaces/{workspaceId}/files`\n\n**operationId:** `create_preloaded_files_bridge_api_v1_workspaces__workspaceId__files_post`\n\nCarga un archivo adjunto, como un PDF, una imagen o un documento, antes de crear un mensaje. Esta operación devuelve los datos de un PUT prefirmado; los bytes del archivo se cargan por separado. Cuando la carga termine correctamente, utiliza el `mediaId` devuelto en la operación de envío. Sigue [Enviar un archivo adjunto](https://docs.bridge.new/es/guides/send-attachments.md) para los pasos de suma de comprobación, carga y mensaje.\n\nGenera URL prefirmadas para cargar archivos (Presigned PUT). Valida la extensión, contentType y los límites por tipo. La suma de comprobación es obligatoria: envía el resumen SHA-256 en checksumBase64 (Base64). La carga debe incluir la cabecera x-amz-checksum-sha256 con el mismo valor.\n\n---\nPara cargar los archivos, DEBES utilizar la URL prefirmada devuelta con el método HTTP PUT. Carga el archivo exactamente en la URL indicada, sin modificaciones, tal como exige AWS S3 para un PUT con URL prefirmada. Consulta la documentación oficial de AWS S3: [Documentación de AWS S3 sobre Presigned PUT](https://docs.aws.amazon.com/AmazonS3/latest/userguide/PresignedUrlUploadObject.html).\nIncluye todas las cabeceras obligatorias indicadas en la respuesta, por ejemplo, 'x-amz-checksum-sha256' con el valor SHA-256 correcto. AWS rechazará la carga si no utilizas el método HTTP o las cabeceras correctos.\n\n<table><tr><th>Tipo</th><th>Extensión</th><th>Tipo de contenido</th><th>Tamaño máximo</th></tr><tr><td rowspan=\"4\">Imagen</td><td>.jpeg</td><td>image/jpeg</td><td rowspan=\"4\">16 MB</td></tr><tr><td>.jpg</td><td>image/jpeg</td></tr><tr><td>.png</td><td>image/png</td></tr><tr><td>.webp</td><td>image/webp</td></tr><tr><td rowspan=\"2\">GIF</td><td>.gif</td><td>image/gif</td><td rowspan=\"2\">3 MB</td></tr><tr><td>.mp4</td><td>video/mp4</td></tr><tr><td rowspan=\"3\">Vídeo</td><td>.avi</td><td>video/x-msvideo</td><td rowspan=\"3\">64 MB</td></tr><tr><td>.mov</td><td>video/quicktime</td></tr><tr><td>.mp4</td><td>video/mp4</td></tr><tr><td rowspan=\"4\">Audio</td><td>.m4a</td><td>audio/mp4</td><td rowspan=\"4\">16 MB</td></tr><tr><td>.mp3</td><td>audio/mpeg</td></tr><tr><td>.ogg</td><td>audio/ogg</td></tr><tr><td>.wav</td><td>audio/wav</td></tr><tr><td rowspan=\"8\">Documento</td><td>.doc</td><td>application/msword</td><td rowspan=\"8\">100 MB</td></tr><tr><td>.docx</td><td>application/vnd.openxmlformats-officedocument.wordprocessingml.document</td></tr><tr><td>.pdf</td><td>application/pdf</td></tr><tr><td>.ppt</td><td>application/vnd.ms-powerpoint</td></tr><tr><td>.pptx</td><td>application/vnd.openxmlformats-officedocument.presentationml.presentation</td></tr><tr><td>.txt</td><td>text/plain</td></tr><tr><td>.xls</td><td>application/vnd.ms-excel</td></tr><tr><td>.xlsx</td><td>application/vnd.openxmlformats-officedocument.spreadsheetml.sheet</td></tr></table>\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Consultar atributos personalizados por workspaceid",
      "source": "https://docs.bridge.new/es/api-reference/custom-attributes-api/consultar-atributos-personalizados-por-workspaceid",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/custom-attributes-api/consultar-atributos-personalizados-por-workspaceid.md",
      "description": "Devuelve los atributos personalizados del workspace indicado.\n\nDe forma predeterminada, solo devuelve atributos **activos** (sin un `deletedAt` en el pasado).\n\n**Filtros:**\n- `category`: filtra por `OPEN` o `CLOSED`. Omítelo para devolver todas las categorías.\n- `includeArchived`: usa `true` para incluir atributos archivados (con `deletedAt` en el pasado). Predeterminado: `false`.\n- `isRequired`: usa `true` para devolver solo atributos obligatorios y `false` para devolver solo opcionales. Omítelo para devolver todos.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/settings/attributes`\n\n**operationId:** `get_custom_attributes_by_workspace_bridge_api_v1_workspaces__workspaceId__settings_attributes_get`\n\nDevuelve los atributos personalizados del workspace indicado.\n\nDe forma predeterminada, solo devuelve atributos **activos** (sin un `deletedAt` en el pasado).\n\n**Filtros:**\n- `category`: filtra por `OPEN` o `CLOSED`. Omítelo para devolver todas las categorías.\n- `includeArchived`: usa `true` para incluir atributos archivados (con `deletedAt` en el pasado). Predeterminado: `false`.\n- `isRequired`: usa `true` para devolver solo atributos obligatorios y `false` para devolver solo opcionales. Omítelo para devolver todos.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Obtener canales de proveedores por workspace",
      "source": "https://docs.bridge.new/es/api-reference/provider-channels-api/obtener-canales-de-proveedores-por-workspace",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/provider-channels-api/obtener-canales-de-proveedores-por-workspace.md",
      "description": "Obtiene los canales de proveedores por identificador de workspace.\n\nEsta respuesta expone `provider` e `identifier`, similar a un número telefónico, para cada canal; no devuelve `providerChannelId`. Para las líneas de un Agent, lee `agents[].lines[].providerChannelId` en la lista de Agents. No sustituyas un ID de canal por un número telefónico. Consulta [Conceptos e identificadores](/es/guides/identifiers).",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/provider-channels`\n\n**operationId:** `get_provider_channels_by_workspace_id_bridge_api_v1_workspaces__workspaceId__provider_channels_get`\n\nObtiene los canales de proveedores por identificador de workspace.\n\nEsta respuesta expone `provider` e `identifier`, similar a un número telefónico, para cada canal; no devuelve `providerChannelId`. Para las líneas de un Agent, lee `agents[].lines[].providerChannelId` en la lista de Agents. No sustituyas un ID de canal por un número telefónico. Consulta [Conceptos e identificadores](https://docs.bridge.new/es/guides/identifiers.md).\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Obtener canales por workspace y tipo de proveedor",
      "source": "https://docs.bridge.new/es/api-reference/provider-channels-api/obtener-canales-por-workspace-y-tipo-de-proveedor",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/provider-channels-api/obtener-canales-por-workspace-y-tipo-de-proveedor.md",
      "description": "Obtiene los canales de proveedores por identificador de workspace y tipo de proveedor.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/provider-channels/{messageProviderType}`\n\n**operationId:** `get_provider_channels_by_workspace_id_and_provider_type_bridge_api_v1_workspaces__workspaceId__provider_channels__messageProviderType__get`\n\nObtiene los canales de proveedores por identificador de workspace y tipo de proveedor.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Iniciar conversación saliente de leadscout con un lead conocido",
      "source": "https://docs.bridge.new/es/api-reference/leadscout-api/iniciar-conversaci%C3%B3n-saliente-de-leadscout-con-un-lead-conocido",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/leadscout-api/iniciar-conversaci%C3%B3n-saliente-de-leadscout-con-un-lead-conocido.md",
      "description": "Inicia una conversación saliente de LeadScout con un Contact conocido. El Contact debe existir previamente. Bridge selecciona un Agent de prospección para una línea de WhatsApp apta. La plantilla se referencia mediante template.id o template.name; id tiene prioridad si se proporcionan ambos. Debe existir y estar APPROVED, y cualquier Bridge User de handoffOverride debe ser válido.\n\nSe respeta un contact.providerChannelId explícito. Sin él, la selección automática prefiere una línea libre, después una conversación liberada recuperable con este Contact y, por último, una conversación activa ocupada solo cuando forceSend=true. La disponibilidad se evalúa por Contact en cada línea, no por la ocupación global de la línea.\n\nforceSend=true reutiliza una conversación activa apta; no la ignora ni crea una nueva. Una reutilización exitosa devuelve alreadyInitiated=true y persiste la nueva plantilla y los seguimientos. Una conversación liberada recuperable se puede recuperar con cualquiera de los dos valores, conserva su ID y devuelve recovered=true. Esta opción no habilita las conversaciones bloqueadas ni las liberadas no recuperables. La ruta heredada puede reutilizar una conversación controlada por un humano u otro Agent; a diferencia del envío saliente de Agents, no exige la comprobación de control por el Agent solicitado.\n\nUna sesión abierta de LeadScout que no haya vencido sigue bloqueando una nueva solicitud saliente con 409 BRIDGE_AI_LEADSCOUT_0017; si no se puede finalizar una sesión vencida, devuelve 409 BRIDGE_AI_LEADSCOUT_0018. Las demás validaciones siguen vigentes. Los mensajes adicionales se persisten; persistirlos no demuestra su entrega ni que se espere la respuesta del lead. Una solicitud fallida puede dejar trabajo parcial, por lo que no debes tratar forceSend como idempotencia ni reintentar a ciegas un resultado incierto.\n\nConsulta [la guía completa de envío saliente](/es/guides/agent-outbound) para la matriz false/true, los indicadores de respuesta, las diferencias con el envío saliente de Agents, los errores y la transferencia.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `post /bridge/api/v1/workspaces/{workspaceId}/leadscout/outbound`\n\n**operationId:** `initiate_leadscout_outbound_bridge_api_v1_workspaces__workspaceId__leadscout_outbound_post`\n\nInicia una conversación saliente de LeadScout con un Contact conocido. El Contact debe existir previamente. Bridge selecciona un Agent de prospección para una línea de WhatsApp apta. La plantilla se referencia mediante template.id o template.name; id tiene prioridad si se proporcionan ambos. Debe existir y estar APPROVED, y cualquier Bridge User de handoffOverride debe ser válido.\n\nSe respeta un contact.providerChannelId explícito. Sin él, la selección automática prefiere una línea libre, después una conversación liberada recuperable con este Contact y, por último, una conversación activa ocupada solo cuando forceSend=true. La disponibilidad se evalúa por Contact en cada línea, no por la ocupación global de la línea.\n\nforceSend=true reutiliza una conversación activa apta; no la ignora ni crea una nueva. Una reutilización exitosa devuelve alreadyInitiated=true y persiste la nueva plantilla y los seguimientos. Una conversación liberada recuperable se puede recuperar con cualquiera de los dos valores, conserva su ID y devuelve recovered=true. Esta opción no habilita las conversaciones bloqueadas ni las liberadas no recuperables. La ruta heredada puede reutilizar una conversación controlada por un humano u otro Agent; a diferencia del envío saliente de Agents, no exige la comprobación de control por el Agent solicitado.\n\nUna sesión abierta de LeadScout que no haya vencido sigue bloqueando una nueva solicitud saliente con 409 BRIDGE_AI_LEADSCOUT_0017; si no se puede finalizar una sesión vencida, devuelve 409 BRIDGE_AI_LEADSCOUT_0018. Las demás validaciones siguen vigentes. Los mensajes adicionales se persisten; persistirlos no demuestra su entrega ni que se espere la respuesta del lead. Una solicitud fallida puede dejar trabajo parcial, por lo que no debes tratar forceSend como idempotencia ni reintentar a ciegas un resultado incierto.\n\nConsulta [la guía completa de envío saliente](https://docs.bridge.new/es/guides/agent-outbound.md) para la matriz false/true, los indicadores de respuesta, las diferencias con el envío saliente de Agents, los errores y la transferencia.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Solicitar transferencia manual de leadscout a usuarios internos",
      "source": "https://docs.bridge.new/es/api-reference/leadscout-api/solicitar-transferencia-manual-de-leadscout-a-usuarios-internos",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/leadscout-api/solicitar-transferencia-manual-de-leadscout-a-usuarios-internos.md",
      "description": "Solicita la transferencia manual de una conversación controlada por LeadScout a uno o más usuarios internos.\n\nLa solicitud se confirma con `202 Accepted`; la asignación se procesa de forma asíncrona. La respuesta repite los destinatarios solicitados y un ID de seguimiento para correlación. La resolución de usuarios internos (por ID o EMAIL) ocurre después y no se refleja en esta respuesta.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `post /bridge/api/v1/workspaces/{workspaceId}/leadscout/conversations/{conversationId}/handoff`\n\n**operationId:** `request_leadscout_handoff_bridge_api_v1_workspaces__workspaceId__leadscout_conversations__conversationId__handoff_post`\n\nSolicita la transferencia manual de una conversación controlada por LeadScout a uno o más usuarios internos.\n\nLa solicitud se confirma con `202 Accepted`; la asignación se procesa de forma asíncrona. La respuesta repite los destinatarios solicitados y un ID de seguimiento para correlación. La resolución de usuarios internos (por ID o EMAIL) ocurre después y no se refleja en esta respuesta.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Descubrir las variables agnósticas de una plantilla",
      "source": "https://docs.bridge.new/es/api-reference/templates-api/descubrir-las-variables-agn%C3%B3sticas-de-una-plantilla",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/templates-api/descubrir-las-variables-agn%C3%B3sticas-de-una-plantilla.md",
      "description": "Devuelve las variables de una plantilla: `key`/`label`/`callerMustSupply`/`isCustom`/`default`, independientes de la ubicación en Meta.\n\nNunca devuelve la dirección o el índice de una posición de Meta.\n\n`templateId` acepta el `id` o el `name` de la plantilla. Las operaciones salientes aceptan `template.id` o `template.name`, con prioridad para un id no vacío. El inicio de conversaciones utiliza `onboardingTemplates[].templateId`. Utiliza el selector que exige la operación de envío. Consulta [la receta de plantillas](/es/guides/send-template).\n\nUna variable con `callerMustSupply: true` no tiene una fuente declarada: quien llama debe incluir su `key` en `parameters` al enviar; de lo contrario, el envío falla con un 422 que identifica ese mismo `key`.\nUna variable con `callerMustSupply: false` la resuelve Bridge por su cuenta, por ejemplo, el nombre del destinatario, o ya tiene un valor que quien llama puede sobrescribir opcionalmente.\nUna variable con `isCustom: true` es un valor que solo conoce quien llama y tiene un `default`: envíala en `parameters` para usar tu propio valor, u omítela o déjala en blanco para enviar `default`.\n\nCódigos de error:\n- BRIDGE_CORE_0301: el workspace de la ruta no coincide con el workspace de quien llama (403)\n- BRIDGE_TEMPLATE_0001: no se encontró una PROVIDER_TEMPLATE para este workspace e identificador. Incluye por igual un id/name desconocido, una plantilla de otro workspace y una plantilla que no es PROVIDER_TEMPLATE (404); este endpoint nunca confirma la existencia de una plantilla fuera del workspace de quien llama",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/templates/{templateId}`\n\n**operationId:** `get_template_discovery_bridge_api_v1_workspaces__workspaceId__templates__templateId__get`\n\nDevuelve las variables de una plantilla: `key`/`label`/`callerMustSupply`/`isCustom`/`default`, independientes de la ubicación en Meta.\n\nNunca devuelve la dirección o el índice de una posición de Meta.\n\n`templateId` acepta el `id` o el `name` de la plantilla. Las operaciones salientes aceptan `template.id` o `template.name`, con prioridad para un id no vacío. El inicio de conversaciones utiliza `onboardingTemplates[].templateId`. Utiliza el selector que exige la operación de envío. Consulta [la receta de plantillas](https://docs.bridge.new/es/guides/send-template.md).\n\nUna variable con `callerMustSupply: true` no tiene una fuente declarada: quien llama debe incluir su `key` en `parameters` al enviar; de lo contrario, el envío falla con un 422 que identifica ese mismo `key`.\nUna variable con `callerMustSupply: false` la resuelve Bridge por su cuenta, por ejemplo, el nombre del destinatario, o ya tiene un valor que quien llama puede sobrescribir opcionalmente.\nUna variable con `isCustom: true` es un valor que solo conoce quien llama y tiene un `default`: envíala en `parameters` para usar tu propio valor, u omítela o déjala en blanco para enviar `default`.\n\nCódigos de error:\n- BRIDGE_CORE_0301: el workspace de la ruta no coincide con el workspace de quien llama (403)\n- BRIDGE_TEMPLATE_0001: no se encontró una PROVIDER_TEMPLATE para este workspace e identificador. Incluye por igual un id/name desconocido, una plantilla de otro workspace y una plantilla que no es PROVIDER_TEMPLATE (404); este endpoint nunca confirma la existencia de una plantilla fuera del workspace de quien llama\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Obtener usuario interno por un identificador",
      "source": "https://docs.bridge.new/es/api-reference/internal-users-api/obtener-usuario-interno-por-un-identificador",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/internal-users-api/obtener-usuario-interno-por-un-identificador.md",
      "description": "Obtiene un Bridge User específico por cualquiera de sus identificadores dentro del workspace.\n\n`type=ID` devuelve el mismo usuario que GET /users/{userId}, la URL canónica de un usuario interno y la opción preferida cuando ya tienes su ID.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/users/lookup`\n\n**operationId:** `retrieve_internal_user_by_identifier_bridge_api_v1_workspaces__workspaceId__users_lookup_get`\n\nObtiene un Bridge User específico por cualquiera de sus identificadores dentro del workspace.\n\n`type=ID` devuelve el mismo usuario que GET /users/{userId}, la URL canónica de un usuario interno y la opción preferida cuando ya tienes su ID.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Obtener usuario interno por id",
      "source": "https://docs.bridge.new/es/api-reference/internal-users-api/obtener-usuario-interno-por-id",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/internal-users-api/obtener-usuario-interno-por-id.md",
      "description": "Obtiene un usuario interno específico (agente humano) por su identificador único dentro del workspace.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/users/{userId}`\n\n**operationId:** `retrieve_internal_user_by_id_bridge_api_v1_workspaces__workspaceId__users__userId__get`\n\nObtiene un usuario interno específico (agente humano) por su identificador único dentro del workspace.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Listar usuarios internos",
      "source": "https://docs.bridge.new/es/api-reference/internal-users-api/listar-usuarios-internos",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/internal-users-api/listar-usuarios-internos.md",
      "description": "Consulta una lista paginada de usuarios internos del workspace.\n\nSe ordena por fecha de creación. Los filtros `email` y `status` están obsoletos y se eliminarán; para encontrar un usuario interno por un identificador, usa /users/lookup.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/users`\n\n**operationId:** `get_internal_users_bridge_api_v1_workspaces__workspaceId__users_get`\n\nConsulta una lista paginada de usuarios internos del workspace.\n\nSe ordena por fecha de creación. Los filtros `email` y `status` están obsoletos y se eliminarán; para encontrar un usuario interno por un identificador, usa /users/lookup.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Listar los agents de un workspace",
      "source": "https://docs.bridge.new/es/api-reference/agents-api/listar-los-agents-de-un-workspace",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/agents-api/listar-los-agents-de-un-workspace.md",
      "description": "Lista los Agents del workspace con su estado, disponibilidad y líneas.\n\nIncluye todos los Agents, cualquiera que sea su estado; `available` indica si pueden iniciar conversaciones. Una página puede contener menos elementos que `limit`; sigue paginando mientras `cursor` no sea null.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/agents`\n\n**operationId:** `list_agents_bridge_api_v1_workspaces__workspaceId__agents_get`\n\nLista los Agents del workspace con su estado, disponibilidad y líneas.\n\nIncluye todos los Agents, cualquiera que sea su estado; `available` indica si pueden iniciar conversaciones. Una página puede contener menos elementos que `limit`; sigue paginando mientras `cursor` no sea null.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Iniciar conversación saliente con un contact como agent específico",
      "source": "https://docs.bridge.new/es/api-reference/agents-api/iniciar-conversaci%C3%B3n-saliente-con-un-contact-como-agent-espec%C3%ADfico",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/agents-api/iniciar-conversaci%C3%B3n-saliente-con-un-contact-como-agent-espec%C3%ADfico.md",
      "description": "Inicia una conversación saliente con un Contact conocido, atendida por el Agent indicado.\n\nFunciona con Agents LeadScout y Service. Primero se resuelve el Contact y después el Agent, que debe existir en el workspace y estar disponible (consulta `GET /agents`). La plantilla se referencia mediante `template.id` o `template.name` (id tiene prioridad si se envían ambos), debe existir y estar APPROVED, y cualquier Bridge User de `handoffOverride` debe ser válido. Si `template.media.mediaId` es desconocido, la solicitud falla con 400 `BRIDGE_AI_LEADSCOUT_0016` solo después de crear o recuperar la conversación, por lo que un reintento tras ese error puede responder de otra manera. Las reglas del cuerpo (`consent.status=GRANTED` sin `capturedAt`, o `template.media` sin exactamente uno de `mediaId` o `url`) fallan con 400 `BRIDGE_CORE_0103`.\n\nLa conversación se abre en una de las líneas activas de WhatsApp del Agent, bajo su control, con la plantilla como primer mensaje. Se elige una línea en este orden:\n- Una línea libre.\n- En su defecto, una línea con una conversación liberada recuperable con este Contact. La recuperación devuelve `recovered=true` y reemplaza el contexto saliente anterior y `agentContext`. Esto ocurre incluso con `forceSend=false`.\n- Si ninguna línea está libre o es recuperable: `forceSend=false` (predeterminado) falla con 409 `BRIDGE_AI_LEADSCOUT_0008`; `forceSend=true` reutiliza una línea ocupada por una conversación activa con este Contact, dando preferencia a una que controle este Agent. Si la conversación elegida está controlada por otro Agent o un Bridge User, la llamada falla con 409 `BRIDGE_AI_AGENT_OUTBOUND_0006` y no se escribe nada. Libérala primero y reintenta después. Nunca se usan líneas cuya conversación esté bloqueada o se haya liberado sin recuperación, por lo que, si ninguna línea está ocupada por una conversación activa, la llamada falla con 409 `BRIDGE_AI_LEADSCOUT_0008` incluso con `forceSend=true`.\n\n`contact.providerChannelId` es una preferencia: la línea indicada se usa cuando está libre o es recuperable; de lo contrario, se aplica el mismo orden entre todas las líneas del Agent. Entre las líneas ocupadas, tiene prioridad una que controle este Agent; si no existe, se reutiliza la línea indicada (y puede fallar con 0006).\n\nLa reutilización de una conversación depende del tipo de Agent:\n- LeadScout: si su sesión de LeadScout sigue abierta y no ha vencido, la llamada falla con 409 `BRIDGE_AI_LEADSCOUT_0017` (`extra` incluye `conversationId`, `sessionId` y `stage`). Si no se puede finalizar una sesión vencida, falla con 409 `BRIDGE_AI_LEADSCOUT_0018`.\n- Service Agent: se continúa una sesión de servicio abierta que no haya vencido; una sesión vencida se cierra como abandonada y se abre una nueva.\n\nConsulta [la guía completa de envío saliente](/es/guides/agent-outbound) para los requisitos, la tabla de decisión de forceSend, la recuperación, el trabajo parcial y las decisiones de reintento seguro.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `post /bridge/api/v1/workspaces/{workspaceId}/agents/{agentId}/outbound`\n\n**operationId:** `start_agent_outbound_bridge_api_v1_workspaces__workspaceId__agents__agentId__outbound_post`\n\nInicia una conversación saliente con un Contact conocido, atendida por el Agent indicado.\n\nFunciona con Agents LeadScout y Service. Primero se resuelve el Contact y después el Agent, que debe existir en el workspace y estar disponible (consulta `GET /agents`). La plantilla se referencia mediante `template.id` o `template.name` (id tiene prioridad si se envían ambos), debe existir y estar APPROVED, y cualquier Bridge User de `handoffOverride` debe ser válido. Si `template.media.mediaId` es desconocido, la solicitud falla con 400 `BRIDGE_AI_LEADSCOUT_0016` solo después de crear o recuperar la conversación, por lo que un reintento tras ese error puede responder de otra manera. Las reglas del cuerpo (`consent.status=GRANTED` sin `capturedAt`, o `template.media` sin exactamente uno de `mediaId` o `url`) fallan con 400 `BRIDGE_CORE_0103`.\n\nLa conversación se abre en una de las líneas activas de WhatsApp del Agent, bajo su control, con la plantilla como primer mensaje. Se elige una línea en este orden:\n- Una línea libre.\n- En su defecto, una línea con una conversación liberada recuperable con este Contact. La recuperación devuelve `recovered=true` y reemplaza el contexto saliente anterior y `agentContext`. Esto ocurre incluso con `forceSend=false`.\n- Si ninguna línea está libre o es recuperable: `forceSend=false` (predeterminado) falla con 409 `BRIDGE_AI_LEADSCOUT_0008`; `forceSend=true` reutiliza una línea ocupada por una conversación activa con este Contact, dando preferencia a una que controle este Agent. Si la conversación elegida está controlada por otro Agent o un Bridge User, la llamada falla con 409 `BRIDGE_AI_AGENT_OUTBOUND_0006` y no se escribe nada. Libérala primero y reintenta después. Nunca se usan líneas cuya conversación esté bloqueada o se haya liberado sin recuperación, por lo que, si ninguna línea está ocupada por una conversación activa, la llamada falla con 409 `BRIDGE_AI_LEADSCOUT_0008` incluso con `forceSend=true`.\n\n`contact.providerChannelId` es una preferencia: la línea indicada se usa cuando está libre o es recuperable; de lo contrario, se aplica el mismo orden entre todas las líneas del Agent. Entre las líneas ocupadas, tiene prioridad una que controle este Agent; si no existe, se reutiliza la línea indicada (y puede fallar con 0006).\n\nLa reutilización de una conversación depende del tipo de Agent:\n- LeadScout: si su sesión de LeadScout sigue abierta y no ha vencido, la llamada falla con 409 `BRIDGE_AI_LEADSCOUT_0017` (`extra` incluye `conversationId`, `sessionId` y `stage`). Si no se puede finalizar una sesión vencida, falla con 409 `BRIDGE_AI_LEADSCOUT_0018`.\n- Service Agent: se continúa una sesión de servicio abierta que no haya vencido; una sesión vencida se cierra como abandonada y se abre una nueva.\n\nConsulta [la guía completa de envío saliente](https://docs.bridge.new/es/guides/agent-outbound.md) para los requisitos, la tabla de decisión de forceSend, la recuperación, el trabajo parcial y las decisiones de reintento seguro.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    },
    {
      "title": "Registrar un lead de campaña",
      "source": "https://docs.bridge.new/es/api-reference/campaign-leads/registrar-un-lead-de-campa%C3%B1a",
      "markdownUrl": "https://docs.bridge.new/es/api-reference/campaign-leads/registrar-un-lead-de-campa%C3%B1a.md",
      "description": "Registra un lead captado por la página de destino de un tenant y pone en cola el primer mensaje saliente de WhatsApp. Un 202 significa que el lead fue aceptado, no que se haya enviado un mensaje.",
      "kind": "operation",
      "contentMarkdown": "**Referencia de la operación:** `post /leadscout/campaign-leads`\n\n**operationId:** `create_campaign_lead_leadscout_campaign_leads_post`\n\nRegistra un lead captado por la página de destino de un tenant y pone en cola el primer mensaje saliente de WhatsApp. Un 202 significa que el lead fue aceptado, no que se haya enviado un mensaje.\n\n[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/campaign-leads.openapi.yaml)\n\nEste corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud.\n"
    }
  ]
}
