// Delete messages older than 6 months (4,380 hours)
const response = await client.post("/retention_policy", {
policy: "old-messages",
max_age_hours: 4380,
});
// Delete channels inactive for more than 6 months
const response = await client.post("/retention_policy", {
policy: "inactive-channels",
max_age_hours: 4380,
});Data Retention Policy
The Data Retention Policy feature allows you to automatically clean up old messages and inactive channels from your application. This helps you manage storage costs, comply with data governance requirements, and keep your application focused on relevant, recent data.
Data retention cleanup permanently deletes data. Deleted messages, channels, and their associated data (reactions, attachments, members, etc.) cannot be recovered. Make sure you understand the implications before enabling retention policies.
Overview
Stream Chat supports two types of retention policies:
- Old Messages (
old-messages): Automatically deletes messages older than a specified age. - Inactive Channels (
inactive-channels): Automatically deletes channels that have been inactive for longer than a specified period. A channel is considered inactive based on the most recent of itscreated_at,updated_at, orlast_message_attimestamps.
Key characteristics:
- Retention policies are configured at the app level using server-side API calls
- Data is hard-deleted, not archived — deleted data cannot be recovered
- Minimum retention age is 24 hours, maximum is 10 years (87,600 hours)
- A 24-hour grace period applies after enabling or updating a policy before any cleanup begins
- Cleanup runs asynchronously in the background — after enabling a policy, it may take hours or even days for all eligible data to be removed depending on the volume of data. During this period, expired data may still appear in API responses
- Both policy types can be active simultaneously
- When a policy is enabled or updated, email notifications are sent to all admin team members
- Retention policy settings and cleanup run history are visible in the Stream Dashboard
The Retention Policy API is a server-side only feature. All endpoints require authentication with a server-side API key. Client-side tokens cannot access these endpoints.
Setting a Retention Policy
To enable automatic cleanup, create a retention policy by specifying the policy type and the maximum age in hours.
# Delete messages older than 6 months (4,380 hours)
response = client.post("/retention_policy", data={
"policy": "old-messages",
"max_age_hours": 4380,
})
# Delete channels inactive for more than 6 months
response = client.post("/retention_policy", data={
"policy": "inactive-channels",
"max_age_hours": 4380,
})# Delete messages older than 6 months (4,380 hours)
client.post("/retention_policy", data: {
policy: "old-messages",
max_age_hours: 4380
})
# Delete channels inactive for more than 6 months
client.post("/retention_policy", data: {
policy: "inactive-channels",
max_age_hours: 4380
})// Delete messages older than 6 months (4,380 hours)
$response = $client->post('/retention_policy', [
'policy' => 'old-messages',
'max_age_hours' => 4380,
]);
// Delete channels inactive for more than 6 months
$response = $client->post('/retention_policy', [
'policy' => 'inactive-channels',
'max_age_hours' => 4380,
]);// Delete messages older than 6 months (4,380 hours)
resp, err := client.Post("/retention_policy", map[string]interface{}{
"policy": "old-messages",
"max_age_hours": 4380,
})
// Delete channels inactive for more than 6 months
resp, err := client.Post("/retention_policy", map[string]interface{}{
"policy": "inactive-channels",
"max_age_hours": 4380,
})// Delete messages older than 6 months (4,380 hours)
var response = client.post("/retention_policy", Map.of(
"policy", "old-messages",
"max_age_hours", 4380
));
// Delete channels inactive for more than 6 months
var response = client.post("/retention_policy", Map.of(
"policy", "inactive-channels",
"max_age_hours", 4380
));// Delete messages older than 6 months (4,380 hours)
var response = await client.PostAsync("/retention_policy", new
{
policy = "old-messages",
max_age_hours = 4380,
});
// Delete channels inactive for more than 6 months
var response = await client.PostAsync("/retention_policy", new
{
policy = "inactive-channels",
max_age_hours = 4380,
});Request Parameters
| Field | Type | Description | Required |
|---|---|---|---|
policy | string | The policy type: old-messages or inactive-channels | Yes |
max_age_hours | integer | Maximum age in hours before data is eligible for deletion. Must be between 24 and 87,600 (10 years). | Yes |
If a policy already exists for the specified type, calling this endpoint again will update the existing policy with the new max_age_hours value.
Retrieving Retention Policies
Retrieve all active retention policies for your application.
const response = await client.get("/retention_policy");
console.log(response.retention_policies);
// [
// { policy: "old-messages", config: { max_age_hours: 4380 }, enabled_at: "..." },
// { policy: "inactive-channels", config: { max_age_hours: 8760 }, enabled_at: "..." }
// ]response = client.get("/retention_policy")
print(response["retention_policies"])resp, err := client.Get("/retention_policy")Deleting a Retention Policy
Remove a retention policy to stop automatic cleanup for that policy type. Data that has already been deleted cannot be recovered.
// Stop deleting old messages
await client.post("/retention_policy/delete", {
policy: "old-messages",
});
// Stop deleting inactive channels
await client.post("/retention_policy/delete", {
policy: "inactive-channels",
});# Stop deleting old messages
client.post("/retention_policy/delete", data={
"policy": "old-messages",
})// Stop deleting old messages
resp, err := client.Post("/retention_policy/delete", map[string]interface{}{
"policy": "old-messages",
})Viewing Cleanup Run History
You can monitor the progress and history of retention cleanup runs. This is useful for verifying that cleanup is working as expected and understanding how much data has been removed.
// Get the latest cleanup runs
const response = await client.get("/retention_policy/runs", {
limit: 10,
offset: 0,
});
console.log(response.retention_policy_runs);
// [
// {
// policy: "old-messages",
// date: "2026-03-20",
// started_at: "2026-03-20T02:00:00Z",
// finished_at: "2026-03-20T02:15:30Z",
// status: "completed",
// stats: { messages_deleted: 15420 }
// }
// ]response = client.get("/retention_policy/runs", params={
"limit": 10,
"offset": 0,
})
print(response["retention_policy_runs"])resp, err := client.Get("/retention_policy/runs?limit=10&offset=0")Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 25 | Number of runs to return (max 100) |
offset | integer | 0 | Offset for pagination |