WorkflowsMCP

Daily standup digest: Slack → Notion

Collect standup thread replies, summarise them, file the digest in Notion.

@workflowsmcpApr 2, 2026Verified Aug 2026standupasync-updatesai-summaryautomation

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

  1. 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.

  2. 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.

  3. 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.

  4. 04

    AI summarises into three buckets

    Highlights, Blockers, Shipped. Blockers are extracted as discrete labels so they can drive a multi-select.

  5. 05

    Digest lands in Notion

    One new page per day in Standup Log, linked back to the original Slack thread.

  6. 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

  1. 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.

  2. 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 Scopes
    channels: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
  3. 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.history
    curl -s -G "https://slack.com/api/conversations.history" \
      -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
      -d channel=C04STANDUP \
      -d oldest=1770768000 \
      -d limit=50
  4. 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.replies
    curl -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

  1. 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).

  2. 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.

  3. 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 }
      }
    }