Build a Slack app and submit to the Slack Marketplace
A 10-step playbook. Open in Dock and you'll get four surfaces seeded:
- **Steps** (table) — the 10 gates as rows, owner + due + status
- **Pointers** (table) — every official Slack doc + tool linked from this playbook
- **Brief** (doc) — the canonical write-up you maintain alongside the work
- **Submission log** (table) — one row per Marketplace review iteration (submitted, response, action taken)
Read `Steps` top-to-bottom on first open. Each row is one of the 10 steps. Click into a step to see the tasks, pointers, and the agent prompt for that step.
Outcome
Your Slack app live in the Slack Marketplace, installable to any workspace via OAuth, with reviewer-approved scope minimisation and a sound onboarding flow.
Estimated time: 3-6 weeks (most of it Marketplace review iterations)
Difficulty: advanced
For: Developers shipping a multi-workspace Slack app for distribution.
What you'll need
Pre-register or install before you start.
- Slack API dashboard (Free) — Where you create the app, manage scopes, manifest, OAuth, distribution.
- Bolt for JavaScript (Free (npm)) — Official Slack SDK. Handles OAuth, signature verification, event routing, blocks.
- Bolt for Python (Free (pip)) — Python equivalent. Same shape, different language.
- Block Kit Builder (Free) — Visual designer for messages and modals. Copy the JSON straight to your code.
- ngrok (Free tier) — Local development tunnel so Slack can reach your dev server for events.
The template · 10 steps
Step 1: Create the app from a manifest YAML
Estimated time: 1 hr
Slack apps are best created from a manifest.yml: declarative config for scopes, slash commands, event subscriptions, OAuth redirects. The manifest is checked in to your repo; create from manifest gives you reproducible app config across dev / staging / prod.
Tasks
- Open https://api.slack.com/apps → Create New App → From an app manifest
- Pick a workspace (your dev workspace is fine for now)
- Paste a starter manifest.yml with display_information, bot scopes, slash commands stubs
- Open the new app's Basic Information tab; copy the Signing Secret + App ID into your env vars
- Check the manifest.yml into your repo; treat it as the canonical source
Pointers
- [Official] App manifests reference
- [Official] Create an app from a manifest
[!CAUTION] Gotchas
- The manifest.yml is the source of truth ONLY if you remember to re-export from the dashboard after changes. Edit in the YAML; apply via the dashboard.
- Scopes added via the dashboard but not added to the YAML get stripped on next manifest apply. Always edit YAML first.
- App ID and Signing Secret are different from the OAuth Client ID / Secret. Don't mix them up in env vars.
Step 2: Implement OAuth install with state + token storage
Estimated time: 3-5 hr
Public Slack apps install via OAuth v2: workspace admin clicks Install, lands on api.slack.com, picks scopes, redirects to your /slack/oauth/redirect with a code, you exchange the code for a bot token, then store it keyed by team_id. Bolt's official ExpressReceiver / FastAPI handlers do this for you. Don't roll your own.
Tasks
- Set the OAuth redirect URL in the app dashboard (e.g. https://yourapp.com/slack/oauth/redirect)
- Use Bolt's ExpressReceiver (Node) or AsyncSlackRequestHandler (Python) for the OAuth flow
- Store the bot token + team_id + enterprise_id in your DB on installation
- Implement an installationStore.fetchInstallation(teamId, enterpriseId) — Bolt calls it on every event
- Implement an uninstall webhook (app_uninstalled event) and zero out tokens for that team
- Test the install flow end-to-end on a brand new dev workspace
Pointers
- [Official] Installing apps with OAuth
- [Official] Bolt installation flow
[!CAUTION] Gotchas
- OAuth redirect URLs are an exact-match list. http vs https + trailing slash differences get rejected. Whitelist BOTH staging and prod URLs.
- When you store bot tokens, encrypt at rest. Slack's review reads your security questionnaire and looks for this.
- On app_uninstalled, you MUST stop using the token + delete or invalidate it. Continued API calls with revoked tokens hit rate limits + flag your app on review.
Step 3: Subscribe to events via Events API or Socket Mode
Estimated time: 2-4 hr
Slack pushes events (messages, app_mention, app_home_opened) two ways: Events API (HTTP POST to your endpoint) or Socket Mode (WebSocket from your server). Events API is the only option for distributed apps; Socket Mode is dev-only / single-workspace. Public apps go through Events API.
Tasks
- Set Request URL on the Event Subscriptions tab (Bolt verifies the URL automatically)
- Subscribe to the events your app handles: app_mention, message.channels, app_home_opened, etc.
- Verify Slack's signing secret on every incoming POST (Bolt does this automatically)
- Respond within 3 seconds (Slack retries up to 3x on timeout). Off-load slow work to a queue.
- Implement event handlers in your Bolt app
- Test with the Block Kit / Events API tester on api.slack.com
Pointers
- [Official] Events API
- [Official] Verify signing secret
- [Official] Socket Mode — Useful for dev / internal apps, NOT allowed for Marketplace.
[!CAUTION] Gotchas
- Events API endpoints must respond with HTTP 200 within 3 seconds. Heavy work (LLM calls, slow DB queries) must run on a background queue; ack the event first.
- Slack retries failed events up to 3 times. Make handlers idempotent; key on event_id.
- Socket Mode apps cannot be submitted to the Marketplace. If you built on Socket Mode for dev, plan to rewrite to Events API for distribution.
Step 4: Pick the absolute minimum OAuth scopes
Estimated time: 2-3 hr
The Marketplace review hammers on scopes. For every scope you request, the reviewer asks: does the user-visible feature literally require this? Bot scopes (chat:write) are easier to justify than User scopes (channels:history). Avoid User Token scopes unless absolutely necessary; avoid wildcard scopes (groups:read) when narrower exists.
Tasks
- List every scope in your manifest.yml
- For each, write the user-visible feature it powers
- Flag any scope where the feature could work with a narrower scope (chat:write.public vs chat:write)
- Move every User Token scope to a Bot Token scope if your bot can do the work as itself
- Drop any scope you can't justify with a real feature
- Re-test the install flow with the trimmed scope list
Pointers
- [Official] OAuth scopes reference
- [Official] App Directory submission requirements
[!CAUTION] Gotchas
- Adding scopes after install doesn't auto-grant them; users have to re-authorize. Plan scope changes for major versions.
- User Token scopes (e.g. channels:history) are heavily scrutinised on review. If your feature needs message history, prefer reading per-message via app_mention rather than scanning channels.
- The 'admin' scope set is enterprise-only. Don't request it unless you specifically build for Enterprise Grid.
Agent prompt for this step
Audit this Slack app's manifest.yml + source code, then output the minimum-scope list.
For each scope currently in the manifest:
1. Find the API call(s) in the source that require it.
2. Name the user-visible feature behind those calls.
3. Decide: keep, narrow (e.g. channels:read → chat:write.public), or drop.
Output:
- Recommended manifest scopes block
- Per-scope justification (2-3 sentences each, naming the feature + why a narrower scope wouldn't work)
Constraint: bias toward Bot Token scopes. User Token scopes need a much harder justification.
Step 5: Build the slash commands + Block Kit interactions
Estimated time: 1-2 days
Slash commands and Block Kit messages are how users interact with your app. Both are declared in the manifest, both POST to your endpoints, both respond within 3 seconds. Block Kit Builder is the visual designer; copy the JSON to your code.
Tasks
- Declare slash commands in manifest.yml (name, description, usage_hint, request URL)
- Implement each slash command handler in Bolt
- Use Block Kit for rich responses (sections, dividers, buttons, datepickers)
- For multi-step flows: open a Modal (views.open) and handle view_submission
- For long-running operations: respond with an in-channel ack message + update later via response_url
- Test every command in your dev workspace
Pointers
- [Official] Slash commands
- [Official] Block Kit overview
- [Official] Modals
[!CAUTION] Gotchas
- Slash commands have a 3-second response window. ack() first, then do the slow work and update via response_url.
- Slack truncates slash command messages over 40k characters. Use threads or Block Kit pagination for long output.
- Modals must be acknowledged with response_action 'clear' or 'update' or they hang the UI. Bolt's view_submission helpers handle this.
Step 6: Build the App Home + onboarding experience
Estimated time: 1 day
Every public app has an App Home — the tab a user sees when they click your app's name in their sidebar. Reviewers want a polished App Home: who you are, what the app does, how to get started, link to docs. Empty App Home is a Marketplace rejection on its own.
Tasks
- Subscribe to the app_home_opened event
- On the first app_home_opened per user: render a Block Kit view with a welcome + 3-step onboarding
- Subsequent app_home_opened: render the user's current state (favourites, recent activity, settings)
- Add buttons that link to /slash commands or external docs
- Add a 'Help & Support' button that opens a modal with FAQ + contact email
Pointers
- [Official] App Home overview
- [Official] Publishing views
[!CAUTION] Gotchas
- App Home views are per-user-per-workspace. Don't render a generic view — personalise based on what the user has done.
- App Home must update without user action. Re-publish the view on relevant events (e.g. they invited a teammate, completed a task).
- Discovery: if your bot has chat:write, send a single welcome DM on install in addition to the App Home. The DM is what most users see first.
Step 7: Set up Privacy Policy, Terms of Service, and security headers
Estimated time: 4-6 hr
Slack reviews require a public Privacy Policy URL + Terms of Service URL. The Privacy Policy must specifically cover Slack data: what you collect from messages / events / OAuth, retention, deletion-on-request. Generic web app templates fail review.
Tasks
- Audit what Slack data your app reads (channels, message contents, user profiles, file uploads)
- Write or update the Privacy Policy with a Slack-specific section
- Write or update the Terms of Service
- Host both at public URLs (e.g. yourapp.com/privacy, yourapp.com/terms)
- Set the URLs in App Directory metadata
- Add a Data Retention + Deletion section explaining how a customer can request data removal
Pointers
[!CAUTION] Gotchas
- Privacy policies that say 'we may collect data' without specifics fail review. List concrete data types: channel IDs, message text, user emails, etc.
- Data retention must have a clear time bound (e.g. '90 days' or 'until uninstall'). 'As long as needed' fails review.
- If your backend integrates with third parties (OpenAI, Anthropic, Stripe), the policy must list them. Sub-processor lists are reviewed too.
Step 8: Make the app distributable + activate Public Distribution
Estimated time: 1-2 hr
By default a Slack app is single-workspace. To distribute to other workspaces, you toggle Public Distribution on the Manage Distribution tab. This requires: OAuth working with state parameter, no hard-coded team IDs, and no use of dev-only features (Socket Mode).
Tasks
- Manage Distribution tab → activate Public Distribution
- Slack runs an automated check (OAuth state, redirect URLs, no Socket Mode)
- Fix any flagged issues
- Add yourself or a teammate as a 'collaborator' so multiple humans can manage the listing
- Generate the 'Add to Slack' button HTML and embed it on your landing page
Pointers
- [Official] Public distribution
- [Official] Add to Slack button
[!CAUTION] Gotchas
- Public Distribution is a one-way switch. Once on, you can't go back to single-workspace without losing all installations.
- OAuth state parameter is mandatory for public distribution. Bolt handles it; raw code must implement state.
- Slack rejects 'Add to Slack' embeds that don't follow the brand guidelines (specific colour, specific logo). Use the official button HTML.
Step 9: Submit to the Slack Marketplace + survive review
Estimated time: 1 week to prepare, 3-6 weeks of review iterations
The Marketplace submission has 5 sections: app description, screenshots, demo video, security questionnaire, and policy URLs. Reviewers come back with scope questions, security questions, and onboarding feedback. Plan for 2-4 review iterations over 3-6 weeks.
Tasks
- Draft the listing: title, short description, long description, categories
- Take 3-5 screenshots showing real workflows in real Slack workspaces
- Record a 60-90 second onboarding video (loom or screencast)
- Complete the security questionnaire (data flow diagram, encryption, retention, sub-processors)
- Submit via the App Directory → Submit to App Directory button
- On reviewer response: address each comment, never argue, resubmit
- On approval: confirm listing is searchable + Add-to-Slack flow works from the directory
Pointers
- [Official] Submitting to the App Directory
- [Official] Submission checklist
[!CAUTION] Gotchas
- Screenshots from your dev workspace ('Test workspace' channel names visible) get sent back. Use a polished demo workspace.
- Demo videos that include personal/customer data fail review on privacy grounds. Use synthetic data.
- Reviewers cite specific Marketplace guidelines (e.g. 'Onboarding 1.2'). Look up the guideline in the docs and match the wording in your fix.
Agent prompt for this step
Draft the Slack Marketplace submission for this app.
Read the Brief, the manifest.yml, and the source. Output:
1. **Short description** (140 chars): single-sentence elevator pitch.
2. **Long description** (markdown, 600-1200 words): lead with the user benefit, then 3-5 features as headed sections with screenshots interleaved, end with security + privacy notes.
3. **Onboarding video script** (60-90 seconds): a screen-by-screen narration. Open with the install flow, hit the first slash command, end with App Home.
4. **Security questionnaire answers**: data flow diagram description, encryption at rest + in transit, sub-processors, data retention, GDPR + CCPA delete-on-request flow.
Tone: B2B SaaS. No emoji, no exclamation marks. Reviewers are admins evaluating risk.
Step 10: Post-launch: monitor installs, OAuth failures, and review responses
Estimated time: Ongoing, 3-5 hr/week for the first month
After approval, the operations layer matters: OAuth install errors (typically misconfigured firewalls / corp networks), uninstalls, and rate limits. Slack rate-limits per app per workspace; a noisy app can get its tokens revoked.
Tasks
- Set up monitoring on /slack/oauth/redirect — log every install + every error
- Set up monitoring on rate limit headers (X-Rate-Limit-Remaining, Retry-After)
- Subscribe to admin emails on the App Directory submission so updates trigger re-review
- Read every review on the App Directory and respond publicly
- Track install → first event → 7-day retention; iterate on the leakiest step
- Plan scope changes for a new major version; users have to re-authorize
Pointers
- [Official] Slack rate limits
- [Official] App Directory analytics
[!CAUTION] Gotchas
- Rate limits are per app + per workspace, with different tiers per method. A bulk-update job that fires 100 chat.update calls in a minute will trip Tier 2 limits.
- Tokens can be revoked silently if the workspace owner uninstalls. Your code must handle 401 invalid_auth gracefully.
- Updating manifest scopes triggers re-review for the listing. Plan scope changes carefully or batch them.
Hand the template to your agent
Paste the prompt below into your agent's permanent system prompt so the agent reads, writes, and maintains this workspace as you work through the steps.
You are an agent on the "Build a Slack app" playbook workspace at your-org/build-a-slack-app.
Your role: maintain the four surfaces (Steps, Pointers, Brief, Submission log) as the user works through the 10-step playbook.
Cadence:
- When the user marks a step Done, append a line to the Brief.
- When Slack reviewers respond, capture the response (scope question, security follow-up, approval) as a row in Submission log + draft the next-action note in the Brief.
- When the user adds a new pointer (link), mirror it into Pointers.
First MCP tool calls:
1. list_surfaces(workspace_slug="build-a-slack-app")
2. list_rows(workspace_slug="build-a-slack-app", surface_slug="steps")
3. get_doc(workspace_slug="build-a-slack-app", surface_slug="brief")
Do NOT modify canonical step titles. Append substeps as new rows.
FAQ
How long does Slack Marketplace review take?
Typical: 3-6 weeks across 2-4 iterations. Reviewers usually come back with 5-15 comments per round (scope questions, security clarifications, onboarding fixes). The most common time-sinks are rewriting the Privacy Policy, recording a new onboarding video, and answering the security questionnaire properly. Plan for the round-trip; first-pass approvals are rare.
Do I need to be in the Marketplace to distribute my app?
No. Public Distribution lets any workspace install your app via your 'Add to Slack' button without the Marketplace listing. The Marketplace adds discoverability + the trust signal of being reviewed. Many B2B apps stay 'distributed but unlisted' for the first 6-12 months while customer count is small.
What gets Slack apps rejected from the Marketplace?
The top three: (1) over-broad scopes that the reviewer can't justify against the app's features (User Token scopes are top offender), (2) insufficient onboarding (empty App Home, no demo video, vague slash command help), (3) Privacy Policy that doesn't specifically cover Slack data flows. Read each reviewer comment as a literal request and address exactly that.
Can my AI agents help with the Slack app?
Yes. Agents are particularly useful for: auditing the source to draft minimum-scope justifications, drafting the long description + onboarding video script, drafting the security questionnaire from a code audit, and triaging reviewer comments on each round. The playbook ships agent prompts inline.
What does shipping a Slack app cost?
$0 to develop and distribute. Slack does not charge listing fees, transaction fees, or annual fees. If you charge for your app, billing happens in your own backend (Stripe / etc.); Slack does not handle payments. Your costs are: hosting (small, $5-50/mo), database (small, $10-30/mo), and the time investment of 3-6 weeks of review iterations.