PPactDocs
Integrations

Slack

Install Pact into your Slack workspace to fan CRM events into channels, DM users on @mentions, run /pact slash commands, ingest thread replies as comments, and post AI meeting summaries.

Slack

The Slack integration connects your workspace to Pact over OAuth and drives five surfaces: channel routing for CRM events, per-user DMs on @mentions, a /pact slash command, thread replies that flow back into Pact as comments, and post-meeting AI summaries posted to a channel. Everything is tenant-scoped, and outbound delivery is gated behind a feature flag that ships off by default.

Live and enforced

Shipped. Workspace OAuth, channel routes, the Events API webhook, and the slash-command handler live in api/routes/integrations_slack.py; the domain logic is under core/integrations/slack/. Meeting summary fan-out (core/video_meetings/notify.py) was delivered alongside recording-consent enforcement.

Installation

  1. 1

    Configure the Slack app credentials

    Pact needs SLACK_CLIENT_ID and SLACK_CLIENT_SECRET (per-tenant BYOK credentials, or platform env vars). Token encryption via AUTH_TOKEN_ENCRYPTION_KEY must be configured — /start returns HTTP 500 otherwise.

  2. 2

    Start OAuth

    An admin calls POST /v1/integrations/slack/start. Pact persists a single-use state token and returns an authorize_url. The requested bot scopes are chat:write, im:write, and users:read.email; the per-user grant requests chat:write so a user's own DMs are auditable as themselves.

  3. 3

    Complete the redirect

    Slack redirects to GET /v1/integrations/slack/callback. This route takes no auth header — it recovers the tenant from the single-use state token, exchanges the code, and stores the encrypted workspace bot token (xoxb-). If the installer also granted the user scope in the same flow, Pact links their tenant_users row immediately via users.info email lookup, so they don't have to click "Link Slack" separately.

  4. 4

    Enable delivery

    Outbound sends are gated by the per-tenant feature flag SLACK_DELIVERY_ENABLED, which is OFF by default so a freshly connected workspace never starts messaging real users unexpectedly. Turn it on when you're ready.

Delivery is off until you enable the flag

Until SLACK_DELIVERY_ENABLED is on for your tenant, notifications are still recorded (in the notifications table) but no Slack message is actually pushed. The dispatcher returns a result with notes="delivery_disabled" for observability. This is a deliberate safety default, not a limitation.

Channel routing for CRM events

Map Pact event types to Slack channels via /v1/integrations/slack/channel-routes (list / create / delete). When an event fires, core/integrations/slack/dispatcher.py posts a formatted message to every active route and stores a thread link so replies can be ingested. The known event types (GET /v1/integrations/slack/event-types) are:

code
deal.stage_changed          account.high_value
enrichment.completed        compliance.flag_raised
billing.trial_expiring      billing.subscription_changed
@mention

Each type has its own formatter — a stage change posts a :bar_chart: card, enrichment a :sparkles: card, a compliance flag a :warning: card, and so on.

DMs on @mention

When someone @mentions a teammate on a Pact record, core/integrations/slack/notifier.py tries to DM them. It resolves a Slack identity in priority order: (1) the user's explicitly linked slack_user_id, then (2) a users.lookupByEmail call via the workspace bot token. If neither resolves, the notification is marked no_slack_identity and Pact moves on — the mention itself is never blocked by a Slack failure.

The /pact slash command

POST /v1/integrations/slack/commands handles /pact subcommands, validated by the Slack signing secret. Tenant is resolved from the workspace team_id. All queries are tenant-scoped:

CommandWhat it does
/pact dealsLive pipeline overview — open value, stage breakdown, largest open deals
/pact deal <name>Find a specific deal by name
/pact accounts <query>Search accounts by name or domain
/pact contacts <query>Search contacts by name or job title
/pact ai <prompt>Grounded answer over your open pipeline via Pact AI (fast tier)

/pact ai needs an AI key

The AI subcommand makes a real (fast-tier) model call grounded in your open pipeline. If the workspace hasn't configured a Claude key in Pact admin, it degrades honestly with a message telling you to add one — it never fabricates an answer.

Thread replies become comments

Pact registers a Slack Events API webhook at POST /v1/integrations/slack/events (verified by the SLACK_SIGNING_SECRET; it also answers the url_verification challenge during app setup). When a message is a reply in a thread Pact started, and that thread is linked to a record, the reply is written back into Pact as a comment tagged [via Slack] with author Slack:<user_id>. Bot messages and root messages are ignored to prevent echo loops.

Post-meeting AI summaries

Meeting intelligence config exposes post_meeting_slack_enabled and a slack_channel_id. When enabled and the summary is AI-powered, core/video_meetings/notify.py::dispatch_meeting_summary_slack posts a Block Kit summary (title, action items, decisions, and a deep link to the meeting's intelligence page) into the configured channel, reusing the workspace bot token. Like every other Slack path it's best-effort — a missing token or channel returns a skipped result and is logged, never raised.

Auditing and status

  • GET /v1/integrations/slack/status — workspace connection state, team name, bot user id, delivery-flag state, and counters (dm_sent, dm_failed, etc.).
  • GET /v1/integrations/slack/audit — the slash-command audit log (who ran what, and how many results came back).
  • DELETE /v1/integrations/slack — disconnect the workspace.

Two token tiers

The workspace bot token (xoxb-) lives encrypted on the integrations row; per-user tokens (xoxp-) live on tenant_users so DMs survive a workspace-wide bot uninstall. When DMing, Pact prefers the user's own token so the message reads as the user talking to themselves, falling back to the bot token otherwise.