Deleting Channels
You can delete or truncate a channel to remove its contents. To remove only messages while preserving the channel, see Truncate Channel.
Deleting a Channel
You can delete a single Channel using the delete method. This marks the channel as deleted and hides all the messages.
# Get a channel
channel = client.chat.channel("messaging", "general")
channel.delete()If you recreate this channel, it will show up empty. Recovering old messages is not supported, unless the channel was deleted with skip_truncate (see Preserving message history below). Use the disable method if you want a fully reversible change.
Preserving Message History
By default, deleting a channel hides its messages, so a channel later recreated with the same ID starts out empty. Set skip_truncate to true to preserve message history through the delete instead, so a channel later recreated with the same ID (for example with GetOrCreateChannel) restores the full message history.
This is useful for apps where the same pair of users can end up back in the same channel, for example a dating app where two users unmatch and later re-match.
skip_truncate is server-side only and only supported on distinct channels. It cannot be combined with hard_delete, and it cannot be used if the channel's messages were already hidden by an earlier delete or truncate.
channel = client.chat.channel("messaging", "general")
# Preserve history through the soft delete
channel.delete(skip_truncate=True)Deleting Many Channels
You can delete up to 100 channels and optionally all of their messages using this method. This can be a large amount of data to delete, so this endpoint processes asynchronously, meaning responses contain a task ID which can be polled using the getTask endpoint to check status of the deletions. Channels will be soft-deleted immediately so that channels no longer return from queries, but permanently deleting the channel and deleting messages takes longer to process.
By default, messages are soft deleted, which means they are removed from client but are still available via server-side export functions. You can also hard delete messages, which deletes them from everywhere, by setting "hard_delete": true in the request. Messages that have been soft or hard deleted cannot be recovered.
You can also set skip_truncate to true to preserve message history for every channel in the request, the same as for a single channel delete. If any of the given CIDs is not eligible (it isn't a distinct channel, or its messages were already hidden by an earlier delete or truncate), the entire request is rejected and none of the channels are deleted.
This is currently supported on the following SDK versions (or higher):
- Javascript 4.3.0, Python 3.14.0, Ruby 2.12.0, PHP 2.6.0, Go 3.13.0, Java 1.4.0, Unity 2.0.0 and .NET 0.22.0
# soft deletion
response = client.chat.delete_channels(cids=[cid1, cid2])
# hard deletion
response = client.chat.delete_channels(cids=[cid1, cid2], hard_delete=True)
task_response = client.get_task(id=response.data.task_id)
if task_response.data.status == "completed":
# success!
pass
# preserve history (distinct channels only)
response = client.chat.delete_channels(cids=[cid1, cid2], skip_truncate=True)The deleteChannels response contain a taskID which can be polled using the getTask endpoint to check the status of the deletions.
Finding and purging soft-deleted channels
A soft-deleted channel no longer appears in query channels results, but its channel record and messages are kept until the channel is hard deleted. To erase that data, for example to handle a GDPR erasure request, list the soft-deleted channels with queryDeletedChannels, then pass their CIDs to delete many channels with hard_delete set to true.
queryDeletedChannels is server-side only. Calls made with a user token are rejected with a 403.
filter_conditions is optional. Omit it, or pass {}, to list every soft-deleted channel of your app. In a multi-tenant app, filter by team to list the soft-deleted channels of one tenant. See Multi-tenancy for assigning channels to a team.
The example below purges every soft-deleted channel of the app. To purge a single tenant instead, use the commented team filter. Each page holds up to 100 channels, which is also the maximum number of CIDs a single delete call accepts, so every page maps to one delete call.
# Every soft-deleted channel of the app
filter_conditions = {}
# Only the soft-deleted channels of one team
# filter_conditions = {"team": "tenant-a"}
next_cursor = None
while True:
response = client.chat.query_deleted_channels(
filter_conditions=filter_conditions,
limit=100,
next=next_cursor,
)
cids = [channel.cid for channel in response.data.channels]
if cids:
client.chat.delete_channels(cids=cids, hard_delete=True)
next_cursor = response.data.next
if not next_cursor:
breakPurge with the delete many channels endpoint, as above. The single-channel delete does not accept a channel that is already soft-deleted: it responds that the channel does not exist, so it cannot purge the channels that queryDeletedChannels returns.
Hard deletes are processed asynchronously, so a channel keeps appearing in queryDeletedChannels results until its deletion task completes. Follow the next cursor rather than starting again from the first page, and poll the returned task IDs with the getTask endpoint if you need to confirm that the deletions have finished.
Request parameters
| Name | Type | Description | Default | Optional |
|---|---|---|---|---|
filter_conditions |
object | Filter for the soft-deleted channels to return. Omit it, or pass {}, to list every soft-deleted channel of the app. See filterable fields below. |
{} |
Yes |
sort |
array | Sort order. Only created_at is supported, ascending (1) or descending (-1). |
[{ field: "created_at", direction: 1 }] |
Yes |
limit |
integer | Number of channels per page, from 1 to 100. | 25 |
Yes |
next |
string | Cursor for the next page, taken from the previous response. | Yes | |
prev |
string | Cursor for the previous page, taken from the previous response. A request can set next or prev, not both. |
Yes |
The response contains channels, the soft-deleted channels matching the filter, plus the next and prev cursors. Each channel is returned as a channel object with deleted_at set. Messages, members and read state are not included.
Filterable fields
| Field | Operators | Notes |
|---|---|---|
team |
$eq, $in |
Narrows the list to one tenant. |
cid |
$eq, $in |
$in accepts at most 100 CIDs. |
type |
$eq, $in |
|
created_by_id |
$eq, $in |
|
created_at |
$gt, $gte, $lt, $lte |
Use a range to split a large result. |
deleted_at |
$gt, $gte, $lt, $lte |
Only fields that a soft delete leaves intact can be filtered on:
- Custom fields are not supported. Soft-deleting a channel clears its custom data, so a tenant identified only by a custom field cannot be found this way. Use
teamto identify tenants, or keep a record of the CIDs you delete. - Membership filters such as
membersare not supported. Deleting a channel removes its members.
Things to know
- Errors: the request is rejected with a
400when the filter uses an unsupported field or operator (such as a custom field ormembers), whensortuses a field other thancreated_at, when acid$inlists more than 100 CIDs, whenlimitis below 1, or when bothnextandprevare set. A page that takes too long to read returns a408. Narrow the filter with acreated_atrange, or query bycid, and retry. - Duplicate
channel.deletedevents: hard-deleting a channel that was already soft-deleted sends thechannel.deletedevent again. Make your webhook handlers idempotent for this event. - Deleted channel types: a soft-deleted channel whose channel type was deleted afterwards is still listed, with
configset tonull, and can still be hard deleted server-side. Nochannel.deletedevent is sent when it is hard deleted. - Recreated channels: if a listed channel is recreated with the same ID before you delete it, it is a live channel again, and passing its CID to the delete call deletes it again. Delete each page promptly after listing it.