Slack Handles
A SlackHandle reserves a Slack user-group @handle for Firetiger inside a specific Slack workspace (identified by its Connection). Once a handle exists and the Slack user group has been provisioned, you can create SlackAgentMentioned triggers that route @-mentions of that handle to specific agents.
Service: firetiger.slackhandles.v1.SlackHandlesService
Resource name pattern: connections/{connection}/slack-handles/{slack_handle}
Access: Read-write
Resource type: SlackHandle
Why a separate resource
- Identity vs routing: the handle is an identity (who can be paged in Slack); a trigger is the routing rule (which agent responds, on what channels). Separating them lets a trigger be edited/enabled/disabled without churning the Slack user group, and lets the same handle fan out to multiple agents via multiple triggers.
- Workspace scope:
@on-callin two different workspaces are legitimately different identities — the parent-child naming (connections/{connection}/slack-handles/{slack_handle}) makes that explicit.
Prerequisites
The parent Connection must be a Slack connection (CONNECTION_TYPE_SLACK) whose stored OAuth scopes include both usergroups:read and usergroups:write. Missing scopes return a structured FailedPrecondition with reason = SLACK_USERGROUP_SCOPE_MISSING.
Example flow
1. Create a handle
Reserves the @-name in the workspace and provisions or binds to the backing Slack user group. If the handle is unused, Firetiger creates a new bot-owned user group; if a workspace user group already holds the handle (whether bot-created or human-created), Firetiger binds to it and adds the bot to the membership without dropping any existing members. The service enforces one SlackHandle row per (connection, handle) pair.
curl -X POST "https://api.cloud.firetiger.com/firetiger.slackhandles.v1.SlackHandlesService/CreateSlackHandle" \
-u "$USERNAME:$PASSWORD" \
-H "Content-Type: application/json" \
-d '{
"parent": "connections/slack-prod",
"slack_handle_id": "on-call",
"slack_handle": {
"handle": "on-call"
}
}'
{
"slackHandle": {
"name": "connections/slack-prod/slack-handles/on-call",
"handle": "on-call",
"userGroupId": "S0123ABCDEF",
"createTime": "2026-04-23T08:28:56Z",
"updateTime": "2026-04-23T08:28:56Z"
}
}
2. Wire the handle to an agent via a trigger
curl -X POST "https://api.cloud.firetiger.com/firetiger.triggers.v1.TriggersService/CreateTrigger" \
-u "$USERNAME:$PASSWORD" \
-H "Content-Type: application/json" \
-d '{
"trigger_id": "on-call-mentions",
"trigger": {
"display_name": "On-call @mentions",
"agent": "agents/on-call",
"enabled": true,
"configuration": {
"slack_agent_mentioned": {
"slack_handle": "connections/slack-prod/slack-handles/on-call",
"channels": ["#on-call"]
}
}
}
}'
3. List handles on a workspace
curl -X POST "https://api.cloud.firetiger.com/firetiger.slackhandles.v1.SlackHandlesService/ListSlackHandles" \
-u "$USERNAME:$PASSWORD" \
-H "Content-Type: application/json" \
-d '{"parent": "connections/slack-prod"}'
4. Delete a handle
Refused while any trigger still references the handle — delete those first. The Firetiger row is soft-deleted; the underlying Slack user group is left in place, including its membership. Other people in the workspace may rely on that group, so its lifecycle stays in Slack — a workspace admin can disable or delete it from Slack if they want it removed.
curl -X POST "https://api.cloud.firetiger.com/firetiger.slackhandles.v1.SlackHandlesService/DeleteSlackHandle" \
-u "$USERNAME:$PASSWORD" \
-H "Content-Type: application/json" \
-d '{"name": "connections/slack-prod/slack-handles/on-call"}'
Handle drift
The handle string is a snapshot captured at create time. Routing from Slack mentions is keyed off user_group_id, which is stable across renames — so if a Slack admin renames the backing user group out-of-band, mentions continue to route correctly but GetSlackHandle keeps reporting the original handle. The API rejects attempts to change handle in place; the reconcile path is to delete the SlackHandle and create a new one (CreateOrGetByHandle re-binds idempotently to the existing user group, so you don’t lose your Slack user-group ID).
Co-mentions with @firetiger
If both @firetiger and a custom Slack handle appear in a single message (e.g. @firetiger @on-call help), only the custom handle’s trigger fires. The default @firetiger investigation path is suppressed to avoid double-responding to the same message. To get both, send two separate messages.
Structured errors
CreateSlackHandle maps Slack Web-API failures to google.rpc.ErrorInfo with stable reason codes so clients can branch without parsing messages:
| Reason | Meaning | Remediation |
|---|---|---|
SLACK_USERGROUP_SCOPE_MISSING |
Connection lacks usergroups:read/usergroups:write |
Reinstall the Slack app with the updated scopes |
SLACK_USERGROUP_RESTRICTED |
Workspace plan or admin policy blocks user-group management | Admin action outside the app (e.g. upgrade plan, lift restriction) |
SLACK_USERGROUP_DISABLED |
A workspace user group with the handle exists but is currently disabled | Ask a Slack workspace admin to re-enable the group, then retry |
SLACK_CONNECTION_UNAUTHORIZED |
Stored bot token is invalid/revoked | Reinstall the Slack connection |