Documentation 40

Guide · Slack · 3 min read

Where do I get deterministic test data for a Slack bot?

From a Slack Web API replica that answers the same bytes on every run. It holds a simulated company's channels, users and threads, so a bot's tests can assert exact messages instead of mocking them.

01 / The host

Point the bot at the pinned Slack host.

Change the Web API base from slack.com/api to https://slack-2026-08-g12.snap.sandboxapis.dev/api. That pin, the one the eval pack is verified on, never changes, which is what a test suite needs.

The live host, slack.sandboxapis.dev, re-rolls daily and can carry a newer generation of the data set than slack-2026-08-g12.snap.sandboxapis.dev; every answer on this page is for slack-2026-08-g12.snap.sandboxapis.dev.

02 / Read a thread

The message that opened an incident.

This is the first request of the four-hop walk, asked of the pin: the newest message in the incident channel CF1UPUMGC8Q.

request.sh
curl -s "https://slack-2026-08-g12.snap.sandboxapis.dev/api/conversations.history?channel=CF1UPUMGC8Q&limit=1"

It answers with ts 1781726237.230977 and a reply_count of 11, today and on every later run. The thread's replies, the users who posted them and the Jira ticket and pull request the thread is about all exist and agree with each other.

03 / Why it repeats

Same request, same bytes.

A pinned host serves one compiled, read-only file that no request can change, and the build fails if the compiler stops reproducing it byte for byte. Nothing another caller does reaches what you read, so a snapshot test of your bot's output stays green until your code changes.

04 / A bot that posts

Scratch writes: yours, for a day.

By default chat.postMessage gets Slack's own error, because the host is read-only. Turn on scratch writes for one key in your dashboard and that key can post to a channel that exists, or reply in a thread. The message then appears in that key's conversations.history and conversations.replies, for 24 hours, and to no other key. A caller without a scratch key, including the pin your CI reads, gets exactly the bytes it got before.

request.sh
curl -s -X POST "https://slack-2026-08-g12.snap.sandboxapis.dev/api/chat.postMessage" -H "Authorization: Bearer $KEY" \
  -H "content-type: application/json" \
  -d '{"channel":"CF1UPUMGC8Q","thread_ts":"1781726237.230977","text":"Bot test reply"}'

05 / Budget

Enough for a test suite.

With no key, every host shares an anonymous budget of 60 requests an hour per address. A free key raises it to 600 an hour and is the key that can opt in to scratch writes. Next: the Slack agent tutorial.

What this is not

Read this before you rely on it.

SandboxAPIs is read-only: a write returns the provider's own error unless your key has opted in to scratch writes, and those never reach anybody else. Coverage is bounded, and the manifest that says exactly where it stops is public. The data is a simulated company, not yours and not a copy of anybody's. And it reproduces what each vendor documents and publishes, not the vendor's undocumented behaviour, so keep one test against the real service for that.