Interações e comandos
Registre comandos de barra, entenda o fluxo de uma interação e responda com callbacks, follow-ups e respostas efêmeras.
Uma interação acontece quando alguém usa um comando de barra do seu bot, clica num botão ou menu ou envia um modal. O bot recebe o evento INTERACTION_CREATE pelo gateway (ou por HTTP) e tem 3 segundos para dar o primeiro retorno.
Como o usuário vê#
No chat de um servidor, ao digitar / aparece a lista de comandos de todos os bots daquele servidor (globais e do servidor). Ao escolher um, o app mostra um formulário com as opções acima da caixa de mensagem. Ao enviar, o bot responde e a mensagem aparece com a linha "fulano usou /comando". O comando só aparece se o bot estiver no servidor, e só em canais de texto onde a pessoa pode ver e escrever e o bot pode ver.
Registrar comandos#
Comandos são globais (valem em todos os servidores do bot, /applications/:appId/commands) ou de servidor (/applications/:appId/guilds/:g/commands, o bot precisa estar nele). Se existir um comando de servidor com o mesmo nome de um global, o do servidor é o que roda.
Registre tudo de uma vez com PUT, que sobrescreve a lista do escopo (comandos que você não enviar são apagados; os ids dos que continuam são preservados):
curl -s -X PUT $API/applications/$APP_ID/commands \
-H "Authorization: Bot $TOKEN" -H "Content-Type: application/json" \
-d '[
{"name":"ola","description":"Diz olá","options":[
{"name":"nome","description":"Como te chamar","type":"string","required":false}
]},
{"name":"cor","description":"Escolha uma cor","options":[
{"name":"cor","description":"A cor","type":"string","required":true,
"choices":[{"name":"Azul","value":"azul"},{"name":"Verde","value":"verde"}]}
]}
]'Para criar ou atualizar um só, use POST (cria com 201; se o nome já existe no escopo, atualiza com 200).
Campos de um comando:
| Campo | Regra |
|---|---|
name | 1 a 32 caracteres: letras minúsculas, números, - ou _ |
description | 1 a 100 caracteres |
options | até 25 opções (opcional) |
Campos de uma opção: name (mesma regra do comando, sem repetir), description (1 a 100), type, required (opcional) e choices (opcional).
type | O que chega no INTERACTION_CREATE |
|---|---|
string | texto de até 2000 caracteres |
integer | número inteiro |
number | número decimal |
boolean | true ou false |
user | id de um membro do servidor |
channel | id de um canal do servidor que a pessoa vê |
role | id de um cargo do servidor |
choices só existe para string, integer e number: até 25 itens { name, value } (valores de texto até 100 caracteres, ou números do tipo da opção). Limites: 100 comandos por escopo (global, ou cada servidor). Os valores são validados antes de chegarem ao bot; opção obrigatória ausente, valor inválido e opção desconhecida devolvem 400 para quem usou o comando.
Para opções user, channel e role, o data traz também resolved com os detalhes:
"data": {
"name": "dar-cargo",
"options": { "alvo": "6a7c6c99-...", "cargo": "efb6b62a-..." },
"resolved": {
"users": { "6a7c6c99-...": { "id": "6a7c6c99-...", "username": "betov78h", "displayName": "beto", "createdAt": 1791300000000, "prismaActive": false, "prismaSince": null, "pulsing": false, "pulsingSince": null, "pulseBadge": null, "nextPulseBadge": null, "nickname": null, "roleIds": [], "joinedAt": 1791420369512 } },
"roles": { "efb6b62a-...": { "id": "efb6b62a-...", "name": "Moderador", "color": null } }
}
}Cada entrada de resolved.users é o objeto de usuário completo (com createdAt, Prisma, Pulse e presença) mais nickname, roleIds, joinedAt e o pulsingSince daquele servidor: o bastante para um comando userinfo sem outra chamada à API.
Comandos registrados aparecem na aba Comandos do aplicativo (onde dá para excluí-los). Cada pessoa pode usar até 5 comandos a cada 5 segundos.
Fluxo de uma interação#
- A pessoa envia o comando. A API responde
202a ela e entregaINTERACTION_CREATEao bot pelo gateway (ou por HTTP, veja abaixo). - O bot tem 3 segundos para dar o primeiro retorno. Sem retorno, a pessoa vê (só ela) a mensagem efêmera "O aplicativo não respondeu." e o token fica inutilizável (
410). - O retorno é um callback:
POST /interactions/:id/:token/callback(sem cabeçalho Bot).{ "type": "message", "data": { "body": "texto", "embeds": [...], "attachments": ["att:..."], "ephemeral": false } }responde na hora, com uma mensagem normal do bot (guardada no canal).attachmentssão arquivos preparados antes no canal da interação (veja Anexos em respostas de interação).{ "type": "defer" }mostra "NomeDoBot está pensando…" e libera você de pressa. Depois conclua com o primeiro follow-up (ou comPATCH @original).- Cliques em botões e menus e envios de modais usam os mesmos callbacks, mais
update,defer_updateemodal(veja as seções seguintes).
- Follow-ups:
POST /webhooks/:appId/:tokencom{ body, embeds, components, attachments, ephemeral }. Se a interação estava emdefer, o primeiro follow-up substitui o "pensando…" (resposta200); os seguintes criam mensagens novas (201), no máximo 5 por interação. - Editar a resposta:
PATCH /webhooks/:appId/:token/messages/@originalcom{ body, embeds, components, attachments }(qualquer um deles;attachmentssubstitui a lista de anexos). Em interação ainda emdefer, funciona como a primeira resposta. - O token da interação vale 15 minutos. Depois disso as rotas respondem
410(e404quando a limpeza já removeu).
# responder
curl -s -X POST $API/interactions/$ID/$ITOKEN/callback -H "Content-Type: application/json" \
-d '{"type":"message","data":{"body":"Olá!"}}'
# deferir, e concluir depois
curl -s -X POST $API/interactions/$ID/$ITOKEN/callback -H "Content-Type: application/json" -d '{"type":"defer"}'
curl -s -X POST $API/webhooks/$APP_ID/$ITOKEN -H "Content-Type: application/json" -d '{"body":"Pronto!"}'
# editar a resposta original
curl -s -X PATCH $API/webhooks/$APP_ID/$ITOKEN/messages/@original -H "Content-Type: application/json" -d '{"body":"Texto novo"}'Erros dos callbacks e follow-ups: 400 corpo inválido, resposta vazia ou anexo inválido; 404 token errado; 409 a interação já foi respondida (no callback) ou ainda não foi respondida (em follow-up ou edição); 410 expirou ou "não respondeu"; 429 limite de follow-ups ou limite de envio do bot; 403 o bot perdeu a permissão de enviar naquele canal (ou O bot não pode anexar arquivos aqui. sem ATTACH_FILES).
Respostas efêmeras: com "ephemeral": true a mensagem só chega a quem usou o comando, não é guardada (some ao recarregar) e não conta no limite de envio do canal. Ela pode ser editada via @original, mas não aceita anexos. Se você usou defer com ephemeral: true, repita ephemeral: true no primeiro follow-up.
Tipos de interação e respostas (callbacks)#
O INTERACTION_CREATE tem sempre id, token, applicationId, type, guildId, channelId, user e member; o conteúdo de data depende do type:
type | Quando acontece | data |
|---|---|---|
command | alguém usou um comando de barra | { name, options, resolved? } |
component | alguém clicou num botão ou escolheu num menu | { customId, componentType, values, message } |
modal_submit | alguém enviou um modal aberto pelo bot | { customId, fields, message? } |
user é quem interagiu (objeto de usuário, com createdAt, Prisma, Pulse e presença) e member é o objeto de membro dela no servidor: { nickname, roleIds, joinedAt, pulsingSince, timeoutUntil }. Como toda interação acontece num servidor, member está sempre presente (vale também na entrega por HTTP).
Em component, componentType é "button" ou "select", values é a lista de value escolhidos (vazia em botões) e message é a mensagem onde o clique aconteceu (com id, body, embeds, components...). Em modal_submit, fields mapeia o customId de cada campo ao texto digitado, e message aparece quando o modal foi aberto por um clique.
{
"op": "dispatch", "seq": 21, "t": "INTERACTION_CREATE",
"d": {
"id": "5c1e...", "token": "9f3a...", "applicationId": "1af40b9e-...", "type": "component",
"guildId": "682f1017-...", "channelId": "a8c57340-...",
"user": { "id": "bc86cc02-...", "username": "anav78h", "displayName": "ana", "bot": false, "createdAt": 1791400000000 },
"member": { "nickname": null, "roleIds": [], "joinedAt": 1791420368416, "pulsingSince": null, "timeoutUntil": null },
"data": { "customId": "painel:interesses", "componentType": "select", "values": ["jogos", "musica"], "message": { "id": "f251ec04-...", "body": "", "embeds": [], "components": [] } }
}
}Tipos de resposta (POST /interactions/:id/:token/callback, sem cabeçalho Bot; vale uma resposta por interação, a segunda devolve 409):
type | Para que serve | data |
|---|---|---|
message | responde com uma mensagem nova | { body?, embeds?, components?, attachments?, ephemeral? } |
defer | mostra "pensando…" e dá mais tempo; conclua com follow-up ou PATCH @original | { ephemeral? } |
update | em cliques: troca o conteúdo da mensagem do clique | { body?, embeds?, components?, attachments? } (o que não vier fica como estava) |
defer_update | em cliques: confirma o clique sem mudar nada | nenhum |
modal | abre um formulário para a pessoa (veja a próxima seção) | { customId, title, fields } |
updateedefer_updateprecisam de uma mensagem de origem (um clique, ou o envio de um modal aberto por um clique). Em comandos devolvem400. Depois dedefer_updatevocê ainda pode editar a mensagem do clique comPATCH @original; follow-ups criam mensagens novas (até 5 por interação).- Para sumir com os botões depois de usados, responda com
updatee"components": []. - Como sempre, o primeiro retorno tem de sair em 3 segundos, em qualquer tipo de interação.
- Na entrega por HTTP (URL de interações), o corpo da resposta também pode ser qualquer um destes callbacks.
Veja também#
- Receber interações por HTTP, a alternativa ao gateway.
- Componentes e modais, que também geram interações.
- Rotas de comandos e webhooks na Referência REST.