Skip to content

Applications

An application is an OAuth2 client owned by one user account, and every bot account belongs to one application. Creating an application always creates its bot account too. A user owns at most 25 applications. The authorisation code grant, the scopes, and the tokens issued to third-party clients belong to the OAuth2 resource. For a walkthrough, see Creating a bot.

Access rules

The management routes are user-only: they require a user session token, and a valid bot token is rejected with 403 ACCESS_DENIED (an invalid one with 401). Get public application needs no credential. Get bot application accepts only a bot token, and Get current application accepts either.

Only the owner can read or change an application. Another account receives 403 FORBIDDEN.

The credential-rotation routes and Delete application require sudo mode. Put the proof in the JSON body (password, mfa_code, or sudo_proof), or call them from a session that holds a sudo grant from Grant sudo mode. A missing proof returns 403 SUDO_MODE_REQUIRED.

Credentials are shown once

The client secret is returned only by Create application and Reset client secret, and the bot token only by Create application and Reset bot token. TEBHOS stores only a hash of each and cannot show them again.

Bot tokens

A bot token is the application ID, a full stop, and a secret of 32 random bytes encoded as base64url:

1501314428688998182.q0lPd3Jm3wX8Yv1lS4a2bQ6uK9tE7nZcR5hJ0mAoVfI

Send it as Authorization: Bot <token>. The bot user's ID is always equal to the application ID. See Authentication.

Application object

The application as its owner sees it.

Structure

Field Type Description
id snowflake The application ID
name string The application name (1-100 characters)
redirect_uris array[string] The registered OAuth2 redirect URIs, in no defined order; an empty array when there are none
bot_public boolean Whether anyone can install the bot, not only the owner
bot_require_code_grant boolean Whether installing the bot requires a full code grant with a redirect URI
client_secret? string The client secret, present only in the responses of Create application and Reset client secret
bot? application bot object The bot account; absent if the bot account can no longer be read

Example

{
  "id": "1501314428688998182",
  "name": "Party Parrot",
  "redirect_uris": ["https://example.com/callback"],
  "bot_public": true,
  "bot_require_code_grant": false,
  "bot": {
    "id": "1501314428688998182",
    "username": "Party_Parrot",
    "discriminator": "0001",
    "avatar": null,
    "banner": null,
    "bio": null,
    "mfa_enabled": false,
    "authenticator_types": [],
    "flags": 0
  }
}

Application bot object

The bot account an application owns.

Structure

Field Type Description
id snowflake The bot user ID, equal to the application ID
username string The bot's username
discriminator string The four-digit discriminator, zero-padded
avatar ?string The avatar hash, or null
banner ?string The banner hash, or null
bio ?string The profile biography, or null
mfa_enabled boolean Whether authenticator_types is non-empty
authenticator_types array[integer] The authenticator types copied from the owner's account when the bot was created
flags integer The bot's user flags, including the bot flags
token? string The bot token, present only in the response of Create application

Bot flags

Value Name Description
1 << 4 FRIENDLY_BOT The bot accepts friend requests
1 << 5 FRIENDLY_BOT_MANUAL_APPROVAL Friend requests to the bot need manual approval

These bits live in the bot's user flags. Update bot profile can change only these two bits. A client MUST ignore bits it does not recognise.

Public application object

The application as any caller sees it, including a caller that sends no credential.

Structure

Field Type Description
id snowflake The application ID
name string The application name
icon ?string The bot's avatar hash, used as the application icon, or null
description null Always null
redirect_uris array[string] The registered redirect URIs
scopes array[string] ["bot"] when the application has a bot account, otherwise empty
bot_public boolean Whether the caller can install the bot. Always true for the owner, even when the bot is private
bot ?object {id, username, discriminator, global_name, avatar, bot, flags} of the bot account, or null
current_user ?object {id, username, discriminator, global_name, avatar} of the caller, or null when the request has no valid user session

Public data

This object exposes the redirect URI list and the bot profile to anyone. It never contains the client secret, the bot token, or the owner's identity.

Current bot application object

The application behind a bot token, as returned to that token.

Structure

Field Type Description
id snowflake The application ID
name string The application name
icon ?string The bot's avatar hash, or null
description ?string The bot's biography, or null
bot_public boolean Whether anyone can install the bot
bot_require_code_grant boolean Whether installing the bot requires a full code grant
verify_key string A compatibility placeholder: always 64 0 characters
owner object {id, username, discriminator, global_name, avatar} of the owning account
redirect_uris array[string] The registered redirect URIs
bot? application bot object The bot account, without token

Bot profile object

Returned by Update bot profile.

Structure

Field Type Description
id snowflake The bot user ID
username string The bot's username
discriminator string The four-digit discriminator, zero-padded
avatar ?string The avatar hash, or null
banner ?string The banner hash, or null
bio ?string The biography, or null
flags integer The bot's user flags

Bot token reset object

Returned by Reset bot token.

Structure

Field Type Description
token string The new bot token
bot application bot object The bot account, without token

List owned applications

GET /users/@me/applications

Returns an array of every application object the current user owns. Requires a user session token; a request with a Bot credential returns 403 FORBIDDEN. No entry has a client secret or bot token. The list is not paginated.

Rate limit

60 requests per minute for each account, on the oauth_dev:clients:list bucket.

Get current application

GET /oauth2/applications/@me

Returns the caller's applications, selected by credential type:

The response shape depends on the credential

The body is an array for a user and a single object for a bot. A client that accepts both MUST branch on the shape.

Rate limit

60 requests per minute for each user or bot, on the oauth_dev:clients:list bucket.

Get bot application

GET /applications/@me

Returns the current bot application object for the presented bot token. Only Authorization: Bot <token> is accepted.

Response

Status Body Condition
200 current bot application object The application was returned
401 error response The credential is missing, is not a bot token, does not verify, or its application or owner no longer exists (UNAUTHORIZED, message invalid_token)

Every rejection is the same, so a caller cannot tell a malformed token from one whose application was deleted. A bot can use this route to validate its token on start-up.

Get public application

GET /oauth2/applications/{id}/public

Returns the public application object. Authentication is not required. A valid user session fills in current_user, and the owner sees bot_public: true.

Path parameters

Field Type Description
id snowflake The application ID

Response

Status Body Condition
200 public application object The application was returned
400 error response The ID is not a snowflake
404 error response The application does not exist

Rate limit

60 requests per minute for each client, on the oauth_dev:clients:list bucket.

Create application

POST /oauth2/applications

Creates an application together with its bot account. Returns the application object with the initial client_secret and, in bot.token, the initial bot token.

The route is CAPTCHA-gated: when the instance has a CAPTCHA provider, a missing X-Captcha-Token returns 400 CAPTCHA_REQUIRED and a rejected one returns 400 INVALID_CAPTCHA. See CAPTCHA handling.

Request headers

Field Type Description
X-Captcha-Token? string The CAPTCHA solution
X-Captcha-Type? string hcaptcha or turnstile; omit to use the instance provider

JSON body

Field Type Description
name string The application name (1-100 characters after trimming)
redirect_uris? ?array[string] The OAuth2 redirect URIs to register
bot_public? boolean Whether anyone can install the bot (default true)
bot_require_code_grant? boolean Whether installing the bot requires a full code grant (default false)

Redirect URIs are stored exactly as given. Authorise application and the token exchange compare them byte for byte, so register the exact string your callback uses, preferably with https.

Response

Status Body Condition
200 application object The application and its bot were created
400 error response The name is invalid, or the CAPTCHA is missing or rejected
401 error response No valid user session
400 error response MAX_APPLICATIONS: the caller already owns 25 applications
429 error response The route bucket denied the request

Side effects

The bot's username is derived from the application name: ASCII letters, digits, and _ are kept, spaces, -, and . become _, and the result is cut to 32 characters. When that leaves fewer than 2 characters, or the name has no free discriminator, a random name of the form Bot plus 8 letters and digits is used. The discriminator is the lowest free number for that username. The bot starts with no avatar, banner, or biography.

Rate limit

10 requests per hour for each account, on the oauth_dev:clients:create bucket.

Example

curl -X POST https://tebhos.com/api/v1/oauth2/applications \
  -H "Authorization: Bearer <session token>" \
  -H "Content-Type: application/json" \
  -d '{"name": "Party Parrot", "redirect_uris": ["https://example.com/callback"]}'

Get application

GET /oauth2/applications/{id}

Returns one application object. Only the owner can read it.

Path parameters

Field Type Description
id snowflake The application ID

Response

Status Body Condition
200 application object The application was returned
400 error response The ID is not a snowflake
403 error response The caller does not own the application
404 error response The application does not exist

Rate limit

60 requests per minute for each account, on the oauth_dev:clients:list bucket.

Update application

PATCH /oauth2/applications/{id}

Updates an application and returns the resulting application object. Only the owner can update it. An omitted field is left unchanged.

Path parameters

Field Type Description
id snowflake The application ID

JSON body

Field Type Description
name? string The application name (1-100 characters after trimming)
redirect_uris? array[string] The complete new set of redirect URIs. [] removes them all; null or omission leaves the set unchanged
bot_public? boolean Whether anyone can install the bot
bot_require_code_grant? boolean Whether installing the bot requires a full code grant

Removing a redirect URI affects new authorisation requests only. A code already issued for that URI still exchanges with it, and existing tokens are unaffected. Neither the client secret nor the bot token changes.

Response

Status Body Condition
200 application object The application was updated
400 error response The ID or the name is invalid
403 error response The caller does not own the application
404 error response The application does not exist

Rate limit

30 requests per minute for each application, on the oauth_dev:clients:update bucket, shared with Update bot profile.

Update bot profile

PATCH /oauth2/applications/{id}/bot

Updates the application's bot account and returns the bot profile object. Only the owner can update it.

Path parameters

Field Type Description
id snowflake The application ID

JSON body

Field Type Description
username? string The new username (2-32 characters after trimming)
discriminator? integer Accepted only when it equals the current discriminator; the discriminator cannot be chosen
avatar? ?string A new avatar as a data URI (data:image/png;base64,...), or null to remove it
banner? ?string A new banner as a data URI, or null to remove it
bio? ?string The biography (at most 1024 characters), or null to remove it
bot_flags? integer The desired bot flags. Only those two bits are read; every other bit is ignored

An image must be PNG, JPEG, GIF, or WebP and between 1 byte and 8 MiB after decoding. An omitted avatar, banner, or bio leaves the stored value unchanged; only null removes it.

When the username changes, the bot keeps its discriminator if it is free for the new name, and otherwise gets the lowest free one. A name with no free discriminator returns 400.

The update always clears the bot's display name, so a bot is always shown by its username.

Response

Status Body Condition
200 bot profile object The profile was updated
400 error response A field, an image, or the discriminator is invalid, or no discriminator is free
403 error response The caller does not own the application
404 error response The application or its bot account does not exist

Rate limit

30 requests per minute for each application, on the oauth_dev:clients:update bucket, shared with Update application.

Reset bot token

POST /oauth2/applications/{id}/bot/reset-token

Rotates the bot token and returns the bot token reset object. The caller must own the application and prove sudo mode.

Path parameters

Field Type Description
id snowflake The application ID

JSON body

Optional sudo verification fields: password, mfa_code, or sudo_proof. Send an empty body when the session holds a sudo grant.

Response

Status Body Condition
200 bot token reset object The token was rotated
401 error response The password or code is wrong
403 error response The caller does not own the application, or sudo mode was not proven (SUDO_MODE_REQUIRED)
404 error response The application or its bot account does not exist

Rotation disconnects the bot

The previous token stops working immediately, and every Gateway session the bot holds is closed. The bot reconnects only after its operator installs the new token.

The bot's guild and group DM memberships are unchanged.

Rate limit

10 requests per hour for each application, on the oauth_dev:clients:rotate_secret bucket, shared with Reset client secret.

Reset client secret

POST /oauth2/applications/{id}/client-secret/reset

Rotates the OAuth2 client secret and returns the application object with the new client_secret. The caller must own the application and prove sudo mode.

Path parameters

Field Type Description
id snowflake The application ID

JSON body

Optional sudo verification fields, as for Reset bot token.

Response

Status Body Condition
200 application object The secret was rotated
401 error response The password or code is wrong
403 error response The caller does not own the application, or sudo mode was not proven
404 error response The application does not exist

Token exchange, introspection, and revocation stop accepting the previous secret immediately. Existing access and refresh tokens stay valid.

Rate limit

10 requests per hour for each application, on the oauth_dev:clients:rotate_secret bucket, shared with Reset bot token.

Delete application

DELETE /oauth2/applications/{id}

Deletes an application and retires its bot account. Returns 204. The caller must own the application and prove sudo mode.

Path parameters

Field Type Description
id snowflake The application ID

JSON body

Optional sudo verification fields, as for Reset bot token.

Response

Status Body Condition
204 empty The application was deleted
401 error response The password or code is wrong
403 error response The caller does not own the application, or sudo mode was not proven
404 error response The application does not exist

Deletion is permanent

The bot is removed from every guild, its Gateway sessions are closed, and its profile is anonymised (username silinmis_bot_<id>, display name Silinmiş Bot, no avatar, banner, or biography). The application, its client secret, and its bot token are destroyed.

After deletion, the token, introspection, and revocation routes reject the client, and Get current OAuth2 authorisation returns 401 for the application's access tokens. The bot's messages remain, attributed to the anonymised account.

Rate limit

10 requests per hour for each application, on the oauth_dev:clients:delete bucket.