vsyncDOCUMENTAÇÃO

API de bots

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#

CampoTipoO que é
idstringId da conta (o mesmo em todos os servidores).
usernamestringNome de usuário único.
displayNamestringNome de exibição.
botbooleantrue para contas de bot.
avatarUrl, bannerUrlstring ou nullImagens do perfil.
flagsstring[]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>).
createdAtnumberQuando a conta foi criada. Nunca é escondido.
prismaActivebooleanTem assinatura Prisma ativa.
prismaPlan"prisma", "prisma_plus" ou nullPlano atual; null sem assinatura.
prismaSincenumber ou nullAssinante 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.
shareSecondsnumberSegundos transmitindo tela (insígnia de tempo de transmissão).
pulsingbooleanEstá pulsando pelo menos um servidor (veja Pulse).
pulseMonthsnumberMeses completos (de 30 dias) pulsando sem parar.
pulsingSincenumber ou nullPulser desde: data do Pulse ativo mais antigo da conta, em qualquer servidor.
pulseBadge{ id, months } ou nullInsí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 nullPróxima insígnia e quando ela chega (at = pulsingSince + months × 30 dias). null sem Pulse ou já no último nível.
hiddenBadgesstring[]O que o dono escolheu esconder dos outros (PRISMA, PULSE, STREAM_TIME, ADMIN...).
hidePointsbooleanEsconde os pontos.
decorationItemId, nameStyleItemIdstring ou nullMoldura de avatar e estilo de nome equipados na loja.
onlinebooleanPresenç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 nullStatus personalizado.
activity{ name, startedAt } ou nullAtividade (jogo) em andamento.
listeningobjeto ou nullMú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:

  • PRISMA em hiddenBadges: prismaActive vira false e prismaPlan e prismaSince viram null (em GET /users/:id, prisma vira null).
  • PULSE em hiddenBadges: pulsing vira false, pulseMonths vira 0 e pulsingSince, pulseBadge e nextPulseBadge viram null. O pulsingSince por servidor do objeto de membro continua, porque pulsar um servidor é público dentro dele.
  • createdAt e joinedAt não são sensíveis e nunca são escondidos.
  • Outras insígnias escondidas somem de flags.

Objeto de membro#

CampoTipoO que é
nicknamestring ou nullApelido neste servidor.
roleIdsstring[]Ids dos cargos (detalhes em roles de GET /guilds/:g ou do GUILD_CREATE).
joinedAtnumberQuando entrou no servidor.
pulsingSincenumber ou nullDesde quando pulsa este servidor (Pulse ativo mais antigo aqui); null se não pulsa aqui.
timeoutUntilnumber ou nullFim do castigo (timeout) em andamento; null sem castigo.

Onde cada forma aparece:

LugarForma
members em GET /guilds/:g e GUILD_CREATE; member em GET /guilds/:g/members/:idusuá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çõesusuário + presença + nickname, roleIds, joinedAt, pulsingSince
GUILD_MEMBER_ADD{ guildId, user, joinedAt }
author das mensagens, user de GET /bot/mesó usuário (com presença)
account em GET /users/:idperfil 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).

JavaScript
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#