Slack Integration
Pulse's Slack integration is the most-used delivery channel. It posts questions as DMs, collects answers inline, and surfaces digests in team channels. No context switch for your team.
What you need
- A Slack workspace where you have permission to install apps.
- A Pulse deployment (see Installation).
- The Slack-related env vars set:
VITE_SLACK_APP_IDVITE_SLACK_CLIENT_IDPULSE_SLACK_CLIENT_SECRETPULSE_SLACK_SIGNING_SECRET
Creating the Slack app
The first time you set up Pulse, you create a Slack app that belongs to your workspace.
- Go to api.slack.com/apps.
- Click Create new app → From manifest.
- Paste the contents of
docs/slack-manifest.yamlfrom your Pulse repo. The manifest includes:- Required scopes (
chat:write,im:history,commands,users:read, etc.) - Event subscriptions (
message.im,app_mention) - Slash commands (
/pulse) - Interactivity endpoint
- Required scopes (
- Install the app to your workspace.
- Copy Client ID, Client Secret, Signing Secret into your Vercel env vars, then redeploy.
Pointing the app at Pulse
In the Slack app settings:
- Event Subscriptions → Request URL:
https://<your-pulse-domain>/api/slack/events - Interactivity & Shortcuts → Request URL: same as above.
- Slash Commands →
/pulse→ Request URL: same as above.
Slack verifies each URL with a challenge. Pulse's
pulse-slack-events function handles the challenge
automatically.
Connecting your workspace
Once the app is installed:
- In Pulse: Settings → Integrations → Slack → Connect workspace.
- Slack's OAuth page appears; approve.
- Pulse maps each Slack user to the matching Pulse user by email. Unmatched Slack users are invited via email.
How delivery works
Behind the scenes:
- The scheduler picks up a due standup.
- For each participant whose Slack is enabled, Pulse calls
Slack's
chat.postMessagetargeting their DM. - Pulse renders each question as a block message with inputs (short text, buttons, select menus).
- The user submits inline.
- Slack POSTs the submission to
/api/slack/events. - Pulse verifies the signature, stores the response, and acknowledges.
No polling. No "go open this link." The user never leaves Slack.
Slash commands
The /pulse command offers:
/pulse status— your current standups, open surveys, reminders./pulse skip— skip today's standup with an optional reason./pulse run <standup-name>— manually trigger a standup (admin only)./pulse help— lists every command.
Mapping Slack channels to Pulse teams
If you want a standup digest to post to a specific Slack channel:
- Invite the Pulse bot to the channel (
/invite @Pulse). - In Pulse, set the team's digest location to the Slack channel.
Mapping Slack users
By default, Pulse maps Slack users to Pulse users by email. If emails don't match (e.g., alias domains):
Settings → Integrations → Slack → User mapping lets you override per user.
Multi-workspace
One Pulse deployment supports multiple Slack workspaces if you have multiple orgs (e.g., one Slack for the parent company and one for a subsidiary). Install the same app into each; Pulse associates the workspace with the Pulse tenant.
Signature verification
Every inbound Slack request is verified against
PULSE_SLACK_SIGNING_SECRET before any side effect. This is
non-negotiable — without it, anyone could spoof standup answers.
If signature verification fails, Pulse logs the attempt to
slack_signature_failures and responds with 401.
Troubleshooting
| Symptom | Likely cause |
|---|---|
| No standup arrives in Slack DM | Scheduler cron isn't running, or the user isn't mapped. |
| Slack shows "app not installed" | OAuth token expired — reconnect under Settings → Integrations → Slack. |
| Answers don't register | Request URL mismatch, or signature verification failing. |
| Digest goes nowhere | Bot not invited to the digest channel. |
Detailed logs are in the pulse-slack-events Edge Function.
Removing the integration
Settings → Integrations → Slack → Disconnect. The app is uninstalled from Slack. Standups fall back to whatever the per-user alternate channel is (email, Comms, web).