Skip to content
Fluxer API

Current user

The current user is the account that presented the credential, represented as a user object. The routes here read that account, change it, and run its lifecycle operations.

Every route except Get current user is user-only. Those routes reject a bot or OAuth2 bearer credential with 403 ACCESS_DENIED. They also reject an account that has an outstanding required action with 403 ACCOUNT_SUSPICIOUS_ACTIVITY.

Sudo verification asks the account to prove itself again inside the request. Security-sensitive fields and destructive lifecycle operations require it. Proof comes in one of three forms.

Account stateAccepted proof
No authenticator configuredThe current password
An authenticator configuredmfa_method of totp with mfa_code, or mfa_method of webauthn with webauthn_response and webauthn_challenge
No password credential and no authenticatorNone, the requirement is already satisfied

An already valid sudo token replaces any of those forms. Once an account configures an authenticator its password stops working here.

A sudo token is an HS256 JSON Web Token valid for five minutes. It has the account ID as its subject and is rejected for any other account. A successful verification returns the token in the X-Fluxer-Sudo-Mode-JWT response header. Fluxer mints a fresh token only when an authenticator satisfied the requirement. A request presenting an already valid token gets that same token back without an extended lifetime.

A request that does not satisfy the requirement returns 403 SUDO_MODE_REQUIRED, whose body has has_mfa and methods as top-level members. An invalid authenticator code, backup code, or WebAuthn assertion returns INVALID_MFA_CODE on the mfa_code path. An incorrect password returns INVALID_PASSWORD on the password path.

A request presents an existing token in the X-Fluxer-Sudo-Mode-JWT request header. Retain the response header value and send it back on each later operation in the same sudo window.

GET/v1/users/@meBotidentify

Returns the current user object.

  • An OAuth2 bearer credential must hold the identify scope, and one without it is rejected with 403 MISSING_OAUTH_SCOPE, whose body has required_scope.
  • A bearer receives the neutralised representation, and email only when it also holds the email scope.

This route alone admits an account with an outstanding required action, so a client can read and poll the actions it has to complete.

StatusBodyCondition
200user objectCurrent account was returned
403error responseBearer credential lacks the identify scope and the request returns MISSING_OAUTH_SCOPE

40 requests per 10 seconds for each authenticated user, on the user:settings:get bucket, which is shared with Get current user settings.

PATCH/v1/users/@me

Modifies the current account and returns the resulting user object.

  • Changing the username or discriminator to a different value, supplying new_password, or supplying email_token requires sudo verification.
  • A field supplied with the value the account already holds is not a change and does not raise that requirement.
  • An unclaimed account never raises it either.
FieldTypeDescription
username?1stringUsername after trimming (1-32 ASCII letters, digits, or underscores)
discriminator?2string | integerDiscriminator parsed as an integer (1-4 decimal digits)
global_name?3?stringDisplay name after sanitisation (1-32 characters), or null to clear
email?4stringAlways rejected, because an address is applied through email_token
new_password?5stringNew password (8-256 characters)
password?stringCurrent password (8-256 characters), used as sudo verification proof
avatar?6?stringBase64-encoded avatar image, or null to clear
banner?6 7?stringBase64-encoded banner image, or null to clear
bio?8?stringBiography (1-320 characters), or null to clear
pronouns?9?stringPronouns (1-40 characters), or null to clear
accent_color??integerPacked 24-bit RGB colour (0-16777215), or null to clear
timezone?10 11?stringSupported IANA timezone identifier (1-128 characters), or null to clear
timezone_privacy_flags?10integerProfile field privacy flags applied to the profile timezone
premium_badge_hidden?booleanWhether to withhold the premium badge from the public profile
premium_badge_masked?booleanWhether to present a lifetime badge as an ordinary subscription badge
premium_badge_timestamp_hidden?booleanWhether to withhold the premium activation time
premium_badge_sequence_hidden?booleanWhether to withhold the lifetime premium sequence
premium_enabled_override?12booleanWhether a staff override grants premium entitlements
has_dismissed_premium_onboarding?13booleanWhether the premium onboarding flow has been dismissed
has_unread_gift_inventory?14booleanWhether the gift inventory still holds unread items
mention_flags?integerReply mention preference, one of 0, 1, or 2
email_token?15stringEmail token (1-256 characters) issued by verify new email
mfa_method?stringSudo verification method, either totp or webauthn
mfa_code?stringSudo verification authenticator or backup code (1-32 characters)
webauthn_response?WebAuthn assertion objectSudo verification WebAuthn assertion
webauthn_challenge?stringSudo verification WebAuthn challenge (1-256 characters)

1 The value cannot be everyone or here and cannot contain fluxer or system message, on every instance including a self-hosted one

2 Supplying the field without a username requires the custom discriminator entitlement and is otherwise rejected with CHANGING_DISCRIMINATOR_REQUIRES_PREMIUM. A pair already assigned to another account is rejected with TAG_ALREADY_TAKEN

3 Sanitisation strips standalone surrogates, invisible characters, and variation selectors and collapses whitespace before the length is measured

4 Any string value returns EMAIL_MUST_BE_CHANGED_VIA_TOKEN on the email path, joined by INVALID_EMAIL_FORMAT when the string is not an address

5 A claimed account also supplies password, and a body that omits it is rejected with PASSWORD_NOT_SET. A breached password is rejected with PASSWORD_IS_TOO_COMMON

6 The value may have a data:...;base64, prefix. The remaining payload runs 1 to 13981016 characters

7 Every non-null value requires the animated banner entitlement, which gates every profile banner, and is otherwise rejected with BANNERS_REQUIRE_PREMIUM

8 The resolved max_bio_length instance limit applies on top of the schema bound, and a longer value is rejected with CONTENT_EXCEEDS_MAX_LENGTH

9 The value is matched against the instance profile substring blocklist like username, global_name, and bio

10 The pair is staff-only. A request from an account without the STAFF flag has both fields dropped before the update runs

11 An unrecognised identifier is rejected with INVALID_TIMEZONE_IDENTIFIER. Setting a first timezone without timezone_privacy_flags sets those flags to EVERYONE

12 The field requires the STAFF flag, and a caller without it is rejected with 403 MISSING_ACCESS

13 Only true has an effect, recording the current time as the dismissal moment. false is accepted and does nothing

14 Only false has an effect, advancing the gift inventory read cursor to the current sequence. true is accepted and does nothing

15 Supplying the field applies the verified address the token stands for, and the token is deleted once the update lands

To skip the body proof fields, send the sudo token in the X-Fluxer-Sudo-Mode-JWT request header.

A body that has no email_token and nothing beyond mfa_method, mfa_code, webauthn_response, and webauthn_challenge returns the current account unchanged. That check runs before the required action barrier, so it succeeds even while an action is outstanding. A body that has only password is an update with nothing to change, and it still emits User Update.

Fluxer rejects an account with an outstanding required action, with one exemption. A body that has email_token and nothing beyond the sudo verification fields is accepted. Any other defined field removes the exemption.

A claimed account needs a verified email before changing the username, discriminator, display name, avatar, banner, biography, pronouns, accent colour, timezone, timezone privacy, or any premium badge field. A request without one returns 403 PROFILE_EMAIL_VERIFICATION_REQUIRED.

An account is unclaimed while it holds no password credential, is not a bot, and does not have the SSO trait. Such an account may set only new_password, has_dismissed_premium_onboarding, and has_unread_gift_inventory. Any other field is rejected with UNCLAIMED_ACCOUNTS_CAN_ONLY_SET_EMAIL_VIA_TOKEN on the path of the first offending field. The allow-list covers the profile payload only, so email_token and the sudo fields stay available as the way such an account claims itself.

Decoded avatar and banner content stays within the resolved avatar_max_size limit, which defaults to 10485760 bytes, and a larger payload is rejected with IMAGE_SIZE_EXCEEDS_LIMIT. Accepted formats are PNG, JPEG, WebP, GIF, APNG, AVIF, HEIC, HEIF, JPEG XL, and SVG. Anything else, animated AVIF included, is rejected with INVALID_IMAGE_FORMAT, and so is content the Media Proxy cannot identify.

An animated avatar requires the animated avatar entitlement and is otherwise rejected with ANIMATED_AVATARS_REQUIRE_PREMIUM. A successfully decoded avatar or non-null banner derives its dominant colour and returns it later as avatar_color or banner_color.

The username, display name, biography, and pronouns are matched against the instance profile substring blocklist, and a match returns 403 CONTENT_BLOCKED. An account with the STAFF flag is exempt. The biography and pronouns are additionally scanned against the phrase and URL blocklists.

The global content filter applied to every POST, PUT, and PATCH JSON body runs the same pair of blocklists over the whole body before the handler. It reads username, global_name, email, timezone, and discriminator when supplied as a string, alongside the biography and pronouns. It skips avatar, banner, password, new_password, email_token, mfa_code, webauthn_response, webauthn_challenge, and every field whose name ends in _flags, and it ignores any value shorter than 3 characters. A match returns the same 403 CONTENT_BLOCKED, and no flag exempts an account from it.

Each control is separate from the route bucket. A denial returns 400 INVALID_FORM_BODY with the matching validation code rather than 429.

ChangeAllowanceValidation code
Resulting username or discriminator5 per 3 hoursUSERNAME_CHANGED_TOO_MANY_TIMES
Biography to a different value25 per 30 minutesBIO_CHANGED_TOO_MANY_TIMES
Pronouns to a different value25 per 30 minutesPRONOUNS_CHANGED_TOO_MANY_TIMES
Accent colour to a different value25 per 30 minutesACCENT_COLOR_CHANGED_TOO_MANY_TIMES
Any non-null avatar25 per 30 minutesAVATAR_CHANGED_TOO_MANY_TIMES
Any banner value past the entitlement check25 per 30 minutesBANNER_CHANGED_TOO_MANY_TIMES

Fluxer consumes the avatar control before it detects identical content, and clearing the avatar consumes nothing. A clearing request consumes the banner control, and so does a request whose value is unchanged.

StatusBodyCondition
200user objectAccount was returned after applying every permitted field
400error responseBody, image, tag, password, entitlement, secondary control, or sudo proof is invalid
403error responseEmail verification, sudo verification, or a staff-only field is required, or content is blocked

A successful change emits User Update to the account. When a partial user object field changes, other accounts observe the new value. Changing the username, discriminator, or display name also reindexes the account’s guild member records in every guild whose member index exists. A body that takes the early return changes nothing and emits no Dispatch. Any other accepted body emits the Dispatch even when no stored value changed.

20 requests per minute for each authenticated user, on the user:update bucket, which is shared with Accept current policies and Reset current premium state.

DELETE/v1/users/@me/authorized-ipsMFA

Deletes every authorised IP record for the current account. Requires sudo verification. Returns 204 with an empty body and emits no Gateway Dispatch.

A later sign-in from any address then needs fresh IP authorisation.

The body is the sudo verification object. It may be an empty object when the request presents an accepted sudo token.

StatusBodyCondition
204emptyAuthorised IP records were cleared
403error responseSudo verification is required and the request returns SUDO_MODE_REQUIRED

10 requests per minute for each authenticated user, on the user:authorized_ips:forget bucket.

POST/v1/users/@me/disableMFA

Disables the current account while preserving its data. Requires sudo verification.

The operation mints no sudo token and returns no X-Fluxer-Sudo-Mode-JWT header.

The body is the sudo verification object. It may be an empty object when the request presents an accepted sudo token.

StatusBodyCondition
204emptyAccount was disabled
403error responseSudo verification is required and the request returns SUDO_MODE_REQUIRED
500error responseThe account could not be disabled or its sessions could not be deleted

Fluxer marks the account disabled and deletes every authentication session it owns. User Update is published only after that deletion. No client of the account is still connected to receive it. The disabled flag is not part of the public flag bitfield, so other accounts observe no change.

5 requests per hour for each authenticated user, on the user:account:disable bucket.

POST/v1/users/@me/deleteMFA

Schedules deletion of the current account and deletes every authentication session it holds. Requires sudo verification.

  • An account that owns at least one guild is rejected with 400 USER_OWNS_GUILDS.

The body is the sudo verification object. It may be an empty object when the request presents an accepted sudo token.

StatusBodyCondition
204emptyAccount deletion was scheduled
400error responseThe caller owns at least one guild and the request returns USER_OWNS_GUILDS

Fluxer marks the account for deletion at the configured deadline and enqueues it for erasure at that time. When the account has an email address, Fluxer sends a scheduled deletion email in the account locale. Every authentication session is deleted, and User Update is published only after that deletion. The self-deleted flag is not part of the public flag bitfield, so other accounts observe no change until erasure runs.

5 requests per hour for each authenticated user, on the user:account:delete bucket.

POST/v1/users/@me/terms-acceptance

Records acceptance of the current terms of service and privacy policy. Returns the updated user object.

The body is an empty object. An absent or empty body is read as an empty object, and any supplied property is discarded. A body that is not valid JSON returns 400 INVALID_FORM_BODY with INVALID_FORMAT at the body path. A body that parses as valid JSON but is not an object is rejected with 400.

StatusBodyCondition
200user objectPolicy acceptance was recorded
400error responseThe body is not valid JSON, or it parses as JSON that is not an object

Fluxer sets both terms_agreed_at and privacy_agreed_at to the request time and emits User Update to the account. Neither timestamp belongs to the partial user object, so no other account observes the change. Repeating the operation replaces both timestamps.

20 requests per minute for each authenticated user, on the user:update bucket, which is shared with Modify current user and Reset current premium state.

POST/v1/users/@me/premium/reset

Clears every premium field on the current account and returns 204 with an empty body. Requires the STAFF flag.

A caller without that flag is rejected with 403 MISSING_ACCESS.

StatusBodyCondition
204emptyPremium state was cleared
403error responseCaller does not have the STAFF flag and the request returns MISSING_ACCESS

The operation clears premium_type, premium_since, premium_until, premium_gift_extension_ends_at, premium_will_cancel, premium_billing_cycle, premium_grace_ends_at, and premium_lifetime_sequence, plus the stored provider customer and subscription identifiers, the purchase and first refund markers, both gift inventory sequences, and the staff premium override flag. It emits User Update to the account.

Other accounts observe a change only when the account held an animated avatar, whose served avatar hash loses its animation prefix with the entitlement.

20 requests per minute for each authenticated user, on the user:update bucket, which is shared with Modify current user and Accept current policies.