Daily standup digest: Slack → Notion
Collect standup thread replies, summarise them, file the digest in Notion.
Async standups die when nobody reads them. This workflow prompts the team in #standup on a schedule, waits for thread replies, then summarises the thread into Highlights / Blockers / Shipped and appends one page per day to a Notion database. The thread stays the source of truth; Notion becomes the searchable archive your manager actually reads.
How it flows
- 01
Scheduled prompt posts at 09:30
Workflow Builder posts the standup question into #standup; that message's ts is the thread root everything else hangs off.
- 02
Team replies in-thread until 10:30
One reply per person. Late replies are simply excluded — the cutoff is what makes the digest arrive on time.
- 03
Cutoff job pulls the thread
conversations.history recovers the prompt ts, conversations.replies returns the thread; bot messages and the prompt are filtered out.
- 04
AI summarises into three buckets
Highlights, Blockers, Shipped. Blockers are extracted as discrete labels so they can drive a multi-select.
- 05
Digest lands in Notion
One new page per day in Standup Log, linked back to the original Slack thread.
- 06
Link posted back into the thread
A single reply with the Notion URL, so the archive is discoverable from where the conversation happened.
Set up each app
Work through these in order — later apps usually need a token or an id from an earlier one.
Slack
Prompts the team and holds the raw thread
- 01
Schedule the standup prompt
Click Tools in the Slack sidebar (if you do not see Tools, look for Automations) → Workflows → New, top right → Build Workflow → Choose an event → On a schedule. Set 09:30 on weekdays, pick #standup as the channel, and have it post the prompt message. Every reply must land in that message's thread — say so in the prompt text, or people will reply in-channel and the digest will miss them.
- 02
Create a bot token with history scopes
api.slack.com/apps → Create New App → From scratch → OAuth & Permissions → Bot Token Scopes. Add the four scopes below, reinstall the app, then invite it to the channel with /invite @standup-digest.
Bot Token Scopeschannels:history # read the prompt message and its replies in a public #standup channels:read # resolve the channel id from its name chat:write # post the digest link back into the thread users:read # map user ids to display names - 03
Recover the ts of the prompt message
Workflow Builder never hands your app the ts of the message it posted, and conversations.replies cannot run without one — this is the step people discover after everything else already works. At the cutoff, call conversations.history on the same channel with an oldest of midnight, find today's prompt (match on the bot user id that posted it), and use its ts as the thread root.
conversations.historycurl -s -G "https://slack.com/api/conversations.history" \ -H "Authorization: Bearer $SLACK_BOT_TOKEN" \ -d channel=C04STANDUP \ -d oldest=1770768000 \ -d limit=50 - 04
Read the thread at the cutoff
At 10:30 fetch the replies with conversations.replies, passing that ts as the thread root. Drop bot messages and the prompt itself before summarising. limit=200 holds for an internal custom app on Tier 3; distribute the app outside the Marketplace and it drops to 15 results and one request a minute, at which point the cutoff job needs pagination.
conversations.repliescurl -s "https://slack.com/api/conversations.replies" \ -H "Authorization: Bearer $SLACK_BOT_TOKEN" \ -d channel=C04STANDUP \ -d ts=1770802200.001900 \ -d limit=200
Notion
Searchable archive, one page per standup
- 01
Create the "Standup Log" database
Create a new page and under "Get started with" pick Table; typing /database inside an existing page does the same thing. Add exactly these properties (names matter, the API writes to them by name): Name (Title), Date (Date), Team (Select), Highlights (Text), Blockers (Multi-select), Thread (URL), Participants (Number).
- 02
Create an internal connection
app.notion.com/developers/connections (Settings → Connections → "Develop your own connections") → Build → Internal connections → Create a new connection → name it and pick the workspace → Configuration tab → copy the Installation access token. Notion calls these connections now, not integrations. Then open the database → ••• (top right) → Connections → + Add connection → your connection → confirm access. Skipping that last part is the usual cause of a 404 from the API on a database you can plainly see.
- 03
Append the digest page
POST the summary to /v1/pages. Notion-Version is required and 2026-03-11 is the current one. The pre-2025 versions still floating around in old tutorials predate the database/data-source split, so they hold only while a database has exactly one data source: page creation with a database_id parent breaks the day someone adds a second. Retrieve the database once, keep its data source id, and parent on that instead.
POST https://api.notion.com/v1/pages · Notion-Version: 2026-03-11{ "parent": { "type": "data_source_id", "data_source_id": "8f2c1d0e4b7a4c9f8e1d2c3b4a5f6e7d" }, "properties": { "Name": { "title": [{ "text": { "content": "Standup — 2026-02-11" } }] }, "Date": { "date": { "start": "2026-02-11" } }, "Team": { "select": { "name": "Platform" } }, "Highlights": { "rich_text": [{ "text": { "content": "Billing migration is on staging." } }] }, "Blockers": { "multi_select": [{ "name": "waiting-on-review" }] }, "Thread": { "url": "https://acme.slack.com/archives/C04STANDUP/p1770802200001900" }, "Participants": { "number": 7 } } }