Skip to content
Integrations
Integrations

Slack

Trigger AgentField reasoners from signed Slack Events API requests.

Slack connect dialog for a signed Events API trigger

The slack source verifies Slack's request signature and routes workspace events to a reasoner.

Source Surface

SurfaceValue
Source nameslack
KindHTTP webhook
SecretRequired; Slack signing secret from secret_env
ConfigOptional tolerance_seconds, default 300
Event typeEnvelope type, or inner event.type for event_callback
IdempotencySlack event_id
Reasoner inputSlack envelope as event, with trigger metadata in _meta

Slack does not ship a separate capability node in OSS. The integration surface is the signed Events API source.

Agent Code

from agentfield import Agent, on_event

app = Agent(node_id="slack-agent")

@app.reasoner()
@on_event(
    source="slack",
    types=["app_mention", "message"],
    secret_env="SLACK_SIGNING_SECRET",
)
async def handle_slack(event: dict, trigger=None):
    slack_event = event.get("event", event)
    return {
        "type": trigger.event_type if trigger else event.get("type"),
        "text": slack_event.get("text"),
        "channel": slack_event.get("channel"),
    }

app.run()

Slack Setup

Create a Slack app, enable Event Subscriptions, and use the AgentField trigger URL as the request URL. Set the control-plane env var named by secret_env to the app's signing secret.

Useful Slack events:

  • app_mention
  • message.channels
  • message.im
  • reaction_added

Dispatch Contract

For event_callback, AgentField filters on the inner event type but keeps the envelope available:

{
  "event": {
    "type": "event_callback",
    "event_id": "Ev123",
    "event": {
      "type": "app_mention",
      "text": "<@bot> triage this",
      "channel": "C123"
    }
  },
  "_meta": {
    "source": "slack",
    "event_type": "app_mention",
    "idempotency_key": "Ev123"
  }
}
  • Slack signatures use v0:<timestamp>:<raw_body>.
  • AgentField rejects requests outside the configured timestamp tolerance.
  • event_callback payloads are unwrapped so reasoners can filter on the inner event type.