Slack Integration
Connect your decoupled.io organization to Slack so the work happening across your headless Drupal sites shows up in the channels your team already uses — and so you can drive the dashboard from a slash command without context-switching.
The integration ships in two layers:
- Notifications (one-way: dashboard → Slack) — block-formatted alerts for spaces, deploys, support tickets, billing, and backups, routed per category to whichever channel you choose.
- Slash commands (two-way: Slack → dashboard) —
/decoupledcommands to list spaces, check status, create / delete spaces, and trigger config deploys, all signature-verified and permission-checked.
Privacy: the bot only reads the public/private channel list it's a member of (so the channel picker can show names) and writes notifications to channels you explicitly route. We never read user messages.
Quick start
- Sign in at https://dashboard.decoupled.io and open Apps & Integrations from the user menu.
- Click Connect Slack and authorize the app for your workspace.
- Pick a channel for each notification category (spaces, deploys, support, backups, billing). Each pick fires a test message to verify the bot can post — if the bot isn't in the channel, invite it with
/invite @decoupled.ioand try again. - Type
/decoupled helpin any channel where the bot is present.
That's it. Notifications start landing immediately; slash commands are available right away.
Notifications
| Category | Events you'll see |
|---|---|
| Spaces | Created, ready, failed, archived |
| Deploys | Started, succeeded, failed, plus tier-initialization (dev → test → live) |
| Support | New tickets, customer replies, status changes |
| Backups | Nightly backup completed (with size) or failed (with workflow run link) |
| Billing | Payment failures, subscription cancellations |
Each message is rendered with Block Kit and includes:
- Your organization name (so multi-org agencies can disambiguate at a glance)
- The event title and a one-line summary
- Key fields (space name, environment tier, source/target for deploys, etc.)
- An Open dashboard action button
Routing rules
- One channel per category — pick once, applies to every event in that category for your org.
- Test-on-select — the dashboard tries to post a test message before persisting the route, so misconfigurations (bot not in channel, missing scope, archived channel) surface immediately instead of on the first real event.
- Send-test buttons — every saved route has a paper-airplane button next to it that fires a synthetic event through the same renderer real events use.
- Failures bypass coalescing — a
deploy.failedorbilling.payment_failedevent always sends immediately even if the actor's window is otherwise being deduped.
Cascading-event coalescing
A typical action like "create dev → init test → init live" can fire 9+ events in a few minutes. Without batching, the channel turns into wallpaper.
The integration applies a 60-second window keyed on (organization, actor):
- The first event in a window posts immediately.
- Subsequent events from the same actor in the same window are suppressed.
- When the window closes, you get a single follow-up: "+ N additional steps — view activity".
You'll see the long form of every event for solo work; cascades collapse to one + summary.
Diagnostics
Open the Show recent delivery attempts panel on the integration card to see the last 50 outbound posts, their status (sent / failed / skipped), and the exact Slack error code on failures. This is the fastest path from "I'm not getting alerts" to a fix.
The most common error you'll see is not_in_channel — the bot isn't a member of the routed channel. Invite it with /invite @decoupled.io and re-test.
Slash commands
All commands run under the invoking Slack user's identity, mapped to a decoupled.io account by email match. So your Slack profile email must be the same as your decoupled.io login email.
Replies are ephemeral by default — only you see them. Notifications and follow-up state changes still land in the routed channels for everyone.
Read-only
/decoupled help # command reference
/decoupled spaces # list spaces in your org
/decoupled space status <name> # details for one space
Write
Multi-word names work — no quotes needed, just type them naturally.
/decoupled space create My New Site # free-tier space
/decoupled space create My New Site --starter # consumes a starter license slot
/decoupled space create My New Site --pro # consumes a pro license slot
/decoupled space delete My Site confirm # destructive — see below
/decoupled deploy My Site test # config deploy dev → test
/decoupled deploy My Site live confirm # config deploy → live
Confirmation rules
- Destructive ops (
space delete,deploy ... live) require a trailing confirmation token. Accepted forms (case-insensitive):confirm,CONFIRM,--confirm,--force,yes. Cheaper to type correctly than a button-modal flow and just as safe. deploy ... testdoesn't need confirmation — test environments are by definition disposable.space deleteis owner-only. Org members who didn't create the space can't nuke it from Slack.
Paid-tier creation
The --pro and --starter flags create paid spaces by consuming an existing license slot on your billing account. We never bump license counts or trigger Stripe charges from Slack — buying a new license still happens in the dashboard at /subscription. This keeps every Stripe-touching code path in one place, so there's no risk of double-billing or license drift.
If you don't have a free slot available, the command replies with a link to the subscription page rather than silently spending money.
Async pattern
Most write commands kick off background work that takes longer than Slack's 3-second response budget:
| Command | Sync part | Async follow-up |
|---|---|---|
space create |
Insert DB row, dispatch background-create webhook | The existing space.active Slack notification fires when Drupal is up (~60s) |
deploy |
Mark target in_progress, dispatch FlyProvider workflow |
The existing deploy.succeeded / deploy.failed notification fires when the GHA workflow finishes (2–5 min) |
space delete |
Synchronous: DB row + usage row removed immediately | Fly tenant destroy runs background |
The slash command always returns a "started" reply within 1–2 seconds; the routed Slack channel gets the success/failure ping when the actual work completes. Configure your spaces and deploys notification channels if you want to see this loop close.
What the slash command can NOT do (today)
These intentionally stay in the dashboard:
- DB+Files deploys (the destructive sibling of config deploys)
- Buying new licenses (or any other Stripe write)
- Frontend / Netlify / Vercel template wiring
- Updating space config, preview URLs, OAuth credentials
- Cross-org operations — the slash command always operates on the actor's primary org
If you need any of these from a workflow, our n8n integration calls the same MCP tools the dashboard uses and has a richer surface than slash commands.
Permissions you grant
The Slack app requests:
chat:write— post notifications and slash command replieschannels:read,groups:read— list public + private channels in the channel pickerchannels:join— auto-join future public channels you route notifications to (private channels still need a manual/invite)users:read.email— required for slash commands; lets us match a Slack user to a decoupled.io account
We never request scopes to read message content or send DMs.
Troubleshooting
| Symptom | Most likely cause |
|---|---|
not_in_channel in delivery log |
Bot isn't a member. Invite with /invite @decoupled.io. |
channel_not_found |
The channel was deleted or renamed; re-pick it in the integration settings. |
| Slash command replies with "missing email scope" | The Slack app needs users:read.email. Reconnect from the integration settings. |
| Slash command replies with "I couldn't find a decoupled.io account" | Your Slack profile email doesn't match your decoupled.io login email. Update one to match. |
| Notifications stopped after a Stripe issue | Check the integration card for an "error" badge — Slack's auth_revoked / token_revoked errors flip the status to error. Click Reconnect. |
dispatch_failed from Slack |
Slack didn't get a response within 3s. Open the Vercel logs and look for the slash-command request to see what blocked. |
Removing the integration
Click Disconnect on the integration card. The decoupled.io app is removed from your Slack workspace, the encrypted bot token is wiped from our database, and notifications stop immediately. You can reinstall any time.