# Reminders & Bookmarks

Message reminders let users schedule notifications for specific messages, making it easier to follow up later. When a reminder includes a timestamp, it's like saying "remind me later about this message," and the user who set it will receive a notification at the designated time. If no timestamp is provided, the reminder functions more like a bookmark, allowing the user to save the message for later reference.

Reminders require Push V3 to be enabled - see details [here](/chat/docs/<framework>/push_template/)

## Enabling Reminders

The Message Reminders feature must be activated at the channel level before it can be used. You have two configuration options: activate it for a single channel using configuration overrides, or enable it globally for all channels of a particular type.

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
// Enabling it for a channel
await channel.updatePartial({
  config_overrides: {
    user_message_reminders: true,
  },
});

// Enabling it for a channel type
const update = await client.updateChannelType("messaging", {
  user_message_reminders: true,
});
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
// Enabling it for a channel
$client->updateChannelPartial("messaging", "general", new Models\UpdateChannelPartialRequest(
    set: (object)["config_overrides" => (object)["user_message_reminders" => true]],
));

// Enabling it for a channel type
$client->updateChannelType("messaging", new Models\UpdateChannelTypeRequest(
    userMessageReminders: true,
));
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
require 'getstream_ruby'
Models = GetStream::Generated::Models

# Enabling it for a channel
client.chat.update_channel_partial('messaging', channel_id, Models::UpdateChannelPartialRequest.new(
  set: { 'config_overrides' => { 'user_message_reminders' => true } }
))

# Enabling it for a channel type
client.chat.update_channel_type('messaging', Models::UpdateChannelTypeRequest.new(
  user_message_reminders: true,
  automod: 'disabled',
  automod_behavior: 'flag',
  max_message_length: 5000
))
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
// Enabling it for a channel
await chat.UpdateChannelPartialAsync("messaging", channelId,
    new UpdateChannelPartialRequest
    {
        Set = new Dictionary<string, object>
        {
            ["config_overrides"] = new Dictionary<string, object> { ["user_message_reminders"] = true }
        }
    });

// Enabling it for a channel type
await chat.UpdateChannelTypeAsync("messaging", new UpdateChannelTypeRequest
{
    UserMessageReminders = true,
    Automod = "disabled",
    AutomodBehavior = "flag",
    MaxMessageLength = 5000
});
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
// Backend SDK

// Enabling it for a channel type
chat.updateChannelType("messaging", UpdateChannelTypeRequest.builder()
    .userMessageReminders(true)
    .automod("disabled")
    .automodBehavior("flag")
    .maxMessageLength(5000)
    .build()).execute();
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
# Enabling it for a channel
channel.update_channel_partial(
    set={"config_overrides": {"user_message_reminders": True}}
)

# Enabling it for a channel type
client.chat.update_channel_type(
    name="messaging",
    automod="disabled",
    automod_behavior="flag",
    max_message_length=5000,
    user_message_reminders=True,
)
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
// Enabling it for a channel
channel.UpdateChannelPartial(ctx, &getstream.UpdateChannelPartialRequest{
    Set: map[string]any{
        "config_overrides": map[string]any{
            "user_message_reminders": true,
        },
    },
})

// Enabling it for a channel type
client.Chat().UpdateChannelType(ctx, "messaging", &getstream.UpdateChannelTypeRequest{
    UserMessageReminders: getstream.PtrTo(true),
    Automod:              "disabled",
    AutomodBehavior:      "flag",
    MaxMessageLength:     5000,
})
```

</codetabs-item>

</codetabs>

Message reminders allow users to:

- schedule a notification after given amount of time has elapsed
- bookmark a message without specifying a deadline

## Limits

- A user cannot have more than 250 reminders scheduled
- A user can only have one reminder created per message

## Creating a Message Reminder

You can create a reminder for any message. When creating a reminder, you can specify a reminder time or save it for later without a specific time.

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
// Backend SDK
// Create a reminder with a specific due date
const reminder = await client.createReminder(
  "message-id",
  "user-id",
  new Date(Date.now() + 3600000),
);

// Create a "Save for later" reminder without a specific time
const reminder = await client.createReminder("message-id", "user-id");

// JavaScript SDK
// Create a reminder with a specific due date (direct API call)
await client.createReminder({
  messageId: "message-id",
  // Remind in offsetMs
  remind_at: new Date(new Date().getTime() + offsetMs).toISOString(),
});

// Create a reminder with a specific due date (client state optimistic update (no server-side use))
await client.reminders.upsertReminder({
  messageId: "message-id",
  remind_at: new Date(new Date().getTime() + offsetMs).toISOString(),
});

// Create a "Save for later" reminder without a specific time (direct API call)
await client.createReminder({
  messageId: "message-id",
});

// Create a "Save for later" reminder without a specific time (client state optimistic update (no server-side use))
await client.reminders.upsertReminder({
  messageId: "message-id",
});
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
// Create a reminder with a specific due date
$client->createReminder("message-id", new Models\CreateReminderRequest(
    remindAt: new \DateTime("+1 hour"),
    userID: "user-id",
));

// Create a "Save for later" reminder without a specific time
$client->createReminder("message-id", new Models\CreateReminderRequest(
    userID: "user-id",
));
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
require 'getstream_ruby'
Models = GetStream::Generated::Models

# Create a reminder with a specific due date
reminder = client.chat.create_reminder('message-id', Models::CreateReminderRequest.new(
  user_id: 'user-id',
  remind_at: (Time.now + 3600).utc.iso8601
))

# Create a "Save for later" reminder without a specific time
reminder = client.chat.create_reminder('message-id', Models::CreateReminderRequest.new(
  user_id: 'user-id'
))
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
// Create a reminder with a specific due date
await chat.CreateReminderAsync("message-id", new CreateReminderRequest
{
    RemindAt = DateTime.UtcNow.AddHours(1),
    UserID = "user-id"
});

// Create a "Save for later" reminder without a specific time
await chat.CreateReminderAsync("message-id", new CreateReminderRequest
{
    UserID = "user-id"
});
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
// Backend SDK

// Create a reminder with a specific due date
Calendar cal = Calendar.getInstance();
cal.add(Calendar.HOUR, 1);
Date remindAt = cal.getTime();

chat.createReminder("message-id", CreateReminderRequest.builder()
    .remindAt(remindAt)
    .userID("user-id")
    .build()).execute();

// Create a "Save for later" reminder without a specific time
chat.createReminder("message-id", CreateReminderRequest.builder()
    .userID("user-id")
    .build()).execute();
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
from datetime import datetime, timedelta

# Create a reminder with a specific due date
remind_at = datetime.now() + timedelta(hours=1)
reminder = client.chat.create_reminder(
    message_id="message-id", user_id="user-id", remind_at=remind_at
)

# Create a "Save for later" reminder without a specific time
reminder = client.chat.create_reminder(message_id="message-id", user_id="user-id")
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
import "time"

// Create a reminder with a specific due date
t := time.Now().Add(time.Hour)
remindAt := getstream.Timestamp{Time: &t}
resp, err := client.Chat().CreateReminder(ctx, "message-id", &getstream.CreateReminderRequest{
    RemindAt: &remindAt,
    UserID:   getstream.PtrTo("user-id"),
})

// Create a "Save for later" reminder without a specific time
resp, err := client.Chat().CreateReminder(ctx, "message-id", &getstream.CreateReminderRequest{
    UserID: getstream.PtrTo("user-id"),
})
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
// Get a message controller for the message
let messageController = chatClient.messageController(
    cid: ChannelId(type: .messaging, id: "general"),
    messageId: "message-id"
)

// Create a reminder with a specific due date
messageController.createReminder(
    remindAt: Date().addingTimeInterval(3600) // Reminder in 1 hour
) { result in
    switch result {
    case .success(let reminder):
        print("Reminder created: \(reminder)")
    case .failure(let error):
        print("Failed to create reminder: \(error)")
    }
}

// Create a "Save for later" reminder without a specific time
messageController.createReminder(
    remindAt: nil // No specific reminder time
) { result in
    switch result {
    case .success(let reminder):
        print("Message saved for later: \(reminder)")
    case .failure(let error):
        print("Failed to save message for later: \(error)")
    }
}
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
// Create a reminder with a specific due date
client.createReminder(
    messageId = "message-id",
    // Remind in 1 hour
    remindAt = Date().apply { time += 1.hours.inWholeMilliseconds }
).enqueue { /* ... */ }

// Create a "Save for later" reminder without a specific time
client.createReminder(
    messageId = "message-id",
    remindAt = null, // No specific remind time
).enqueue { /* ... */ }
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
// Create a reminder with a specific due date
await client.createReminder(
  messageId,
  // Remind in 1 hour
  remindAt: DateTime.now().add(const Duration(hours: 1)),
);

// Create a "Save for later" reminder without a specific time
await client.createReminder(messageId);
```

</codetabs-item>

</codetabs>

## Updating a Message Reminder

You can update an existing reminder for a message to change the reminder time.

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
// Backend SDK
// Update a reminder with a new due date
const updatedReminder = await client.updateReminder(
  "message-id",
  "user-id",
  new Date(Date.now() + 7200000),
);

// Convert a timed reminder to "Save for later"
const updatedReminder = await client.updateReminder(
  "message-id",
  "user-id",
  null,
);

// JavaScript SDK
// Update a reminder with a new due date (direct API call)
await client.updateReminder({
  messageId: "message-id",
  // Remind in newOffsetMs
  remind_at: new Date(new Date().getTime() + newOffsetMs).toISOString(),
  // in case of server-side integration, include the id of a user on behalf of which the reminder is created
  //user_id: 'some-user-id'
});

// Update a reminder with a new due date (client state optimistic update (no server-side use))
await client.reminders.upsertReminder({
  messageId: "message-id",
  // Remind in newOffsetMs
  remind_at: new Date(new Date().getTime() + newOffsetMs).toISOString(),
  // in case of server-side integration, include the id of a user on behalf of which the reminder is created
  //user_id: 'some-user-id'
});

// Convert a timed reminder to "Save for later" (direct API call)
await client.updateReminder({
  messageId: "message-id",
  remind_at: null,
  // in case of server-side integration, include the id of a user on behalf of which the reminder is created
  //user_id: 'some-user-id'
});

// Convert a timed reminder to "Save for later" (client state optimistic update (no server-side use))
await client.reminders.upsertReminder({
  messageId: "message-id",
  remind_at: null,
});
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
// Update a reminder with a new due date
$client->updateReminder("message-id", new Models\UpdateReminderRequest(
    remindAt: new \DateTime("+2 hours"),
    userID: "user-id",
));

// Convert a timed reminder to "Save for later"
$client->updateReminder("message-id", new Models\UpdateReminderRequest(
    remindAt: null,
    userID: "user-id",
));
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
require 'getstream_ruby'
Models = GetStream::Generated::Models

# Update a reminder with a new due date
updated_reminder = client.chat.update_reminder('message-id', Models::UpdateReminderRequest.new(
  user_id: 'user-id',
  remind_at: (Time.now + 7200).utc.iso8601
))

# Convert a timed reminder to "Save for later"
updated_reminder = client.chat.update_reminder('message-id', Models::UpdateReminderRequest.new(
  user_id: 'user-id',
  remind_at: nil
))
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
// Update a reminder with a new due date
await chat.UpdateReminderAsync("message-id", new UpdateReminderRequest
{
    RemindAt = DateTime.UtcNow.AddHours(2),
    UserID = "user-id"
});

// Convert a timed reminder to "Save for later"
await chat.UpdateReminderAsync("message-id", new UpdateReminderRequest
{
    RemindAt = null,
    UserID = "user-id"
});
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
// Backend SDK

// Update a reminder with a new due date
Calendar cal = Calendar.getInstance();
cal.add(Calendar.HOUR, 2);
Date remindAt = cal.getTime();

chat.updateReminder("message-id", UpdateReminderRequest.builder()
    .remindAt(remindAt)
    .userID("user-id")
    .build()).execute();

// Convert a timed reminder to "Save for later"
chat.updateReminder("message-id", UpdateReminderRequest.builder()
    .remindAt(null)
    .userID("user-id")
    .build()).execute();
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
from datetime import datetime, timedelta

# Update a reminder with a new due date
remind_at = datetime.now() + timedelta(hours=2)
updated_reminder = client.chat.update_reminder(
    message_id="message-id", user_id="user-id", remind_at=remind_at
)

# Convert a timed reminder to "Save for later"
updated_reminder = client.chat.update_reminder(
    message_id="message-id", user_id="user-id", remind_at=None
)
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
import "time"

// Update a reminder with a new due date
t := time.Now().Add(2 * time.Hour)
remindAt := getstream.Timestamp{Time: &t}
resp, err := client.Chat().UpdateReminder(ctx, "message-id", &getstream.UpdateReminderRequest{
    RemindAt: &remindAt,
    UserID:   getstream.PtrTo("user-id"),
})

// Convert a timed reminder to "Save for later"
resp, err := client.Chat().UpdateReminder(ctx, "message-id", &getstream.UpdateReminderRequest{
    UserID: getstream.PtrTo("user-id"),
})
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
// Get a message controller for the message
let messageController = chatClient.messageController(
    cid: ChannelId(type: .messaging, id: "general"),
    messageId: "message-id"
)

// Update a reminder with a new due date
messageController.updateReminder(
    remindAt: Date().addingTimeInterval(7200) // New reminder time (2 hours)
) { result in
    switch result {
    case .success(let reminder):
        print("Reminder updated: \(reminder)")
    case .failure(let error):
        print("Failed to update reminder: \(error)")
    }
}

// Convert a timed reminder to "Save for later"
messageController.updateReminder(
    remindAt: nil // Remove specific reminder time
) { result in
    switch result {
    case .success(let reminder):
        print("Reminder updated to save for later: \(reminder)")
    case .failure(let error):
        print("Failed to update reminder: \(error)")
    }
}
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
// Update a reminder with a new due date
client.updateReminder(
    messageId = "message-id",
    // New reminder time in 2 hours
    remindAt = Date().apply { time += 2.hours.inWholeMilliseconds }
).enqueue { /* ... */ }

// Convert a timed reminder to "Save for later"
client.updateReminder(
    messageId = "message-id",
    remindAt = null, // Remove specific reminder time
).enqueue { /* ... */ }
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
// Update a reminder with a new due date
await client.updateReminder(
  messageId,
  // New reminder time in 2 hours
  remindAt: DateTime.now().add(const Duration(hours: 2)),
);

// Convert a timed reminder to "Save for later"
await client.updateReminder(
  messageId,
  remindAt: null, // Remove specific reminder time
);
```

</codetabs-item>

</codetabs>

## Deleting a Message Reminder

You can delete a reminder for a message when it's no longer needed.

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
// Backend SDK
// Delete the reminder for the message
await client.deleteReminder("message-id", "user-id");

// JavaScript SDK
// Delete a reminder for a message with id 'message-id' (direct API call)
await client.deleteReminder("message-id");

// Delete a reminder for a message with id 'message-id' (client state optimistic update (no server-side use))
await client.reminders.deleteReminder("message-id");
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
// Delete the reminder for the message
$client->deleteReminder("message-id", "user-id");
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
require 'getstream_ruby'
Models = GetStream::Generated::Models

# Delete the reminder for the message
client.chat.delete_reminder('message-id', 'user-id')
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
// Delete the reminder for the message
await chat.DeleteReminderAsync("message-id", new { user_id = "user-id" });
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
// Backend SDK

// Delete the reminder for the message
chat.deleteReminder("message-id", DeleteReminderRequest.builder()
    .UserID("user-id")
    .build()).execute();
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
# Delete the reminder for the message
client.chat.delete_reminder(message_id="message-id", user_id="user-id")
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
// Delete the reminder for the message
_, err := client.Chat().DeleteReminder(ctx, "message-id", &getstream.DeleteReminderRequest{
    UserID: getstream.PtrTo("user-id"),
})
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
// Get a message controller for the message
let messageController = chatClient.messageController(
    cid: ChannelId(type: .messaging, id: "general"),
    messageId: "message-id"
)

// Delete the reminder for the message
messageController.deleteReminder { result in
    switch result {
    case .success:
        print("Reminder deleted successfully")
    case .failure(let error):
        print("Failed to delete reminder: \(error)")
    }
}
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
// Delete the reminder for the message
client.deleteReminder("message-id").enqueue { /* ... */ }
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
// Delete the reminder for the message
await client.deleteReminder(messageId);
```

</codetabs-item>

</codetabs>

## Querying Message Reminders

The SDK allows you to fetch all reminders of the current user. You can filter, sort, and paginate through all the user's reminders.

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
// Query reminders for a user (server-side)
const reminders = await client.queryReminders({ user_id: "user-id" });

// Query reminders with filters (server-side)
const reminders = await client.queryReminders({
  user_id: "user-id",
  filter: { channel_cid: "messaging:general" },
});

// JavaScript SDK
// Retrieve the first page of reminders for the current user (direct API call).
await client.queryReminders();

// For the client-side pagination there are two methods representing two directions of pagination

// Query the first page (client state optimistic update (no server-side use))
await client.reminders.queryNextReminders();
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
// Query reminders for a user
$response = $client->queryReminders(new Models\QueryRemindersRequest(
    userID: "user-id",
));

// Query reminders with filters
$response = $client->queryReminders(new Models\QueryRemindersRequest(
    filter: (object)["channel_cid" => "messaging:general"],
    userID: "user-id",
));
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
require 'getstream_ruby'
Models = GetStream::Generated::Models

# Query reminders for a user
reminders = client.chat.query_reminders(Models::QueryRemindersRequest.new(
  user_id: 'user-id'
))

# Query reminders with filters
reminders = client.chat.query_reminders(Models::QueryRemindersRequest.new(
  user_id: 'user-id',
  filter: { 'channel_cid' => 'messaging:general' }
))
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
// Query reminders for a user
var resp = await chat.QueryRemindersAsync(new QueryRemindersRequest
{
    UserID = "user-id"
});

// Query reminders with filters
var filteredResp = await chat.QueryRemindersAsync(new QueryRemindersRequest
{
    UserID = "user-id",
    Filter = new Dictionary<string, object> { ["channel_cid"] = "messaging:general" }
});
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
// Backend SDK

// Query reminders for a user
var reminders = chat.queryReminders(QueryRemindersRequest.builder()
    .userID("user-id")
    .build()).execute().getData();

// Query reminders with filters
Map<String, Object> filter = Map.of("channel_cid", "messaging:general");
var filteredReminders = chat.queryReminders(QueryRemindersRequest.builder()
    .userID("user-id")
    .filter(filter)
    .build()).execute().getData();
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
# Query reminders for a user
reminders = client.chat.query_reminders(user_id="user-id")

# Query reminders with filters
reminders = client.chat.query_reminders(
    user_id="user-id",
    filter={"channel_cid": "messaging:general"},
)
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
// Query reminders for a user
resp, err := client.Chat().QueryReminders(ctx, &getstream.QueryRemindersRequest{
    UserID: getstream.PtrTo("user-id"),
})

// Query reminders with filters
resp, err := client.Chat().QueryReminders(ctx, &getstream.QueryRemindersRequest{
    UserID: getstream.PtrTo("user-id"),
    Filter: map[string]any{
        "channel_cid": "messaging:general",
    },
})
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
// Create a reminder list controller
let reminderListController = chatClient.messageReminderListController()

// Sync reminders
reminderListController.synchronize { error in
    if let error = error {
        print("Failed to synchronize reminders: \(error)")
    }
}
reminderListController.delegate = self

// Get notified about reminders changes
class MyReminderListView: MessageReminderListControllerDelegate {
    let controller: MessageReminderListController

    init(controller: MessageReminderListController) {
        self.controller = controller
        controller.delegate = self
    }

    func controller(
        _ controller: MessageReminderListController,
        didChangeReminders changes: [ListChange<MessageReminder>]
    ) {
        // Handle changes to reminders
        print("New reminders: \(controller.reminders)")
    }
}
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
// Retrieve the first 25 reminders for the current user.
client.queryReminders(filter = Filters.neutral(), limit = 25).enqueue { /* ... */ }
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
// Retrieve all reminders for the current user.
await client.queryReminders();
```

</codetabs-item>

</codetabs>

### Filtering Reminders

You can filter the reminders based on different criteria:

- `message_id` - Filter by the message that the reminder is created on.
- `remind_at` - Filter by the reminder time.
- `created_at` - Filter by the creation date.
- `channel_cid` - Filter by the channel ID.

The most common use case would be to filter by the reminder time. Like filtering overdue reminders, upcoming reminders, or reminders with no due date (saved for later).

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
// Server-side SDK
// Filter overdue reminders
const overdueFilter = { remind_at: { $lt: new Date() } };
const overdueReminders = await client.queryReminders({
  user_id: "user-id",
  filter: overdueFilter,
});

// Filter upcoming reminders
const upcomingFilter = { remind_at: { $gt: new Date() } };
const upcomingReminders = await client.queryReminders({
  user_id: "user-id",
  filter: upcomingFilter,
});

// Filter reminders with no due date (saved for later)
const savedFilter = { remind_at: null };
const savedReminders = await client.queryReminders({
  user_id: "user-id",
  filter: savedFilter,
});

// JavaScript SDK
// Direct API call
// Create filter for overdue reminders
await client.queryReminders({
  filter: {
    remind_at: { $lte: new Date().toISOString() },
  },
  sort: {
    remind_at: -1, // sort from the most recently expired
  },
});

// Create filter for upcoming reminders
await client.queryReminders({
  filter: {
    remind_at: { $gt: new Date().toISOString() },
  },
  sort: {
    remind_at: 1, // sort from the nearest to expire
  },
});

// Create filter for reminders with no due date (saved for later)
await client.queryReminders({
  filter: {
    remind_at: null,
  },
  sort: {
    created_at: -1, // sort from the most recently created
  },
});

// Client-side calls with local state updates before starting the pagination.
// Setting sort or filters resets the pagination state

// Create filter for overdue reminders
client.reminders.paginator.filters = {
  remind_at: { $lte: new Date().toISOString() },
};
client.reminders.paginator.sort = {
  remind_at: -1, // sort from the most recently expired
};

// Create filter for upcoming reminders
client.reminders.paginator.filters = {
  remind_at: { $gt: new Date().toISOString() },
};
client.reminders.paginator.sort = {
  remind_at: 1, // sort from the nearest to expire
};
// Create filter for reminders with no due date (saved for later)

client.reminders.paginator.filters = {
  remind_at: null,
};
client.reminders.paginator.sort = {
  created_at: -1, // sort from the most recently created
};

// adjust the page size
client.reminders.paginator.pageSize = 15;
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
// Filter overdue reminders
$response = $client->queryReminders(new Models\QueryRemindersRequest(
    filter: (object)["remind_at" => (object)['$lt' => (new \DateTime())->format(\DateTime::ATOM)]],
    userID: "user-id",
));

// Filter upcoming reminders
$response = $client->queryReminders(new Models\QueryRemindersRequest(
    filter: (object)["remind_at" => (object)['$gt' => (new \DateTime())->format(\DateTime::ATOM)]],
    userID: "user-id",
));

// Filter reminders with no due date (saved for later)
$response = $client->queryReminders(new Models\QueryRemindersRequest(
    filter: (object)["remind_at" => null],
    userID: "user-id",
));
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
require 'getstream_ruby'
Models = GetStream::Generated::Models

# Filter overdue reminders
overdue_reminders = client.chat.query_reminders(Models::QueryRemindersRequest.new(
  user_id: 'user-id',
  filter: { 'remind_at' => { '$lt' => Time.now.utc.iso8601 } }
))

# Filter upcoming reminders
upcoming_reminders = client.chat.query_reminders(Models::QueryRemindersRequest.new(
  user_id: 'user-id',
  filter: { 'remind_at' => { '$gt' => Time.now.utc.iso8601 } }
))

# Filter reminders with no due date (saved for later)
saved_reminders = client.chat.query_reminders(Models::QueryRemindersRequest.new(
  user_id: 'user-id',
  filter: { 'remind_at' => nil }
))
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
// Filter overdue reminders
var overdueResp = await chat.QueryRemindersAsync(new QueryRemindersRequest
{
    UserID = "user-id",
    Filter = new Dictionary<string, object>
    {
        ["remind_at"] = new Dictionary<string, object> { ["$lt"] = DateTime.UtcNow }
    }
});

// Filter upcoming reminders
var upcomingResp = await chat.QueryRemindersAsync(new QueryRemindersRequest
{
    UserID = "user-id",
    Filter = new Dictionary<string, object>
    {
        ["remind_at"] = new Dictionary<string, object> { ["$gt"] = DateTime.UtcNow }
    }
});

// Filter reminders with no due date (saved for later)
var savedResp = await chat.QueryRemindersAsync(new QueryRemindersRequest
{
    UserID = "user-id",
    Filter = new Dictionary<string, object> { ["remind_at"] = null }
});
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
// Backend SDK
import java.util.Date;

// Filter overdue reminders
Map<String, Object> overdueFilter = Map.of("remind_at", Map.of("$lt", new Date()));
var overdueReminders = chat.queryReminders(QueryRemindersRequest.builder()
    .userID("user-id")
    .filter(overdueFilter)
    .build()).execute().getData();

// Filter upcoming reminders
Map<String, Object> upcomingFilter = Map.of("remind_at", Map.of("$gt", new Date()));
var upcomingReminders = chat.queryReminders(QueryRemindersRequest.builder()
    .userID("user-id")
    .filter(upcomingFilter)
    .build()).execute().getData();

// Filter reminders with no due date (saved for later)
Map<String, Object> savedFilter = new HashMap<>();
savedFilter.put("remind_at", null);
var savedReminders = chat.queryReminders(QueryRemindersRequest.builder()
    .userID("user-id")
    .filter(savedFilter)
    .build()).execute().getData();
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
from datetime import datetime

# Filter overdue reminders
overdue_reminders = client.chat.query_reminders(
    user_id="user-id",
    filter={"remind_at": {"$lt": datetime.now().isoformat()}},
)

# Filter upcoming reminders
upcoming_reminders = client.chat.query_reminders(
    user_id="user-id",
    filter={"remind_at": {"$gt": datetime.now().isoformat()}},
)

# Filter reminders with no due date (saved for later)
saved_reminders = client.chat.query_reminders(
    user_id="user-id",
    filter={"remind_at": None},
)
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
import "time"

// Filter overdue reminders
overdueResp, err := client.Chat().QueryReminders(ctx, &getstream.QueryRemindersRequest{
    UserID: getstream.PtrTo("user-id"),
    Filter: map[string]any{
        "remind_at": map[string]any{"$lt": time.Now()},
    },
})

// Filter upcoming reminders
upcomingResp, err := client.Chat().QueryReminders(ctx, &getstream.QueryRemindersRequest{
    UserID: getstream.PtrTo("user-id"),
    Filter: map[string]any{
        "remind_at": map[string]any{"$gt": time.Now()},
    },
})

// Filter reminders with no due date (saved for later)
savedResp, err := client.Chat().QueryReminders(ctx, &getstream.QueryRemindersRequest{
    UserID: getstream.PtrTo("user-id"),
    Filter: map[string]any{
        "remind_at": nil,
    },
})
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
// Create filter for overdue reminders
let query = MessageReminderListQuery(
    filter: .overdue, // Same as .less(.remindAt, than: Date())
    sort: [.init(key: .remindAt, isAscending: false)]
)

// Create filter for upcoming reminders
let query = MessageReminderListQuery(
    filter: .upcoming, // Same as .greater(.remindAt, than: Date())
    sort: [.init(key: .remindAt, isAscending: true)]
)

// Create filter for reminders with no due date (saved for later)
let query = MessageReminderListQuery(
    filter: .isNil(.remindAt),
    sort: [.init(key: .createdAt, isAscending: false)]
)

// Apply the filter to the controller
let reminderListController = chatClient.messageReminderListController(query: query)
reminderListController.delegate = self
reminderListController.synchronize()
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
// Retrieve the first 25 overdue reminders for the current user sorted by remindAt.
val now = Date()
client.queryReminders(
    filter = Filters.lessThanEquals("remind_at", now),
    limit = 25,
    sort = QuerySortByField.descByName("remind_at"),
).enqueue { /* ... */ }

// Retrieve the first 25 upcoming reminders for the current user sorted by remindAt.
val now = Date()
client.queryReminders(
    filter = Filters.greaterThanEquals("remind_at", now),
    limit = 25,
    sort = QuerySortByField.ascByName("remind_at"),
).enqueue { /* ... */ }

// Retrieve the first 25 reminders saved for later (no remind_at).
client.queryReminders(
    filter = Filters.notExists("remind_at"),
    limit = 25,
    sort = QuerySortByField.descByName("created_at"),
).enqueue { /* ... */ }
```

</codetabs-item>

</codetabs>

### Pagination

If you have many reminders, you can paginate the results.

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
// Server-side SDK
// Load reminders with pagination
const reminders = await client.queryReminders({
  user_id: "user-id",
  limit: 10,
  offset: 0,
});

// Load next page
const nextReminders = await client.queryReminders({
  user_id: "user-id",
  limit: 10,
  offset: 10,
});

// JavaScript SDK
// Load the next page (direct API call).
await client.queryReminders({ filter, sort, limit, next }); // limit is the page size

// Load the previous page (direct API call).
await client.queryReminders({ filter, sort, limit, prev }); // limit is the page size

// For the client-side pagination there are two methods representing two directions of pagination

// Set the filter and (or) sort params - this resets the pagination
client.reminders.paginator.filters = filters;
client.reminders.paginator.sort = sort;

// Query the next page of reminders starting from 0 (client state optimistic update
await client.reminders.queryNextReminders();

// Query the previous page of reminders if already some reminders were queried previously
await client.reminders.queryPreviousReminders();
```

</codetabs-item>

<codetabs-item value="php" label="PHP">

```php
// Load reminders with pagination
$response = $client->queryReminders(new Models\QueryRemindersRequest(
    userID: "user-id",
    limit: 10,
));

// Load next page using cursor
if ($response->getData()->next) {
    $nextResponse = $client->queryReminders(new Models\QueryRemindersRequest(
        userID: "user-id",
        limit: 10,
        next: $response->getData()->next,
    ));
}
```

</codetabs-item>

<codetabs-item value="ruby" label="Ruby">

```ruby
require 'getstream_ruby'
Models = GetStream::Generated::Models

# Load reminders with pagination
reminders = client.chat.query_reminders(Models::QueryRemindersRequest.new(
  user_id: 'user-id',
  limit: 10
))

# Load next page using cursor
if reminders.next
  next_reminders = client.chat.query_reminders(Models::QueryRemindersRequest.new(
    user_id: 'user-id',
    limit: 10,
    next: reminders.next
  ))
end
```

</codetabs-item>

<codetabs-item value="csharp" label="C#">

```csharp
// Load reminders with pagination
var resp = await chat.QueryRemindersAsync(new QueryRemindersRequest
{
    UserID = "user-id",
    Limit = 10
});

// Load next page using cursor
if (resp.Data.Next != null)
{
    var nextResp = await chat.QueryRemindersAsync(new QueryRemindersRequest
    {
        UserID = "user-id",
        Limit = 10,
        Next = resp.Data.Next
    });
}
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
// Backend SDK

// Load reminders with pagination
var reminders = chat.queryReminders(QueryRemindersRequest.builder()
    .userID("user-id")
    .limit(10)
    .build()).execute().getData();

// Load next page
var nextReminders = chat.queryReminders(QueryRemindersRequest.builder()
    .userID("user-id")
    .limit(10)
    .next(reminders.getNext())
    .build()).execute().getData();
```

</codetabs-item>

<codetabs-item value="python" label="Python">

```python
# Load reminders with pagination
reminders = client.chat.query_reminders(user_id="user-id", limit=10)

# Load next page using cursor
if reminders.data.next:
    next_reminders = client.chat.query_reminders(
        user_id="user-id", limit=10, next=reminders.data.next
    )
```

</codetabs-item>

<codetabs-item value="go" label="Go">

```go
// Load reminders with pagination
resp, err := client.Chat().QueryReminders(ctx, &getstream.QueryRemindersRequest{
    UserID: getstream.PtrTo("user-id"),
    Limit:  getstream.PtrTo(10),
})

// Load next page using cursor
nextResp, err := client.Chat().QueryReminders(ctx, &getstream.QueryRemindersRequest{
    UserID: getstream.PtrTo("user-id"),
    Limit:  getstream.PtrTo(10),
    Next:   resp.Data.Next,
})
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
// Load more reminders
reminderListController.loadMoreReminders { error in
    switch result {
    case .success(let newReminders):
        print("Loaded \(newReminders.count) more reminders")
    case .failure(let error):
        print("Failed to load more reminders: \(error)")
    }
}
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
// Load first page of reminders
val result = client.queryReminders(
    filter = filter,
    limit = limit,
).await().getOrThrow()

// Load next page of reminders
val nextPageKey = result.next
client.queryReminders(
    filter = filter,
    limit = limit,
    next = nextPageKey, // Pass the next page key for pagination
).enqueue { /* ... */ }
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
// Load more reminders
final response = await client.queryReminders(
  sort: sort,
  filter: filter,
  // Pass the limit and next page key for pagination
  pagination: PaginationParams(limit: limit, next: nextPageKey),
);
```

</codetabs-item>

</codetabs>

## Events

The following WebSocket events are available for message reminders:

- `reminder.created` - Triggered when a reminder is created
- `reminder.updated` - Triggered when a reminder is updated
- `reminder.deleted` - Triggered when a reminder is deleted
- `notification.reminder_due` - Triggered when a reminder's due time is reached

When a reminder's due time is reached, the server also sends a push notification to the user. Ensure push notifications are configured in your app.

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
client.on("reminder.created", (event) => {
  console.log("Reminder created for message:", event.message_id);
});

client.on("reminder.updated", (event) => {
  console.log("Reminder updated for message:", event.message_id);
});

client.on("reminder.deleted", (event) => {
  console.log("Reminder deleted for message:", event.message_id);
});

client.on("notification.reminder_due", (event) => {
  console.log("Reminder due for message:", event.message_id);
});

// Unsubscribe when done
const { unsubscribe } = client.on("reminder.created", handler);
unsubscribe();
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
let chatClient = ChatClient.shared
let eventsController = chatClient.eventsController()
eventsController.delegate = self

public func eventsController(_ controller: EventsController, didReceiveEvent event: any Event) {
    if let event = event as? MessageReminderCreatedEvent {
        print("Reminder created for message: \(event.messageId)")
    } else if let event = event as? MessageReminderUpdatedEvent {
        print("Reminder updated for message: \(event.messageId)")
    } else if let event = event as? MessageReminderDeletedEvent {
        print("Reminder deleted for message: \(event.messageId)")
    } else if let event = event as? MessageReminderDueEvent {
        print("Reminder due for message: \(event.messageId)")
    }
}
```

</codetabs-item>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
client.subscribeFor(
    ReminderCreatedEvent::class.java,
    ReminderUpdatedEvent::class.java,
    ReminderDeletedEvent::class.java,
    NotificationReminderDueEvent::class.java,
) { event ->
    when (event) {
        is ReminderCreatedEvent -> {
            println("Reminder created for message: ${event.messageId}")
        }
        is ReminderUpdatedEvent -> {
            println("Reminder updated for message: ${event.messageId}")
        }
        is ReminderDeletedEvent -> {
            println("Reminder deleted for message: ${event.messageId}")
        }
        is NotificationReminderDueEvent -> {
            println("Reminder due for message: ${event.messageId}")
        }
        else -> {}
    }
}
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
client.on(EventType.reminderCreated).listen((event) {
  print('Reminder created for message: ${event.messageId}');
});

client.on(EventType.reminderUpdated).listen((event) {
  print('Reminder updated for message: ${event.messageId}');
});

client.on(EventType.reminderDeleted).listen((event) {
  print('Reminder deleted for message: ${event.messageId}');
});

client.on(EventType.notificationReminderDue).listen((event) {
  print('Reminder due for message: ${event.messageId}');
});
```

</codetabs-item>

</codetabs>

## Webhooks

The same events are available as webhooks to notify your backend systems:

- `reminder.created`
- `reminder.updated`
- `reminder.deleted`
- `notification.reminder_due`

These webhook events contain the same payload structure as their WebSocket counterparts. For more information on configuring webhooks, see the [Webhooks documentation](/chat/docs/<framework>/webhook_events/).


---

This page was last updated at 2026-03-13T13:15:47.975Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/android/message_reminders/](https://getstream.io/chat/docs/android/message_reminders/).