Slack chat.delete API: Who Can Delete What, Tested
chat.delete removes a message by channel and ts. We deleted bot messages, a person's messages, a thread parent and an already deleted message with bot and user tokens, and list every response, including cant_delete_message and the tombstone a thread parent leaves.
On this page
To delete a Slack message with the API, call chat.delete with the channel ID and the message ts, using a token with chat:write. A bot token can delete only messages its own bot posted. For anyone else's message it returns cant_delete_message, and you need that person's user token, or the token of an admin who may delete messages in the workspace. We tested each case on 1 October 2026 in our own test workspace.
Delete a message with chat.delete
curl -s https://slack.com/api/chat.delete \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \
-d channel=C0C5UGH9QPL -d ts=1790818270.840989
{"ok": true, "channel": "C0C5UGH9QPL", "ts": "1790818270.840989"}
The ts is the one chat.postMessage returned, or the ts of the message in conversations.history. The message vanished from the channel with no "deleted" line in its place. To find the ts of a message by hand, copy its link: the part after /p in /archives/C0C5UGH9QPL/p1790818270840989 is the ts without the dot.
Who can delete which message
Our test user is the workspace's Primary Owner. These are the results:
| Message | Token | Result |
|---|---|---|
| Posted by our bot | Bot token | ok: true |
| Posted by our bot in #social, a channel the bot never joined | Bot token | ok: true |
| Typed by a person in the Slack app | Bot token | cant_delete_message |
| Posted with the person's user token through our app | Bot token | cant_delete_message |
| Typed by a person in the Slack app | That person's user token | ok: true |
| Posted by our bot | The Primary Owner's user token | ok: true |
The fourth row is easy to get wrong. A message your app posted with a user token belongs to that user, not to your bot, even though Slack shows it with your app's name. Your bot token cannot delete it.
The last row worked because our user is the Primary Owner. The workspace has no other members, so we could not test a regular member's user token on someone else's message. The cant_delete_message response, in full:
{"ok": false, "error": "cant_delete_message"}
Never appear "away" on Slack again
Cloud-based. No downloads. Works 24/7 even when your laptop is off.
message_not_found and the other errors
| What we sent | Response |
|---|---|
A ts we had already deleted | {"ok": false, "error": "message_not_found"} |
A real ts with the wrong channel ID | {"ok": false, "error": "message_not_found"} |
ts=12345 | {"ok": false, "error": "message_not_found"} |
No ts at all | invalid_arguments, with [ERROR] missing required field: ts |
The message_ts of an ephemeral message | {"ok": false, "error": "message_not_found"} |
message_not_found does not tell you whether the message is gone or your channel ID is wrong. If a delete that should work returns it, check that the channel ID is the one the message was posted in. Ephemeral messages cannot be deleted this way at all; Slack ephemeral messages shows the response_url call that does remove them.
Deleting a thread parent
We posted a parent with two replies from the bot and deleted the parent. The replies stayed, and the parent turned into a placeholder:
conversations.history returned it as a tombstone:
{"subtype": "tombstone", "text": "This message was deleted.", "user": "USLACKBOT", "hidden": true, "type": "message", "ts": "1790818289.911899", "thread_ts": "1790818289.911899", "reply_count": 2}
When we then deleted both replies, the tombstone left the channel and conversations.history too. Deleting the tombstone itself returned message_not_found. So to remove a whole thread without a trace, delete the replies as well as the parent. Replies come from conversations.replies, as in our channel history script.
FAQ
Does a deleted message leave a trace in the channel? Not a plain message. Ours disappeared with nothing in its place; only the thread parent left a placeholder. Whether the company can still read a deleted message depends on the workspace's retention settings, explained in can Slack see deleted messages.
Can I delete many messages at once?
No, chat.delete takes one ts per call. Loop over the ts values, and keep under the rate limits in Slack API rate limits.
Stop Jiggling Your Mouse.
Join hundreds of remote workers who never worry about their Slack status. Set it up once, stay green forever.
Related Articles
Slack OAuth Redirect URL on localhost: What Slack Accepts, Tested
We added localhost, 127.0.0.1, https, custom-scheme and tunnel redirect URLs to a Slack app on 1 October 2026, then ran the OAuth flow against a local server. What was accepted, how Slack matches the URL, and the PKCE rules.
Slack App Manifest Example: YAML and JSON That Worked, Tested
A Slack app manifest we used to create a working app on 1 October 2026, in YAML and JSON, plus the validation errors from broken versions and real output from apps.manifest.validate, export, create and update.
Slack expired_trigger_id: How Long a trigger_id Lasts, Measured
We opened a Slack modal with views.open after delays from 0 to 5 seconds, 28 times, on 1 October 2026. The success rate per delay, the exact errors, and the Bolt code that avoids expired_trigger_id.