Gateway
Todo o tempo real do Concord passa por um WebSocket:
wss://app.concord.win/ws
Não há sharding, não há intents, não há segundo socket para voz. Um bot e o aplicativo web falam exatamente o mesmo protocolo.
Entrar
Duas regras e nada mais:
- a primeira mensagem precisa chegar em 10 segundos, senão a conexão é fechada sem aviso;
- ela é um JSON com o campo
token.
{"type": "auth", "token": "Bot NDc.xxxxxxxx…"}
type dessa primeira mensagem é decorativoO servidor lê só o campo token. Mandar {"token": "..."} sozinho funciona igual. O "type": "auth" está aí porque o cliente web manda — não porque alguém o leia.
O prefixo Bot é o que diz ao servidor que isso é um token de aplicação e não um token de sessão
de pessoa. Se o seu cliente consegue mandar cabeçalho no handshake (qualquer coisa fora do
navegador consegue), prefira o cabeçalho e deixe o frame sem prefixo:
Authorization: Bot NDc.xxxxxxxx…
Deu certo, chega o welcome:
{"type": "welcome", "me": {"id": 47, "name": "Tocadiscos", "bot": true, …},
"ice": {…}, "room": null, "sfu": true}
Deu errado:
{"type": "error", "code": "auth", "message": "Sessão inválida, entre de novo"}
Depois do welcome vem um state, e aí a conexão está pronta.
Formato das mensagens
Todas, nos dois sentidos, são JSON com um campo type em snake_case:
{"type": "chat", "channel": 12, "text": "oi"}
Mensagem maior que 256 KB derruba a conexão.
state é uma foto, não um delta
{"type": "state", "servers": [...], "online": [...]}
O state chega no começo e de novo a cada mudança que afete o que você vê: alguém entrou na
voz, um canal nasceu, um cargo mudou. Ele nunca é parcial — é sempre o retrato inteiro.
Então substitua o seu estado local por ele. Quem tenta mesclar state com o que já tinha
acaba com canal fantasma e membro duplicado.
O que o bot normalmente escuta
type | Quando chega |
|---|---|
welcome | logo depois do login |
state | no começo e a cada mudança estrutural |
chat | mensagem nova num canal de texto |
chat_edited / chat_deleted | edição e remoção |
dm | mensagem direta |
joined / left | você entrou ou saiu de um canal de voz |
signal | sinalização WebRTC entre pares |
error / warn / info | recusas e avisos |
O que o bot normalmente manda
type | Para quê |
|---|---|
chat | {"type":"chat","channel":12,"text":"oi"} |
chat_react | reagir — o campo é e, não emoji |
history | pedir mensagens antigas de um canal |
join / leave | entrar e sair de um canal de voz |
media | o que está ligado na voz |
presence | idle, dnd ou invisible |
status | o recado ao lado do nome |
As cinco armadilhas
Estas não dá para adivinhar lendo o protocolo. Todas já custaram tempo.
1. Não existe evento de interação
Não há interaction_create nem caixa de comandos no gateway. Comando de barra é texto. Seu bot
lê o chat, vê que começa com o prefixo e despacha:
if (msg.text.startsWith('/')) despachar(msg);
É por isso que o nescord dispara @SlashCommand a partir do messageCreate.
2. Menção é texto puro
Não existe <@47>. Menção é literalmente @usuario, @everyone, @todos, @aqui, @here.
Isso tem consequência de segurança: se o seu bot ecoa texto de alguém (nome de música, resultado de
busca), ele pode ecoar um @everyone. Veja
Boas práticas.
3. O envio não volta com id
O servidor não confirma um chat com o id da mensagem. Ele reemite um chat para todo mundo
do canal, inclusive para quem mandou. Quem precisa do id (para editar ou apagar depois) casa o
eco pelo autor e pelo texto.
E sim: seu bot recebe de volta as próprias mensagens. Ignore msg.from === meuId ou você entra em
laço.
4. presence só aceita três valores
idle, dnd, invisible. Qualquer outra coisa vira string vazia, que é o mesmo que "online".
Mandar "online" funciona por acidente, não por desenho.
5. media exige os quatro booleanos
{"type": "media", "mic": true, "cam": false, "screen": false, "deaf": false}
Faltando um campo, a mensagem é descartada em silêncio. Não há valor padrão.
Reconexão
A conexão cai: internet, deploy, reinício. O Concord guarda a vaga na voz por 20 segundos. Se
você voltar dentro disso, o welcome vem com room preenchido e o bot continua na sala.
Fora desses 20 segundos, a vaga é liberada e é preciso mandar join de novo.
O token do bot não vence por tempo. O que o derruba é alguém gerar outro no portal — aí a conexão cai e reconectar não adianta: o token antigo não existe mais.