> ## 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.

# Conexões

> Permita que seu aplicativo aja em nome de um usuário em serviços de terceiros via OAuth.

Conexões são credenciais que um usuário mantém para um serviço externo (Linear, GitHub, Slack, ...). Seu app declara **como** essas credenciais são obtidas — um **provedor de conexão** — e as consome em tempo de execução para fazer chamadas autenticadas à API de terceiros.

Atualmente, apenas o OAuth 2.0 tem suporte. Tipos de credenciais futuros (tokens de acesso pessoal, chaves de API, autenticação básica) serão conectados à mesma interface — apps que já usam `defineConnectionProvider({ type: 'oauth', ... })` não precisarão migrar.

<AccordionGroup>
  <Accordion title="defineConnectionProvider" description="Declare como as conexões do seu app são obtidas">
    Um provedor de conexão descreve o handshake OAuth de que seu app precisa. O usuário clica em "Adicionar conexão" nas configurações do seu app, conclui a tela de consentimento do provedor e uma linha `ConnectedAccount` é criada no seu workspace.

    Uma configuração funcional precisa de **dois arquivos** — o provedor de conexão e uma declaração correspondente de `serverVariables` em `defineApplication` que contém as credenciais do 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,
        },
      },
    });
    ```

    Pontos-chave:

    * `name` é a string de identificador exclusivo usada em `listConnections({ providerName })` (kebab-case, deve corresponder a `^[a-z][a-z0-9-]*$`).
    * `displayName` aparece na aba de configurações do app e na lista de ferramentas de IA.
    * `clientIdVariable` / `clientSecretVariable` são **nomes**, não valores — devem corresponder às chaves declaradas em `defineApplication.serverVariables`. Os `client_id` e `client_secret` reais são inseridos pelo administrador do servidor por meio da interface de registro do app e nunca são versionados no seu repositório.
    * Use `serverVariables` (não `applicationVariables`) — as credenciais OAuth são do servidor como um todo e há um app OAuth por servidor do Twenty.
    * Até que ambos os `serverVariables` sejam preenchidos, a aba de configurações do app mostra uma dica "precisa de administrador do servidor" e o botão "Adicionar conexão" fica desativado.
    * `type: 'oauth'` é o único valor compatível atualmente. O discriminador é compatível com versões futuras: tipos futuros (`'pat'`, `'api-key'`, ...) adicionarão novos blocos de subconfiguração ao lado de `oauth`.

    O URL de callback do OAuth que seu provedor precisa adicionar à lista de permissões é:

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

  <Accordion title="Execute uma função lógica ao conectar" description="Reaja no momento em que uma conexão é estabelecida">
    Alguns provedores fornecem dados no momento da conexão que você precisa manter antes que a conexão possa ser usada — o exemplo clássico é o Slack, em que a resposta OAuth identifica o `team_id` do workspace pelo qual os eventos de entrada serão indexados. Defina `onConnectLogicFunction` para fazer referência a uma função lógica no mesmo app (pelo seu `universalIdentifier`), e ela será executada logo após o `ConnectedAccount` ser criado.

    ```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',
      },
    });
    ```

    O hook é executado **de forma assíncrona no workspace que está se conectando** (ele é enfileirado, não aguardado), portanto um hook lento ou com falha nunca bloqueia ou quebra o callback OAuth — torne-o idempotente e faça com que ele mesmo gerencie suas próprias novas tentativas. O manipulador recebe:

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

    A partir daí, use `getConnection(connectedAccountId)` para ler o token de acesso atualizado e chamar a API do provedor (por exemplo, Slack `auth.test`) ou persistir um mapeamento com o [armazenamento de chave-valor](/l/pt/developers/extend/apps/logic/key-value-store).
  </Accordion>

  <Accordion title="listConnections / getConnection" description="Use conexões a partir de uma função de lógica">
    Dentro de um handler de função de lógica, `listConnections({ providerName })` retorna as linhas `ConnectedAccount` deste app para o provedor fornecido, com tokens de acesso atualizados.

    ```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 conexão tem:

    | Campo             | Descrição                                                                                                                  |
    | ----------------- | -------------------------------------------------------------------------------------------------------------------------- |
    | `id`              | ID de linha exclusivo; passe para `getConnection(id)` para buscar novamente um único registro                              |
    | `visibility`      | `'user'` (privada para um membro do workspace) ou `'workspace'` (compartilhada com todos os membros)                       |
    | `scopes`          | Permissões OAuth concedidas pelo provedor de origem (distintas de `visibility` — não têm relação)                          |
    | `userWorkspaceId` | O id de userWorkspace do proprietário — útil para selecionar "a conexão do usuário da requisição" em gatilhos de rota HTTP |
    | `accessToken`     | Token de acesso OAuth recente (atualizado automaticamente se estiver expirado)                                             |
    | `name` / `handle` | O nome de exibição da conexão (derivado automaticamente no callback do OAuth, renomeável pelo usuário)                     |
    | `authFailedAt`    | Definido quando a atualização mais recente falhou; o usuário deve reconectar                                               |

    Pontos-chave:

    * Passe `{ providerName }` para filtrar por provedor; omita para obter todas as conexões que este app possui em todos os provedores.
    * O servidor atualiza transparentemente o token de acesso antes de retornar. Seu handler sempre vê um token utilizável (ou `authFailedAt` definido).
    * `getConnection(id)` é o equivalente de uma única linha.
  </Accordion>

  <Accordion title="Visibilidade por usuário vs. compartilhada no workspace" description="Como os usuários escolhem entre credenciais privadas e compartilhadas">
    Quando um usuário clica em "Adicionar conexão", é solicitado que escolha uma visibilidade:

    * **Apenas para mim** — a credencial é privada para o usuário que a conectou. Qualquer função de lógica chamada em seu nome (gatilho de rota HTTP com `isAuthRequired: true`) a vê; gatilhos cron e eventos de banco de dados não.
    * **Compartilhada no workspace** — qualquer membro do workspace pode usar a credencial. Gatilhos de cron / banco de dados também a veem, pois não há um usuário da requisição.

    Use a adequada para cada handler:

    ```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');
    ```

    Várias conexões por (usuário, provedor) são permitidas, então o mesmo usuário pode manter "Linear pessoal" e "Linear de trabalho" lado a lado.
  </Accordion>

  <Accordion title="Configuração única do provedor" description="Registre seu app OAuth no serviço de terceiros">
    Para cada provedor de conexão, o administrador do servidor precisa primeiro registrar um app OAuth no serviço de terceiros.

    1. Acesse as configurações de desenvolvedor do provedor (por exemplo, [https://linear.app/settings/api/applications/new](https://linear.app/settings/api/applications/new)).
    2. Defina a **URI de redirecionamento** como `\<SERVER_URL>/auth/apps/callback`.
    3. Copie o **ID do cliente** e o **Segredo do cliente** gerados.
    4. Abra o app instalado no Twenty como administrador do servidor → defina os valores nos `serverVariables` correspondentes.
    5. Os membros do workspace podem então adicionar conexões na seção **Conexões** de cada app.
  </Accordion>
</AccordionGroup>
