Skip to content

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 on this page except Get current user requires a user session (Authorization: Bearer <token>). A valid bot token or a valid OAuth2 access token is rejected with 403 ACCESS_DENIED.

Route Purpose
GET /users/@me Get current user
PATCH /users/@me Modify current user
POST /users/@me/avatar/upload-url, POST /users/@me/avatar/confirm Change avatar
POST /users/@me/banner/upload-url, POST /users/@me/banner/confirm Change banner
DELETE /users/@me/authorized-ips Forget authorised IPs
POST /auth/account/disable Disable current account
POST /auth/account/delete Schedule current account deletion
POST /users/@me/terms-acceptance Accept current policies

Sudo verification

Security-sensitive changes (the username, lifecycle operations, forgetting authorised IPs, and several MFA routes) require proof of identity in the request body. The same three optional fields are accepted everywhere:

Field Type Description
password? string The current password. Accepted only when the account has no TOTP authenticator and no registered passkey
mfa_code? string A current TOTP code or an unused backup code. Spaces are ignored
sudo_proof? string A one-time proof issued after a successful passkey assertion. See MFA

The first non-empty field in the order sudo_proof, mfa_code, password is checked.

Account state Accepted proof
No TOTP authenticator and no passkey password, mfa_code or sudo_proof
A TOTP authenticator or at least one passkey mfa_code or sudo_proof only; password alone is rejected

A request without an accepted proof fails with 403:

{
  "error": "SUDO_REQUIRED",
  "code": "SUDO_MODE_REQUIRED",
  "message": "..."
}

A wrong password or code fails with 401 UNAUTHORIZED. Password attempts are limited to 10 per 5 minutes per account (bucket auth:sudo_pwd) and code attempts to 10 per 15 minutes (bucket auth:sudo_mfa).

Sudo grants

POST /auth/sudo with the same proof fields grants a 5-minute sudo window that is bound to the session that requested it, and returns {"granted_at", "expires_at"}. DELETE /auth/sudo revokes it. Some routes on other pages check this grant instead of body fields, for example deleting your own messages in bulk and application management when no proof fields are sent. GET /auth/sudo/mfa-methods returns {"totp", "webauthn", "has_mfa"} so a client knows which proof to ask for. See MFA.

Get current user

GET /users/@me

Returns the current user object. This is the one route on this page that also accepts a bot token (Authorization: Bot <token>); a bot receives its own user object with bot: true.

Also accepts an OAuth2 access token with the identify scope.

Access token response

With an OAuth2 access token the response is the same user object, with private fields replaced by neutral values:

Field Value
email The address only when the token also holds the email scope; otherwise null
email_bounced, authenticator_types Omitted
acls, traits, required_actions []
mfa_enabled, nsfw_allowed, premium_will_cancel, premium_badge_hidden, premium_badge_masked, premium_badge_timestamp_hidden, premium_badge_sequence_hidden, premium_purchase_disabled, premium_enabled_override, premium_perks_disabled, has_dismissed_premium_onboarding, has_ever_purchased, has_unread_gift_inventory false
password_last_changed_at, premium_since, premium_until, premium_billing_cycle, premium_lifetime_sequence, pending_bulk_message_deletion null
unread_gift_inventory_count 0

Every other field is returned as it is for a session.

Response

Status Body Condition
200 user object Account was returned
401 error Missing or invalid credential
403 error An OAuth2 access token without the identify scope (MISSING_OAUTH_SCOPE)

Rate limit

40 requests per 10 seconds per user, bucket user:settings:get, shared with Get current user settings.

curl https://tebhos.com/api/v1/users/@me \
  -H "Authorization: Bearer $TEBHOS_TOKEN"
const res = await fetch("https://tebhos.com/api/v1/users/@me", {
  headers: { Authorization: `Bot ${process.env.TEBHOS_BOT_TOKEN}` },
});
const me = await res.json();
console.log(me.username, me.id);
import os, requests

r = requests.get(
    "https://tebhos.com/api/v1/users/@me",
    headers={"Authorization": f"Bot {os.environ['TEBHOS_BOT_TOKEN']}"},
)
print(r.json()["username"])

Modify current user

PATCH /users/@me

Modifies the current account and returns the resulting user object. Every field is optional; an omitted field is left unchanged. A body that changes nothing is not an error and returns the current user.

The body is processed in three steps, and an error in an earlier step stops the request: account fields are validated first, then a username change runs, then profile fields are written, and finally account fields are stored.

JSON body

Username (requires sudo verification)

Field Type Description
username? string New username. Lowercased, 3-32 characters of a-z, 0-9, _ and -. A username held by another account returns 409 CONFLICT
password? / mfa_code? / sudo_proof? string Sudo verification proof. Only read when username is present

Profile

Field Type Description
global_name? ?string Display name, 2-32 characters, or null to clear it. name is accepted as an alias and wins when both are sent
bio? ?string Biography, up to 4000 characters. Null or "" clears it
pronouns? ?string Pronouns, up to 40 characters. Null or "" clears them
accent_color? ?integer Accent colour as packed 24-bit RGB, or null to clear it
timezone? string IANA timezone identifier (up to 128 characters), trimmed. "" clears it. An unknown identifier returns 400 INVALID_FORM_BODY (INVALID_TIMEZONE_IDENTIFIER)
timezone_privacy_flags? integer Profile field privacy flags for the timezone. Setting a first timezone without this field sets it to EVERYONE
custom_status? string Custom status text, up to 100 characters. "" clears the text, emoji and expiry together
custom_status_emoji_id? string Custom status emoji: a custom emoji ID or a Unicode emoji (up to 100 characters)
custom_status_expires_at? ISO8601 timestamp When the custom status expires
image_url? string Only "" is meaningful: it removes the avatar. Upload a new avatar with Change avatar
banner_color? string Profile banner colour as #RRGGBB (exactly 7 characters)
banner_type? string Banner display type (up to 20 characters), for example color or image
banner_image_url? string Banner image URL (up to 512 characters); "" clears it. Upload a new banner with Change banner
active_frame_url? string Avatar frame to display (up to 512 characters); "" removes it
active_badge_url? string Premium badge to display; "" removes it. The account must hold TEBHOS Pro long enough for the badge's tier, otherwise 403
active_badge_name? string Name of the selected premium badge
boost_badge_url? string Booster badge to display; "" removes it. Requires enough days of continuous guild boosting for the badge's tier, otherwise 403; an unknown badge returns 400
boost_badge_name? string Name of the selected booster badge

Account

Field Type Description
mention_flags? integer Reply mention preference: 0, 1 or 2. Anything else returns 400
premium_badge_hidden? boolean Hide the premium badge from the public profile
premium_badge_masked? boolean Show a lifetime badge as an ordinary subscription badge
premium_badge_timestamp_hidden? boolean Hide the premium start date
premium_badge_sequence_hidden? boolean Hide the lifetime sequence number
premium_enabled_override? boolean Staff only. Other accounts receive 403 MISSING_ACCESS
has_dismissed_premium_onboarding? boolean Only true has an effect: it records the dismissal time
has_unread_gift_inventory? boolean Only false has an effect: it marks the gift inventory as read

Not accepted here

Email and password changes use the code-based flows on Email and password. Avatars and banners use the upload routes below. discriminator and date_of_birth cannot be changed.

Limits

Change Allowance Error
Any request with profile fields 20 per 60 seconds per user (bucket user:update) 429
Username 5 per 3 hours per user (bucket username_change), counted after sudo verification 429
Biography to a different value 25 per 30 minutes 400 INVALID_FORM_BODY, BIO_CHANGED_TOO_MANY_TIMES on bio
Pronouns to a different value 25 per 30 minutes 400 INVALID_FORM_BODY, PRONOUNS_CHANGED_TOO_MANY_TIMES on pronouns
Accent colour to a different value 25 per 30 minutes 400 INVALID_FORM_BODY, ACCENT_COLOR_CHANGED_TOO_MANY_TIMES on accent_color

Saving the value a field already holds does not count against the per-field allowances.

Response

Status Body Condition
200 user object Changes applied
400 error A field failed validation
401 error Wrong sudo password or code
403 error Sudo proof missing (SUDO_MODE_REQUIRED), staff-only field, or badge not unlocked
409 error CONFLICT Username is taken
429 error Rate limited

Side effects

The account's own sessions receive USER_UPDATE with the private user object at the top level. Guild members and friends receive the profile change as well, and the Gateway derives GUILD_MEMBER_UPDATE for guilds whose cached member data changed. See Gateway events.

curl -X PATCH https://tebhos.com/api/v1/users/@me \
  -H "Authorization: Bearer $TEBHOS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"global_name": "Aria", "pronouns": "she/her", "mention_flags": 2}'

Change avatar

Avatars are uploaded directly to storage with a pre-signed URL, then confirmed.

Create avatar upload URL

POST /users/@me/avatar/upload-url

Field Type Description
filename string Original file name; must not be blank
content_type string image/png, image/jpeg, image/jpg, image/gif or image/webp
size integer File size in bytes, 1 to 8388608 (8 MiB)

Returns:

Field Type Description
upload_url string Pre-signed URL. Send the file with PUT and the same Content-Type
storage_key string Key to pass to the confirm route
url string Temporary public URL of the upload
expires_in integer Seconds the upload URL stays valid (300)

Confirm avatar

POST /users/@me/avatar/confirm

Field Type Description
storage_key string The storage_key from the previous step. It must belong to your account

TEBHOS strips image metadata (EXIF, GPS and similar), stores the file under its content hash, and returns {"avatar_hash", "image_url"}. An animated avatar (GIF, APNG or animated WebP, detected from the bytes) requires TEBHOS Pro and otherwise fails with 403. Avatar changes are limited to 25 per 30 minutes (400 INVALID_FORM_BODY, AVATAR_CHANGED_TOO_MANY_TIMES). A successful change emits USER_UPDATE.

To remove the avatar, send {"image_url": ""} to Modify current user.

See Uploads for the general upload flow.

Change banner

POST /users/@me/banner/upload-url and POST /users/@me/banner/confirm

Same bodies, limits and flow as Change avatar. The confirm route returns {"banner_hash", "banner_image_url"}. An animated banner requires TEBHOS Pro. Banner changes are limited to 25 per 30 minutes (BANNER_CHANGED_TOO_MANY_TIMES). The banner hash appears in the user object only while the account has premium.

Forget authorised IPs

DELETE /users/@me/authorized-ips

Deletes every authorised IP record of the account, so the next sign-in from any address needs fresh IP authorisation. Requires sudo verification; the body carries the proof fields.

Response

Status Body Condition
204 empty Records were cleared
403 error SUDO_MODE_REQUIRED No accepted proof

Rate limit

10 requests per 60 seconds per user, bucket user:authorized_ips:forget.

Disable current account

POST /auth/account/disable

Disables the account while keeping its data, and ends every session it owns, including the one that made the request. Signing in again re-activates the account. Requires sudo verification.

Response

Status Body Condition
204 empty Account was disabled
401 error Wrong password or code
403 error SUDO_MODE_REQUIRED No accepted proof

Rate limit

5 requests per hour per user, bucket user:account:disable.

Schedule current account deletion

POST /auth/account/delete

Schedules the account for deletion 14 days from now and ends every session. Signing in before the deadline cancels the deletion. Requires sudo verification.

Transfer guild ownership first

An account that owns a guild cannot be deleted; the request fails with 400 BAD_REQUEST. Transfer or delete each owned guild first.

Response

Status Body Condition
204 empty Deletion was scheduled
400 error The account owns at least one guild
403 error SUDO_MODE_REQUIRED No accepted proof

Rate limit

5 requests per hour per user, bucket user:account:delete.

curl -X POST https://tebhos.com/api/v1/auth/account/delete \
  -H "Authorization: Bearer $TEBHOS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mfa_code": "123456"}'

Accept current policies

POST /users/@me/terms-acceptance

Records acceptance of the current terms of service and privacy policy by setting terms_agreed_at and privacy_agreed_at to the request time. The body is ignored. Returns the updated user object and emits USER_UPDATE to the account's sessions. Repeating the call replaces both timestamps.

Rate limit

20 requests per 60 seconds per user, bucket user:update.

Legacy profile reads

The TEBHOS web client also uses two older, flat profile reads. New integrations should prefer Get current user.

Route Returns
GET /auth/me A flat TEBHOS profile record of the current account (profile customisation, MFA timestamps, premium summary)
GET /me The current account as a profile object, including email