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

# Verbindungen

> Ermöglichen Sie Ihrer App, im Namen eines Benutzers über OAuth in Diensten von Drittanbietern zu handeln.

Verbindungen sind Anmeldedaten, die ein Benutzer für einen externen Dienst besitzt (Linear, GitHub, Slack, ...). Ihre App legt fest, **wie** diese Anmeldedaten bezogen werden — ein **Verbindungsanbieter** — und verwendet sie zur Laufzeit, um authentifizierte Aufrufe an die Drittanbieter-API zu tätigen.

Derzeit wird nur OAuth 2.0 unterstützt. Zukünftige Anmeldedatentypen (Personal Access Tokens, API-Schlüssel, Basic Auth) werden in dieselbe Oberfläche integriert — Apps, die bereits `defineConnectionProvider({ type: 'oauth', ... })` müssen nicht migriert werden.

<AccordionGroup>
  <Accordion title="defineConnectionProvider" description="Legen Sie fest, wie die Verbindungen Ihrer App bezogen werden">
    Ein Verbindungsanbieter beschreibt den OAuth-Handshake, den Ihre App benötigt. Der Benutzer klickt in den Einstellungen Ihrer App auf "Verbindung hinzufügen", schließt den Zustimmungsbildschirm des Anbieters ab, und in seinem Arbeitsbereich wird eine `ConnectedAccount`-Zeile erstellt.

    Eine funktionierende Einrichtung benötigt **zwei Dateien** — den Verbindungsanbieter und eine passende `serverVariables`-Deklaration in `defineApplication`, die die OAuth-Client-Anmeldedaten enthält.

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

    Hauptpunkte:

    * `name` ist die eindeutige Bezeichner-Zeichenfolge, die in `listConnections({ providerName })` verwendet wird (kebab-case, muss `^[a-z][a-z0-9-]*$` entsprechen).
    * `displayName` wird im Einstellungs-Tab der jeweiligen App und in der KI-Toolliste angezeigt.
    * `clientIdVariable` / `clientSecretVariable` sind **Namen**, keine Werte — sie müssen den in `defineApplication.serverVariables` deklarierten Schlüsseln entsprechen. Die tatsächlichen `client_id` und `client_secret` werden vom Serveradministrator über die App-Registrierungsoberfläche eingegeben und niemals in Ihr Repository eingecheckt.
    * Verwenden Sie `serverVariables` (nicht `applicationVariables`) — OAuth-Anmeldedaten gelten serverweit und es gibt eine OAuth-App pro Twenty-Server.
    * Solange beide `serverVariables` nicht ausgefüllt sind, zeigt der Einstellungs-Tab pro App den Hinweis "Benötigt Server-Admin" an und der Button "Verbindung hinzufügen" ist deaktiviert.
    * `type: 'oauth'` ist derzeit der einzige unterstützte Wert. Der Diskriminator ist vorwärtskompatibel: zukünftige Typen (`'pat'`, `'api-key'`, ...) werden neue Unterkonfigurationsblöcke neben `oauth` hinzufügen.

    Die OAuth-Callback-URL, die Ihr Anbieter auf die Whitelist setzen muss, lautet:

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

  <Accordion title="Beim Verbindungsaufbau eine Logikfunktion ausführen" description="Reagiere in dem Moment, in dem eine Verbindung hergestellt wird">
    Einige Anbieter liefern dir beim Verbindungsaufbau Daten, die du persistieren musst, bevor die Verbindung nutzbar ist – das klassische Beispiel ist Slack, bei dem die OAuth-Antwort die `team_id` des Workspaces angibt, anhand derer eingehende Ereignisse zugeordnet werden. Setze `onConnectLogicFunction` so, dass auf eine Logikfunktion in derselben App (über ihren `universalIdentifier`) verwiesen wird; sie wird direkt nach dem Erstellen des `ConnectedAccount` ausgeführt.

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

    Der Hook wird **asynchron im verbindenden Workspace** ausgeführt (er wird in eine Warteschlange gestellt, nicht abgewartet), sodass ein langsamer oder fehlerhafter Hook niemals den OAuth-Callback blockiert oder unterbricht – mache ihn idempotent und lass ihn seine eigenen Wiederholungen handhaben. Der Handler erhält:

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

    Verwenden Sie von dort `getConnection(connectedAccountId)`, um das aktuelle Zugriffstoken auszulesen und die API des Anbieters aufzurufen (z. B. Slack `auth.test`) oder eine Zuordnung im [Key-Value Store](/l/de/developers/extend/apps/logic/key-value-store) zu persistieren.
  </Accordion>

  <Accordion title="listConnections / getConnection" description="Verbindungen aus einer Logikfunktion verwenden">
    Innerhalb eines Logikfunktions-Handlers gibt `listConnections({ providerName })` die `ConnectedAccount`-Zeilen dieser App für den angegebenen Anbieter zurück, mit aktualisierten Zugriffstoken.

    ```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 };
    };
    ```

    Jede Verbindung hat:

    | Feld              | Beschreibung                                                                                                                       |
    | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
    | `id`              | Eindeutige Zeilen-ID; an `getConnection(id)` übergeben, um eine einzelne Verbindung erneut abzurufen                               |
    | `visibility`      | `'user'` (privat für ein Mitglied des Arbeitsbereichs) oder `'workspace'` (mit allen Mitgliedern geteilt)                          |
    | `scopes`          | Vom Upstream-Anbieter gewährte OAuth-Berechtigungen (unabhängig von `visibility` — diese sind nicht miteinander verknüpft)         |
    | `userWorkspaceId` | Die userWorkspace-ID des Eigentümers — nützlich, um "die Verbindung des anfragenden Benutzers" in HTTP-Routen-Triggern auszuwählen |
    | `accessToken`     | Frisches OAuth-Zugriffstoken (wird bei Ablauf automatisch erneuert)                                                                |
    | `name` / `handle` | Anzeigename der Verbindung (automatisch beim OAuth-Callback abgeleitet, vom Benutzer umbenennbar)                                  |
    | `authFailedAt`    | Gesetzt, wenn die jüngste Aktualisierung fehlgeschlagen ist; der Benutzer muss die Verbindung erneut herstellen                    |

    Hauptpunkte:

    * Übergeben Sie `{ providerName }`, um nach Anbieter zu filtern; lassen Sie es weg, um alle Verbindungen dieser App über alle Anbieter hinweg zu erhalten.
    * Der Server aktualisiert das Zugriffstoken vor der Rückgabe transparent. Ihr Handler sieht stets ein verwendbares Token (oder `authFailedAt` ist gesetzt).
    * `getConnection(id)` ist das Pendant für eine einzelne Zeile.
  </Accordion>

  <Accordion title="Sichtbarkeit: pro Benutzer vs. im Arbeitsbereich geteilt" description="Wie Benutzer zwischen privaten und geteilten Anmeldedaten wählen">
    Wenn ein Benutzer auf "Verbindung hinzufügen" klickt, wird er aufgefordert, eine Sichtbarkeit auszuwählen:

    * **Nur für mich** — die Anmeldedaten sind für den sich verbindenden Benutzer privat. Jede Logikfunktion, die in seinem/ihrem Auftrag aufgerufen wird (HTTP-Routen-Trigger mit `isAuthRequired: true`), sieht sie; Cron-Trigger und Datenbankereignisse nicht.
    * **Im Arbeitsbereich geteilt** — jedes Arbeitsbereichsmitglied kann die Anmeldedaten verwenden. Cron-/Datenbank-Trigger sehen sie ebenfalls, da sie keinen anfragenden Benutzer haben.

    Verwenden Sie für jeden Handler die richtige Option:

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

    Mehrere Verbindungen pro (Benutzer, Anbieter) sind erlaubt, sodass derselbe Benutzer "Persönliches Linear" und "Arbeits-Linear" nebeneinander haben kann.
  </Accordion>

  <Accordion title="Einmalige Anbietereinrichtung" description="Registrieren Sie Ihre OAuth-App beim Drittanbieterdienst">
    Für jeden Verbindungsanbieter muss der Serveradministrator zunächst eine OAuth-App beim Drittanbieter registrieren.

    1. Gehen Sie zu den Entwickler-Einstellungen des Anbieters (z. B. [https://linear.app/settings/api/applications/new](https://linear.app/settings/api/applications/new)).
    2. Setzen Sie die **Redirect-URI** auf `\<SERVER_URL>/auth/apps/callback`.
    3. Kopieren Sie die generierte **Client ID** und das **Client Secret**.
    4. Öffnen Sie die installierte App in Twenty als Serveradministrator → setzen Sie die Werte in den entsprechenden `serverVariables`.
    5. Mitglieder des Arbeitsbereichs können dann Verbindungen im **Verbindungen**-Abschnitt der jeweiligen App hinzufügen.
  </Accordion>
</AccordionGroup>
