Skip to main content

Slack Bot

Ask ZenSearch questions directly from Slack. The bot responds in-thread with cited answers, source references, and follow-up suggestions.

info

The Slack bot is separate from the Slack data connector. The connector indexes your Slack messages for search. The bot lets you query ZenSearch from within Slack.

Using the Bot

Mention in a Channel

Mention the bot in any channel it's been added to:

@ZenSearch how do I configure SSO?

The bot responds in a thread with:

  • A cited answer based on your indexed knowledge
  • Source references (up to 5)
  • Follow-up suggestion buttons

Direct Message

Send a DM to the bot — no @ mention needed:

What data sources are supported?

Slash Command

Use the slash command for a private response visible only to you:

/zensearch what are the API rate limits?
note

Slash command responses are ephemeral (private). Follow-up suggestions are not available in ephemeral mode — use @ mentions or DMs for interactive conversations.

Conversations

The bot maintains conversation context within a Slack thread. Follow-up questions in the same thread use previous context for better answers.

  • Thread scope: Each Slack thread maps to a ZenSearch conversation
  • Session duration: 24 hours of inactivity starts a new conversation
  • Cross-platform: Conversations started in Slack can be continued in the web app

Follow-up Suggestions

After each answer, the bot may suggest related questions as clickable buttons. Clicking a suggestion posts a new message in the same thread.

Work Object Previews (Unfurl + Flexpane)

When a ZenSearch-indexed URL appears in Slack — either pasted by a user or rendered as a citation in an agent answer — Slack shows a rich preview card below the message. Clicking the card opens a per-viewer flexpane (right-side detail panel) with full document content if the viewer has permission to see it.

What renders in the unfurl card (broadcast-safe)

The unfurl card is visible to every member of the channel, so it intentionally shows only metadata that's safe to broadcast:

  • Document title
  • Source system (Confluence, Jira, Notion, GitHub, Salesforce, etc.)
  • Last-modified timestamp ("Updated 3 days ago")
  • A View in ZenSearch deep link

The card never shows document body, snippet, or summary content — those are per-viewer and live in the flexpane.

What renders in the flexpane (per-viewer)

Clicking the unfurl opens the flexpane on the right side of Slack. ZenSearch resolves the viewer's Slack identity to their ZenSearch user and renders one of four states:

StateWhat the viewer sees
Linked + permittedTitle + source + freshness + category + summary + action buttons
Linked + denied"You don't have access to this document. Ask the owner to share it."
Unlinked"Link your account" CTA — DM the bot once or sign in to ZenSearch to auto-link
Document removed"This document isn't available in ZenSearch anymore."

Two-key safety gate

A document only unfurls when both conditions are met:

  1. Its collection has allow_slack_unfurl = true (admin opt-in, default off)
  2. It has an "anyone-can-access" permission row from the source system (broadcast-safe)

Either gate alone is insufficient — a misconfigured upstream "shared with anyone" doesn't accidentally broadcast titles to whole Slack workspaces.

Agent citations

The same pipeline applies to citations the agent emits in its DM/thread answers. Each cited source URL becomes a clickable Work Object card with the same flexpane behavior — so a Confluence link cited in an agent answer is just as flexpane-clickable as one a user pastes.

Agent Approvals

When an agent action in a Slack conversation requires policy approval, the bot posts an approval card in the originating thread with Approve and Deny buttons.

  • Only team Admins and Owners can approve or deny
  • The card updates to show who took action and the decision
  • Approved actions resume automatically; denied actions stop the agent

Delegated delegate_to_human approvals use the same approval system, but their proactive Slack notification is a direct message to the resolved approver when the workspace and user identity are linked. They also remain available from the Governance dashboard.

Setup (Admin)

Prerequisites

  • A Slack workspace where you have admin permissions
  • A ZenSearch team with data sources configured

1. Create a Slack App

  1. Go to api.slack.com/apps and click Create New App > From scratch
  2. Name it (e.g., "ZenSearch") and select your workspace

Bot Token Scopes

Under OAuth & Permissions > Scopes > Bot Token Scopes, add:

ScopePurpose
app_mentions:readRespond to @mentions
chat:writePost messages
channels:historyRead channel messages (for thread follow-ups)
groups:historyRead private channel messages
im:historyRead DM messages
mpim:historyRead group DM messages
users:readRead user profiles
users:read.emailRead user emails (for automatic identity matching)
commandsHandle slash commands
links:readReceive link_shared events for ZenSearch-indexed URLs (Work Object previews)
links:writeRender unfurl cards via chat.unfurl (Work Object previews)

OAuth Redirect URL

Under OAuth & Permissions > Redirect URLs, add:

https://YOUR_API_DOMAIN/api/v1/integrations/slack/auth/callback

Event Subscriptions

Under Event Subscriptions, enable events and set the request URL to:

https://YOUR_API_DOMAIN/api/v1/surfaces/slack/events

Subscribe to these bot events:

  • app_mention — Respond to @mentions
  • message.im — Respond to DMs
  • message.channels — Thread follow-ups in channels
  • message.groups — Thread follow-ups in private channels
  • link_shared — Render Work Object unfurl cards for ZenSearch-indexed URLs
  • entity_details_requested — Open per-viewer flexpane when a user clicks an unfurl

Under App unfurl domains, add the patterns ZenSearch can route to a document:

*.atlassian.net *.notion.so docs.google.com drive.google.com
*.sharepoint.com *.zendesk.com service-now.com *.salesforce.com
*.hubspot.com github.com

Add any customer-owned domains for connectors you index (web crawler, Confluence Data Center, self-hosted Jira, etc.).

Interactivity

Under Interactivity & Shortcuts, enable and set the request URL to:

https://YOUR_API_DOMAIN/api/v1/surfaces/slack/interactions

Slash Commands (Optional)

Under Slash Commands, create a /zensearch command pointing to:

https://YOUR_API_DOMAIN/api/v1/surfaces/slack/commands

Work Object Previews

Under Features > Work Object Previews, toggle the feature on, then click Add entity type and register:

slack#/entities/file

This is the entity_type our app sends in entity.presentDetails responses. Without it, Slack ignores entity_details_requested events and the flexpane stays dark even though unfurls still render.

Per-collection opt-in

Work Object unfurls are off-by-default per collection. After connecting a Slack workspace, enable unfurls on the collections that should participate:

UPDATE collections SET allow_slack_unfurl = true WHERE id = '<collection-uuid>';

A dedicated admin UI toggle is on the roadmap.

2. Configure ZenSearch

Set these environment variables on the core-api service:

VariableDescription
SLACK_SIGNING_SECRETFrom your Slack app's Basic Information page
SLACK_CLIENT_IDFrom Basic Information > App Credentials
SLACK_CLIENT_SECRETFrom Basic Information > App Credentials
SLACK_BOT_ENABLEDSet to true to enable the bot
SLACK_OAUTH_REDIRECT_URLhttps://YOUR_API_DOMAIN/api/v1/integrations/slack/auth/callback

Restart the core-api service after setting these values.

3. Connect the Workspace

  1. Go to Settings > Integrations > Slack in the ZenSearch web app
  2. Click Add to Slack
  3. Authorize the app in the Slack popup
  4. The workspace appears as connected

4. User Identity Linking

ZenSearch automatically matches Slack users to ZenSearch accounts by email on first message (using the users:read.email scope). No manual setup is needed if user emails match.

If automatic matching fails, users can be linked manually via the identity links API:

curl -X POST https://YOUR_API_DOMAIN/api/v1/identity-links \
-H "Authorization: Bearer <token>" \
-d '{
"platform": "slack",
"external_user_id": "U1234ABCD",
"external_team_id": "T1234ABCD",
"user_id": "<zensearch-user-uuid>",
"team_id": "<zensearch-team-uuid>"
}'
caution

Users without a linked identity (and no matching email) will see: "Your identity is not linked to ZenSearch. Ask your admin to link your account."

Troubleshooting

Bot Not Responding

  • Verify SLACK_BOT_ENABLED=true is set
  • Check that the bot is added to the channel
  • Verify the Events API URL is reachable from Slack
  • Check core-api logs for errors

Identity Not Linked

  • Ensure the Slack user has a verified email that matches their ZenSearch account
  • Or create an explicit identity link via the API

"Still processing your previous message..."

  • The bot processes one message per thread at a time
  • Wait for the current response to complete before sending another