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.
| Field | Type | Required | Description |
|---|---|---|---|
provider | identifier | Yes | Catalog provider for managed OAuth, or any valid key for self-managed. |
label | string | No | Display label on the Connections page. |
description | string | No | Description on the Connections page. |
base_url | string | With auth | Absolute http(s) API origin for self-managed mode. |
auth | identifier | With base_url | Auth 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.
- Deploy with
git pushorswirls deploy. The Connections page lists every declared slot with its binding state. - Click Connect on a slot. The provider's OAuth consent screen opens with the catalog scopes for that provider.
- 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:andconnection:on one node. Pick one:authfor your own credentials,connectionfor a Swirls-brokered grant. - Setting
auth:on an integration node. Integration nodes takeconnection:only. - Setting
method:orpath:on a node that usesaction:. The action block owns the transport. - Calling the provider with
fetchfrom 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
- Actions and the catalog: typed provider operations and
swirls add - Credential profiles: for credentials you hold yourself (
authblocks) - Secrets: the project vault behind those profiles
- Channels: binding connections to chat platforms
Credential profiles
Reusable credential profiles for outbound HTTP and inbound form gates. Declared as auth blocks in the file — OAuth client credentials, API keys, basic, and bearer.
Actions and the catalog
Typed provider operations installed with swirls add. Browse the integration catalog, install action blocks, generate them from any API spec, and request new providers.