feat(users): add temporary new conversation limits (#3100)

This commit is contained in:
Hampus
2026-10-02 01:28:35 +02:00
committed by GitHub
parent b375abc20a
commit 98cce4815d
130 changed files with 995 additions and 259 deletions
@@ -157,7 +157,7 @@ Starts a direct message or group direct message call, or adds ringing recipients
- The caller must satisfy the [access rules](#access-rules).
- Every explicitly named recipient must be a current recipient other than the caller.
- A direct message also requires that the caller is allowed to send the other recipient a direct message.
- A direct message also requires that the caller is allowed to send the other recipient a direct message, including the [new conversation limit](/http-api/users/private-channels/#new-conversation-limit).
### Path parameters
@@ -193,6 +193,7 @@ A named recipient is only rung when the incoming call policy described by [Get c
| 400 | [error response](/http-api/#error-response) | The direct message send policy rejects the caller and the request returns `CANNOT_SEND_MESSAGES_TO_USER` |
| 400 | [error response](/http-api/#error-response) | That same policy rejects a caller who has never claimed its credentials with `UNCLAIMED_ACCOUNT_CANNOT_SEND_DIRECT_MESSAGES` |
| 400 | [error response](/http-api/#error-response) | A concurrent request already created the call and the request returns `CALL_ALREADY_EXISTS` |
| 403 | [error response](/http-api/#error-response) | A limited caller rings an account that has not written in the direct message and the request returns `NEW_CONVERSATIONS_LIMITED` |
| 404 | [error response](/http-api/#error-response) | Channel does not exist or the caller is not a recipient, each returning `UNKNOWN_CHANNEL` |
### Side effects
@@ -304,6 +304,10 @@ Remove the followed channels posting here before converting it to an announcemen
Only text and announcement channels can be converted into each other
### `NEW_CONVERSATIONS_LIMITED`
You can't start new conversations right now. Please try again later
### `COMMUNICATION_DISABLED`
Communication is disabled
@@ -1149,6 +1149,7 @@ Creates a message from a JSON body or from multipart form data. Returns the crea
- Embeds require [EMBED_LINKS](/http-api/permissions/), attachments require [ATTACH_FILES](/http-api/permissions/), a favourite meme requires both, and active everyone mentions require [MENTION_EVERYONE](/http-api/permissions/).
- Slowmode applies to a non-bot caller unless they hold [BYPASS_SLOWMODE](/http-api/permissions/).
- A one-to-one direct message also applies the recipient's direct message policy and relationship state, and a denial returns 400 `CANNOT_SEND_MESSAGES_TO_USER`.
- A message in a one-to-one direct message is refused with 403 `NEW_CONVERSATIONS_LIMITED` when the caller is under a [new conversation limit](/http-api/users/private-channels/#new-conversation-limit), the recipient is not a friend or a bot, and the recipient has not written in that direct message.
- An unclaimed account can send only to its own personal notes channel, and a send to any other channel is refused with 400 `UNCLAIMED_ACCOUNT_CANNOT_SEND_MESSAGES` before the channel is resolved.
- A non-bot caller must have started a session, and one that has not is refused with the field code `MUST_START_SESSION_BEFORE_SENDING`.
@@ -1276,6 +1277,7 @@ The resolved `max_voice_message_duration` limit defaults to 1200 seconds.
| 403 | [error response](/http-api/#error-response) | Is timed out and the request returns `COMMUNICATION_DISABLED` |
| 403 | [error response](/http-api/#error-response) | Is age restricted from the channel and the request returns `NSFW_CONTENT_AGE_RESTRICTED` |
| 403 | [error response](/http-api/#error-response) | Message sending is temporarily disabled for the guild and the request returns `FEATURE_TEMPORARILY_DISABLED` |
| 403 | [error response](/http-api/#error-response) | A limited caller messages an account that has not written in the direct message and the request returns `NEW_CONVERSATIONS_LIMITED` |
| 404 | [error response](/http-api/#error-response) | Channel, referenced message, sticker, or guild does not exist or is unavailable, or the supplied nonce was last used in a different channel and the request returns `UNKNOWN_MESSAGE` |
:::caution[Slowmode denials are 400, not 429]
@@ -1309,6 +1311,7 @@ Modifies a message. Returns the updated [message](#message-object) object. Emits
- The target must be a `DEFAULT` or `REPLY` message, and any other type fails with 400 `CANNOT_MODIFY_SYSTEM_WEBHOOK`.
- A message that has [message snapshots](#message-snapshot-object) cannot be edited by its author and fails with the field code `MESSAGES_WITH_SNAPSHOTS_CANNOT_BE_EDITED`. A non-author moderator holding `MANAGE_MESSAGES` can still toggle `SUPPRESS_EMBEDS` and change existing attachment metadata on a forwarded message.
- The author can modify every supported field, and a timed-out author is refused with 403 `COMMUNICATION_DISABLED`.
- An author edit in a one-to-one direct message is refused with 403 `NEW_CONVERSATIONS_LIMITED` when the author is under a [new conversation limit](/http-api/users/private-channels/#new-conversation-limit), the recipient is not a friend or a bot, and the recipient has not written in that direct message.
- A caller who is not the author can act only in a guild channel, must hold [MANAGE_MESSAGES](/http-api/permissions/), and can change only `SUPPRESS_EMBEDS` and the metadata of attachments that already exist. A non-author edit that does not satisfy all these conditions fails with 403 `CANNOT_EDIT_OTHER_USER_MESSAGE`.
- `MANAGE_MESSAGES` is an [elevated permission](/http-api/permissions/#elevated-permissions), so a caller who holds it with no enrolled authenticator receives 400 [`TWO_FACTOR_REQUIRED`](/http-api/errors/) in a guild whose [MFA level](/http-api/guilds/#mfa-levels) is elevated, unless they own the guild.
- A caller who does not hold the bit at all is treated as any other non-author and receives 403 `CANNOT_EDIT_OTHER_USER_MESSAGE`.
@@ -1364,6 +1367,7 @@ An `id` that names no attachment on the message is skipped, and the edit still s
| 403 | [error response](/http-api/#error-response) | The caller is timed out and the request returns `COMMUNICATION_DISABLED` |
| 403 | [error response](/http-api/#error-response) | The caller is age restricted from the channel and the request returns `NSFW_CONTENT_AGE_RESTRICTED` |
| 403 | [error response](/http-api/#error-response) | Message sending is temporarily disabled for the guild and the request returns `FEATURE_TEMPORARILY_DISABLED` |
| 403 | [error response](/http-api/#error-response) | A limited author edits a direct message the other account has not written in and the request returns `NEW_CONVERSATIONS_LIMITED` |
| 404 | [error response](/http-api/#error-response) | Channel or message does not exist |
| 429 | [error response](/http-api/#error-response) | The published message edit allowance is used up, returning `PUBLISHED_MESSAGE_EDIT_RATE_LIMITED` |
@@ -1840,6 +1844,7 @@ Pins a `DEFAULT` or `REPLY` message. Returns 204 with an empty body on success.
- A guild caller requires [PIN_MESSAGES](/http-api/permissions/) and channel access.
- A guild caller without [READ_MESSAGE_HISTORY](/http-api/permissions/) can pin only a message on or after the guild's message history cutoff.
- A one-to-one direct message caller must satisfy the recipient's direct message policy, and one who may not send fails with 400 `CANNOT_SEND_MESSAGES_TO_USER`.
- A one-to-one direct message pin is refused with 403 `NEW_CONVERSATIONS_LIMITED` when the caller is under a [new conversation limit](/http-api/users/private-channels/#new-conversation-limit), the recipient is not a friend or a bot, and the recipient has not written in that direct message.
- A group direct message and the personal notes channel apply no send policy.
- The operation is idempotent.
@@ -1860,6 +1865,7 @@ Pins a `DEFAULT` or `REPLY` message. Returns 204 with an empty body on success.
| 400 | [error response](/http-api/#error-response) | The target is a system message and the request returns `CANNOT_MODIFY_SYSTEM_WEBHOOK` |
| 400 | [error response](/http-api/#error-response) | The private channel's send policy denies the caller and the request returns `CANNOT_SEND_MESSAGES_TO_USER` |
| 403 | [error response](/http-api/#error-response) | Caller lacks `VIEW_CHANNEL` or `PIN_MESSAGES` and the request returns `MISSING_PERMISSIONS`, or message sending is temporarily disabled for the guild and the request returns `FEATURE_TEMPORARILY_DISABLED` |
| 403 | [error response](/http-api/#error-response) | The caller is under a new conversation limit in a direct message the recipient has not written in, and the request returns `NEW_CONVERSATIONS_LIMITED` |
| 404 | [error response](/http-api/#error-response) | Channel or message does not exist, or the message is outside the caller's message history cutoff |
### Side effects
@@ -2055,7 +2061,7 @@ Adds the authenticated identity's reaction. Returns 204 with an empty body. Emit
- In a guild channel a custom emoji also requires [USE_EXTERNAL_EMOJIS](/http-api/permissions/).
- A non-bot caller must have started a session, and one that has not receives the field code `MUST_START_SESSION_BEFORE_SENDING`.
- An unclaimed account can react only in its personal notes channel, and elsewhere receives 400 `UNCLAIMED_ACCOUNT_CANNOT_ADD_REACTIONS`.
- This route applies no direct message send policy.
- This route applies no direct message send policy. A one-to-one direct message reaction is still refused with 403 `NEW_CONVERSATIONS_LIMITED` when the caller is under a [new conversation limit](/http-api/users/private-channels/#new-conversation-limit), the recipient is not a friend or a bot, and the recipient has not written in that direct message.
### Path parameters
@@ -2094,6 +2100,7 @@ Adds the authenticated identity's reaction. Returns 204 with an empty body. Emit
| 403 | [error response](/http-api/#error-response) | Caller lacks `VIEW_CHANNEL`, `ADD_REACTIONS`, or `USE_EXTERNAL_EMOJIS` and the request returns `MISSING_PERMISSIONS` |
| 403 | [error response](/http-api/#error-response) | The caller is timed out and the request returns `COMMUNICATION_DISABLED` |
| 403 | [error response](/http-api/#error-response) | The caller has an unverified email and the request returns `REACTION_EMAIL_VERIFICATION_REQUIRED` |
| 403 | [error response](/http-api/#error-response) | The caller is under a new conversation limit in a direct message the recipient has not written in, and the request returns `NEW_CONVERSATIONS_LIMITED` |
| 403 | [error response](/http-api/#error-response) | Reactions are temporarily disabled for the guild and the request returns `FEATURE_TEMPORARILY_DISABLED` |
| 404 | [error response](/http-api/#error-response) | Channel or message does not exist, or the message is outside the caller's message history cutoff |
@@ -86,11 +86,17 @@ When the instance [community policy](/http-api/instance/#community-policy-object
An unclaimed account holds no password and did not arrive through SSO. Fluxer rejects an unclaimed caller with 400 `UNCLAIMED_ACCOUNT_CANNOT_JOIN_GROUP_DMS` when `recipients` is supplied, and with 400 `UNCLAIMED_ACCOUNT_CANNOT_SEND_DIRECT_MESSAGES` otherwise. An ordinary caller then needs a verified email address, failing which the request returns 403 `DIRECT_MESSAGE_EMAIL_VERIFICATION_REQUIRED`. A bot caller is exempt from the email requirement and is never unclaimed.
### New conversation limit
An account can be limited from starting new conversations. While the limit stands, opening a direct message with an account that is not a friend returns 403 `NEW_CONVERSATIONS_LIMITED`, unless the other account has already written in a direct message between the two. The same check applies to sending, editing, pinning and reacting in a direct message, to ringing a direct message call, and to sending a friend request.
Friends, bots, conversations where the other account has written, incoming friend requests, group DMs and guild channels are unaffected. Bots, staff and accounts marked as trusted are never limited. The limit ends on its own, and a moderator who restores the account, marks it trusted or removes a flag from it lifts the limit at once.
### Direct message admission
A request naming the caller as its own target returns 400 `CANNOT_DM_YOURSELF` as the field code on `recipient_id` under `INVALID_FORM_BODY`. An unresolved target returns 404 `UNKNOWN_USER`.
Fluxer reads no block state, no friendship, and no shared guild on this route. A target that resolves is admitted, so the caller opens a direct message with an account that has blocked them. `CANNOT_SEND_MESSAGES_TO_USER` is reachable from [Create message](/http-api/messages/#create-message) alone, which applies the recipient's direct message policy on every send.
Fluxer reads no block state and no shared guild on this route, and it reads friendship only for a caller under a [new conversation limit](#new-conversation-limit). A target that resolves is admitted, so the caller opens a direct message with an account that has blocked them. `CANNOT_SEND_MESSAGES_TO_USER` is reachable from [Create message](/http-api/messages/#create-message) alone, which applies the recipient's direct message policy on every send.
:::caution[Blocking removes no channel from the blocked account]
Blocking closes no existing channel. The blocked account still opens the pair's direct message through this route and receives 200. Only the send is refused, with 400 `CANNOT_SEND_MESSAGES_TO_USER`.
@@ -139,7 +145,7 @@ Fluxer holds a bot caller to no friendship. A recipient that has blocked the bot
| --- | --- | --- |
| 200 | [channel](/http-api/channels/#channel-object) object | The direct message was opened or the group DM was created |
| 400 | [error response](/http-api/#error-response) | CAPTCHA, account eligibility, the recipient set, relationship policy, a group DM limit, or instance policy rejects creation |
| 403 | [error response](/http-api/#error-response) | An ordinary caller's email address is unverified and the request returns `DIRECT_MESSAGE_EMAIL_VERIFICATION_REQUIRED` |
| 403 | [error response](/http-api/#error-response) | An ordinary caller's email address is unverified and the request returns `DIRECT_MESSAGE_EMAIL_VERIFICATION_REQUIRED`, or a limited caller opens a new conversation and the request returns `NEW_CONVERSATIONS_LIMITED` |
| 404 | [error response](/http-api/#error-response) | The caller or the direct message recipient does not resolve |
### Side effects
@@ -141,7 +141,7 @@ Fluxer resolves the tag to exactly one account before any relationship rule runs
| --- | --- | --- |
| 200 | [relationship](#relationship-object) object | A pending request, an existing relationship, or an accepted friendship was returned |
| 400 | [error response](/http-api/#error-response) | The tag is unresolved, the caller or target is ineligible, target or block policy rejects the request, deployment policy disables the operation, or the [relationship limit](#relationship-limit) is reached |
| 403 | [error response](/http-api/#error-response) | The caller's email address is unverified and the request returns `FRIEND_REQUEST_EMAIL_VERIFICATION_REQUIRED` |
| 403 | [error response](/http-api/#error-response) | The caller's email address is unverified and the request returns `FRIEND_REQUEST_EMAIL_VERIFICATION_REQUIRED`, or the caller is under a new conversation limit and the request returns `NEW_CONVERSATIONS_LIMITED` |
| 404 | [error response](/http-api/#error-response) | The caller or resolved target no longer exists, or the pending request being accepted has been withdrawn |
### Side effects
@@ -166,7 +166,7 @@ Fluxer checks the current relationship state next. A pending request from the ta
The remaining rules reject an unclaimed caller with 400 `UNCLAIMED_ACCOUNT_CANNOT_SEND_FRIEND_REQUESTS` and an unverified email with 403 `FRIEND_REQUEST_EMAIL_VERIFICATION_REQUIRED`. A bot target is rejected with 400 `FRIEND_REQUEST_BLOCKED` unless it has `FRIENDLY_BOT`. A target with the internal app store reviewer flag is rejected with the same code.
A target the caller has blocked returns 400 `CANNOT_SEND_FRIEND_REQUEST_TO_BLOCKED_USER`. A target that has blocked the caller returns 400 `FRIEND_REQUEST_BLOCKED`. Fluxer reads the target's [friend source flags](/http-api/users/#friend-source-flags) next<sup>1</sup>, and a target accepting requests only from mutual friends or mutual guild members rejects an unrelated caller with 400 `FRIEND_REQUEST_BLOCKED`. The [relationship limit](#relationship-limit) applies last, independently for both accounts.
A target the caller has blocked returns 400 `CANNOT_SEND_FRIEND_REQUEST_TO_BLOCKED_USER`. A target that has blocked the caller returns 400 `FRIEND_REQUEST_BLOCKED`. Fluxer reads the target's [friend source flags](/http-api/users/#friend-source-flags) next<sup>1</sup>, and a target accepting requests only from mutual friends or mutual guild members rejects an unrelated caller with 400 `FRIEND_REQUEST_BLOCKED`. An account under a [new conversation limit](/http-api/users/private-channels/#new-conversation-limit) then returns 403 `NEW_CONVERSATIONS_LIMITED`, unless the target is a bot or has already written in a direct message with it. The [relationship limit](#relationship-limit) applies last, independently for both accounts.
<sup>1</sup> The friend source evaluation is skipped when the target has no stored settings, which admits the request as though the target permitted requests from anyone
@@ -202,7 +202,7 @@ The body can be omitted, in which case it is treated as an empty object.
| --- | --- | --- |
| 200 | [relationship](#relationship-object) object | A pending request, an existing relationship, or an accepted friendship was returned |
| 400 | [error response](/http-api/#error-response) | The caller or target is ineligible, target or block policy rejects the request, deployment policy disables the operation, or the [relationship limit](#relationship-limit) is reached |
| 403 | [error response](/http-api/#error-response) | The caller's email address is unverified and the request returns `FRIEND_REQUEST_EMAIL_VERIFICATION_REQUIRED` |
| 403 | [error response](/http-api/#error-response) | The caller's email address is unverified and the request returns `FRIEND_REQUEST_EMAIL_VERIFICATION_REQUIRED`, or the caller is under a new conversation limit and the request returns `NEW_CONVERSATIONS_LIMITED` |
| 404 | [error response](/http-api/#error-response) | The caller, the target account, or the pending request being accepted does not exist |
### Side effects