Pré-requisitos (capacidades A–D)
Antes de olhar uma rota, um payload ou um exemplo de assinatura, vale responder a uma pergunta mais básica: o seu servidor é capaz de integrar? Esta página é essa checagem. Ela lista o que o seu engine precisa saber fazer, agrupado em quatro capacidades — A, B, C e D. Nenhuma delas é preferência ou boa prática opcional: cada requisito existe porque a ausência dele quebra um fluxo, e vários custam dinheiro, porque estorno de compra é pago pela plataforma.
Para o dono de servidor que está avaliando: leia isto como uma lista de compras técnica. Você não precisa usar o nosso Agent nem o nosso Lua de referência — precisa entregar estas capacidades por algum caminho. O Agent e a referência são um caminho pronto para quem não quer construir do zero. Se o seu engine é da família TFS, boa parte disto já vem resolvida pela referência.
A. Transporte e assinatura
Seção intitulada “A. Transporte e assinatura”Esta é a capacidade que decide se você consegue integrar. Se o seu engine não tem criptografia de chave pública, a assinatura precisa nascer fora dele — e é exatamente o que o Agent faz.
| # | Requisito | Sustenta | Sem ele |
|---|---|---|---|
| A1 | DEVE assinar JWS RS256 destacado em toda chamada de saída ao contrato | todas as rotas servidor→plataforma | nenhuma rota é aceita — o contrato exige assinatura sempre, não só API key |
| A2 | DEVE nunca bloquear o loop principal do jogo esperando rede (transporte assíncrono) | todas | um freeze de rede congela todos os jogadores, não só quem integrou |
| A3 | DEVE manter o relógio sincronizado por NTP | todas | a janela de frescor é apertada (exp − iat ≤ 300s, tolerância de 60s); relógio torto vira 401 intermitente e difícil de diagnosticar |
| A4 | DEVE expor um endpoint de webhook https que só verifica assinatura, nunca assina, e é idempotente por transactionId | webhooks transfer_order e transaction_terminal | ou o endpoint aceita ordem forjada de transferir item, ou entrega em duplicata — a entrega é at-least-once |
B. Durabilidade — as três que importam
Seção intitulada “B. Durabilidade — as três que importam”“O market precisa ser durável” é a intuição certa, mas imprecisa. Não é o market inteiro: são três durabilidades pontuais, cada uma uma âncora que precisa sobreviver a um evento específico.
| # | Requisito | Sustenta | Sem ele |
|---|---|---|---|
| B1 | DEVE ter uma identidade estável do anúncio (itemRef) que sobrevive a um ciclo de save do servidor | registrar anúncio (POST /v1/api/market/listings), ajustar ou retirar anúncio (PUT /v1/api/market/listings), criar transação (POST /v1/api/transactions) | o anúncio vira órfão no primeiro save; a plataforma não consegue mais reencontrá-lo para ajustar ou retirar |
| B2 | DEVE manter um registro local durável do que foi anunciado (itemRef ↔ oferta), independente da tabela nativa do market | ajustar ou retirar anúncio | sem memória do que foi anunciado, é impossível detectar que uma oferta sumiu e chamar WITHDRAW — nasce o anúncio fantasma |
| B3 | DEVE entregar em destino durável que sobrevive a rollback/crash (depot durável, nunca inventário de quem pode deslogar) | confirmar entrega (POST /v1/api/transactions/{transactionId}/delivery), webhook transfer_order | item entregue evapora num crash antes do próximo save; a transação fica concluída sem o item ter chegado |
A frase para levar a cada uma:
- B1 — sua chave de anúncio não pode derivar de um id que o seu servidor renumera. Descubra o que sobrevive a um ciclo de save antes de escolher a chave.
- B2 — você precisa lembrar, do seu lado, o que anunciou, porque a sua tabela de market apaga a linha exatamente no evento a que você precisa reagir (venda por moeda do jogo, retirada, expiração).
- B3 — item entregue tem de continuar entregue depois de um crash. Se o seu save só roda em logout, force um após a entrega, ou torne a entrega reconciliável pela consulta de transação.
C. Autoridade de negócio fica com você
Seção intitulada “C. Autoridade de negócio fica com você”A plataforma não gerencia estoque e não conhece o jogo. Quem arbitra item, posse e estoque é o seu servidor.
| # | Requisito | Sustenta | Sem ele |
|---|---|---|---|
| C1 | DEVE verificar posse e estoque do item no seu lado; criar a oferta no market é o que reserva (tira o item do inventário do vendedor) | registrar anúncio | anúncio de item que o vendedor não tem; a falha aparece só na entrega, quando o dinheiro já se moveu |
| C2 | DEVE sincronizar o anúncio com o market do jogo: detectar consumo/retirada e chamar a rota de ajustar ou retirar anúncio | ajustar ou retirar anúncio | a plataforma vende o que não existe mais → estorno, pago por ela |
| C3 | DEVE provar que a chamada veio de sessão de jogo viva nas rotas transportadas pelo client — nonce de uso único, TTL curto | criar transação, registrar anúncio | qualquer um que capture um envelope anuncia ou compra em nome de outro |
| C4 | DEVE aplicar rate limit nas rotas transportadas pelo client antes de verificar a assinatura | criar transação, registrar anúncio | verificar RS256 custa CPU; uma enxurrada de payloads inválidos vira negação de serviço mesmo sendo toda rejeitada |
D. A fronteira do client é hostil
Seção intitulada “D. A fronteira do client é hostil”O client do jogo roda na máquina do jogador. Onde ele entra no fluxo, entra como transporte e UX — nunca como autoridade.
| # | Requisito | Sustenta | Sem ele |
|---|---|---|---|
| D1 | DEVE manter nenhuma decisão de negócio no client; ele transporta o envelope assinado (que nasce no servidor) e desenha a UI | criar transação, registrar anúncio | os módulos são texto puro no disco do jogador, sem assinatura nem verificação — autorizar ali é entregar a chave a quem edita o arquivo |
| D2 | DEVE converter o encoding na fronteira do client (a plataforma responde UTF-8; o client pode renderizar outro charset) | qualquer texto exibido ao jogador | a message em pt-BR chega com acento quebrado (Anúncio), e a mensagem pronta para exibir deixa de ser exibível |
Se o seu engine é da família TFS
Seção intitulada “Se o seu engine é da família TFS”Tudo acima é engine-agnóstico. Num servidor TFS 0.3, cada requisito esbarra num gap concreto do engine — e o Lua e o módulo de client de referência já cobrem esses gaps. É o valor de partir da referência em vez do zero: o itemRef estável, o flush de save antes de ler o market, a fila em diretório em vez de tabela Lua compartilhada e a conversão de encoding já vêm resolvidos.
Sobram do seu lado apenas os requisitos que dependem de escolha de operação: C2 (sincronizar), C3 (nonce de sessão) e C4 (rate limit). Se o engine é de outra família, você reimplementa A–D pelo caminho dele, e a referência serve como exemplo executável do formato de assinatura e do modelo de fila.