Interações
Receba comandos, cliques e modais pelo Gateway ou webhook e responda.
Uma interação nasce quando alguém usa um slash command, clica num botão ou menu, ou envia um modal aberto pelo seu bot. Ela precisa ser respondida em até 15 minutos; depois disso expira.
Tipos de interação
| kind | Origem | Campos extras |
|---|---|---|
command | Slash command | command: { id, name, options } |
component | Clique em botão / escolha em menu | messageId, customId, componentValues (array de strings nos menus, senão null) |
modal_submit | Envio de um modal | messageId, customId (do modal), componentValues = { [custom_id]: valor } |
{
"id": "uuid-da-interacao",
"kind": "command",
"command": { "id": "…", "name": "sauda", "options": { "quem": "mundo" } },
"serverId": "…",
"channelId": "…",
"invokingUserId": "…"
}Como chegam ao bot
O modo é definido na aplicação: sem URL configurada = Gateway; com URL = webhook.
Modo Gateway (padrão)
O evento INTERACTION_CREATE chega no socket do bot. Requer o intent interactions.receive.
Modo webhook
O NEX faz POST na sua URL HTTPS a cada interação, com User-Agent: NexBotWebhook/1.0 e os cabeçalhos de assinatura:
X-Nex-Timestamp: 1759672800
X-Nex-Signature: sha256=<hex>
X-Nex-Signature-Previous: sha256=<hex> // só na 1ª hora após rotacionar o segredoA assinatura é um HMAC-SHA256 de `${timestamp}.${corpo}` com o segredo de assinatura da aplicação. Aceite se qualquer uma das duas bater.
const crypto = require('crypto');
function assinaturaValida(rawBody, timestamp, header, segredo) {
if (!header) return false;
const esperado = 'sha256=' + crypto.createHmac('sha256', segredo)
.update(`${timestamp}.${rawBody}`).digest('hex');
const a = Buffer.from(header), b = Buffer.from(esperado);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}| Regra de entrega | Valor |
|---|---|
| Tempo limite por tentativa | 3 s |
| Tentativas | 3 (imediata, +2 s, +8 s) em erro de rede ou 5xx |
| Resposta 4xx | não tenta de novo; a interação expira |
| Redirecionamentos | não são seguidos |
| Corpo da sua resposta | até 64 KB |
Você pode responder no próprio corpo do 200 (um JSON com type, igual ao do /respond) ou devolver qualquer outro 2xx e responder depois pela API.
command chegam como command: { id, name }, sem options. Comandos com argumentos precisam do modo Gateway.Para testar a URL, use o botão do portal: ele envia { "type": "PING" } assinado.
Responder
/api/bot/interactions/:id/respond{ "type": 4, "content": "…", "embeds": [], "components": [], "flags": 0 }| type | Nome | Para | Efeito |
|---|---|---|---|
| 4 | CHANNEL_MESSAGE_WITH_SOURCE | todos | Envia uma mensagem no canal. Com flags: 64 (efêmera), só quem interagiu vê. |
| 5 | DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE | todos | Mostra "pensando…" para quem interagiu. Responda de novo na mesma interação em até 15 min. |
| 6 | DEFERRED_UPDATE_MESSAGE | component, modal_submit | Reconhece sem efeito visível. |
| 7 | UPDATE_MESSAGE | component, modal_submit | Edita a mensagem original (mesmas regras do PATCH). Só se a mensagem for da sua aplicação. |
| 9 | MODAL | command, component | Abre um formulário. É final: não dá para responder de novo. |
O formato antigo { "content": "…" } continua funcionando (vira tipo 4). Efêmeras (flag 64) não valem para os tipos 6, 7 e 9.
| Erro | Motivo |
|---|---|
| 400 | Corpo inválido para o tipo de resposta (a mensagem diz o campo). |
| 403 | Tipo 7 em mensagem de outra aplicação. |
| 404 | Interação não existe ou é de outra aplicação. |
| 409 | Interação já respondida ou expirada. |
Modais
{
"type": 9,
"modal": {
"title": "Fale conosco", // 1–45
"custom_id": "contato", // 1–100
"components": [ // 1–5 Labels
{
"type": 18, "label": "Seu nome", "description": "opcional, até 100",
"component": { "type": 4, "custom_id": "nome", "style": 1, "required": true, "min_length": 2, "max_length": 50 }
}
]
}
}Text Input (type: 4): style 1 (linha) ou 2 (parágrafo), min_length 0–4000, max_length 1–4000, value e placeholder (100) opcionais, required padrão true. Quando a pessoa envia, sua aplicação recebe uma nova interação modal_submit.