Skip to content

User content collections

Recent mentions, saved messages and scheduled messages are private lists that only the account owning them can read. Other routes on this page delete the messages the caller wrote: one form runs straight away with a filter, the other deletes everything and waits a day. Data exports are covered on Data harvests.

All routes here are for user accounts only. A request with a Bot token is rejected with 403 ACCESS_DENIED when the token is valid, or with 401 when it is not (see Authentication). Errors use the standard error response with error, code and message fields.

Saved message object

A saved entry is a private bookmark that pairs one message with the channel it was saved from. Saving a message does not notify anyone, including its author.

The entry does not store a copy of the message. TEBHOS reads the message again on every list request, so an entry can carry content on one read and not on the next.

Structure

Field Type Description
id snowflake The ID of the saved entry. Always the same as message_id, because an account can save a message only once
message_id snowflake The ID of the saved message
channel_id snowflake The channel given when the message was saved
saved_at ISO8601 timestamp When the message was saved
status string The saved message status of the entry
content ?string The message text, or null when status is missing_permissions
author ?partial user object The message author, or null when status is missing_permissions. When the author cannot be resolved, this object contains only id
created_at ?ISO8601 timestamp Always null. The message creation time can be read from the message_id snowflake
is_deleted boolean Always false

The entry is a summary of the message, not a full message object. Fetch the message from its channel to get attachments, embeds and reactions.

Saved message statuses

Value Description
available The caller can still view the channel, and content and author are filled in
missing_permissions The caller can no longer view the channel (lost VIEW_CHANNEL, left the guild, or the channel is gone), so content and author are null. The entry is kept so the caller can still remove it

Recent mention object

A recent mention entry is created automatically when a message mentions the account. There is no route for creating entries. Entries expire from storage 7 days after they are recorded.

Structure

Field Type Description
message_id snowflake The ID of the message that mentioned the account
channel_id snowflake The channel containing the message
guild_id snowflake The guild of the channel, or "0" for a channel outside a guild
mention_everyone boolean Whether the entry was recorded as an @everyone or @here mention
mention_role boolean Whether the entry was recorded as a role mention

List recent mentions

GET /users/@me/mentions

Returns an array of up to 100 recent mention entries for the caller, newest first (by descending message ID).

This route takes no query parameters: there is no limit, before or filter, and the response has no cursor. The entries are the stored records. TEBHOS does not load the messages or check them against the caller's current permissions, so an entry can refer to a message that has since been deleted. Fetch the message from its channel to show it.

Response

Status Body Condition
200 array of recent mention objects The entries were returned
[
  {
    "message_id": "1501314428688998182",
    "channel_id": "1501300000000000001",
    "guild_id": "1501299999999999999",
    "mention_everyone": false,
    "mention_role": false
  }
]

Rate limit

40 requests per 10 seconds per user, on the user:mentions:read bucket. See Rate limits.

Mark recent mentions read

POST /users/@me/mentions/read

Removes every entry from the caller's recent mention history. It takes no request body and returns 204 with an empty body.

No list of IDs

This route does not accept a message_ids list. It always clears the whole history. To remove a single entry, use Delete recent mention.

Removing entries does not mark the messages as read. The unread mention count on each channel stays the same. Read states explains acknowledgement.

Side effects

TEBHOS reads up to 1000 of the newest entries, deletes the whole history, and then sends one RECENT_MENTION_DELETE Gateway event ({"message_id": "..."}) to all of the caller's sessions for each entry it read.

Rate limit

60 requests per 10 seconds per user, on the user:mentions:delete bucket. This bucket is shared with Delete recent mention.

Delete recent mention

DELETE /users/@me/mentions/{message_id}

Removes one entry from the caller's recent mention history and returns 204 with an empty body.

Path parameters

Field Type Description
message_id snowflake The message ID of the recent mention entry

Response

Status Body Condition
204 empty The entry was removed, or no matching entry was found
400 error response message_id is not a valid snowflake (BAD_REQUEST)

Side effects

TEBHOS looks for the entry among the caller's 200 newest entries. If it finds a match, it deletes the entry and sends RECENT_MENTION_DELETE ({"message_id": "..."}) to all of the caller's sessions. If there is no match, including an entry older than the newest 200, nothing is written and no event is sent. The message stays in its channel.

Rate limit

60 requests per 10 seconds per user, on the user:mentions:delete bucket. This bucket is shared with Mark recent mentions read.

List saved messages

GET /users/@me/saved-messages

Returns the caller's saved messages, newest first (by descending message ID). The response is an object with an items array of saved message objects. It has no cursor, so use before and limit to page.

TEBHOS checks VIEW_CHANNEL once per channel. An entry whose channel the caller can no longer view is returned with status missing_permissions. An entry whose message no longer exists is left out of the response but is not deleted. Because of this, items can contain fewer entries than limit.

Query parameters

Field Type Description
limit? integer The maximum number of entries read from the collection. Values outside the range are clamped to 1-100. Default 50
before? snowflake Return only entries with a lower message ID. A value that cannot be parsed is ignored

Response

Status Body Condition
200 {"items": [saved message object]} The entries were returned
500 error response Channel permissions could not be checked. TEBHOS returns an error rather than risk showing content the caller may not be allowed to see
{
  "items": [
    {
      "id": "1501314428688998182",
      "message_id": "1501314428688998182",
      "saved_at": "2026-09-20T18:04:33.120+00:00",
      "channel_id": "1501300000000000001",
      "status": "available",
      "content": "Meeting notes are pinned.",
      "is_deleted": false,
      "created_at": null,
      "author": {"id": "1501290000000000042", "username": "aria", "discriminator": "0", "global_name": "Aria", "avatar": null, "avatar_color": null, "flags": 0}
    }
  ]
}

Rate limit

40 requests per 10 seconds per user, on the user:saved_messages:read bucket.

Save message

POST /users/@me/saved-messages

Adds a message to the caller's saved collection and returns 204 with an empty body. The caller needs VIEW_CHANNEL on a guild channel, or must be a recipient of a DM or group DM.

JSON body

Field Type Description
channel_id snowflake The channel containing the message. This value is stored with the entry exactly as given
message_id snowflake The ID of the message to save

Collection limit

An account can save at most 100 messages. This is a fixed limit, not an instance setting. Saving a new message when the collection is full returns 400 BAD_REQUEST. Saving a message that is already in the collection is always accepted, even when the collection is full.

Response

Status Body Condition
204 empty The message is in the saved collection
400 error response An ID is not a valid snowflake, or the collection is full (BAD_REQUEST)
403 error response The caller cannot view the channel
404 error response The channel is unknown, or the message is not in that channel (NOT_FOUND)

Side effects

Saving a message that is already stored rewrites the entry. On every accepted save, SAVED_MESSAGE_CREATE is sent to all of the caller's sessions. Its payload is the full message object as the caller can see it, with user_id and message_id added. If the message cannot be loaded for the event, the save still succeeds but no event is sent.

Rate limit

30 requests per 10 seconds per user, on the user:saved_messages:write bucket. This bucket is shared with Unsave message.

Unsave message

DELETE /users/@me/saved-messages/{message_id}

Removes a message from the caller's saved collection and returns 204 with an empty body. The caller does not need current access to the channel.

Path parameters

Field Type Description
message_id snowflake The message ID of the saved entry

Response

Status Body Condition
204 empty The message is no longer in the saved collection
400 error response message_id is not a valid snowflake

Side effects

TEBHOS always runs the delete. SAVED_MESSAGE_DELETE ({"user_id": "...", "message_id": "..."}) is sent to all of the caller's sessions on every accepted request, including a request for a message the account never saved. The message stays in its channel.

Rate limit

30 requests per 10 seconds per user, on the user:saved_messages:write bucket. This bucket is shared with Save message.

Channel-scoped save routes

POST /channels/{channel_id}/messages/{message_id}/save and DELETE /channels/{channel_id}/messages/{message_id}/save do the same work as the two routes above, with the same permission checks, collection limit and events. They take no body. The POST returns 201 {"ok": true} and the DELETE returns 200 {"ok": true}. These routes have no route-level rate limit.

Scheduled message object

A scheduled message is text that TEBHOS posts to a channel for the caller at a later time. A background worker checks for due messages every 30 seconds, so a message is posted up to about 30 seconds after scheduled_at.

Structure

Field Type Description
id snowflake The ID of the scheduled message
channel_id snowflake The target channel
content string The text that will be sent
file_url ?string The file URL given at creation. It is stored, but the posted message does not include it
scheduled_at ISO8601 timestamp When the message is due
created_at ISO8601 timestamp When the message was scheduled

When a scheduled message is posted, it is removed from the list and a normal MESSAGE_CREATE is sent to the channel. If posting fails, the entry is marked invalid and is not retried. Invalid entries are hidden from every route below.

Schedule message

POST /scheduled-messages

Schedules a message and returns 201 with the scheduled message object. The caller needs SEND_MESSAGES in the target channel. The same operation is also available as POST /channels/{channel_id}/messages/schedule, which takes the channel from the path (see Messages).

JSON body

Field Type Description
channel_id snowflake The target channel
content string The message text. Must not be blank, and at most 4000 bytes
scheduled_at ISO8601 timestamp When to send. Must be at least 1 minute and at most 30 days after the request
reply_to_id? snowflake A message to reply to. A value that cannot be parsed is ignored
file_url? string Stored with the entry, but not sent

Limits

An account can have at most 50 pending scheduled messages. The 51st returns 400 BAD_REQUEST.

Response

Status Body Condition
201 scheduled message object The message was scheduled
400 error response The channel ID, content or time is invalid, or the pending limit has been reached
403 error response The caller lacks SEND_MESSAGES in the channel

List scheduled messages

GET /users/@me/scheduled-messages

Also available as GET /scheduled-messages. Returns {"items": [scheduled message object]} with up to 100 pending entries. Entries that have already been sent or are marked invalid are not included. The order of the entries is not defined.

Get scheduled message

GET /users/@me/scheduled-messages/{id}

Also available as GET /scheduled-messages/{id}. Returns one pending scheduled message. A message that belongs to another account, has already been sent or has been marked invalid returns 404 NOT_FOUND.

Edit scheduled message

PATCH /scheduled-messages/{id}

Changes the text or time of a pending scheduled message and returns 204 with an empty body.

Field Type Description
content? string New text. Must not be blank, and at most 4000 bytes
scheduled_at? ISO8601 timestamp New time, with the same 1 minute to 30 day window as when scheduling

Returns 404 NOT_FOUND when the scheduled message does not exist or belongs to another account.

Cancel scheduled message

DELETE /users/@me/scheduled-messages/{id}

Also available as DELETE /scheduled-messages/{id}. Cancels a pending scheduled message and returns 204 with an empty body. Returns 404 NOT_FOUND when the message does not exist, belongs to another account or has already been sent.

The scheduled-message routes have no route-level rate limit.

Delete current user's messages

POST /users/@me/messages/bulk-delete-mine

Deletes the messages the caller wrote in the channel types chosen by the body. Requires sudo mode and returns 202 with an empty body.

Deletion is permanent

Every selected message is deleted from its channel for every recipient, and no operation can restore it. Get explicit confirmation from the user before you send this request.

Sudo mode

This route checks for a sudo grant held by the current session. You get one with POST /auth/sudo, which is valid for 5 minutes (see MFA). Sudo fields in the request body are ignored. Without a valid grant, the route returns 403 with code SUDO_MODE_REQUIRED.

JSON body

Every field is optional.

Field Type Description
include_dms? boolean Whether one-to-one DMs are included. This covers every channel outside a guild that is not a group DM. Default true
include_group_dms? boolean Whether group DMs are included. Default true
include_guilds? boolean Whether guild channels are included. Default true
start_date? ISO8601 timestamp Inclusive lower bound on message time. A value that cannot be parsed is ignored
end_date? ISO8601 timestamp Inclusive upper bound on message time. A value that cannot be parsed is ignored

Message time comes from the timestamp in the message snowflake, so editing a message does not change which window it falls in.

Accepted but ignored on TEBHOS

The body can also contain scope, include_dms_closed, guild_filter_mode, excluded_guild_ids and included_guild_ids. TEBHOS parses these fields but does not apply them: there is no guild include/exclude filter and no "inaccessible only" mode. TEBHOS does not check the date order, and it does not reject a body with every toggle set to false (such a request deletes nothing).

Behaviour

  • The deletion runs while the request is open. By the time 202 is returned, the messages have been deleted.
  • Only the caller's 10,000 most recent messages are considered. To delete older messages, send the request again.
  • For each affected channel, TEBHOS sends one MESSAGE_DELETE_BULK event ({"channel_id": "...", "ids": [...]}) to that channel.
  • No summary direct message is sent when the deletion finishes.

Response

Status Body Condition
202 empty The selected messages were deleted
403 error response No valid sudo grant for this session (SUDO_MODE_REQUIRED)
500 error response Messages could not be read or deleted. Some messages may already have been deleted

Rate limit

5 requests per 30 minutes per user, on the user:messages:bulk_delete_mine_filtered bucket. The limit is checked before sudo.

Delete current user's messages in a guild

POST /users/@me/guilds/{guild_id}/messages/bulk-delete-mine

Deletes every message the caller wrote in any channel of one guild. The caller must be a member of the guild; otherwise the route returns 404 NOT_FOUND. The route requires the same session sudo grant as Delete current user's messages. It takes no body and returns 202 once the deletion has finished. It considers the caller's 10,000 most recent messages and sends one MESSAGE_DELETE_BULK event per channel.

Rate limit: 10 requests per 10 seconds per user and guild, on the guild:leave bucket.

Request bulk message deletion

POST /profile/purge-messages

Schedules deletion of every message the caller has sent, starting 24 hours from now. Returns 200 with the schedule. Unlike Delete current user's messages, this route takes no filter and waits a day. Until then, the deletion can be cancelled.

Sending the request again replaces the pending schedule with a new one that starts 24 hours from the new request. An account can have only one pending deletion. The current schedule is shown as pending_bulk_message_deletion on the user object and by Get bulk message deletion status.

Deletion is permanent once it runs

When the schedule runs, it deletes every message the caller wrote at or before the scheduled time, in every channel. Cancel bulk message deletion is the only way to stop it.

JSON body (sudo verification)

Unlike the route above, this route checks sudo inline in the request body and ignores session sudo grants. Send exactly one proof:

Field Type Description
password? string The account password. Accepted only when the account has no MFA
mfa_code? string An authenticator (TOTP) code or an unused backup code
sudo_proof? string A single-use proof from a passkey assertion (see MFA)

If more than one field is present, sudo_proof is checked first, then mfa_code, then password.

Response

Status Body Condition
200 {"scheduled_at", "message_count", "channel_count"} The deletion was scheduled
401 error response The password, code or passkey proof is wrong (UNAUTHORIZED)
403 error response No proof was given, or only a password was given for an MFA account (SUDO_MODE_REQUIRED)
{
  "scheduled_at": "2026-09-24T09:15:02.481+00:00",
  "message_count": 1284,
  "channel_count": 37
}

message_count and channel_count are counted when the request is made and are not updated while the schedule waits.

Side effects

The request itself does not delete anything and sends no Gateway event. A background task runs every 10 minutes. After scheduled_at has passed, it deletes the messages, clears the schedule and removes the pending deletion from the account. These deletions send no MESSAGE_DELETE events, and nothing tells the client that the deletion has finished. Poll Get bulk message deletion status if you need to know.

Rate limit

3 requests per hour per user, on the profile:purge bucket. This limit is checked only after sudo verification succeeds. Wrong proofs are limited separately: 10 attempts per 15 minutes for mfa_code and 10 attempts per 5 minutes for password, per user.

Get bulk message deletion status

GET /profile/purge-status

Returns the pending bulk deletion for the caller. When nothing is pending, every field is null.

Field Type Description
scheduled_at ?ISO8601 timestamp When the deletion runs
message_count ?integer Messages counted when the deletion was scheduled
channel_count ?integer Channels counted when the deletion was scheduled

Cancel bulk message deletion

DELETE /profile/purge-messages

Cancels a pending bulk message deletion and returns 200 {"message": "..."}. This route needs no sudo verification. It returns 200 even when nothing is pending. It sends no Gateway event. After the scheduled deletion has started, there is nothing left to cancel, and deleted messages cannot be restored.