Objetos: usuário e membro
Campos do objeto de usuário (conta, Prisma, Pulse, insígnias e presença) e do objeto de membro (apelido, cargos, entrada no servidor), com um exemplo de comando userinfo.
Toda pessoa que aparece para o bot (autor de mensagem, quem usou um comando, item de members, resolved.users...) é um objeto de usuário: a identidade pública da conta, igual à que o app usa para desenhar nome, avatar e insígnias. Quando a pessoa aparece dentro de um servidor, vem junto o objeto de membro, com o que só existe naquele servidor (apelido, cargos, quando entrou).
Todas as datas são milissegundos desde 1970 (o mesmo Date.now() do JavaScript). null quer dizer "não se aplica" ou "o dono escondeu".
Objeto de usuário#
| Campo | Tipo | O que é |
|---|---|---|
id | string | Id da conta (o mesmo em todos os servidores). |
username | string | Nome de usuário único. |
displayName | string | Nome de exibição. |
bot | boolean | true para contas de bot. |
avatarUrl, bannerUrl | string ou null | Imagens do perfil. |
flags | string[] | Insígnias da conta (ADMIN, VERIFIED, PARTNER, STAFF, EARLY_SUPPORTER, VERIFIED_BOT_DEVELOPER, níveis de presentes e de Pulse...) e sobrescritas do admin (BADGE_SHOW_<id> e BADGE_HIDE_<id>). |
createdAt | number | Quando a conta foi criada. Nunca é escondido. |
prismaActive | boolean | Tem assinatura Prisma ativa. |
prismaPlan | "prisma", "prisma_plus" ou null | Plano atual; null sem assinatura. |
prismaSince | number ou null | Assinante desde: início do período atual de Prisma, sem interrupção. Renovar não muda a data; deixar vencer e assinar de novo começa um período novo. |
shareSeconds | number | Segundos transmitindo tela (insígnia de tempo de transmissão). |
pulsing | boolean | Está pulsando pelo menos um servidor (veja Pulse). |
pulseMonths | number | Meses completos (de 30 dias) pulsando sem parar. |
pulsingSince | number ou null | Pulser desde: data do Pulse ativo mais antigo da conta, em qualquer servidor. |
pulseBadge | { id, months } ou null | Insígnia de Pulse atual: o nível mais alto alcançado. Quem pulsa já tem o nível de 1 mês (PULSE_1) desde o primeiro dia; os outros exigem aquela quantidade de meses (PULSE_2, PULSE_3, PULSE_6, PULSE_9, PULSE_12, PULSE_15, PULSE_18, PULSE_24). Respeita as sobrescritas do admin em flags. |
nextPulseBadge | { id, months, at } ou null | Próxima insígnia e quando ela chega (at = pulsingSince + months × 30 dias). null sem Pulse ou já no último nível. |
hiddenBadges | string[] | O que o dono escolheu esconder dos outros (PRISMA, PULSE, STREAM_TIME, ADMIN...). |
hidePoints | boolean | Esconde os pontos. |
decorationItemId, nameStyleItemId | string ou null | Moldura de avatar e estilo de nome equipados na loja. |
online | boolean | Presença ao vivo (só quando o objeto vem com presença, veja abaixo). |
status | "online", "idle", "dnd" ou "offline" | Status atual. |
customStatus | { text, emoji, expiresAt } ou null | Status personalizado. |
activity | { name, startedAt } ou null | Atividade (jogo) em andamento. |
listening | objeto ou null | Música do Spotify visível. |
Presença: online, status, customStatus, activity e listening existem nos objetos com presença ao vivo (author das mensagens, user das interações, members de GET /guilds/:g, GET /guilds/:g/members/:id, GUILD_CREATE) e não em GET /users/:id.
Privacidade#
Os campos refletem as escolhas de privacidade do dono da conta e o bot não consegue contorná-las:
PRISMAemhiddenBadges:prismaActivevirafalseeprismaPlaneprismaSinceviramnull(emGET /users/:id,prismaviranull).PULSEemhiddenBadges:pulsingvirafalse,pulseMonthsvira0epulsingSince,pulseBadgeenextPulseBadgeviramnull. OpulsingSincepor servidor do objeto de membro continua, porque pulsar um servidor é público dentro dele.createdAtejoinedAtnão são sensíveis e nunca são escondidos.- Outras insígnias escondidas somem de
flags.
Objeto de membro#
| Campo | Tipo | O que é |
|---|---|---|
nickname | string ou null | Apelido neste servidor. |
roleIds | string[] | Ids dos cargos (detalhes em roles de GET /guilds/:g ou do GUILD_CREATE). |
joinedAt | number | Quando entrou no servidor. |
pulsingSince | number ou null | Desde quando pulsa este servidor (Pulse ativo mais antigo aqui); null se não pulsa aqui. |
timeoutUntil | number ou null | Fim do castigo (timeout) em andamento; null sem castigo. |
Onde cada forma aparece:
| Lugar | Forma |
|---|---|
members em GET /guilds/:g e GUILD_CREATE; member em GET /guilds/:g/members/:id | usuário + presença + campos de membro, tudo no mesmo objeto |
INTERACTION_CREATE (gateway e HTTP) | user (usuário com presença) e member (objeto de membro) separados |
data.resolved.users das interações | usuário + presença + nickname, roleIds, joinedAt, pulsingSince |
GUILD_MEMBER_ADD | { guildId, user, joinedAt } |
author das mensagens, user de GET /bot/me | só usuário (com presença) |
account em GET /users/:id | perfil público completo: usuário sem presença, mais bio, connections, prisma: { active, source, expiresAt, plan, since }... |
Exemplo: comando userinfo#
Com um comando registrado com a opção alvo do tipo user, o bot já recebe tudo no INTERACTION_CREATE, sem outra chamada. Para pessoas que não vieram na interação, use GET /guilds/:g/members/:id (membro completo) ou GET /users/:id (só a conta).
const MES_PULSE = 30 * 24 * 3600 * 1000;
const fmt = new Intl.DateTimeFormat("pt-BR", { dateStyle: "long", timeZone: "America/Sao_Paulo" });
const data = (ms) => (ms ? fmt.format(new Date(ms)) : null);
const emDias = (ms) => Math.max(0, Math.ceil((ms - Date.now()) / 86_400_000));
async function userinfo(d) {
// d é o `d` do INTERACTION_CREATE. Sem `alvo`, mostra quem usou o comando.
const alvoId = d.data.options?.alvo;
let user, member;
if (alvoId && d.data.resolved?.users?.[alvoId]) {
user = member = d.data.resolved.users[alvoId]; // já tem joinedAt e pulsingSince
} else if (alvoId) {
const res = await fetch(`${API}/guilds/${d.guildId}/members/${alvoId}`, { headers: { Authorization: `Bot ${TOKEN}` } });
if (res.status === 404) return { body: "Essa pessoa não está no servidor." };
user = member = (await res.json()).member;
} else {
user = d.user;
member = d.member;
}
const linhas = [
`**${member.nickname ?? user.displayName}** (@${user.username})`,
`Conta criada em ${data(user.createdAt)}`,
`Entrou no servidor em ${data(member.joinedAt)}`,
];
if (user.prismaActive) {
const plano = user.prismaPlan === "prisma_plus" ? "Prisma+" : "Prisma";
linhas.push(user.prismaSince ? `${plano} desde ${data(user.prismaSince)}` : `Assinante ${plano}`);
}
if (user.pulsing) {
linhas.push(`Pulser desde ${data(user.pulsingSince)} (${user.pulseMonths} ${user.pulseMonths === 1 ? "mês" : "meses"})`);
if (user.pulseBadge) linhas.push(`Insígnia atual: Pulse ${user.pulseBadge.months} ${user.pulseBadge.months === 1 ? "mês" : "meses"}`);
if (user.nextPulseBadge) {
const n = user.nextPulseBadge;
linhas.push(`Próxima: Pulse ${n.months} meses em ${data(n.at)} (faltam ${emDias(n.at)} dias)`);
} else if (user.pulseBadge) {
linhas.push("Já está no último nível de Pulse!");
}
}
if (member.pulsingSince) linhas.push(`Pulsa este servidor desde ${data(member.pulsingSince)}`);
if (member.timeoutUntil) linhas.push(`De castigo até ${data(member.timeoutUntil)}`);
return { body: linhas.join("\n") };
}Lembre que prismaSince, pulsingSince, pulseBadge e nextPulseBadge podem ser null mesmo com prismaActive/pulsing em true (conta antiga sem a data registrada); trate sempre o null. Para calcular "meses pulsando" por conta própria, use Math.floor((Date.now() - pulsingSince) / MES_PULSE), que é a regra do pulseMonths.
Veja também#
- Referência REST:
GET /guilds/:g/members/:ideGET /users/:id. - Referência do gateway: exemplos de
GUILD_CREATE,GUILD_MEMBER_ADDeINTERACTION_CREATE. - Interações e comandos: o
membere oresolveddas interações.