Editing emote sets
A channel shows one active emote set. Change it with a single mutation, whether it's one emote or five hundred. Requires the SETS_WRITE scope and ownership of the set or editor rights on its channel.
1. Find the set
Look the channel up by its Twitch user ID (the numeric ID, not the login name):
GraphQL
query ActiveSet($twitchId: String!) {
channelByPlatform(platform: TWITCH, platformId: $twitchId) {
id
activeSet { id name capacity emoteCount }
}
}2. Apply operations
editEmoteSet takes a list of operations and runs them in order:
| Type | Effect |
|---|---|
ADD | Adds the emote under its own name, or under alias if given. |
RENAME | Sets the chat name to alias; alias: null resets it to the emote's original name. |
REMOVE | Removes the emote from the set. |
GraphQL
mutation Edit($set: ID!, $ops: [EmoteSetOp!]!) {
editEmoteSet(id: $set, ops: $ops) {
results { emoteId ok errorCode errorMessage entry { name originalName } }
set { emoteCount }
}
}Variables
{
"set": "01J9Z3K8Q0M6W4N2B7C5D1E3F9",
"ops": [
{ "type": "ADD", "emoteId": "01M43XZ4N6EKDAAJST7XW4V6JV" },
{ "type": "ADD", "emoteId": "01M43Y39XKE6MR2A7GJDJANCB1", "alias": "catDance" },
{ "type": "RENAME", "emoteId": "01M3ZQ8T1V7K9X2C4B6N8M0P2R", "alias": "KEKW" },
{ "type": "RENAME", "emoteId": "01M3ZR0A2B4C6D8E0F2G4H6J8K", "alias": null },
{ "type": "REMOVE", "emoteId": "01M3ZS1B3C5D7E9F1G3H5J7K9M" }
]
}3. Read the results
Each operation succeeds or fails on its own: a name conflict skips that one emote, everything else still applies. Results come back in the order you sent them.
Response
{
"data": {
"editEmoteSet": {
"results": [
{ "emoteId": "01M43XZ4…", "ok": true, "errorCode": null, "entry": { "name": "pepeHappy", "originalName": null } },
{ "emoteId": "01M43Y39…", "ok": false, "errorCode": "name_conflict", "entry": null },
…
],
"set": { "emoteCount": 211 }
}
}
}| errorCode | Meaning |
|---|---|
name_conflict | Another emote in the set already uses exactly that chat name (names are case-sensitive, like in chat). |
already_in_set | ADD for an emote that is already in the set. |
set_full | The set reached its capacity. |
emote_not_ready | The emote is still processing or was rejected. |
invalid_alias | Aliases are 2–100 characters without spaces. |
not_found | The emote doesn't exist or isn't in the set (RENAME/REMOVE). |
Order matters, and helps
Because operations run in order, you can free a name and reuse it in the same request: put the
REMOVE or RENAME before the ADD. Up to 500 operations per call; chat clients receive one realtime update for the whole
batch.Example: a chat command
JavaScript
// !addemote <emote id> [alias]: a minimal chat command handler
async function addEmote(twitchId, emoteId, alias) {
const { channelByPlatform: ch } = await gql(ACTIVE_SET, { twitchId });
if (!ch?.activeSet) return 'This channel has no active JilTV set.';
const { editEmoteSet } = await gql(EDIT, {
set: ch.activeSet.id,
ops: [{ type: 'ADD', emoteId, alias }],
});
const [r] = editEmoteSet.results;
if (r.ok) return `Added ${r.entry.name}`;
return {
name_conflict: 'That name is taken in this set. Try another alias.',
already_in_set: 'Already in the set.',
set_full: 'The set is full.',
}[r.errorCode] ?? r.errorMessage;
}
async function gql(query, variables) {
const res = await fetch('https://api.jiltv.app/v1/graphql', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.JILTV_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables }),
});
const { data, errors } = await res.json();
if (errors) throw new Error(`${errors[0].extensions?.code}: ${errors[0].message}`);
return data;
}More set operations
createEmoteSet,updateEmoteSet(name, capacity) anddeleteEmoteSetmanage sets themselves.- Channel editors act with the permissions the owner gave them:
EMOTES_ADD,EMOTES_REMOVEandEMOTES_RENAMEper batch operation (missing ones fail withforbiddenfor that operation only),SETS_CREATE(withownerId),SETS_EDITandSETS_DELETE.emoteSet(id) { viewerPermissions }tells you what you may do. setActiveEmoteSet(scopeCHANNELS_WRITE) switches which set a channel shows, e.g. for a seasonal set.user(id) { emoteSets { … } }lists someone's sets.