# Connettori

Come i connettori e le connessioni forniscono agli agenti un accesso limitato agli strumenti esterni.

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

Un connettore collega un progetto a uno strumento o servizio esterno. L'agente
lo usa come strumento. Beeuni gestisce ogni chiamata, così le credenziali del
connettore non entrano mai nella sandbox.

La maggior parte dei connettori si dichiara in `beeuni.yaml`. Consulta il
[riferimento del manifest](/docs/it/project/manifest) per tutti i campi. Beeuni dichiara
i connettori di canale e computer quando colleghi una piattaforma di chat o un
computer.

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

## Sfogliare e aggiungere un connettore

Apri **Connectors** per sfogliare il catalogo gestito. L'elenco predefinito
contiene toolkit di provider gestiti collegabili con l'autenticazione gestita
 dal provider o una configurazione di autenticazione personalizzata abilitata.
Non è necessaria una connessione esistente nel progetto. Un toolkit che richiede
una configurazione OAuth personalizzata non verificata resta nascosto finché non
è possibile verificarla.

Per le origini dirette, abilita **Connectors API Discover** nei flag delle
funzionalità del progetto, quindi seleziona **API / MCP** nella stessa pagina.
L'abilitazione del flag non sostituisce il catalogo gestito predefinito. Il
catalogo diretto raggruppa le superfici API pubblicate di OpenAPI, MCP, GraphQL,
Postman e altre. Seleziona una scheda, scegli una superficie pubblicata e
compila il modulo di connessione. Le superfici con sola documentazione aprono la
documentazione del provider; non vengono presentate come modelli pronti per la
connessione. Usa **Add → Manual** per un'API grezza o uno schema non presente nel
catalogo. L'individuazione diretta funziona anche senza un provider gestito
configurato.

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

## Connettori, connessioni e account

Un connettore è il pacchetto di accesso destinato all'agente: una capacità
dichiarata (quali azioni, come raggiungere il servizio). Non è un ruolo e non
garantisce permessi Beeuni: un agente raggiunge un connettore solo se il suo
manifest include lo slug tra le autorizzazioni e il verdetto del ruolo consente
la chiamata. Consulta [Un vocabolario, due associazioni](/docs/it/accounts#one-vocabulary-two-bindings). Un
connettore contiene:

- uno slug univoco nel progetto
- un nome visualizzato
- un'app del provider
- criteri del connettore

Una connessione è un **account** — una singola identità autorizzata — per il
connettore: una credenziale, un'autorizzazione OAuth o una chiave API. Un
connettore può avere più account affiancati. Ogni account usa i criteri del
connettore. Il `owner_type` di ciascun account determina chi può eseguire una
chiamata con quell'account:

- `project` — un account **condiviso**. Accessibile a chiunque abbia accesso al
  connettore, persone o account di servizio (agenti, trigger).
- `member` — un account **privato**, di proprietà di un membro del progetto
  (`owner_id`). Accessibile solo a quel membro e solo in una sessione
  **privata**. Un account di servizio (un agente o un trigger che agisce senza
  supervisione) non può mai usare l'account privato di un membro.

Più connettori possono fare riferimento alla stessa app del provider. Usa
connettori separati se un'app richiede criteri diversi.

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

### Aggiungere un account

Apri il connettore in **Customize → Connectors**. La scheda **Accounts** elenca
in un unico elenco tutti gli account che puoi usare o gestire. Ogni scheda indica
chi può usare l'account: **Only you**, **Everyone in project** oppure i gruppi e
le persone con cui è condiviso.

Seleziona **Add account**, assegna un nome all'account e scegli **Who can use
it**:

- **Only you** — un account privato. Qualsiasi membro può aggiungerne uno.
- **Everyone in the project** — un account condiviso.
- **Specific people or groups** — un account condiviso, limitato alle persone,
  ai gruppi e agli agenti selezionati.

Le due opzioni di condivisione richiedono `project.connector.connections.manage`. Per **Specific people or
groups**, Beeuni scrive le autorizzazioni prima che tu autorizzi l'account, così
l'account non contiene mai credenziali mentre è accessibile all'intero progetto.
Il nome dell'account deve essere nuovo: viene rifiutato se un account dello
stesso proprietario usa già quel nome.

Quando un agente ha bisogno di un account, pubblica nella chat una scheda
**Connect**. La scheda apre la stessa finestra di dialogo, con il nome suggerito
dall'agente già inserito e il pubblico richiesto preselezionato. Beeuni crea un
nuovo account, non autorizza di nuovo uno esistente e comunica all'agente il
nome del nuovo account, così può eseguire chiamate con quell'account.

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

### Scegliere chi può usare un account condiviso

Un account condiviso è utilizzabile da tutti i membri del progetto finché non
ne limiti l'accesso. Seleziona **Share** sulla scheda dell'account. La finestra
di dialogo è la stessa **Grant access** usata per gli agenti. Mostra chi può
usare l'account al momento e consente di aggiungere:

- **Everyone in the project** — l'impostazione predefinita.
- **Groups** — tutti i membri di ciascun gruppo.
- **People** — un membro per volta. Seleziona solo te per riservare l'account a
  te stesso.
- **Agents** — tutte le sessioni dell'agente, inclusi trigger e sessioni
  condivise. Chiunque possa eseguire l'agente può usare l'account tramite esso.

Le modifiche hanno effetto solo quando selezioni **Save**. Rimuovendo l'ultimo
gruppo o l'ultima persona, l'account torna a essere utilizzabile da tutti; la
finestra di dialogo indica il risultato prima del salvataggio.

Un account con accesso limitato segue le regole degli account privati, ma al
posto del proprietario si applica il pubblico autorizzato:

- Una persona inclusa nel pubblico può usarlo, solo in una sessione privata.
- Un agente incluso nel pubblico può usarlo in tutte le sue sessioni.
- Nessun altro agente, né alcun trigger di altri agenti, può usarlo.
- Una sessione associata all'account non può essere condivisa, a meno che
  l'account non sia condiviso con l'agente specifico della sessione.
- Solo una persona può modificare chi può usare un account. Una sessione agente
  riceve `403`.

Una persona che non fa parte del pubblico non vede l'account. Chi gestisce le
connessioni del progetto continua a vederlo, contrassegnato come **Not shared
with you**, e può quindi modificare chi può usarlo.

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

### Condividere il proprio account privato

Anche il proprio account **Only you** ha un pulsante **Share**. Condividerlo lo
trasforma in un account condiviso con le persone e i gruppi selezionati (resti
incluso, a meno che non ti rimuova), oppure con tutti i membri del progetto. Da
quel momento è un account condiviso: anche chi gestisce le connessioni del
progetto può gestirlo.

- La condivisione richiede `project.connector.connections.manage`, lo stesso permesso necessario per
  aggiungere un account condiviso. Senza, il pulsante è disabilitato e ne
  spiega il motivo.
- Beeuni scrive prima le autorizzazioni e trasforma l'account in condiviso con
  un unico aggiornamento, così non è mai accessibile a tutto il progetto nel
  frattempo.
- Un account condiviso con lo stesso nome nel connettore impedisce la
  condivisione (`409`): rinomina prima uno dei due.

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

Un elenco `principals` vuoto lo condivide con tutti. Dalla CLI:
`beeuni connectors connections share <connection-id> --group <group-id>`
(anche `--user <email|id>`, ripetibile, o `--everyone`).

Ogni voce del pubblico è un'assegnazione di oggetto `connection` nell'archivio
 delle autorizzazioni:

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

Dalla CLI, le stesse operazioni di scrittura sono:

```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` è `user`, `group` o `project` (tutti i membri del progetto;
  `principal_id` è l'ID del progetto).
- Per concedere o revocare un'autorizzazione serve `project.connector.connections.manage`.
- Solo un account condiviso può essere limitato tramite queste autorizzazioni.
  Un account privato o un ID che non corrisponde a una connessione del progetto
  restituisce `404`; per condividere il proprio account privato, usa invece
  la route `share` descritta sopra.
- `GET /projects/{projectId}/connections` restituisce le autorizzazioni di ogni account condiviso in
  `shared_with`; `usable: false` su un account che il chiamante vede solo per gestirlo.
  Il selettore di sessione mostra solo gli account utilizzabili.

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

### Con quale identità agisce un account

L'`label` di un account è un nome scelto prima dell'autorizzazione. Non indica quale accesso è stato usato. Lo indica `connected_as`: l'e-mail, il nome utente o il nome visualizzato che il provider comunica per l'account autorizzato.

- Beeuni lo legge quando si completa un'autorizzazione gestita: prima il nome visualizzato dell'account connesso, poi lo strumento «chi sono» 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 e Google Sheets non espongono questo strumento, quindi il loro `connected_as` resta `null`.
- Se un account ha ancora un'etichetta predefinita (`Private connection`, `Project connection` o il nome del connettore), l'etichetta viene sostituita con questa identità. Un'etichetta scelta da una persona non viene mai sostituita.
- La pagina di connessione mostra «Connesso come …» appena l'account viene caricato, così è subito visibile se un account condiviso è stato autorizzato con un accesso personale.
- `connected_as` è presente su ogni connessione (`GET /projects/{projectId}/connections`), nell'elenco degli account, in `beeuni connectors accounts <slug>` e `beeuni connectors connections ls` (la colonna `CONNECTED AS`) e sulle righe degli account in **Personalizza → Connettori**.

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

### Rinominare un account

Rinomina un account senza autorizzarlo di nuovo:

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

Nella dashboard, apri il connettore, poi seleziona **⋯ → Rinomina** sulla riga dell'account. Cambia solo l'etichetta. L'account autorizzato, il proprietario, l'indicatore di predefinito e lo stato del provider restano invariati. Si applica la stessa condizione prevista per la disconnessione: il tuo account privato oppure `project.connector.connections.manage` per un account condiviso.

La ridenominazione viene rifiutata con `400` per `me`, `project` o un'etichetta nel formato UUID, perché `--account` li risolve prima delle etichette. Viene rifiutata con `409` se un altro account dello stesso proprietario ha già quell'etichetta, senza distinzione tra maiuscole e minuscole.

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

### Collegare un account diverso

Un link di connessione per uno slot che contiene già un account attivo non lo autorizza di nuovo. Il provider riutilizza l'account e la pagina di connessione mostra **Già connesso**. Per usare un accesso diverso, aggiungi un nuovo account al connettore, impostalo come predefinito, poi disconnetti quello vecchio.

Una chiamata che non specifica un account usa prima l'account privato predefinito del chiamante, poi l'account condiviso predefinito del progetto. Ogni risultato della chiamata indica con quale account è stata eseguita (`account: { connection_id, label,
owner_type }`), così la trascrizione mostra sempre l'identità usata dalla chiamata allo strumento. Elenca gli account con cui è possibile chiamare un connettore, con il predefinito per primo, usando `GET /connectors/projects/{projectId}/connectors/{slug}/accounts`.

> **Warning**
> `authorization_strategy` (`project` | `user`) era una MODALITÀ a livello di connettore che rendeva mutuamente esclusivi gli account di proprietà del progetto e quelli di proprietà dei membri: un connettore con strategia `user` non poteva offrire account condivisi, quindi non disponeva di un flusso di connessione utilizzabile da un account di servizio. È deprecata: il manifest e `PUT .../authorization-strategy` la accettano ancora e rispondono senza errori, ma non viene più letta. Ora la regola di accesso è interamente definita da `owner_type` su ogni connessione.

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

## Provider

Un connettore usa un tipo di provider:

- **composio** — OAuth gestito per le app SaaS supportate
- **pipedream** — OAuth gestito legacy, mantenuto solo per il rollback
- **openapi**, **postman**, **graphql**, **http** — connettori API diretti
- **mcp** — un server MCP remoto tramite HTTP o SSE
- **channel** — connessione a una piattaforma di chat
- **computer** — il computer collegato di ogni membro costituisce un account

Consulta [Slack e canali](/docs/it/connect/slack) e [Computer](/docs/it/connect/computers) per i flussi gestiti dai provider.

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

### Disponibilità delle app

Il catalogo dei connettori mostra le app attualmente disponibili per la connessione. Alcune richiedono una configurazione aggiuntiva dell’autenticazione e potrebbero apparire solo dopo il suo completamento.

## Autenticazione e policy

Una connessione viene autenticata tramite:

- OAuth gestito, un'installazione di un canale o una concessione OAuth2 nativa
- una chiave API o un token inseriti tramite la dashboard

Beeuni crittografa i dati della connessione e risolve le credenziali lato server per ogni chiamata allo strumento. L'agente richiede un'azione. Beeuni aggiunge le credenziali, verifica i permessi dell'agente e la policy del connettore e della connessione, chiama l'API esterna e restituisce il risultato.

Le policy dei connettori appartengono al connettore. Una connessione non può sostituirle. Le misure di sicurezza del progetto si applicano al di sopra delle policy del connettore e della connessione.

Per impostazione predefinita, un'azione del connettore non corrispondente a una regola viene eseguita senza approvazione. Imposta `policy.default_mode: risk` per richiedere l'approvazione delle azioni di scrittura e distruttive che non corrispondono a una regola. Imposta `sensitive: true` per rendere `require_approval` l'impostazione predefinita del connettore per le azioni non corrispondenti, incluse le letture. Le regole esplicite del progetto o del connettore e della connessione hanno comunque la precedenza.

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

### Approvare una singola chiamata regolamentata

`require_approval` crea una decisione per una singola chiamata al connettore. Il connettore restituisce `202 pending_approval` con `approval_url`, `approval_summary` e `execution_id`. Non mantiene aperta una richiesta HTTP.

Condividi `approval_url` con qualsiasi collega. L'URL identifica la richiesta, ma non conferisce autorizzazioni. Per accedere alla pagina è necessario aver effettuato l'accesso a Beeuni. Beeuni verifica poi che l'account possa accedere al progetto e approvare le azioni.

La pagina di approvazione mostra i parametri oscurati che il connettore riceverà. Il chiamante può aggiungere `approval_context` (CLI: `--reason`) per descrivere l'effetto. Usalo quando i parametri sono solo riferimenti: `gmail.send_draft` accetta l'ID di una bozza, quindi l'agente specifica il destinatario, l'oggetto e il testo. La pagina mostra questo testo come descrizione dell'agente, non come informazione verificata. I parametri restano la prova. Beeuni non invia mai `approval_context` al provider.

Approva o rifiuta la chiamata una sola volta. Aggiungi un messaggio facoltativo alla decisione. Il messaggio viene restituito all'agente insieme alla decisione, così puoi indicare cosa fare invece in caso di rifiuto.

Ogni chiamata in attesa compare anche in **Revisione → Richiede il tuo intervento** per il progetto. Apri **Revisione** dalla barra laterale: il conteggio indica quanti elementi sono in attesa. La chiamata si apre nella stessa vista di approvazione del relativo link, così puoi esaminare il connettore, i parametri e la descrizione dell'agente prima di decidere.

Quando la chiamata proviene da una sessione Slack o Teams, Beeuni pubblica una
scheda di approvazione in quel thread. La scheda mostra la descrizione
dell'agente, i parametri e **Approve** / **Deny**. In Slack, **Reply…** apre un
campo per inviare un messaggio all'agente; in Teams, la scheda contiene il campo
per il messaggio. Solo un project manager o la persona che ha avviato la
sessione può decidere. Una decisione presa in qualsiasi punto (il thread,
Beeuni o la pagina di approvazione) sostituisce i pulsanti della scheda con
l'esito e l'agente continua nello stesso thread. Beeuni invia la decisione alla
sessione tramite un callback persistente. Un'approvazione si applica solo
all'hash esatto della richiesta. Un destinatario, oggetto, corpo, canale, URL o
altro parametro modificato richiede una nuova decisione.

Apri il pannello **Audit** della sessione per usare la stessa vista dei
parametri. Le voci storiche rimangono di sola lettura. Non esiste un'opzione di
approvazione a livello di sessione. Usa una policy esplicita `always_run` solo
quando un'azione del connettore deve essere eseguita senza supervisione.

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

## Connettersi con OAuth

### Apri la pagina Connettori del progetto
Apri il progetto. Seleziona **Connectors**, quindi seleziona l'app.

### Seleziona l'ambito dell'account
Seleziona **Project** per un account condiviso, accessibile da chiunque abbia
ricevuto l'autorizzazione al connettore. Seleziona **User** per un account
privato, di tua proprietà e accessibile solo da te, esclusivamente in una
sessione privata.

### Completa l'autorizzazione
Completa il flusso OAuth. Beeuni memorizza l'account connesso come connessione.

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

## Connettere un server MCP che usa OAuth 2.1

Beeuni implementa la specifica di autorizzazione MCP. Apri il connettore,
seleziona **Add credential**, quindi seleziona la scheda **OAuth 2.0**. Beeuni
contatta il server e legge i relativi metadati:

1. La richiesta non autenticata restituisce `401` con
   `WWW-Authenticate: Bearer resource_metadata="…"`.
2. Beeuni legge i metadati della risorsa protetta (RFC 9728) a quell'URL o a
   `/.well-known/oauth-protected-resource`.
3. Beeuni legge i metadati del server di autorizzazione (RFC 8414 o discovery
   OpenID Connect) per il primo server di autorizzazione indicato dalla risorsa.

Quando il server pubblicizza `registration_endpoint`, Beeuni si registra come
client OAuth (RFC 7591) e mostra un solo pulsante: **Connect &lt;server&gt;**. Non
devi creare alcuna applicazione né copiare alcun ID client o segreto. Beeuni
esegue quindi Authorization Code con PKCE (S256) e associa il token al server
con il parametro `resource` (RFC 8707).

Registra questo URI di reindirizzamento quando un server ne richiede uno in
anticipo:

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

Quando il server pubblica gli endpoint ma non `registration_endpoint`, Beeuni
precompila l'URL di autorizzazione, l'URL del token e gli ambiti. Inserisci l'ID
client di un'app che hai creato con quel provider. Quando il server non pubblica
metadati, inserisci ogni campo.

Beeuni mantiene la sessione MCP: esegue `initialize` e
`notifications/initialized` su richiesta, quindi invia `Mcp-Session-Id` nelle chiamate
successive. Un server che risponde senza una sessione non vede l'handshake.

Beeuni associa ogni connessione al server di autorizzazione che l'ha emessa.
Quando il callback contiene un parametro `iss` (RFC 9207), Beeuni lo
rifiuta a meno che non corrisponda all'emittente registrato: un codice creato da
un server diverso viene rifiutato prima di essere riscattato.

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

### Autorizzare dalla CLI

La dashboard è un modo per eseguire questo flusso, non l'unico. Dichiara il
connettore in `beeuni.yaml`, quindi autorizzalo da un terminale o da una
sessione dell'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
```

Il comando crea la connessione, esegue la catena di discovery, registra Beeuni
come client quando il server supporta RFC 7591 e restituisce l'URL da approvare:

```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 restituisce `authorization_url` alla persona con cui sta lavorando. Dopo
l'approvazione, l'agente conferma:

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

Il comando termina con un codice diverso da zero mentre lo stato è `error`.
Usa `--scope` per restringere ciò che viene richiesto. Usa `--client-id` e
`--client-secret` per un server che non supporta la registrazione dinamica del client.

Beeuni recupera nuovamente il catalogo degli strumenti del connettore non appena
l'autorizzazione viene completata, così il connettore esce dallo stato
`error` senza una sincronizzazione manuale.

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

## Connettere un'API diretta con OAuth2

I connettori diretti supportano:

- credenziali client
- authorization code con PKCE
- autorizzazione del dispositivo
- registrazione dinamica del client (RFC 7591)

Per le credenziali client, inserisci l'URL del token, l'ID client, gli ambiti e
il segreto client. Puoi usare l'autenticazione dell'endpoint del token
`client_secret_basic`, `client_secret_post`, `client_secret_jwt` o `private_key_jwt`.

Per l'authorization code, inserisci l'URL di autorizzazione e l'URL del token.
Per l'autorizzazione del dispositivo, inserisci l'URL di autorizzazione del
dispositivo e l'URL del token. Un URL di discovery RFC 8414 può fornire questi
endpoint.

Beeuni cifra la configurazione OAuth2 e i token. Aggiorna i token di accesso
prima della scadenza e memorizza ogni token di aggiornamento ruotato. La
revoca della connessione blocca la chiamata successiva al connettore.

Per Microsoft Graph, usa:

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

Per le chiamate REST dirette a SharePoint, usa l'ambito della risorsa
SharePoint:

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

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

## Connettersi con una chiave API

### Dichiara il connettore
```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
```

Il manifest accetta ancora una chiave `authorization_strategy` per compatibilità
all'indietro. Beeuni la ignora: quando aggiungi la relativa credenziale,
imposta invece il proprietario (condiviso o privato) per ogni connessione.

### Unisci la richiesta di modifica
Beeuni legge il manifest dal branch predefinito. Il connettore diventa attivo
dopo l'unione della richiesta di modifica.

### Aggiungi la connessione
Apri il connettore e imposta la relativa credenziale. Beeuni memorizza il
valore crittografato. Non scrive il valore nel manifest.

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

## Concedere l'accesso a un agente

Aggiungi lo slug del connettore al campo `connectors` dell'agente:

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

Ometti `connectors` e l'agente riceverà `none`. Unisci la modifica prima che
abbia effetto.

`connectors_required` è deprecato. Il manifest lo accetta ancora, ma nessuno lo legge: una
sessione non viene mai rifiutata al momento della creazione per un connettore
privo di un account utilizzabile. In pratica, un rifiuto alla creazione della
sessione per un connettore mancante non era attuabile: un connettore solo
privato non aveva alcun account condiviso da offrire, quindi il rifiuto non
aveva un rimedio che il chiamante potesse applicare. Ora il controllo avviene
sulla **chiamata** del connettore: un agente a cui è stato concesso `stripe-read` può
iniziare immediatamente il proprio turno e viene negata solo una chiamata che
richiede effettivamente il connettore (vedi [Quando una chiamata viene negata](#when-a-call-is-denied)), con un rimedio allegato.

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

## Selezionare un account

Esistono due modi indipendenti per scegliere con quale account eseguire una
chiamata: fissarne uno per l'intera sessione oppure indicarne uno in una singola
chiamata.

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

### Fissare un valore predefinito per l'intera sessione

Una sessione può sostituire l'account predefinito del connettore per ogni
chiamata che esegue:

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

La chiave di associazione è lo slug del connettore. Il valore è un account
(connessione) che il chiamante di questa sessione ha il diritto di raggiungere.

Usa `GET /projects/{projectId}/sessions/{sessionId}/scope` per leggere l'associazione effettiva. Usa `PUT` sullo stesso
percorso per sostituirla. La sostituzione si applica alla chiamata dello
strumento successiva senza riavviare la sessione.

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

### Indicare un account in una singola chiamata

Elenca gli account con cui è possibile chiamare un connettore, prima quello
predefinito, con:

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

Quindi specifica un account nella chiamata, tramite ID connessione o etichetta (senza distinzione tra maiuscole e minuscole), oppure
con le due parole selettore `me` (il tuo account privato predefinito) e
`project` (l'account condiviso predefinito del progetto):

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

Se una chiamata non specifica un account, viene prima usato l'account privato predefinito di chi la effettua, poi l'account condiviso predefinito del progetto: il comportamento non cambia rispetto a prima che un connettore potesse contenere più account. Se un account specificato non viene trovato, la chiamata viene **negata** e non viene mai reindirizzata silenziosamente a un account diverso (vedi [Quando una chiamata viene negata](#when-a-call-is-denied)). Ogni chiamata riuscita indica l'account utilizzato: `account: { connection_id, label,
owner_type }`.

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

## Usare un connettore in una sessione

All'interno di una sessione, usa la CLI Connector:

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

`connectors` elenca i connettori disponibili. `accounts` elenca gli account che chi effettua la chiamata può usare `stripe-read`, prima quello predefinito, poi gli account condivisi e quelli privati all'interno di ciascun gruppo. `call` esegue un'azione con l'account `--account` specificato oppure, se omesso, usa la stessa risoluzione predefinita disponibile prima che un connettore potesse contenere più account.

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

### Risultati di grandi dimensioni

Una chiamata di elenco o ricerca può restituire più dati di quanti un modello riesca a leggere: l'output dello strumento oltre ~50 KB viene troncato. Salva il risultato in un file ed elaboralo con il codice:

```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` scrive l'intero risultato JSON, creando le directory genitore. Stdout riceve l'involucro della chiamata senza `data`, oltre a `saved_to`, `bytes` e `shape`: la struttura di `data` (chiavi, lunghezze degli array e ogni `pageInfo`). Il codice di uscita non cambia.

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

### Allegare file

Una chiamata non include mai i byte dei file nei suoi argomenti. Prepara il file, poi inserisci il suo riferimento negli argomenti. Il gateway legge i byte lato server e li inserisce nella richiesta.

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

`--attach` prepara il file e aggiunge un riferimento all'array degli allegati dell'azione. L'array è indicato nello schema di input dell'azione: `attachments` per il canale Email, `body.message.attachments` per Microsoft Graph `sendMail`. Se lo schema è insolito, specifica il nome con `--attach-path body.message.attachments`.
Gli argomenti JSON di grandi dimensioni vanno inseriti in un file (`@mail.json`) o forniti tramite stdin (`-`).

Per posizionare un file autonomamente, preparalo prima:

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

Inserisci `ref` in un punto qualsiasi degli argomenti. Il gateway lo sostituisce in base alla posizione:

| Posizione di `ref` | Sostituito con |
| --- | --- |
| Un elemento di un array degli allegati i cui elementi sono oggetti | L'elemento allegato del provider. La forma è determinata dallo schema dell'elemento: Microsoft Graph `fileAttachment` (`name` + `contentBytes` o `@odata.type`), Postmark (`Name` + `Content`), Mailjet (`Filename` + `Base64Content`), SendGrid e Resend (`filename` + `content`), Brevo (`name` + `content`). Qualsiasi altra forma dell'elemento viene rifiutata con `attachment_item_shape_unknown`. |
| Un campo stringa, ad es. `contentBytes` o un `content` di un file GitHub | Il contenuto del file in base64. |
| `attachments[]` del canale Email | Un URL di download firmato per il provider Email. |

Regole:

- I file devono provenire da `/workspace/output`, `/workspace/artifacts`,
  `/workspace/reports` o `/workspace/deliverables`. I collegamenti simbolici e fisici vengono rifiutati. Copia prima il file in una di queste posizioni.
- Una chiamata può contenere fino a 20 file e 25 MiB in totale. L'API a monte può imporre un limite inferiore: Microsoft Graph documenta 3 MB come dimensione massima di un file allegabile in una richiesta `sendMail`.
- Un file preparato è privato della sessione che lo ha preparato, può essere usato una sola volta ed è eliminato dopo 24 ore. Una chiamata non riuscita lo rende nuovamente disponibile per un nuovo tentativo.
- Il record di audit, l'anteprima di approvazione e il modello vedono solo il riferimento, mai i byte. Se un errore a monte restituisce il file, i dati base64 vengono rimossi.
- I connettori gestiti non accettano file preparati (`connector_attachments_unsupported`).

Il server MCP offre lo stesso flusso: `call` accetta `attachment_files` (e un `attachment_path` facoltativo), mentre `upload_attachment` restituisce un `ref`. L'equivalente nell'SDK è `connectors.uploadAttachment(bytes, { filename, contentType,
connector })`, which returns `ref`.

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

### Risultati delle chiamate

`POST /connectors/projects/{projectId}/call` restituisce un singolo oggetto JSON. Questi campi sono uguali per ogni binding (OpenAPI, HTTP, MCP, GraphQL, `composio`,
`pipedream`, computer):

| Campo | Con | Valore |
| --- | --- | --- |
| `data` | 200 | La risposta grezza a monte, invariata. |
| `output` | 200 | Il payload senza l'involucro del binding: `composio` `data.result`, MCP `result.structuredContent ?? result.content`, GraphQL `data.data`. È assente quando coincide con `data` (chiamate OpenAPI, HTTP, Postman, channel, `pipedream` e computer), così il corpo contiene il payload una sola volta: leggi `output ?? data`. L'SDK lo compila. |
| `binding` | 200, 500, 429, 503 | Il binding che ha eseguito la chiamata: `openapi`, `http`, `mcp`, `graphql`, `composio`, `pipedream`, `pipedream_proxy`, `postman`, `tunnel`. `null` in caso di errore prima che l'azione venga risolta. |
| `upstream_status` | 200, 500, 429, 503 | Lo stato HTTP a monte. `null` quando nessun servizio a monte ha risposto (timeout, richiesta rifiutata, computer). `composio` e `pipedream` segnalano gli errori del provider all'interno di una risposta 200, quindi Beeuni imposta `502` in questi casi (`400` per una query Linear rifiutata, `429` per un limite di frequenza). |
| `upstream_error` | 200 | Presente quando il servizio a monte ha segnalato un errore all'interno di una risposta 2xx: un risultato di uno strumento MCP con `isError: true` o un errore JSON-RPC, oppure `errors` di GraphQL senza dati. La chiamata conta comunque come eseguita: `ok` resta `true`. |
| `retry_after_seconds` | 429, 503 | Il valore `Retry-After` del servizio a monte, in secondi, se presente. La risposta include anche l'intestazione `Retry-After`. |

Lo stato HTTP di una chiamata non riuscita:

- Un `429` a monte restituisce `429`. Un `503` a monte restituisce `503`. Attendi `retry_after_seconds` (o rallenta le richieste) e riprova.
- Gli altri errori a monte restituiscono `500` con la causa in `reason`.

- Una risposta a monte superiore a 64 MiB restituisce `500` con `reason: "upstream_response_too_large: …"`. Beeuni smette di leggere al raggiungimento del limite. Richiedi una pagina più piccola o applica un filtro.
- Se un servizio a monte non risponde entro la scadenza, viene restituito `500` con `reason: "upstream_timeout: …"`. La scadenza è di 60 secondi per impostazione predefinita. Imposta un timeout client superiore, così il gateway risponderà sempre per primo.

Una chiamata a un connettore non è idempotente. Beeuni non elimina le chiamate duplicate. Dopo `upstream_timeout` o un'interruzione lato client, la chiamata potrebbe essere stata eseguita a monte: prima di ripetere un'operazione di scrittura (come inviare un'email o creare un record), controllane l'effetto.

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

### Chiamate tipizzate dal codice

`beeuni connectors types` genera un file di dichiarazione TypeScript per ogni azione che puoi chiamare. Il tipo degli argomenti di ogni azione deriva dallo schema di input e il tipo del risultato dallo schema di output. Il tipo del risultato descrive il campo `output` della chiamata.

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

Includi il file nel tuo `tsconfig.json`. Poi effettua la chiamata tramite `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);
```

L'handle del connettore legge lo stesso file e `run` restituisce direttamente l'output tipizzato oppure genera un errore tipizzato (vedi Connettori dal codice):

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

`callAction(slug, action, args, options)` invia la stessa richiesta di
`call('<slug>.<action>', args, options)` e restituisce lo stesso risultato. Cambiano solo i tipi: un argomento mancante o sconosciuto causa un errore di compilazione e `output` ha il tipo generato. Un'azione che non è inclusa nel file accetta qualsiasi oggetto e restituisce `output: unknown`.

- I connettori OpenAPI, HTTP, MCP e GraphQL pubblicano uno schema di output quando la sorgente ne dichiara uno. Un risultato GraphQL è tipizzato come oggetto.
- I connettori gestiti non pubblicano schemi di output. Il loro risultato è `unknown`. La CLI li nomina dopo aver scritto il file.
- Ogni voce `$defs` diventa un tipo con nome (`BeeuniConnectorDef<n>_<name>`), così uno schema ricorsivo rimane finito. Uno schema che non può essere compilato (un'unione che contiene sé stessa) o i cui tipi superano i 256 KB per una singola azione diventa `unknown`.
- Esegui di nuovo il comando dopo aver aggiunto un connettore o quando ne viene sincronizzata una nuova versione.
- Il catalogo restituisce gli schemi di output solo su richiesta:
  `GET /connectors/projects/{projectId}/catalog?include_output_schemas=true`
  aggiunge `outputSchema` a ogni azione (`null` quando non è memorizzato alcuno schema).

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

### Quando una chiamata viene negata

Una chiamata negata restituisce `{ ok: false, status: "denied", reason, hint }`. `reason` è un codice stabile; `hint` indica cosa fare.

| `reason` | HTTP | Significato | Presente anche nel corpo |
| --- | --- | --- | --- |
| `connector_not_assigned` | 403 | La concessione `connectors:` dell'agente in esecuzione in `beeuni.yaml` non include questo connettore. | `agent`, `granted` (l'elenco o `"all"`), `manifest_revision` e `manifest_commit` (il manifest da cui proviene la concessione). |
| `connector_not_connected` | 403 | Nessun account utilizzabile per questa chiamata. Il connettore non ha alcun account per questo chiamante (nesbeeuni credenziale memorizzata oppure l'app non è mai stata autorizzata — `beeuni connectors ls` lo indica come `needs_auth`), oppure `--account` ne ha indicato uno che non è stato risolto. | `connect_url` — un link ospitato per autorizzare un account, se il chiamante può generarne uno — quando non è connesso alcun account. `requested_account` e `available_accounts` — il nome non risolto e i nomi che lo sono stati — quando `--account` ne ha indicato uno. |
| `connector_disabled` | 403 | Il connettore è dichiarato ma disabilitato. | — |
| `connector_not_found` | 404 | Nel progetto non è dichiarato alcun connettore con questo slug. | — |
| `action_not_found` | 404 | Il connettore non dispone di questa azione. | — |

`connect_url` è l'unico rimedio per un connettore non connesso: una sessione non viene mai rifiutata in anticipo per questo motivo (vedi [Concedere a un agente l'accesso](#grant-an-agent-access)), quindi la negazione stessa offre la soluzione. L'agente mostra il link così com'è; la trascrizione web lo visualizza come pulsante Connetti con un solo clic. Per impostazione predefinita, il link autorizza un account privato per la persona che lo apre: connettere un account condiviso è una scelta esplicita (`beeuni connectors connect stripe-read --owner project`, subordinata a `project.connector.write`).

Il connettore del canale che ha creato una sessione (Slack, Teams, email) è sempre utilizzabile da quella sessione, indipendentemente da quanto indicato nella concessione dell'agente, così l'agente può sempre rispondere nella conversazione da cui è stato interpellato.

La concessione di una sessione segue `beeuni.yaml`: una modifica a `connectors:` dell'agente in esecuzione (incluso `beeuni connectors add --apply`) si applica alla chiamata successiva. La concessione registra il blob del manifest e il commit da cui proviene; una lettura che lo sostituirebbe a partire dallo stesso blob viene prima confermata da una seconda lettura, mentre una lettura da un commit precedente non lo sostituisce.

Slack e Microsoft Teams si collegano dalla dashboard come le app OAuth. Collegando Slack viene scritto per te un connettore `channel` in `beeuni.yaml`. Vedi [Slack e canali](/docs/it/connect/slack).
