# Conectores

Cómo los conectores y las conexiones dan a los agentes acceso limitado a herramientas externas.

Canonical page: https://beeuni.ai/docs/es/connect/connectors

Un conector vincula un proyecto con una herramienta o servicio externo. El agente
lo invoca como herramienta. Beeuni gestiona cada llamada, por lo que el entorno aislado nunca almacena la
credencial del conector.

La mayoría de los conectores se declaran en `beeuni.yaml`. Consulta la
[referencia del manifiesto](/docs/es/project/manifest) para ver todos los campos. Beeuni declara
conectores de canales y de computadoras cuando conectas una plataforma de chat o una
máquina.

<a id="browse-and-add-a-connector"></a>

## Explorar y añadir un conector

Abre **Connectors** para explorar el catálogo administrado. De forma predeterminada, la lista incluye
kits de herramientas de proveedores administrados que se pueden conectar con autenticación gestionada por el proveedor o con una configuración de autenticación personalizada habilitada. No requiere que ya exista una conexión en tu proyecto. Un kit de herramientas que necesite una configuración OAuth personalizada sin verificar permanece oculto hasta que se pueda verificar esa configuración.

Para ver fuentes directas, habilita **Connectors API Discover** en las marcas de funciones del proyecto
y luego selecciona **API / MCP** en la misma página. Habilitar la marca no
reemplaza el catálogo administrado predeterminado. El catálogo directo agrupa superficies publicadas de OpenAPI, MCP, GraphQL, Postman y otras API. Selecciona una tarjeta, elige una superficie publicada y completa el formulario de conexión. Las superficies que solo tienen documentación abren la documentación del proveedor; no se presentan como plantillas listas para conectar.
Usa **Add → Manual** para una API sin procesar o un esquema que no esté en el catálogo.
La detección directa también funciona sin un proveedor administrado configurado.

<a id="connectors-connections-and-accounts"></a>

## Conectores, conexiones y cuentas

Un conector es el paquete de acceso que ve el agente: una capacidad declarada (qué
actions permite y cómo llegar al servicio). No es un rol ni tiene permisos de Beeuni:
un agente accede a un conector solo cuando la autorización de su manifiesto incluye el
slug y el veredicto del rol permite la llamada. Consulta
[Un vocabulario, dos vinculaciones](/docs/es/accounts#one-vocabulary-two-bindings). Un
conector contiene:

- un slug único en el proyecto
- un nombre para mostrar
- una aplicación del proveedor
- políticas del conector

Una conexión es una **cuenta** —una identidad autorizada— para el
conector: una credencial, una autorización OAuth o una clave de API. Un conector puede tener
varias cuentas a la vez. Todas las cuentas usan las políticas del conector.
El `owner_type` de cada cuenta determina quién puede realizar una llamada con ella:

- `project` — una cuenta **compartida**. Pueden acceder a ella todas las personas o cuentas de servicio (agente, activador) a las que se conceda el conector.
- `member` — una cuenta **privada**, propiedad de un miembro del proyecto
  (`owner_id`). Solo puede acceder a ella ese miembro y únicamente en una sesión **privada**.
  Una cuenta de servicio (un agente o un activador que actúa sin supervisión) nunca puede usar la cuenta privada de un miembro.

Varios conectores pueden hacer referencia a la misma aplicación del proveedor. Usa conectores separados cuando una aplicación necesite políticas distintas.

<a id="add-an-account"></a>

### Añadir una cuenta

Abre el conector en **Customize → Connectors**. La pestaña **Accounts** muestra
todas las cuentas que puedes usar o administrar en una sola lista. Cada tarjeta indica quién puede usar
la cuenta: **Only you**, **Everyone in project** o los grupos y personas con quienes se comparte.

Selecciona **Add account**, asigna un nombre a la cuenta y elige **Who can use it**:

- **Only you** — una cuenta privada. Cualquier miembro puede añadir una.
- **Everyone in the project** — una cuenta compartida.
- **Specific people or groups** — una cuenta compartida, limitada a las personas,
  grupos y agentes que elijas.

Las dos opciones para compartir requieren `project.connector.connections.manage`. Para
**Specific people or groups**, Beeuni escribe las autorizaciones antes de que autorices
la cuenta, así que la cuenta nunca almacena una credencial mientras está abierta a todo
el proyecto. El nombre de una cuenta debe ser nuevo: se rechaza un nombre que ya use una cuenta del mismo propietario.

Cuando un agente necesita una cuenta, publica una tarjeta **Connect** en el chat. La
tarjeta abre el mismo diálogo, con el nombre sugerido por el agente ya rellenado y la audiencia que solicitó preseleccionada. Beeuni crea una cuenta nueva, nunca vuelve a autorizar una existente e indica al agente el nombre de la nueva cuenta para que pueda realizar llamadas con ella.

<a id="choose-who-can-use-a-shared-account"></a>

### Elegir quién puede usar una cuenta compartida

Una cuenta compartida puede usarla cualquier persona del proyecto hasta que limites el acceso.
Selecciona **Share** en la tarjeta de la cuenta. El diálogo es el mismo **Grant access**
que se usa para los agentes. Muestra quién puede usar la cuenta en ese momento y permite añadir:

- **Everyone in the project** — la opción predeterminada.
- **Groups** — todos los miembros de cada grupo.
- **People** — un miembro por entrada. Elige solo tu nombre para reservar la cuenta para ti.
- **Agents** — todas las sesiones de ese agente, incluidos los activadores y las sesiones compartidas. Cualquier persona que pueda ejecutar el agente puede usar la cuenta a través de él.

Los cambios no se aplican hasta que selecciones **Save**. Si quitas el último grupo o la última persona,
la cuenta vuelve a estar disponible para todos; el diálogo indica el resultado antes de que guardes.

A una cuenta con acceso limitado se le aplican las reglas de una cuenta privada, con la audiencia en
lugar del propietario:

- Una persona de la audiencia puede usarla, únicamente en una sesión privada.
- Un agente de la audiencia puede usarla en todas sus sesiones.
- Ningún otro agente ni ningún activador de otro agente puede usarla.
- Una sesión que la vincule no se puede compartir, salvo que la cuenta se comparta con el agente de esa misma sesión.
- Solo una persona puede cambiar quién puede usar una cuenta. Una sesión de agente obtiene `403`.

Una persona que no forme parte de la audiencia no verá la cuenta. Quienes administran las conexiones del proyecto sí la verán, marcada como **Not shared with you**, para poder cambiar quién puede usarla.

<a id="share-your-own-private-account"></a>

### Compartir tu propia cuenta privada

Tu cuenta **Only you** también tiene un botón **Share**. Al compartirla, se convierte en una cuenta compartida para las personas y los grupos que elijas (seguirás teniendo acceso, salvo que te quites), o para todo el proyecto. A partir de ese momento, es una cuenta compartida: quienes administran las conexiones del proyecto también pueden administrarla.

- Para compartirla se necesita `project.connector.connections.manage`, el mismo permiso que para
  añadir una cuenta compartida. Sin él, el botón está deshabilitado e indica el motivo.
- Beeuni escribe primero las autorizaciones y convierte la cuenta en compartida en una sola actualización,
  así que nunca queda abierta a todo el proyecto entre un paso y otro.
- Una cuenta compartida del mismo nombre en el conector impide compartirla (`409`): cambia primero el nombre de una.

```text
POST /projects/{projectId}/connections/{connectionId}/share
     {"principals": [{"principal_type": "group", "principal_id": "<group-id>"}]}
```

Una lista `principals` vacía la comparte con todos. Desde la CLI:
`beeuni connectors connections share <connection-id> --group <group-id>`
(también `--user <email|id>`, repetible, o `--everyone`).

Cada entrada de la audiencia es una asignación de objeto `connection` en el almacén de autorizaciones:

```text
POST   /accounts/{accountId}/iam/assignments
       {"principal_type": "group", "principal_id": "<group-id>",
        "role_key": "agent-user", "scope_type": "project", "scope_id": "<project-id>",
        "object_type": "connection", "object_id": "<connection-id>"}
DELETE /accounts/{accountId}/iam/assignments/{assignmentId}
```

Desde la CLI, las mismas escrituras son:

```bash
beeuni access grant --group <group-id> --connection <connection-id>
beeuni access grant --everyone --connection <connection-id>
beeuni access revoke <assignment-id>
beeuni connectors connections ls   # the WHO CAN USE column
```

- `principal_type` es `user`, `group` o `project` (todos en el proyecto;
  `principal_id` es el id del proyecto).
- Para conceder o revocar una autorización se necesita `project.connector.connections.manage`.
- Solo se puede limitar el acceso a una cuenta compartida mediante estas autorizaciones. Una cuenta privada,
  o un id que no corresponda a una conexión de este proyecto, devuelve `404`; comparte tu
  propia cuenta privada mediante la ruta `share` anterior.
- `GET /projects/{projectId}/connections` devuelve las autorizaciones de cada cuenta compartida
  en `shared_with`, y `usable: false` para una cuenta que la persona que llama solo puede ver para
  administrarla. El selector de sesiones solo ofrece cuentas que se pueden usar.

<a id="which-identity-an-account-acts-as"></a>

### Con qué identidad actúa una cuenta

El `label` de una cuenta es un nombre elegido antes de la autorización. No indica qué inicio de sesión se usó. `connected_as` sí lo hace: el correo electrónico, el inicio de sesión o el nombre visible que el proveedor informa para la cuenta autorizada.

- Beeuni lo lee cuando finaliza una autorización gestionada: primero el nombre visible de la cuenta conectada y después la herramienta «quién soy» del toolkit (Gmail, Google Calendar, Google Drive, Linear, GitHub, Slack, Notion, Outlook, Microsoft Teams, HubSpot, Jira, Asana, Figma, Airtable, Salesforce, Trello, Dropbox, Calendly). Google Docs y Google Sheets no exponen una herramienta de este tipo, por lo que su `connected_as` permanece `null`.
- Una cuenta que aún tenga una etiqueta predeterminada (`Private connection`, `Project connection` o el nombre del conector) cambia su etiqueta a esa identidad. Una etiqueta elegida por alguien nunca se reemplaza.
- La página de conexión muestra «Connected as …» en cuanto se incorpora la cuenta, de modo que una cuenta compartida autorizada con un inicio de sesión personal queda visible de inmediato.
- `connected_as` aparece en cada conexión (`GET /projects/{projectId}/connections`), en la lista de cuentas, en `beeuni connectors accounts <slug>` y `beeuni connectors connections ls` (la columna `CONNECTED AS`), y en las filas de cuentas de **Customize → Connectors**.

<a id="rename-an-account"></a>

### Cambiar el nombre de una cuenta

Cambia el nombre de una cuenta sin volver a autorizarla:

```text
PUT /projects/{projectId}/connections/{connectionId}/label   {"label": "Support inbox"}
beeuni connectors connections rename <connection-id> Support inbox
```

En el panel, abre el conector y selecciona **⋯ → Rename** en la fila de la cuenta. Solo cambia la etiqueta. La cuenta autorizada, su propietario, su indicador de cuenta predeterminada y el estado del proveedor permanecen sin cambios. Se aplica la misma restricción que para desconectar: tu propia cuenta privada o `project.connector.connections.manage` para una compartida.

El cambio de nombre se rechaza con `400` para `me`, `project` o una etiqueta con formato de UUID, porque `--account` resuelve esos valores antes que las etiquetas. Se rechaza con `409` cuando otra cuenta del mismo propietario ya tiene esa etiqueta, comparando sin distinguir mayúsculas de minúsculas.

<a id="connect-a-different-account"></a>

### Conectar otra cuenta

Un enlace de conexión para un espacio que ya contiene una cuenta activa no vuelve a autorizarla. El proveedor reutiliza la cuenta y la página de conexión muestra **Already connected**. Para usar otro inicio de sesión, añade una cuenta nueva al conector, conviértela en la predeterminada y desconecta la anterior.

Una llamada que no especifica ninguna cuenta se resuelve primero con la cuenta privada predeterminada del propio usuario que llama y después con la cuenta compartida predeterminada del proyecto. El resultado de cada llamada indica con qué cuenta se ejecutó (`account: { connection_id, label,
owner_type }`), por lo que la transcripción siempre muestra la identidad que usó la llamada a la herramienta.
Enumera las cuentas como las que se puede llamar en un conector, con la predeterminada primero, mediante `GET /connectors/projects/{projectId}/connectors/{slug}/accounts`.

> **Warning**
> `authorization_strategy` (`project` | `user`) era un MODE a nivel de conector que hacía que las cuentas propiedad del proyecto y las cuentas propiedad de miembros fueran mutuamente excluyentes: un conector con estrategia `user` no podía ofrecer ninguna cuenta compartida, por lo que no tenía un flujo de conexión en ningún lugar donde una cuenta de servicio pudiera usarlo. Está obsoleto: el manifiesto y `PUT .../authorization-strategy` todavía lo aceptan y responden sin error, pero ya nada lo lee. `owner_type` en cada conexión es ahora toda la regla de acceso.

<a id="providers"></a>

## Proveedores

Un conector utiliza un tipo de proveedor:

- **composio** — OAuth administrado para aplicaciones SaaS compatibles
- **pipedream** — OAuth administrado heredado, conservado solo para reversiones
- **openapi**, **postman**, **graphql**, **http** — conectores de API directos
- **mcp** — un servidor MCP remoto mediante HTTP o SSE
- **channel** — una conexión con una plataforma de chat
- **computer** — la máquina conectada de cada miembro es una cuenta

Consulta [Slack y canales](/docs/es/connect/slack) y [Computers](/docs/es/connect/computers) para conocer los flujos de proveedores administrados.

<a id="apps-that-need-your-own-oauth-app"></a>

### Disponibilidad de las aplicaciones

El catálogo de conectores muestra las aplicaciones disponibles para conectar. Algunas requieren una configuración de autenticación adicional y pueden no aparecer hasta que se complete.

## Autenticación y políticas

Una conexión se autentica mediante:

- OAuth administrado, una instalación de canal o una concesión OAuth2 nativa
- una clave de API o un token introducido mediante el panel

Beeuni cifra los datos de conexión y los resuelve en el servidor para cada llamada a una herramienta. El agente solicita una acción. Beeuni adjunta la credencial, comprueba la concesión del agente y la política de conexión del conector, llama a la API externa y devuelve el resultado.

Las políticas de los conectores pertenecen al conector. Una conexión no puede anularlas. Las reglas de protección del proyecto se aplican por encima de las políticas de conexión del conector.

De forma predeterminada, una acción de conector no coincidente se ejecuta sin aprobación. Establece `policy.default_mode: risk` para exigir aprobación para acciones de escritura y destructivas no coincidentes. Establece `sensitive: true` para convertir `require_approval` en el valor predeterminado de acciones no coincidentes del conector, incluidas las lecturas. Las reglas explícitas del proyecto o de la conexión del conector siguen aplicándose primero.

<a id="approve-one-governed-call"></a>

### Aprobar una llamada gobernada

`require_approval` crea una decisión para una única llamada al conector. El conector devuelve `202 pending_approval` con `approval_url`, `approval_summary` y `execution_id`. No mantiene abierta una solicitud HTTP.

Comparte `approval_url` con cualquier compañero de equipo. La URL identifica la solicitud, pero no concede autoridad. La página requiere una cuenta de Beeuni con sesión iniciada. Beeuni verifica entonces que la cuenta pueda acceder al proyecto y aprobar acciones en él.

La página de aprobación muestra los parámetros redactados que recibirá el conector. El usuario que llama puede añadir `approval_context` (CLI: `--reason`) para describir el efecto. Úsalo cuando los parámetros sean solo referencias: `gmail.send_draft` recibe un ID de borrador, por lo que el agente indica el destinatario, el asunto y el cuerpo. La página muestra este texto como la descripción del agente, no como información verificada. Los parámetros siguen siendo la evidencia. Beeuni nunca envía `approval_context` al proveedor.

Aprueba o rechaza la llamada una vez. Añade un mensaje opcional a la decisión. El mensaje vuelve al agente junto con la decisión, de modo que un rechazo puede indicar qué hacer en su lugar.

Cada llamada pendiente también aparece en **Review → Needs you** del proyecto. Abre **Review** desde la barra lateral; su contador muestra cuántos elementos esperan tu atención. Una llamada se abre en la misma vista de aprobación que su enlace de aprobación, para que veas el conector, los parámetros y la descripción del agente antes de decidir.

Cuando la llamada proviene de una sesión de Slack o Teams, Beeuni publica una tarjeta de aprobación en ese hilo. La tarjeta muestra la descripción del agente, los parámetros y **Approve** / **Deny**. En Slack, **Reply…** abre un cuadro para enviar un mensaje al agente; en Teams, la tarjeta incluye el cuadro de mensaje. Solo un responsable del proyecto o la persona que inició la sesión puede decidir. Una decisión tomada en cualquier lugar (el hilo, Beeuni o la página de aprobación) sustituye los botones de la tarjeta por el resultado, y el agente continúa en el mismo hilo. Beeuni devuelve la decisión a la sesión mediante una devolución de llamada persistente. La aprobación se aplica únicamente al resumen criptográfico exacto de la solicitud. Si cambia el destinatario, el asunto, el cuerpo, el canal, la URL u otro parámetro, se requiere una nueva decisión.

Abre el panel **Audit** de la sesión para consultar la misma vista de parámetros. Las entradas históricas son de solo lectura. No hay una opción de aprobación para toda la sesión. Usa una política explícita `always_run` solo cuando una acción del conector deba ejecutarse sin supervisión.

<a id="connect-with-oauth"></a>

## Conectar con OAuth

### Abre la página Connectors del proyecto
Abre el proyecto. Selecciona **Connectors** y luego la aplicación.

### Selecciona el ámbito de la cuenta
Selecciona **Project** para una cuenta compartida, a la que puede acceder cualquiera a quien se le conceda el conector. Selecciona **User** para una cuenta privada, que te pertenece y a la que solo tú puedes acceder, y únicamente en una sesión privada.

### Completa la autorización
Completa el flujo de OAuth. Beeuni guarda la cuenta conectada como una conexión.

<a id="connect-an-mcp-server-that-uses-oauth-21"></a>

## Conectar un servidor MCP que usa OAuth 2.1

Beeuni implementa la especificación de autorización de MCP. Abre el conector, selecciona **Add credential** y luego la pestaña **OAuth 2.0**. Beeuni sondea el servidor y lee sus metadatos:

1. El sondeo sin autenticar devuelve `401` con
   `WWW-Authenticate: Bearer resource_metadata="…"`.
2. Beeuni lee los metadatos del recurso protegido (RFC 9728) en esa URL o en
   `/.well-known/oauth-protected-resource`.
3. Beeuni lee los metadatos del servidor de autorización (RFC 8414 o detección de OpenID Connect) del primer servidor de autorización que indique el recurso.

Cuando ese servidor anuncia `registration_endpoint`, Beeuni se registra como cliente OAuth (RFC 7591) y muestra un único botón: **Connect &lt;server&gt;**. No tienes que crear una aplicación ni copiar un ID o secreto de cliente. A continuación, Beeuni ejecuta Authorization Code con PKCE (S256) y vincula el token al servidor con el parámetro `resource` (RFC 8707).

Registra este URI de redirección si un servidor lo necesita de antemano:

```text
https://api.beeuni.ai/v1/connectors/oauth2/callback
```

Cuando el servidor publica endpoints, pero no `registration_endpoint`, Beeuni completa de antemano la URL de autorización, la URL del token y los ámbitos. Introduce el ID de cliente de una aplicación que crees con ese proveedor. Si el servidor no publica metadatos, introduce todos los campos.

Beeuni mantiene la sesión MCP: ejecuta `initialize` y
`notifications/initialized` cuando se necesitan y luego envía `Mcp-Session-Id` en las llamadas posteriores. Un servidor que responde sin una sesión nunca llega a ver el protocolo de enlace.

Beeuni vincula cada conexión al servidor de autorización que la emitió. Si la devolución de llamada incluye un parámetro `iss` (RFC 9207), Beeuni lo rechaza a menos que coincida con el emisor registrado: se rechaza un código creado por otro servidor antes de canjearlo.

<a id="authorize-from-the-cli"></a>

### Autorizar desde la CLI

El panel es una forma de ejecutar este flujo, pero no la única. Declara el conector en `beeuni.yaml` y luego autorízalo desde un terminal o una sesión de agente:

```yaml
connectors:
  - slug: read-ai
    name: Read AI
    provider: mcp
    url: 'https://api.read.ai/mcp'
    auth:
      type: bearer
```

```text
beeuni connectors authorize read-ai --json
```

El comando crea la conexión, ejecuta la cadena de detección, registra Beeuni como cliente si el servidor admite RFC 7591 y devuelve la URL que se debe aprobar:

```json
{
  "connection_id": "7b1a16b2-...",
  "registered": true,
  "scopes": ["openid", "offline_access", "mcp:execute", "meeting:read"],
  "authorization_url": "https://authn.read.ai/oauth2/auth?response_type=code&...",
  "expires_at": "2026-08-19T14:48:26.345Z"
}
```

Un agente devuelve `authorization_url` a la persona con la que está trabajando. Después de que esta lo apruebe, el agente confirma:

```text
beeuni connectors authorize read-ai --status
```

El comando termina con un código distinto de cero mientras el estado sea `error`. Usa `--scope` para limitar lo que se solicita. Usa `--client-id` y `--client-secret` con un servidor que no admita el registro dinámico de clientes.

Beeuni vuelve a obtener el catálogo de herramientas del conector en cuanto se completa la autorización, por lo que el conector sale del estado `error` sin necesidad de sincronizarlo manualmente.

<a id="connect-a-direct-api-with-oauth2"></a>

## Conectar una API directa con OAuth2

Los conectores directos admiten:

- credenciales de cliente
- código de autorización con PKCE
- autorización de dispositivo
- registro dinámico de clientes (RFC 7591)

Para las credenciales de cliente, introduce la URL del token, el ID de cliente, los ámbitos y el secreto de cliente. Puedes usar la autenticación del endpoint del token `client_secret_basic`, `client_secret_post`,
`client_secret_jwt` o `private_key_jwt`.

Para el código de autorización, introduce la URL de autorización y la URL del token. Para la autorización de dispositivo, introduce la URL de autorización de dispositivo y la URL del token. Una URL de detección RFC 8414 puede proporcionar estos endpoints.

Beeuni cifra la configuración de OAuth2 y los tokens. Actualiza los tokens de acceso antes de que caduquen y guarda cada token de actualización rotado. Revocar la conexión bloquea la siguiente llamada al conector.

Para Microsoft Graph, usa:

```text
https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token
https://graph.microsoft.com/.default
```

Para llamadas directas a SharePoint REST, usa el ámbito de recurso de SharePoint:

```text
https://{tenant}.sharepoint.com/.default
```

<a id="connect-with-an-api-key"></a>

## Conectar con una clave de API

### Declara el conector
```yaml
connectors:
- slug: stripe-read
name: Stripe read access
provider: openapi
spec: 'https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json'
auth:
type: bearer
policies:
- match: 'get_*'
action: always_run
- match: '*'
action: block
```

El manifiesto sigue aceptando una clave `authorization_strategy` por compatibilidad con versiones anteriores. Beeuni la ignora: al añadir las credenciales de cada conexión, define su propietario (compartido o privado).

### Fusiona la solicitud de cambio
Beeuni lee el manifiesto de la rama predeterminada. El conector se activa cuando se fusiona la solicitud de cambio.

### Añade la conexión
Abre el conector y configura sus credenciales. Beeuni guarda el valor cifrado. No escribe el valor en el manifiesto.

<a id="grant-an-agent-access"></a>

## Conceder acceso a un agente

Añade el identificador del conector al campo `connectors` del agente:

```yaml
agents:
  release-bot:
    connectors: [stripe-read]
```

Si omites `connectors`, el agente obtiene `none`. Fusiona el cambio para que surta efecto.

`connectors_required` está obsoleto. El manifiesto aún lo acepta, pero no se lee en ninguna parte: nunca se rechaza la creación de una sesión porque un conector no tenga una cuenta utilizable. En la práctica, no se podía llegar a rechazar la creación de una sesión por falta de un conector: un conector solo privado no tenía ninguna cuenta compartida que ofrecer, así que quien solicitaba la sesión no podía hacer nada para solucionar el rechazo. Ahora, el control se aplica a la **llamada** al conector: un agente al que se le ha concedido `stripe-read` puede iniciar su turno de inmediato, y solo se deniega la llamada que realmente necesita el conector (consulta [Cuándo se deniega una llamada](#when-a-call-is-denied)), con una solución incluida.

<a id="select-an-account"></a>

## Seleccionar una cuenta

Hay dos formas independientes de elegir con qué cuenta se ejecuta una llamada: fijar una para toda la sesión o indicar una en una sola llamada.

<a id="pin-a-session-wide-default"></a>

### Fijar un valor predeterminado para toda la sesión

Una sesión puede anular la cuenta predeterminada del conector para todas las llamadas que realice:

```json
{
  "connector_bindings": {
    "stripe-read": {
      "connection_id": "00000000-0000-4000-8000-000000000000"
    }
  }
}
```

La clave de vinculación es el identificador del conector. El valor es una cuenta (conexión) a la que quien realiza las llamadas de esta sesión tiene derecho a acceder.

Usa `GET /projects/{projectId}/sessions/{sessionId}/scope` para consultar la vinculación efectiva. Usa `PUT` en la misma ruta para sustituirla. El cambio se aplica en la siguiente llamada a una herramienta, sin reiniciar la sesión.

<a id="name-an-account-on-one-call"></a>

### Indicar una cuenta en una sola llamada

Enumera las cuentas con las que se puede llamar a un conector —con la predeterminada primero— mediante:

```text
GET /connectors/projects/{projectId}/connectors/{slug}/accounts
```

```json
{
  "connector": "stripe-read",
  "accounts": [
    { "connection_id": "...", "label": "Shared workspace", "owner_type": "project", "is_default": true, "connected_as": "billing@example.com" },
    { "connection_id": "...", "label": "My Stripe", "owner_type": "member", "is_default": false, "connected_as": null }
  ]
}
```

Luego nombra una en la llamada, por ID de conexión o por etiqueta (sin distinguir mayúsculas y minúsculas), o
con las dos palabras selectoras `me` (tu propia cuenta privada predeterminada) y
`project` (la cuenta compartida predeterminada del proyecto):

```text
beeuni connectors call stripe-read get_balance '{}' --account me
beeuni connectors call stripe-read get_balance '{}' --account "Shared workspace"
```

Una llamada que no indica ninguna cuenta se resuelve primero en la cuenta privada predeterminada de quien llama y luego en la cuenta compartida predeterminada del proyecto, igual que antes de que un conector pudiera tener más de una cuenta. Si no se resuelve una cuenta indicada, la llamada se **deniega**; nunca se sustituye silenciosamente por otra (consulta [Cuándo se deniega una llamada](#when-a-call-is-denied)). El resultado de cada llamada exitosa indica con qué cuenta se ejecutó: `account: { connection_id, label,
owner_type }`.

<a id="use-a-connector-in-a-session"></a>

## Usar un conector en una sesión

Dentro de una sesión, usa Connector CLI:

```text
beeuni connectors ls
beeuni connectors accounts stripe-read
beeuni connectors call stripe-read <action> '<json-args>' [--account <id|label|me|project>]
```

`connectors` muestra los conectores incluidos en el ámbito. `accounts` muestra las cuentas que quien llama puede usar `stripe-read` como, primero la predeterminada y luego las compartidas antes que las privadas dentro de cada grupo. `call` ejecuta una acción, con la cuenta `--account` indicada o, si se omite, con la misma resolución predeterminada que se usaba antes de que un conector pudiera tener más de una cuenta.

<a id="large-results"></a>

### Resultados grandes

Una llamada de lista o búsqueda puede devolver más información de la que un modelo puede leer: los resultados de herramientas de más de ~50 KB se truncan. Guarda el resultado en un archivo y procésalo con código:

```text
beeuni connectors call linear graphql.issues '{"first":250}' --out /workspace/output/issues.json
# → { "ok": true, "account": …, "saved_to": "/workspace/output/issues.json",
#     "bytes": 93037, "shape": { "issues": { "nodes": "array(250) of {id,title,…}",
#     "pageInfo": { "hasNextPage": true, "endCursor": "…" } } } }
jq '.data.issues.nodes[] | {id, title}' /workspace/output/issues.json
```

`--out` escribe el resultado JSON completo y crea los directorios principales. La salida estándar recibe el contenedor de la llamada sin `data`, además de `saved_to`, `bytes` y `shape`: el esquema de `data` (claves, longitudes de las matrices y cada `pageInfo`). El código de salida no cambia.

<a id="attach-files"></a>

### Adjuntar archivos

Una llamada nunca incluye bytes de archivos en sus argumentos. Prepara el archivo y luego incluye su referencia en los argumentos. La puerta de enlace lee los bytes en el servidor y los escribe en la solicitud.

```text
beeuni connectors call microsoft-graph.sendmail @mail.json \
  --attach /workspace/artifacts/report.pdf
```

`--attach` prepara el archivo y añade una referencia a la matriz de adjuntos de la acción. La matriz se encuentra en el esquema de entrada de la acción: `attachments` para el canal Email, `body.message.attachments` para Microsoft Graph `sendMail`. Si el esquema no es habitual, indica el nombre con `--attach-path body.message.attachments`.
Los argumentos JSON grandes se incluyen en un archivo (`@mail.json`) o en stdin (`-`).

Para colocar un archivo por tu cuenta, primero prepáralo:

```text
beeuni connectors upload /workspace/artifacts/report.pdf --connector microsoft-graph
# → { "attachment_id": "…", "ref": { "$beeuni_attachment": "…" }, … }
```

Coloca `ref` en cualquier parte de los argumentos. La puerta de enlace lo sustituye según su posición:

| Posición de `ref` | Sustitución |
| --- | --- |
| Un elemento de una matriz de adjuntos cuyos elementos son objetos | El elemento de adjunto del proveedor. El esquema del elemento determina el formato: Microsoft Graph `fileAttachment` (`name` + `contentBytes` o `@odata.type`), Postmark (`Name` + `Content`), Mailjet (`Filename` + `Base64Content`), SendGrid y Resend (`filename` + `content`), Brevo (`name` + `content`). Cualquier otro formato de elemento se rechaza con `attachment_item_shape_unknown`. |
| Un campo de cadena, por ejemplo `contentBytes` o un `content` de archivo de GitHub | El valor base64 del archivo. |
| `attachments[]` del canal Email | Una URL de descarga firmada para el proveedor de Email. |

Reglas:

- Los archivos deben proceder de `/workspace/output`, `/workspace/artifacts`,
  `/workspace/reports` o `/workspace/deliverables`. Se rechazan los enlaces simbólicos y los enlaces físicos. Copia primero el archivo allí.
- Una llamada puede incluir hasta 20 archivos y un total de 25 MiB. La API de destino puede establecer un límite menor: Microsoft Graph indica que 3 MB es el tamaño máximo de archivo que se puede adjuntar en una solicitud `sendMail`.
- Un archivo preparado es privado para la sesión que lo preparó, se usa una sola vez y se elimina al cabo de 24 horas. Si la llamada falla, queda disponible para volver a intentarlo.
- El registro de auditoría, la vista previa de aprobación y el modelo solo ven la referencia, nunca los bytes. Si un error de destino devuelve el archivo, se elimina el valor base64.
- Los conectores administrados no aceptan archivos preparados
  (`connector_attachments_unsupported`).

El servidor MCP ofrece el mismo flujo: `call` recibe `attachment_files` (y un `attachment_path` opcional), y `upload_attachment` devuelve un `ref`. El equivalente del SDK es `connectors.uploadAttachment(bytes, { filename, contentType,
connector })`, which returns `ref`.

<a id="call-results"></a>

### Resultados de llamadas

`POST /connectors/projects/{projectId}/call` responde con un objeto JSON. Estos
campos son iguales en todos los enlaces (OpenAPI, HTTP, MCP, GraphQL, `composio`,
`pipedream`, computadoras):

| Campo | En | Valor |
| --- | --- | --- |
| `data` | 200 | La respuesta sin procesar del servicio de destino, sin cambios. |
| `output` | 200 | El contenido sin el contenedor del enlace: `composio` `data.result`, MCP `result.structuredContent ?? result.content`, GraphQL `data.data`. No aparece cuando coincide con `data` (llamadas de OpenAPI, HTTP, Postman, canal, `pipedream` y computadora), por lo que el cuerpo incluye el contenido una sola vez: lee `output ?? data`. El SDK lo completa. |
| `binding` | 200, 500, 429, 503 | El enlace que ejecutó la llamada: `openapi`, `http`, `mcp`, `graphql`, `composio`, `pipedream`, `pipedream_proxy`, `postman`, `tunnel`. `null` si se produce un error antes de que se resuelva la acción. |
| `upstream_status` | 200, 500, 429, 503 | El estado HTTP del servicio de destino. `null` si ningún servicio de destino respondió (por ejemplo, por tiempo de espera, solicitud rechazada o computadora). `composio` y `pipedream` notifican los errores del proveedor dentro de una respuesta 200, por lo que Beeuni establece `502` en esos casos (`400` si se rechaza una consulta de Linear, `429` si se alcanza el límite de solicitudes). |
| `upstream_error` | 200 | Aparece cuando el servicio de destino notifica un error dentro de una respuesta 2xx: el resultado de una herramienta MCP con `isError: true` o un error JSON-RPC, o `errors` de GraphQL sin datos. La llamada cuenta como ejecutada: `ok` sigue siendo `true`. |
| `retry_after_seconds` | 429, 503 | El valor de `Retry-After` del servicio de destino, en segundos, si lo envió. La respuesta también incluye el encabezado `Retry-After`. |

El estado HTTP de una llamada fallida:

- Una respuesta `429` indica que el servicio de destino devuelve `429`. Una respuesta `503` indica que devuelve `503`. Espera `retry_after_seconds` (o aumenta el intervalo entre intentos) y vuelve a llamar.
- Los demás errores del servicio de destino responden con `500` y especifican la causa en `reason`.

- Si la respuesta del servicio de destino supera los 64 MiB, responde con `500` y `reason: "upstream_response_too_large: …"`. Beeuni deja de leer al alcanzar el límite. Solicita una página más pequeña o aplica un filtro.
- Si el servicio de destino no responde dentro del plazo, responde con `500` y `reason: "upstream_timeout: …"`. El plazo predeterminado es de 60 segundos. Establece un tiempo de espera del cliente superior para que la puerta de enlace responda siempre primero.

Las llamadas a conectores no son idempotentes. Beeuni no elimina las llamadas repetidas. Después de `upstream_timeout` o de cancelar desde el cliente, es posible que la llamada se haya ejecutado en el servicio de destino: comprueba sus efectos antes de repetir una escritura (por ejemplo, un correo enviado o un registro creado).

<a id="typed-calls-from-code"></a>

### Llamadas tipadas desde código

`beeuni connectors types` escribe un archivo de declaración TypeScript para cada acción que puedes llamar. Cada acción obtiene el tipo de sus argumentos del esquema de entrada y el tipo del resultado del esquema de salida. El tipo del resultado describe el campo `output` de la llamada.

```sh
beeuni connectors types --out src/beeuni-connectors.d.ts
beeuni connectors types --connector linear,github --out src/beeuni-connectors.d.ts
```

Incluye el archivo en tu `tsconfig.json`. Luego llama a través de `callAction`:

```ts
import { createBeeuni } from '@beeuni/sdk';

const connectors = createBeeuni({ backendUrl, getToken }).project(projectId).connectors;
const result = await connectors.callAction('linear', 'list_issues', { team: 'CORE' });
if (result.ok) console.log(result.output?.issues.length);
```

El controlador del conector lee el mismo archivo, y `run` devuelve el resultado tipado o lanza un error tipado (consulta Conectores desde código):

```ts
const issues = await createBeeuni({ backendUrl, getToken })
  .project(projectId)
  .connector('linear')
  .run('list_issues', { team: 'CORE' });
```

`callAction(slug, action, args, options)` envía la misma solicitud que
`call('<slug>.<action>', args, options)` y devuelve el mismo resultado. Solo cambian los tipos: los argumentos que faltan o no se reconocen generan un error de compilación, y
`output` tiene el tipo generado. Una acción que no aparece en el archivo acepta cualquier objeto y devuelve `output: unknown`.

- Los conectores OpenAPI, HTTP, MCP y GraphQL publican un esquema de salida cuando su fuente lo declara. El resultado de GraphQL se tipa como un objeto.
- Los conectores gestionados no publican ningún esquema de salida. Su resultado es `unknown`. La CLI les asigna un nombre después de escribir el archivo.
- Cada entrada de `$defs` se convierte en un tipo con nombre (`BeeuniConnectorDef<n>_<name>`), de modo que un esquema recursivo siga siendo finito. Un esquema que no se pueda compilar (una unión que se contiene a sí misma) o cuyos tipos superen los 256 KB por acción se convierte en `unknown`.
- Vuelve a ejecutar el comando después de añadir un conector o cuando se sincronice una versión nueva.
- El catálogo devuelve esquemas de salida solo si se solicitan:
  `GET /connectors/projects/{projectId}/catalog?include_output_schemas=true`
  añade `outputSchema` a cada acción (`null` si no hay ninguno almacenado).

<a id="when-a-call-is-denied"></a>

### Cuando se deniega una llamada

Una llamada denegada responde `{ ok: false, status: "denied", reason, hint }`. `reason` es un código estable; `hint` indica qué hacer.

| `reason` | HTTP | Significado | También en el cuerpo |
| --- | --- | --- | --- |
| `connector_not_assigned` | 403 | La concesión de `connectors:` del agente en ejecución en `beeuni.yaml` no incluye este conector. | `agent`, `granted` (la lista o `"all"`), `manifest_revision` y `manifest_commit` (el manifiesto del que procede la concesión). |
| `connector_not_connected` | 403 | No hay ninguna cuenta utilizable para esta llamada. El conector no tiene ninguna cuenta para este usuario (no hay credenciales almacenadas o la aplicación nunca se autorizó — `beeuni connectors ls` la muestra como `needs_auth`), o bien `--account` indicó una que no se pudo resolver. | `connect_url` — un enlace alojado para autorizar una cuenta, cuando el usuario puede generarlo — si no hay ninguna cuenta conectada. `requested_account` y `available_accounts` — el nombre que no se pudo resolver y los nombres que sí se resolvieron — cuando `--account` indicó uno. |
| `connector_disabled` | 403 | El conector está declarado, pero desactivado. | — |
| `connector_not_found` | 404 | No hay ningún conector con este slug declarado en el proyecto. | — |
| `action_not_found` | 404 | El conector no tiene esa acción. | — |

`connect_url` es toda la solución para un conector sin conectar: nunca se rechaza una sesión de antemano por ese motivo (consulta [Conceder acceso a un agente](#grant-an-agent-access)), así que la propia denegación incluye la solución. El agente muestra el enlace tal cual; la transcripción web lo presenta como un botón «Conectar» de un solo clic. De forma predeterminada, el enlace autoriza una cuenta privada para la persona que lo abre; conectar una cuenta compartida requiere elegirlo explícitamente (`beeuni connectors connect stripe-read --owner project`, sujeto a `project.connector.write`).

El conector del canal que creó una sesión (Slack, Teams, correo electrónico) siempre se puede usar desde esa sesión, independientemente de lo que indique la concesión del agente, para que este siempre pueda responder en el hilo desde el que se le pidió ayuda.

La concesión de una sesión sigue `beeuni.yaml`: un cambio en `connectors:` del agente en ejecución (incluido `beeuni connectors add --apply`) se aplica en la siguiente llamada. La concesión registra de qué blob del manifiesto y de qué commit procede; una lectura que lo reemplazaría a partir del mismo blob se confirma primero con una segunda lectura, y una lectura de un commit anterior nunca lo reemplaza.

Slack y Microsoft Teams se conectan desde el panel de control igual que las aplicaciones OAuth. Al conectar Slack, se escribe un conector `channel` en `beeuni.yaml` para ti. Consulta [Slack y canales](/docs/es/connect/slack).
