> ## Documentation Index
> Fetch the complete documentation index at: https://docs.twenty.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Conexiones

> Permite que tu aplicación actúe en nombre de un usuario en servicios de terceros mediante OAuth.

Las conexiones son credenciales que un usuario posee para un servicio externo (Linear, GitHub, Slack, ...). Tu aplicación declara **cómo** se obtienen esas credenciales — un **proveedor de conexión** — y las consume en tiempo de ejecución para realizar llamadas autenticadas a la API de terceros.

Actualmente solo se admite OAuth 2.0. Los futuros tipos de credenciales (tokens de acceso personal, claves de API, autenticación básica) se integrarán en la misma interfaz — las aplicaciones que ya usan `defineConnectionProvider({ type: 'oauth', ... })` no necesitarán migrar.

<AccordionGroup>
  <Accordion title="defineConnectionProvider" description="Declara cómo se obtienen las conexiones de tu aplicación">
    Un proveedor de conexión describe el flujo de OAuth que tu aplicación necesita. El usuario hace clic en "Agregar conexión" en la configuración de tu aplicación, completa la pantalla de consentimiento del proveedor y se crea una fila `ConnectedAccount` en su espacio de trabajo.

    Una configuración funcional necesita **dos archivos** — el proveedor de conexión y una declaración `serverVariables` correspondiente en `defineApplication` que contiene las credenciales del cliente OAuth.

    ```ts src/connection-providers/linear-connection.ts theme={null}
    import { defineConnectionProvider } from 'twenty-sdk/define';

    export default defineConnectionProvider({
      universalIdentifier: '9c7d1f5e-6a0b-4d44-be0c-3f8b5a9d4e6f',
      name: 'linear',
      displayName: 'Linear',
      icon: 'IconBrandLinear',
      type: 'oauth',
      oauth: {
        authorizationEndpoint: 'https://linear.app/oauth/authorize',
        tokenEndpoint: 'https://api.linear.app/oauth/token',
        scopes: ['read', 'write'],
        // These must match keys in `defineApplication.serverVariables` below.
        clientIdVariable: 'LINEAR_CLIENT_ID',
        clientSecretVariable: 'LINEAR_CLIENT_SECRET',
        // Optional: defaults to 'json'. Some providers (Linear, Slack) want
        // 'form-urlencoded' for the token request.
        tokenRequestContentType: 'form-urlencoded',
        // Optional: defaults to true. Disable only if the provider rejects PKCE.
        usePkce: false,
        // Optional: extra query params on the authorize URL.
        // authorizationParams: { prompt: 'consent' },
        // Optional: provider's RFC 7009 token revocation endpoint, called on disconnect.
        // revokeEndpoint: 'https://example.com/oauth/revoke',
      },
      // Optional: a logic function in this app to run right after a connection is
      // established. See "Run a logic function on connect".
      // onConnectLogicFunction: { universalIdentifier: '3a2b1c0d-...-...' },
    });
    ```

    ```ts src/application.config.ts theme={null}
    import { defineApplication } from 'twenty-sdk/define';

    export default defineApplication({
      universalIdentifier: '...',
      displayName: 'Linear',
      description: 'Connect Linear to Twenty.',
      // OAuth client credentials live on the app registration (one OAuth app per
      // Twenty server, configured by the admin) — not per-workspace. Declare them
      // as serverVariables so the admin can fill them in once for all installs.
      serverVariables: {
        LINEAR_CLIENT_ID: {
          description: 'OAuth client ID from your Linear OAuth application.',
          isSecret: false,
          isRequired: true,
        },
        LINEAR_CLIENT_SECRET: {
          description: 'OAuth client secret from your Linear OAuth application.',
          isSecret: true,
          isRequired: true,
        },
      },
    });
    ```

    Puntos clave:

    * `name` es la cadena de identificador única utilizada en `listConnections({ providerName })` (kebab-case, debe coincidir con `^[a-z][a-z0-9-]*$`).
    * `displayName` se muestra en la pestaña de configuración por aplicación y en la lista de herramientas de IA.
    * `clientIdVariable` / `clientSecretVariable` son **nombres**, no valores — deben coincidir con las claves declaradas en `defineApplication.serverVariables`. Los `client_id` y `client_secret` reales los introduce el administrador del servidor a través de la interfaz de registro de la aplicación; nunca se incluyen en tu repositorio.
    * Usa `serverVariables` (no `applicationVariables`) — las credenciales de OAuth son a nivel de servidor y hay una aplicación OAuth por servidor de Twenty.
    * Hasta que ambos `serverVariables` estén completos, la pestaña de configuración por aplicación muestra un aviso de "requiere administrador del servidor" y el botón "Agregar conexión" está deshabilitado.
    * `type: 'oauth'` es el único valor admitido actualmente. El discriminador es compatible hacia adelante: tipos futuros (`'pat'`, `'api-key'`, ...) agregarán nuevos bloques de subconfiguración junto a `oauth`.

    La URL de callback de OAuth que tu proveedor debe autorizar es:

    ```
    https://<your-twenty-server>/auth/apps/callback
    ```
  </Accordion>

  <Accordion title="Ejecutar una función de lógica al conectar" description="Reaccionar en el momento en que se establece una conexión">
    Algunos proveedores te entregan datos en el momento de la conexión que necesitas conservar antes de que la conexión sea utilizable: el ejemplo clásico es Slack, donde la respuesta de OAuth identifica el `team_id` del espacio de trabajo con el que se asociarán los eventos entrantes. Establece `onConnectLogicFunction` para que haga referencia a una función de lógica en la misma aplicación (por su `universalIdentifier`), y se ejecutará justo después de que se cree el `ConnectedAccount`.

    ```ts src/connection-providers/slack-connection.ts theme={null}
    export default defineConnectionProvider({
      universalIdentifier: '...',
      name: 'slack',
      displayName: 'Slack',
      type: 'oauth',
      oauth: {
        /* ... */
      },
      // Runs claimSlackTeam after every successful Slack connection.
      onConnectLogicFunction: {
        universalIdentifier: '3a2b1c0d-1111-4222-8333-444455556666',
      },
    });
    ```

    El hook se ejecuta **de forma asíncrona en el espacio de trabajo que se está conectando** (se pone en cola, no se espera su finalización), por lo que un hook lento o con fallos nunca bloquea ni interrumpe el callback de OAuth; hazlo idempotente y haz que gestione sus propios reintentos. El controlador recibe:

    ```ts theme={null}
    type OnConnectPayload = {
      connectionProviderId: string;
      connectionProviderName: string; // e.g. 'slack'
      connectedAccountId: string;
    };
    ```

    A partir de ahí, usa `getConnection(connectedAccountId)` para leer el token de acceso reciente y llamar a la API del proveedor (por ejemplo, Slack `auth.test`) o para conservar un mapeo con el [almacenamiento de pares clave-valor](/l/es/developers/extend/apps/logic/key-value-store).
  </Accordion>

  <Accordion title="listConnections / getConnection" description="Usa conexiones desde una función de lógica">
    Dentro de un controlador de función de lógica, `listConnections({ providerName })` devuelve las filas `ConnectedAccount` de esta aplicación para el proveedor indicado, con tokens de acceso actualizados.

    ```ts src/logic-functions/handlers/create-linear-issue-handler.ts theme={null}
    import { listConnections } from 'twenty-sdk/logic-function';

    export const createLinearIssueHandler = async (input: {
      teamId?: string;
      title?: string;
    }) => {
      if (!input.teamId || !input.title) {
        return { success: false, error: 'teamId and title are required' };
      }

      const connections = await listConnections({ providerName: 'linear' });

      // Workspace-shared credentials win when present; fall back to the first
      // user-visibility one. For HTTP-route triggers you typically pick the
      // request user's connection via event.userWorkspaceId instead.
      const connection =
        connections.find((c) => c.visibility === 'workspace') ?? connections[0];

      if (!connection) {
        return {
          success: false,
          error:
            'Linear is not connected. Open the app settings and click "Add connection".',
        };
      }

      // Use connection.accessToken to call the third-party API.
      const response = await fetch('https://api.linear.app/graphql', {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${connection.accessToken}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          query: `mutation { issueCreate(input: { teamId: "${input.teamId}", title: "${input.title}" }) { success } }`,
        }),
      });

      return { success: response.ok };
    };
    ```

    Cada conexión tiene:

    | Campo             | Descripción                                                                                                                      |
    | ----------------- | -------------------------------------------------------------------------------------------------------------------------------- |
    | `id`              | ID de fila único; pásalo a `getConnection(id)` para volver a obtener una sola conexión                                           |
    | `visibility`      | `'user'` (privada para un miembro del espacio de trabajo) o `'workspace'` (compartida con todos los miembros)                    |
    | `scopes`          | Permisos de OAuth concedidos por el proveedor de origen (distintos de `visibility` — no están relacionados)                      |
    | `userWorkspaceId` | El id de userWorkspace del propietario — útil para elegir "la conexión del usuario de la solicitud" en activadores de rutas HTTP |
    | `accessToken`     | Token de acceso OAuth actualizado (se renueva automáticamente si ha expirado)                                                    |
    | `name` / `handle` | El nombre para mostrar de la conexión (derivado automáticamente en el callback de OAuth, el usuario puede cambiarlo)             |
    | `authFailedAt`    | Se establece cuando la actualización más reciente falló; el usuario debe reconectarse                                            |

    Puntos clave:

    * Pasa `{ providerName }` para filtrar por proveedor; omítelo para obtener todas las conexiones que posee esta aplicación en todos los proveedores.
    * El servidor actualiza de forma transparente el token de acceso antes de devolver la respuesta. Tu controlador siempre ve un token utilizable (o `authFailedAt` establecido).
    * `getConnection(id)` es el equivalente de una sola fila.
  </Accordion>

  <Accordion title="Visibilidad por usuario vs. compartida con el espacio de trabajo" description="Cómo los usuarios eligen entre credenciales privadas y compartidas">
    Cuando un usuario hace clic en "Agregar conexión", se le solicita que elija una visibilidad:

    * **Solo para mí** — la credencial es privada para el usuario que se conecta. Cualquier función de lógica llamada en su nombre (activador de ruta HTTP con `isAuthRequired: true`) la ve; los activadores de cron y los eventos de base de datos no.
    * **Compartida en el espacio de trabajo** — cualquier miembro del espacio de trabajo puede usar la credencial. Los activadores de cron y de base de datos también la ven, ya que no tienen usuario de la solicitud.

    Usa la adecuada para cada controlador:

    ```ts theme={null}
    // HTTP-route trigger — prefer the request user's own connection.
    const conn =
      connections.find((c) => c.userWorkspaceId === event.userWorkspaceId) ??
      connections.find((c) => c.visibility === 'workspace');

    // Cron trigger — no request user; only shared credentials are sensible.
    const conn = connections.find((c) => c.visibility === 'workspace');
    ```

    Se permiten múltiples conexiones por (usuario, proveedor), por lo que el mismo usuario puede tener "Linear personal" y "Linear de trabajo" a la vez.
  </Accordion>

  <Accordion title="Configuración única del proveedor" description="Registra tu aplicación OAuth con el servicio de terceros">
    Para cada proveedor de conexión, el administrador del servidor debe registrar primero una aplicación OAuth en el servicio de terceros.

    1. Ve a la configuración de desarrollador del proveedor (p. ej., [https://linear.app/settings/api/applications/new](https://linear.app/settings/api/applications/new)).
    2. Configura el **URI de redirección** en `\<SERVER_URL>/auth/apps/callback`.
    3. Copia el **Client ID** y el **Client Secret** generados.
    4. Abre la aplicación instalada en Twenty como administrador del servidor → establece los valores en los `serverVariables` correspondientes.
    5. Luego, los miembros del espacio de trabajo pueden agregar conexiones desde la sección **Conexiones** por aplicación.
  </Accordion>
</AccordionGroup>
