Slack & Discord Notifications
When a secret changes in production, the team should find out in the channel they already watch — not by checking the dashboard the next morning. Envpilot posts organization activity to Slack and Discord channels: variable changes, access requests, membership changes, and security events.
Notifications carry key names, environments, and actor names — never secret values. A notification channel is never a place where a secret can leak.
Slack & Discord notifications are a Pro feature. See Plans.
Connect a channel#
Connecting takes one click — Envpilot uses each platform's OAuth flow, which creates the webhook for you:
- Go to Organization Settings → Integrations (owner only).
- Click Connect Slack or Connect Discord.
- On the platform's consent screen, pick the channel to post to and approve.
- You land back on the Integrations tab. Envpilot queues a test message and the row updates with the delivery result.
There is nothing to copy out of Slack or Discord admin screens — the platform hands Envpilot the webhook URL during consent. The URL is encrypted in WorkOS Vault; Convex keeps only its opaque Vault reference and a masked preview. The OAuth access token is discarded, never stored.
Add a webhook manually#
If the Connect buttons aren't available (a locked-down Slack workspace, or a self-hosted Envpilot without OAuth apps configured), paste a webhook URL instead:
- Slack: in the target channel → Integrations → Add an app → Incoming Webhooks → create and copy the URL (
https://hooks.slack.com/services/…). - Discord: channel settings → Integrations → Webhooks → New Webhook → Copy Webhook URL (
https://discord.com/api/webhooks/…).
Then Organization Settings → Integrations → Advanced setup, pick the platform, paste the URL, and choose project routing. All webhook URLs — manual or OAuth-connected — are encrypted as credentials, and the UI only ever shows a masked preview.
Route projects to channels#
Every connected destination can receive activity from all projects or only a selected set of projects. Open Manage beside a destination to change its project routing and event groups.
For example, connect the Slack #envpilot channel, choose Selected projects, and select the EnvPilot project. That channel then receives only EnvPilot project activity. Connect Slack or Discord again to route other projects to different channels.
Organization-wide events that do not belong to a project, such as membership changes, are sent only to destinations configured for all projects. Existing destinations default to all projects.
Event groups#
Each destination subscribes to event groups, editable through Manage at any time:
| Group | Covers | Default |
|---|---|---|
| Variables | created, updated, rotated, restored, rolled back, exported | on |
| Requests | access requested, approved, rejected | on |
| Members | invitations, removals, shared-account permission changes | off |
| Security | attributable API denials, API keys, device/extension revokes | off |
Delivery behavior#
- Delivery is fire-and-forget: the audited action only queues preparation and never waits for Slack or Discord.
- Requests time out after 10 seconds. Network errors, HTTP 5xx responses, and rate limits retry up to three total attempts; provider
Retry-Afterguidance is respected. - After 20 consecutive failures a webhook auto-disables instead of hammering a dead endpoint. Re-enabling it (Resume) resets the counter.
- Send test queues a test message on demand; every newly added webhook queues one too. The settings row reports the final delivery status.
- Pausing, removing, or losing the feature gate stops already-queued deliveries because the endpoint is re-checked immediately before every post.
- Up to 10 webhooks per organization.
Self-hosting: enabling the Connect buttons#
The one-click Connect flow needs OAuth apps you register once per platform. Without these env vars the buttons hide and manual entry still works.
Slack — api.slack.com/apps → Create New App:
- Under OAuth & Permissions, add the redirect URL
https://<your-domain>/api/integrations/slack/callbackand the bot scopeincoming-webhook. - To install the app in workspaces other than its development workspace, complete Slack's Manage Distribution checklist and activate public distribution.
- Copy the Client ID and Client Secret into your web environment:
SLACK_CLIENT_ID=...
SLACK_CLIENT_SECRET=...Discord — discord.com/developers/applications → New Application:
- Under OAuth2, add the redirect
https://<your-domain>/api/integrations/discord/callback. - Copy the Client ID and Client Secret:
DISCORD_CLIENT_ID=...
DISCORD_CLIENT_SECRET=...For local Discord testing, register this exact redirect:
http://localhost:3000/api/integrations/discord/callbackSlack requires OAuth redirect URLs to use HTTPS. Its PKCE exception for http://localhost is a desktop flow and cannot request the incoming-webhook bot scope. You can keep the app entirely local by running Next.js with local HTTPS:
bun --cwd apps/web run dev -- --experimental-httpsAccept/trust the generated local certificate in the test browser, set both NEXT_PUBLIC_APP_URL and WORKOS_REDIRECT_URI to the HTTPS localhost origin, and add https://localhost:3000/callback to the WorkOS development environment's allowed redirect URIs. Then register:
https://localhost:3000/api/integrations/slack/callback
https://localhost:3000/api/integrations/discord/callbackAlternatively, use a temporary HTTPS tunnel or a trusted local HTTPS reverse proxy and register its callback URL instead. If the app must remain on plain http://localhost:3000, use Add manually with a disposable Slack incoming webhook; delivery, retries, status, pause/resume, and removal still run end to end.
For Discord or manual-webhook testing, set NEXT_PUBLIC_APP_URL=http://localhost:3000 in the web app's root .env.local. Set the same value in the Convex development deployment so notification links point back to localhost:
bunx convex env set NEXT_PUBLIC_APP_URL http://localhost:3000The four OAuth client variables belong only in .env.local; do not put client secrets in Convex. WORKOS_API_KEY must already be configured in the Convex deployment because webhook URLs are encrypted in WorkOS Vault.
The consent screens use the incoming-webhook (Slack) and webhook.incoming (Discord) scopes — channel-post capability only, no read access to anything.
Limits#
- Pro only (
team_notifications). Free organizations have the feature off and a channel limit of 0. - Up to 10 webhooks per organization (
team_notifications_limit). - Delivery times out after 10 seconds and retries up to three total attempts, respecting the provider's
Retry-After. - Slack and Discord only, via incoming webhooks — post-only scopes, no read access to your workspace.
- Manual Send test is rate limited to 5 per minute per organization.
- Notifications carry event metadata and links, never secret values.