Guild emojis¶
A custom emoji is an image that one guild owns. Members use it in messages as <:name:id> (or <a:name:id> when animated) and in reactions. Get emoji metadata resolves an emoji without membership of its guild.
All routes are relative to https://tebhos.com/api/v1, require authentication and accept both user sessions and bot tokens. A caller who is not a member of the guild, or lacks the required permission, receives 403 FORBIDDEN. Error bodies follow Errors.
Emoji IDs¶
An emoji id is a snowflake string, unique across all guilds. This is the ID to use in message markup, reactions and every route on this page.
Legacy UUID identifiers
Until 21 September 2026 the API returned a UUID as the emoji id. Emojis still carry that kind of identifier as legacy_id (new emojis get one too), so older clients, stored links and message markup keep working. Every route that takes an emoji_id accepts either the snowflake or the legacy UUID. New code should use id only.
Guild emoji object¶
| Field | Type | Description |
|---|---|---|
| id | snowflake | The ID of the emoji |
| legacy_id | ?string | The legacy UUID identifier (see Emoji IDs) |
| guild_id | snowflake | The ID of the guild that owns the emoji |
| name | string | The emoji name, 1-32 ASCII letters, digits and underscores |
| animated | boolean | Whether the image is animated (GIF, animated PNG or animated WebP) |
| available | boolean | Always true |
| nsfw | boolean | Always false |
| image_url | string | The URL of the stored image |
| created_at | ISO8601 timestamp | When the emoji was created |
| user? | partial user object | The account that uploaded the emoji. Only List guild emojis includes it |
{
"id": "1501314428688998182",
"legacy_id": "b4497791-c19c-4b6b-9a2f-df4bc155a9f7",
"guild_id": "1489002177550843904",
"name": "party_parrot",
"animated": true,
"available": true,
"nsfw": false,
"image_url": "https://cdn.tebhos.com/emojis/1489002177550843904/0c8f5a52-7e0b-4f3e-9a41-2d6f3b7c9e10/9f2c1d4e7b.gif",
"created_at": "2026-09-14T09:12:44+00:00"
}
The Gateway Guild Emojis Update event carries the guild's complete emoji list. Its items have id, legacy_id, guild_id, name, image_url, animated, nsfw, created_by, created_at, creator_name and creator_avatar.
Limits¶
| Limit | Value |
|---|---|
| Emojis per guild | 50, or 100 when the uploading member has TEBHOS Pro |
| Image size | 256 KiB (262144 bytes) decoded |
| Image formats | PNG, JPEG, GIF and WebP, detected from the file content. SVG is not accepted |
| Name | 1-32 characters: ASCII letters, digits and _. Unique within the guild |
The per-guild limit is checked against the current emoji count each time an emoji is created, so it depends on whether the member creating the emoji has TEBHOS Pro.
Animated emojis need either TEBHOS Pro for the uploading member or a guild at boost level 1 or higher. Otherwise creating or cloning an animated emoji returns 403 FORBIDDEN.
Emoji create object¶
| Field | Type | Description |
|---|---|---|
| name | string | The emoji name, trimmed |
| image | string | The image as raw base64 or a data: URL |
{
"name": "party_parrot",
"image": "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEAAAAALAAAAAABAAEAAAI="
}
List guild emojis¶
GET /guilds/{guild_id}/emojis
Returns every guild emoji object of the guild, each with user. Requires membership; no permission is checked. There is no pagination.
Rate limit: guild:emojis:list, 60 per 10 seconds per account and guild.
curl https://tebhos.com/api/v1/guilds/1489002177550843904/emojis \
-H "Authorization: Bot $TEBHOS_BOT_TOKEN"
Create guild emoji¶
POST /guilds/{guild_id}/emojis
Creates an emoji from an emoji create object and returns its guild emoji object (without user) with status 200. Requires CREATE_EXPRESSIONS. The guild receives Guild Emojis Update, and an EMOJI_CREATE audit log entry is recorded. The request body may be at most 2 MiB.
Rate limit: guild:emoji:create, 10 per 30 seconds per account and guild.
| Status | Code | Condition |
|---|---|---|
| 400 | INVALID_FORM_BODY |
The name is empty, longer than 32 characters or has other characters |
| 400 | BAD_REQUEST |
The image is empty, not valid base64, larger than 256 KiB or not an accepted format, or the guild is at its emoji limit |
| 403 | FORBIDDEN |
CREATE_EXPRESSIONS is missing, or the image is animated and neither Pro nor boost level 1 applies |
| 409 | CONFLICT |
The guild already has an emoji with that name |
curl -X POST https://tebhos.com/api/v1/guilds/1489002177550843904/emojis \
-H "Authorization: Bot $TEBHOS_BOT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "shipit", "image": "data:image/png;base64,iVBORw0KGgo..."}'
Bulk create guild emojis¶
POST /guilds/{guild_id}/emojis/bulk
Tries to create 1-50 emojis and returns {"success": [...], "failed": [...]}. Requires CREATE_EXPRESSIONS. The request body may be at most 40 MiB.
Rate limit: guild:emoji:bulk_create, 6 per 60 seconds per account and guild.
JSON body¶
| Field | Type | Description |
|---|---|---|
| emojis | array[emoji create object] | The emojis to create, 1-50 items, attempted in order |
Each item is handled independently. success holds the guild emoji objects that were created; failed holds {"name": string, "error": string} for each item that was rejected, where error is a human-readable message. The response is 200 even when every item failed. An empty array or more than 50 items returns 400 INVALID_FORM_BODY.
When at least one emoji was created, the guild receives one Guild Emojis Update.
Clone guild emoji¶
POST /guilds/{guild_id}/emojis/clone
Copies an emoji from any guild into this guild and returns the new guild emoji object. Requires CREATE_EXPRESSIONS in the target guild; membership of the source guild is not needed. The copy gets a new ID, the caller as uploader, and the source image.
Rate limit: guild:emoji:clone, 10 per 30 seconds per account and guild.
JSON body¶
| Field | Type | Description |
|---|---|---|
| source_emoji_id | string | The ID (snowflake or legacy UUID) of the emoji to copy |
| name? | string | A name for the copy. Defaults to the source name |
| Status | Code | Condition |
|---|---|---|
| 403 | FORBIDDEN |
CREATE_EXPRESSIONS is missing, or the source guild has the CLONE_EMOJI_DISABLED feature |
| 404 | NOT_FOUND |
The source emoji does not exist |
| 409 | CONFLICT |
The target guild already has an emoji with that name |
The target guild's emoji limit applies. The copy records an EMOJI_CREATE audit entry and dispatches Guild Emojis Update in the target guild.
Modify guild emoji¶
PATCH /guilds/{guild_id}/emojis/{emoji_id}
Renames an emoji and returns its guild emoji object. The image cannot be changed. The member who uploaded the emoji needs CREATE_EXPRESSIONS; anyone else needs MANAGE_EXPRESSIONS.
Rate limit: guild:emoji:update, 20 per 10 seconds per account and guild.
| Field | Type | Description |
|---|---|---|
| name? | string | The new name. Same rules as on creation |
A rename records an EMOJI_UPDATE audit entry. Every successful request dispatches Guild Emojis Update. An emoji that is not in this guild returns 404 NOT_FOUND, and a name used by another emoji of the guild returns 409 CONFLICT.
Delete guild emoji¶
DELETE /guilds/{guild_id}/emojis/{emoji_id}
Deletes an emoji and returns 204. The uploader needs CREATE_EXPRESSIONS; anyone else needs MANAGE_EXPRESSIONS.
Rate limit: guild:emoji:delete, 10 per 30 seconds per account and guild.
The deletion frees one emoji slot, records an EMOJI_DELETE audit entry and dispatches Guild Emojis Update. Messages that already contain the emoji are not changed. The route takes no purge parameter. An emoji that is not in this guild returns 404 NOT_FOUND.
Upload flow¶
The TEBHOS web app uploads emoji images directly to storage instead of sending base64. Both steps are user-only (a bot token receives 403 ACCESS_DENIED) and require membership and CREATE_EXPRESSIONS.
POST /servers/{guild_id}/emojis/upload-urlwith{"filename": string, "content_type": string, "size": integer}.sizemay be at most 262144 andcontent_typemust be an accepted image type. Returnsupload_url(a presigned URL valid for 300 seconds),storage_key,urlandexpires_in.PUTthe bytes toupload_url, thenPOST /servers/{guild_id}/emojis/confirmwith{"storage_key": string, "name": string, "animated": boolean}.
The confirmation checks the name length (1-32, 400 BAD_REQUEST), name uniqueness (409 CONFLICT) and the animated-emoji rule, records an EMOJI_CREATE audit entry, dispatches Guild Emojis Update and returns {"id", "guild_id", "name", "image_url", "animated"}.