Expressions¶
An expression is a custom emoji or a sticker. Guild-owned expressions are managed on Guild emojis and Guild stickers. This page covers the routes that read an expression without membership of its guild, the lists of every expression the caller can use, and expression packs.
All routes are relative to https://tebhos.com/api/v1 and require authentication. Routes marked user-only refuse a valid bot token with 403 ACCESS_DENIED; the others also accept bot tokens. Error bodies follow Errors.
Expression IDs are snowflake strings. Every route that takes an emoji_id or sticker_id also accepts the legacy UUID form described in Emoji IDs. An unknown ID returns 404 NOT_FOUND.
| Object | Route | Owning resource |
|---|---|---|
| Emoji metadata | Get emoji metadata | Guild emojis |
| Sticker metadata | Get sticker metadata | Guild stickers |
| Sticker | Get sticker | Guild stickers |
| Pack summary | Expression packs | The pack creator |
Emoji metadata object¶
A custom emoji as seen from outside its guild.
| Field | Type | Description |
|---|---|---|
| id | snowflake | The ID of the emoji |
| legacy_id | ?string | The legacy UUID identifier |
| guild_id | snowflake | The ID of the guild that owns the emoji |
| name | string | The emoji name |
| animated | boolean | Whether the image is animated |
| allow_cloning | boolean | Always true on this route. Clone guild emoji still refuses a source guild with CLONE_EMOJI_DISABLED |
{
"id": "1501314428688998182",
"legacy_id": "b4497791-c19c-4b6b-9a2f-df4bc155a9f7",
"guild_id": "1489002177550843904",
"name": "party_parrot",
"animated": true,
"allow_cloning": true
}
Sticker metadata object¶
A sticker as seen from outside its guild.
| Field | Type | Description |
|---|---|---|
| id | snowflake | The ID of the sticker |
| legacy_id | ?string | The legacy UUID identifier |
| guild_id | snowflake | The ID of the guild that owns the sticker |
| name | string | The sticker name |
| animated | boolean | Whether the stored image is a GIF |
| allow_cloning | boolean | false when the owning guild has CLONE_STICKER_DISABLED, otherwise true |
Get emoji metadata¶
GET /emojis/{emoji_id}/metadata
Returns the emoji metadata object of any guild emoji. No membership of the owning guild and no permission is required.
Rate limit: guild:emoji:metadata, 60 per 10 seconds per client.
curl https://tebhos.com/api/v1/emojis/1501314428688998182/metadata \
-H "Authorization: Bot $TEBHOS_BOT_TOKEN"
Get sticker metadata¶
GET /stickers/{sticker_id}/metadata
Returns the sticker metadata object of any guild sticker. No membership of the owning guild and no permission is required.
Rate limit: guild:sticker:metadata, 60 per 10 seconds per client.
Get sticker¶
GET /stickers/{sticker_id}
Returns one sticker for display, for example when a message shows a sticker from a guild the reader is not in. No membership is required. Unlike the other routes, the fields are camelCase:
| Field | Type | Description |
|---|---|---|
| id | snowflake | The ID of the sticker |
| legacyId | ?string | The legacy UUID identifier |
| guildId | snowflake | The owning guild |
| name | string | The sticker name |
| description | ?string | The description |
| imageUrl | string | The URL of the stored image |
| tags | array[string] | Search tags |
| createdBy | snowflake | The uploader |
| createdAt | ISO8601 timestamp | When the sticker was created |
List my guild emojis¶
GET /users/@me/guild-emojis
Returns every custom emoji of every guild the caller is a member of, as {"items": [...]}. Clients use it to build an emoji picker. Each item has id, legacy_id, guild_id, guild_name, name, image_url and animated. Guilds are grouped in order of guild name.
Sending an emoji from another guild in a guild channel, in a message or as a new reaction, requires both USE_EXTERNAL_EMOJIS in that guild and TEBHOS Pro; otherwise the request fails with 403 FORBIDDEN. Direct messages have no such check.
List my guild stickers¶
GET /users/@me/guild-stickers
Returns every sticker of every guild the caller is a member of, as {"items": [...]}. Each item has id, legacy_id, guild_id, guild_name, name, description and image_url.
Sending a sticker from another guild in a guild channel requires both USE_EXTERNAL_STICKERS in that guild and TEBHOS Pro; otherwise the request fails with 403 FORBIDDEN. A message can carry at most 3 stickers.
Expression packs¶
An expression pack is a personal collection of emojis (an emoji pack) or stickers (a sticker pack) owned by one account rather than a guild. Packs are a TEBHOS Pro feature: an account can create and install packs only while it has TEBHOS Pro.
Every pack route is user-only and has no route rate limit.
Pack limits¶
| Limit | Without Pro | With TEBHOS Pro |
|---|---|---|
| Packs created, per type | 0 | 50 |
| Packs installed, per type | 0 | 50 |
| Items per pack | - | 200 |
| Emoji image | - | 256 KiB, PNG, JPEG, GIF or WebP |
| Sticker image | - | 500 KiB, PNG, JPEG, GIF or WebP |
Reaching a limit returns 400 BAD_REQUEST.
Pack summary object¶
| Field | Type | Description |
|---|---|---|
| id | snowflake | The ID of the pack |
| name | string | The pack name, 1-64 characters |
| description | ?string | The description, up to 256 characters |
| type | string | emoji or sticker |
| creator_id | snowflake | The account that created the pack |
| created_at | ISO8601 timestamp | When the pack was created |
| updated_at | ISO8601 timestamp | When the pack was last changed |
| installed_at? | ISO8601 timestamp | When the caller installed it. Only in the installed lists |
{
"id": "1502001122334455667",
"name": "Workshop reactions",
"description": null,
"type": "emoji",
"creator_id": "1489002177550843905",
"created_at": "2026-09-14T09:12:44+00:00",
"updated_at": "2026-09-14T09:12:44+00:00"
}
List my packs¶
GET /packs
Returns the caller's created and installed packs, grouped by type:
{
"emoji": {"installed_limit": 50, "created_limit": 50, "installed": [], "created": []},
"sticker": {"installed_limit": 50, "created_limit": 50, "installed": [], "created": []}
}
Each list holds pack summary objects. The limits are 0 for an account without TEBHOS Pro.
Create pack¶
POST /packs/{pack_type}
Creates an empty pack and returns its pack summary object. {pack_type} is emoji or sticker; any other value returns 400 BAD_REQUEST.
| Field | Type | Description |
|---|---|---|
| name | string | The pack name, 1-64 characters after trimming |
| description? | ?string | Up to 256 characters. Empty means none |
Modify pack¶
PATCH /packs/{pack_id}
Renames a pack and returns its pack summary object. Only the creator can change a pack (403 FORBIDDEN otherwise).
| Field | Type | Description |
|---|---|---|
| name? | string | The new name, 1-64 characters |
Delete pack¶
DELETE /packs/{pack_id}
Deletes a pack. Only the creator can delete it. Returns 204.
Pack items¶
The creator manages a pack's items with these routes. The pack must be of the matching type, otherwise the request fails with 400 BAD_REQUEST; a pack owned by someone else returns 403 FORBIDDEN.
| Route | Description |
|---|---|
GET /packs/emojis/{pack_id} |
List the emojis: id, name, animated, nsfw (always false) and user |
POST /packs/emojis/{pack_id} |
Add an emoji. Body: name (1-32 characters) and image |
POST /packs/emojis/{pack_id}/bulk |
Add 1-50 emojis. Body: {"emojis": [...]}. Returns {"success", "failed"} |
PATCH /packs/emojis/{pack_id}/{emoji_id} |
Rename an emoji. Body: name (required) |
DELETE /packs/emojis/{pack_id}/{emoji_id} |
Remove an emoji. Returns 204 |
GET /packs/stickers/{pack_id} |
List the stickers: id, name, description, tags, animated, nsfw and user |
POST /packs/stickers/{pack_id} |
Add a sticker. Body: name (1-32 characters), description? (up to 256), tags? (up to 20) and image |
POST /packs/stickers/{pack_id}/bulk |
Add stickers. Body: {"stickers": [...]}. Returns {"success", "failed"} |
PATCH /packs/stickers/{pack_id}/{sticker_id} |
Update a sticker. Body: name (required), description? and tags?. tags replaces the list; omitting it clears the tags |
DELETE /packs/stickers/{pack_id}/{sticker_id} |
Remove a sticker. Returns 204 |
For pack items, image must be a data: URL (for example data:image/png;base64,...); raw base64 is refused. The declared media type decides the format, and a GIF, an animated PNG or an animated WebP is marked animated. The item routes return the created or updated item without user.
The delete routes accept the query parameter purge=true, which also deletes the stored image file.
Pack invites¶
GET /packs/{pack_id}/invites lists the pack's invite codes and POST /packs/{pack_id}/invites creates one. Only the creator can use them.
| Field | Type | Description |
|---|---|---|
| max_uses? | integer | 0-100, where 0 means unlimited (default 0) |
| max_age? | integer | Lifetime in seconds, 0-604800, where 0 means no expiry (default 0) |
| unique? | boolean | When false (the default), an existing invite by the caller with the same settings is returned instead of a new one |
A pack can have at most 1000 invites. Each pack invite object has code, type (2 for an emoji pack, 3 for a sticker pack), pack (the pack summary plus creator), inviter, expires_at, temporary, created_at, uses and max_uses.
Pack invite codes cannot be accepted yet
Accept invite and Get invite handle guild invites only. To add someone else's pack, install it by its ID.
Install pack¶
POST /packs/{pack_id}/install
Adds a pack to the caller's installed packs and returns 204. Any existing pack can be installed. Installing needs TEBHOS Pro and counts toward the installed limit for the pack's type.
DELETE /packs/{pack_id}/install removes an installed pack and returns 204.