Documentação completa, com exemplos prontos em Node, PHP e Python:
topidle.com/integracao.html. A equipe do TopIdle também ajuda:
[email protected].
O que responder
Qualquer
2xx é recebido.
409 quer dizer “já processei este evento” e conta como entregue. Recusas que não mudam com insistência (
400,
401,
403,
404,
405,
410,
422,
501) não são reenviadas: o painel e o sino dizem o motivo provável. Erro
5xx e tempo esgotado (5 segundos) são reenviados por até 24 horas. Jogador não encontrado (
400,
404,
422) é avisado no TopIdle e, se corrigir o identificador em até 24 horas, o voto volta com o mesmo
eventId: grave o
eventId só quando o prêmio sair.
O aviso
Um
POST em JSON com
type,
eventId,
gameId,
votedAt,
nextVoteAt (quando esse jogador pode votar de novo neste jogo, pelo plano do momento do voto) e
email ou
playerIdentifier.
Validação do webhook
Compare
X-TopIdle-Signature com o HMAC SHA-256 de
X-TopIdle-Timestamp + "." + corpo_bruto usando o segredo do webhook. Aceite apenas timestamps recentes e compare as assinaturas em tempo constante.
O mesmo identificador aparece em
eventId,
X-TopIdle-Vote-Id e
Idempotency-Key. Grave-o junto com o prêmio, na mesma transação: uma retentativa nunca paga duas vezes, e o jogador que não existe (responda
404 sem gravar) recebe quando corrigir o que digitou.
Identificação do jogador
Se o campo de identificador ficar vazio, o evento envia o
email verificado da conta TopIdle. Se o jogo usa outra conta, configure um rótulo como “Nome do personagem” ou “ID da conta”; o evento passará a enviar
playerIdentifier.
O jogo também pode levar o jogador ao TopIdle por
https://topidle.com/jogo/<id-do-jogo>?playerIdentifier=<id-do-jogador>. O valor será preenchido para o jogador conferir e autorizar antes do voto. Acrescente
&votar=1 (ou use só
?votar=1, se o seu jogo não usa identificador) para o voto já começar na chegada: o jogador só confirma a verificação de humano. Trate-o somente como texto, codifique-o na URL e nunca envie senha, token ou dados de pagamento.
O mesmo
playerIdentifier pode receber um voto por intervalo do jogo, de 24 a 12 horas conforme o plano ativo. Ele não fica vinculado permanentemente a uma conta Google ou Discord.
Recuperação pela API
Se o webhook falhar, consulte
GET /api/v1/votes?after=0 com
Authorization: Bearer SUA_CHAVE. Guarde o último
nextCursor e processe cada
eventId uma única vez.
Consulte o último voto com
GET /api/v1/vote-status?playerIdentifier=NOME ou
?email=EMAIL. Estatísticas públicas ficam em
GET /api/v1/games/ID_DO_JOGO;
dailyRewardsConfirmed informa quantos eventos de recompensa foram aceitos nas últimas 24 horas.
Exemplo de validação (Node/Express)
Use o corpo bruto, valide o HMAC antes do JSON e responda
2xx rapidamente. O banco do jogo deve ter o
eventId como chave única, gravado junto com a recompensa.
app.post("/webhooks/topidle", express.raw({ type: "application/json" }), async (req, res) => {
const ts = req.get("X-TopIdle-Timestamp") || "";
const received = req.get("X-TopIdle-Signature") || "";
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return res.sendStatus(401);
const digest = crypto.createHmac("sha256", WEBHOOK_SECRET)
.update(ts + ".").update(req.body).digest("hex");
const expected = "sha256=" + digest;
if (received.length !== expected.length ||
!crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected))) return res.sendStatus(401);
const event = JSON.parse(req.body);
await rewardOnce(event.eventId, event.playerIdentifier || event.email);
return res.sendStatus(204);
});