# Connectors

How connectors and connections give agents scoped access to external tools.

Canonical page: https://themachine.myapps.ai/docs/connect/connectors

A connector links a project to an external tool or service. The agent
calls it as a tool. Machine brokers each call, so the sandbox never holds the
connector credential.

You declare most connectors in `kortix.yaml`. See the
[manifest reference](/docs/project/manifest) for every field. Machine declares
channel and computer connectors when you connect a chat platform or a
machine.

Some connectors are **Made by Machine**: Machine builds and runs them, and
every project has them without any manifest entry. You only connect your own
key. The first is [Pixio](/docs/connect/pixio), for images, video, and audio.
It sits at the top of the Connectors page's **Discovery** tab.

## Connectors and connections

A connector is the agent-facing permission package. It contains:

- a project-unique slug
- a display name
- a provider app
- one authorization strategy
- connector policies

A connection is one connected account or credential for the connector.
Every connection uses the connector's policies.

The authorization strategy is:

- `project` for connections available to eligible project members
- `user` for a connection owned by the acting project member

A service account cannot use a member's `user` connection. Multiple
connectors can reference the same provider app. Use separate connectors
when one app needs different policies.

## Providers

A connector uses one provider type:

- **pipedream** — managed OAuth for supported SaaS apps
- **openapi**, **postman**, **graphql**, **http** — direct API connectors
- **mcp** — a remote MCP server over HTTP or SSE
- **channel** — a chat platform connection
- **computer** — one permissioned connector profile for one connected machine

See [Slack and channels](/docs/connect/slack) and
[Computers](/docs/connect/computers) for the managed provider flows.

## Authentication and policy

A connection authenticates with:

- OAuth through Pipedream, a channel install, or a native OAuth2 grant
- an API key or token entered through the dashboard or SDK

Machine encrypts connection data and resolves it server-side for each tool
call. The agent requests an action. Machine attaches the credential, checks the
agent grant and connector-connection policy, calls the external API, and returns
the result.

Connector policies belong to the connector. A connection cannot
override them. Project guardrails apply above connector-connection policies.

By default, an unmatched connector action runs without approval. Set
`policy.default_mode: risk` to require approval for unmatched write and
destructive actions. Set `sensitive: true` to make `require_approval` the
connector's unmatched-action default, including reads. Explicit project
or connector-connection rules still apply first.

### Approve one governed call

`require_approval` creates one decision for one connector call. The Connector
returns `202 pending_approval` with `approval_url`, `approval_summary`, and
`execution_id`. It does not keep an HTTP request open.

Share `approval_url` with any teammate. The URL identifies the request but does
not grant authority. The page requires a signed-in Machine account. Machine then
verifies that the account can access and approve actions in the project.

The approval page shows the redacted parameters that the connector will receive.
Approve or deny the call once. Machine sends the decision back into the session
through a durable callback. An approval applies only to the exact request
digest. A changed recipient, subject, body, channel, URL, or other parameter
requires a new decision.

Open the session's **Audit** panel to use the same parameter view. Historical
entries remain read-only. There is no session-wide approval option. Use an
explicit `always_run` policy only when a connector action must run unattended.

## Connect with OAuth

### Open the project's Connectors page

Open the project. Select **Connectors**, then select the app.

### Select the connection scope

Select **Project** for a shared project connection. Select **User** for a
connection owned by the acting project member.

### Complete authorization

Complete the OAuth flow. Machine stores the connected account as a connection.

## Connect a direct API with OAuth2

Direct connectors support:

- client credentials
- authorization code with PKCE
- device authorization

For client credentials, enter the token URL, client ID, scopes, and client
secret. You can use `client_secret_basic`, `client_secret_post`,
`client_secret_jwt`, or `private_key_jwt` token-endpoint authentication.

For authorization code, enter the authorization URL and token URL. For device
authorization, enter the device-authorization URL and token URL. An RFC 8414
discovery URL can provide these endpoints.

Machine encrypts the OAuth2 configuration and tokens. It refreshes access tokens
before expiry. Revoking the connection blocks the next connector call.

For Microsoft Graph, use:

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

For direct SharePoint REST calls, use the SharePoint resource scope:

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

## Connect with an API key

### Declare the connector

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

`authorization_strategy` defaults to `project` when the manifest omits it.

### Merge the change request

Machine reads the manifest from the default branch. The connector becomes
active after the change request merges.

### Add the connection

Open the connector and set its credential. Machine stores the value
encrypted. It does not write the value to the manifest.

## Grant an agent access

Every agent in a project can call every connector connected on that project.
You don't add a connector to an agent for it to work: connect it, and the
next connector call in any session can use it, with no restart.

What still limits a call:

- the connector itself: it must be on the project, enabled, and have an
  active connection
- the role of the person who started the session (an agent never gets more
  than that person has)
- connector policies, approvals, and project guardrails

An agent's `connectors` field in `kortix.yaml` is still read and kept, but it
no longer narrows which connectors the agent can call. Its remaining use is
`connectors_required`:

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

`connectors_required` must be a subset of `connectors`. A session for this agent
returns `409 CONNECTOR_CONNECTION_REQUIRED` before sandbox startup when it
cannot resolve a valid active connection. Merge the change before it takes
effect.

> **Changed on 2026-10-08**
> Agent access used to be deny-by-default: an agent that omitted `connectors`
> got none, and a call to an unlisted connector failed with
> `connector_not_assigned`. That no longer happens.

## Select a session connection

Default resolution follows the connector's authorization strategy. A
session can select a specific connection:

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

The binding key is the connector slug. The value is an active connection that
matches the connector's strategy.

Use `GET /projects/{projectId}/sessions/{sessionId}/scope` to read the effective
binding. Use `PUT` on the same path to replace it. The replacement applies to
the next tool call without restarting the session.

## Use a connector in a session

Inside a session, use the Connector CLI:

```text
kortix connectors ls
kortix connectors call stripe-read <action> '<json-args>'
```

`connectors` lists the connectors in scope. `call` runs one action.

Channels (Slack, Microsoft Teams, Inkbox, and Glyph) connect from the project's **Settings → Channels** page instead of the Connectors page. Connecting Slack writes a `channel` connector to `kortix.yaml` for you. See [Slack & channels](/docs/connect/slack).
