SWIRLS_
Connections

Connection blocks

Credential slots for outbound APIs — managed OAuth in the Portal, or self-managed vault credentials with base_url and auth.

What it is. A named credential slot for outbound API calls. Managed connections use Swirls-brokered OAuth (authorize once in the Portal; no credentials in the file). Self-managed connections declare base_url and auth so credentials come from the project vault.

Use managed when a workflow talks to Slack, GitHub, Linear, Discord, LinkedIn, or Microsoft and you want Portal Connect. Use self-managed for arbitrary APIs or personal API keys. Managed OAuth for other providers is a request away.

Works with type: integration nodes (typed provider calls via action blocks), type: http nodes (via connection:), channels, and the project's Connections page in the Portal.

connection

Connections are project-scoped. You can declare as many of the same provider as you need (for example two separate Slack workspaces). There is no type: field; the connection keyword identifies the block.

FieldTypeRequiredDescription
provideridentifierYesCatalog provider for managed OAuth, or any valid key for self-managed.
labelstringNoDisplay label on the Connections page.
descriptionstringNoDescription on the Connections page.
base_urlstringWith authAbsolute http(s) API origin for self-managed mode.
authidentifierWith base_urlAuth block that supplies vault credentials.
connection slack_sales {
  label: "Sales Slack"
  provider: slack
}

secret petstore_secrets {
  vars: [PETSTORE_TOKEN]
}

auth petstore_bearer {
  type: bearer
  secrets: petstore_secrets
  token: PETSTORE_TOKEN
}

connection petstore {
  provider: petstore
  base_url: "https://petstore.example.com/v2"
  auth: petstore_bearer
}

Managed providers come from the Swirls integration catalog. Self-managed connections skip Portal OAuth and use vault secrets instead.

How nodes use a connection

A connection is referenced by bare name from three places. Agents reach connections the same way: through the integration and HTTP nodes in the workflows they run, and through the channels they answer on.

Integration nodes (preferred)

A type: integration node pairs connection: with action: naming a typed action block. The platform issues a short-lived provider token for the call and routes the request to the provider's API.

connection team_slack {
  label: "Team Slack"
  provider: slack
}

action slack_post_message {
  provider: slack
  method: POST
  path: "/chat.postMessage"
  encoding: form
  scopes: ["chat:write"]
  input: @json { { "type": "object", "required": ["channel", "text"], "properties": { "channel": { "type": "string" }, "text": { "type": "string" } } } }
  output: @json { { "type": "object", "required": ["ok"], "properties": { "ok": { "type": "boolean" } } } }
}

workflow notify {
  label: "Notify"
  root {
    type: code
    label: "Entry"
    code: @ts { return context.nodes.root.input }
  }
  node post_slack {
    type: integration
    label: "Post to Slack"
    connection: team_slack
    action: slack_post_message
    params: @ts {
      return {
        channel: context.nodes.root.output.channel,
        text: context.nodes.root.output.text,
      }
    }
  }
  flow {
    root -> post_slack
  }
}

When action: is set, do not set method: or path: on the node; deploy inlines the transport from the action block. An integration node can also set a raw path: instead of action:, but that form is untyped. auth: is never valid on integration nodes.

HTTP nodes

A type: http node sets connection: when you need full URL control. The token is injected as an Authorization: Bearer header at execution time.

node post_update {
  type: http
  label: "Post to Slack"
  method: "POST"
  connection: slack_sales
  url: @ts { return "https://slack.com/api/chat.postMessage" }
}

A node sets either auth: (a credential profile for credentials you hold) or connection: (a brokered grant), never both.

Channels

channel blocks bind a connection: the same way; the connection's provider must match the channel's platform. Chat uses that connection to authenticate when it replies on the platform. See Channels.

A platform: mcp channel is the exception: it takes connector:, not connection:. A connection is outbound OAuth to a third party; a connector is the inbound OAuth application external MCP clients authenticate against to reach your agent. See MCP channels.

Action blocks

A top-level action block declares a typed provider operation: the transport plus optional input and output JSON schemas. Integration nodes inherit the transport and typing from the block, so params: and the node output are checked against the schemas.

You rarely write action blocks by hand. Browse curated actions in the integration catalog and install them with swirls add; OpenAPI and GraphQL URLs produce the same action artifacts for any other API. The full field reference, the catalog, URL imports, and provider requests live on Actions and the catalog.

Authorize in the Portal

Deploy first, then bind. Because the file references the connection by name (no IDs to copy and no secrets to provision), an agent can author the whole workflow end to end; the only human step is the one-time authorization.

  1. Deploy with git push or swirls deploy. The Connections page lists every declared slot with its binding state.
  2. Click Connect on a slot. The provider's OAuth consent screen opens with the catalog scopes for that provider.
  3. Approve. The account is bound to that slot, and runs can use it immediately.

Bindings are per project and keyed by connection name. Reconnecting a slot replaces the previous account, and Disconnect unbinds it. Renaming a connection block orphans its binding, so a renamed slot must be reconnected.

A deployed slot that has not been bound fails at run time, not at deploy: the node raises a connection-not-bound error telling you to bind it on the Connections page.

Common mistakes

  • Setting both auth: and connection: on one node. Pick one: auth for your own credentials, connection for a Swirls-brokered grant.
  • Setting auth: on an integration node. Integration nodes take connection: only.
  • Setting method: or path: on a node that uses action:. The action block owns the transport.
  • Calling the provider with fetch from a code node. Use an integration or HTTP node so the platform can inject the token; code nodes never see connection credentials.
  • Renaming a connection and expecting the binding to follow. Bindings are keyed by name; reconnect after a rename.

Further reading

On this page