LobbitoAPI

Documentação · v1

Lobbito API

A Lobbito API cria salas personalizadas de Contra Squad no Free Fire, inicia a partida quando todos estão prontos e entrega o vencedor confirmado automaticamente, com abates, mortes e dano de cada jogador. Também roda campeonatos mata-mata completos: chave, check-in, salas, W.O. e avanço até a final.

ItemValor
URL basehttps://api.lobbito.com.br/v1
FormatoJSON em UTF-8, datas em ISO 8601 (UTC)
AutenticaçãoAuthorization: Bearer lbt_live_…
Modos1x1, 2x2, 3x3, 4x4 (Contra Squad)
RastreioToda resposta traz X-Request-Id; informe-o ao suporte

A API cria salas e informa resultados. Saldo, apostas e prêmios ficam no sistema da sua comunidade, que usa o resultado da API para pagar quem venceu.

Guia rápido

  1. Entre no painel com o Discord e assine um plano por Pix.
  2. Crie uma chave de API e guarde-a no servidor do seu bot (ela aparece uma única vez).
  3. Cadastre a URL do webhook e guarde o segredo whsec_….
  4. Crie a primeira sala:
curl -X POST https://api.lobbito.com.br/v1/rooms \
  -H "Authorization: Bearer $LOBBITO_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: aposta-8841" \
  -d '{"mode":"1x1","teams":{"A":["123456789"],"B":["987654321"]},"reference":"aposta-8841"}'
  1. Envie roomId e password aos jogadores. Quando todos entrarem no time certo e marcarem pronto, a partida começa sozinha.
  2. Receba o webhook room.finished com result.winner e pague o vencedor no seu sistema.

Autenticação

Envie a chave no cabeçalho Authorization de toda chamada a /v1. Chaves começam com lbt_live_. Você pode ter até 5 chaves ativas e revogar qualquer uma no painel; a revogação vale na hora.

Authorization: Bearer lbt_live_9fX2…

Use a chave só no servidor (bot, backend). Nunca coloque a chave no navegador, no app do jogador ou num repositório público. A API não aceita chamadas de navegador de outros sites.

Erros

Erros sempre vêm com o status HTTP e este corpo:

{ "error": { "code": "concurrency_limit", "message": "Seu plano permite 2 salas ao mesmo tempo." } }
HTTPcodeQuando acontece
400invalid_request, invalid_jsonCampo faltando ou inválido. A mensagem diz qual.
401unauthorizedChave ausente, errada, revogada ou conta bloqueada.
402plan_requiredO recurso solicitado exige assinatura ativa, como campeonatos.
403plan_featureO recurso não faz parte do seu plano (ex.: campeonatos).
404not_foundRecurso inexistente ou de outra conta.
409invalid_stateAção fora de hora (ex.: cancelar sala já iniciada).
413payload_too_largeCorpo maior que 32 KB.
429rate_limitedRequisições por minuto acima do plano. Veja Retry-After.
429quota_exceededSalas do ciclo esgotadas.
429concurrency_limitSalas ao mesmo tempo acima do plano.
503capacity_unavailableCapacidade momentaneamente esgotada. Tente após Retry-After.
503creation_failedNão foi possível criar a sala agora. A resposta traz também room (status FAILED), que não conta na cota. Tente de novo com outra Idempotency-Key.
500internalFalha nossa. Tente de novo com a mesma Idempotency-Key.

Limites e cotas

LimiteComo funciona
Requisições por minutoPor chave, conforme o plano. Acima disso: 429 rate_limited.
FreeDez salas de teste por conta Discord, sem renovação mensal, com uma sala simultânea. Login, novas chaves e mudanças de plano não reiniciam essa cota. O plano pago preserva os testes restantes.
Salas por cicloConta cada sala criada com sucesso no jogo. O ciclo pago tem 30 dias a partir da ativação. Planos ilimitados retornam roomsLimit: null e roomsRemaining: null; isso significa ilimitado, não zero.
ReservasCREATING e CREATION_UNKNOWN reservam cota antes do envio ao jogo. Falhas comprovadamente anteriores à criação liberam a reserva; uma resposta incerta aguarda conferência e não dispara outra criação.
Salas ao mesmo tempoContam as salas em CREATING e WAITING_PLAYERS e as que começaram há pouco (cerca de 1 minuto). Depois disso, a partida segue até o resultado sem ocupar vaga.
Tamanho do corpo32 KB por requisição.

Consulte o consumo atual em GET /v1/me ou no painel: salas usadas, reservadas, restantes, limite simultâneo e datas do ciclo. Sem assinatura paga ativa, o plano efetivo é Free; subscription.active informa separadamente o estado da assinatura.

Idempotência

Em POST /v1/rooms e POST /v1/tournaments, envie Idempotency-Key (8 a 100 caracteres: letras, números, . _ : -). Repetir a chamada com a mesma chave devolve o mesmo recurso com status 200 e nunca cria uma segunda sala. Use o id da partida ou da aposta do seu sistema.

Em criações de sala, repita a mesma chave com a mesma configuração. Reutilizar a chave com opções diferentes é um conflito, sem consumir outra cota ou criar outra sala. Não gere uma chave nova somente porque a resposta demorou ou a conexão caiu. O painel mantém o identificador da tentativa e consulta seu resultado após recarga, sem guardar senha ou chave de API no navegador.

Listas e paginação

Listas devolvem { "object": "list", "data": [...], "hasMore": true, "nextCursor": "..." }, ordenadas por data e ID. Use limit (1 a 100, padrão 20) e, na página seguinte, envie cursor com o nextCursor recebido. Isso preserva itens criados no mesmo milissegundo. Não combine cursor e before. O parâmetro legado before filtra datas anteriores, mas não deve ser usado para percorrer todas as páginas.

Objeto sala

{
  "id": "room_Q2hX9aK1Lm0p",
  "object": "room",
  "name": "APOSTADOS FF",
  "reference": "aposta-8841",
  "mode": "1x1",
  "map": "Bermuda",
  "status": "WAITING_PLAYERS",
  "roomId": "2045118833",
  "password": "481920",
  "teams": { "A": ["123456789"], "B": ["987654321"] },
  "autoStart": true,
  "autoResult": true,
  "presence": {
    "players": [{ "accountId": "123456789", "nickname": "Kaio", "team": "A", "ready": true }],
    "missing": ["987654321"],
    "updatedAt": "2026-10-25T18:02:10.000Z"
  },
  "result": { "status": "NONE" },
  "tournament": null,
  "joinDeadline": "2026-10-25T18:11:40.000Z",
  "createdAt": "2026-10-25T18:01:40.000Z",
  "startedAt": null, "endedAt": null, "endReason": null
}
CampoDescrição
nameNome da sala no jogo, definido em Nome padrão das salas no painel (1 a 15 caracteres). Vale para todas as salas criadas depois da mudança, inclusive as de campeonatos. null quando você não definiu um nome.
roomId, passwordID e senha da sala no Free Fire. Só existem depois de WAITING_PLAYERS.
teamsIDs do Free Fire esperados em cada lado. A é o primeiro time da sala e B, o segundo.
presenceQuem está na sala, em qual time e se marcou pronto. missing lista quem falta. Atualiza a cada ~10 s enquanto a sala espera.
result.statusNONE (ainda não há), CONFIRMED (vencedor definido) ou PENDING (precisa de conferência).
result.winner"A" ou "B" quando confirmado.
result.sourceAUTO (confirmado automaticamente) ou MANUAL (confirmado por você).
result.statsAbates, mortes e dano de cada jogador na partida, por ID do Free Fire.
tournament{ id, matchId } quando a sala pertence a um campeonato.

Ciclo de vida da sala

statusSignificadoPróximo passo
CREATINGPedido aceito; a sala está sendo criada no jogo.Vira WAITING_PLAYERS ou FAILED. Evento room.ready.
CREATION_UNKNOWNA criação ainda está sendo confirmada. A API resolve sozinha e nunca cria outra sala por cima.Vira WAITING_PLAYERS ou FAILED.
WAITING_PLAYERSSala pronta, aguardando os jogadores.Começa sozinha (autoStart) ou com /start. Sem todos até joinDeadline: CANCELLED.
IN_PROGRESSPartida em andamento.Vira FINISHED com o resultado.
FINISHEDPartida encerrada; veja result.Se result.status for PENDING, confirme manualmente.
CANCELLEDCancelada por você, por ausência ou porque a sala sumiu do jogo.Final. presence mostra quem estava (útil para W.O.).
FAILEDNão foi possível criar a sala no momento. Não conta na cota.Final. Crie outra sala.

Criar sala

POST/v1/rooms
CampoTipoDescrição
mode *string1x1, 2x2, 3x3 ou 4x4.
teamsobjeto{ "A": [ids], "B": [ids] } com exatamente N IDs do Free Fire por lado (N = jogadores por time). Obrigatório para início e resultado automáticos.
autoStartbooleanInicia quando todos estiverem no time certo e prontos. Padrão: true se houver teams.
autoResultbooleanConfirma o vencedor automaticamente ao fim da partida. Padrão: true se houver teams.
passwordstringDe 4 a 8 dígitos. Se omitida, a API gera uma senha de 6 dígitos.
mapIdnúmeroMapa (veja GET /v1/modes). Padrão: 1.
joinTimeoutMinutesnúmeroPrazo para todos entrarem, de 2 a 60. Padrão: 10.
referencestringAté 100 caracteres. Seu identificador (aposta, partida, ticket); volta em todos os eventos.
settingsobjetoConfigurações semânticas de Contra Squad listadas em GET /v1/modes. Inclui gelo e munição infinitos, habilidades, fogo amigo, mira, voz, espectador após morrer, placar, emuladores e banimento de habilidades. Também aceita loja (shop), economia (economy) e moedas por rodada (roundCash). A ausência preserva o preset do formato.

Exemplo de opções: { "mode": "4x4", "settings": { "infiniteGloo": true, "enableHonorChallenge": false } }. O mesmo editor está no painel, sem exigir chave de API. Campos desconhecidos, máscaras binárias e opções ainda não integradas são recusados; não são ignorados como se tivessem sido aplicados.

A loja permite selecionar armas e equipamentos e definir seus preços: shop: [{ "id": 6, "price": 800 }]. Use os IDs e nomes do catálogo autenticado; a referência de itens é o cliente Free Fire 1.132.1. Preços e moedas por rodada vão de 0 a 9950 em passos de 50. A economia usa os IDs 152 a 157, de 0 a 5000 em passos de 50, por exemplo economy: { "152": 500 }. roundCash: [500, 900, 1100] define até 15 posições de dinheiro e não muda o total de rodadas da partida.

O catálogo retorna completeGameParity: false e identifica opções ainda indisponíveis, incluindo total de rodadas e permissões avançadas de espectador. A aceitação das regras pelo servidor do jogo depende da versão em operação; os testes automatizados usam transporte simulado.

As melhorias de uma arma são selecionadas juntas com sua base, como no cliente analisado. Para a REST, envie o grupo visível completo ou somente a base; itens ocultos são derivados pelo servidor. A seleção histórica de um preset continua válida enquanto não for alterada.

Resposta: 201 com a sala pronta (WAITING_PLAYERS, com roomId e password). Se a criação demorar mais de ~25 s, a resposta é 202 com CREATING: aguarde o evento room.ready ou consulte a sala. Use timeout de cliente de pelo menos 40 s. Se a criação falhar na hora, a resposta é 503 creation_failed.

Com teams, quem entrar na sala sem estar na lista é expulso automaticamente.

Consultar e listar salas

GET/v1/rooms/{id}
GET/v1/rooms?limit=20&before=2026-10-25T00:00:00Z

Iniciar a partida

POST/v1/rooms/{id}/start

Inicia na hora, sem esperar todos marcarem pronto. Só vale em WAITING_PLAYERS.

Cancelar a sala

POST/v1/rooms/{id}/cancel

Fecha a sala no jogo e libera a vaga. Só antes da partida começar (WAITING_PLAYERS). Corpo opcional: { "reason": "texto" }. A sala já criada continua contando na cota.

Expulsar jogador

POST/v1/rooms/{id}/kick
{ "accountId": "555555555" }

Resultado automático

Com autoResult e teams, o vencedor é confirmado sozinho, normalmente poucos minutos depois do fim da partida. Você recebe o evento room.finished com:

Quando o vencedor não pode ser confirmado com segurança, o resultado fica PENDING (evento room.result_pending). Isso acontece, por exemplo, em partidas incompletas ou abandonadas, e também quando não há conclusão em 45 minutos depois do início. Nesse caso, o seu ADM confere e confirma o vencedor (veja abaixo).

Oriente os jogadores a jogar só a partida da sala até o resultado sair e a não sair antes do fim. Isso evita quase todas as conferências manuais.

Confirmar o resultado manualmente

POST/v1/rooms/{id}/result
{ "winner": "A", "reason": "conferido pelo vídeo" }

Aceito com a partida em andamento ou com o resultado PENDING. Um resultado CONFIRMED não pode ser alterado. Também serve para salas sem autoResult. Gera room.finished com source: "MANUAL".

Objeto campeonato

{
  "id": "trn_Zk81mQa0Lp2c", "object": "tournament", "name": "Copa Semanal", "mode": "4x4",
  "status": "RUNNING", "startsAt": "2026-10-26T22:00:00.000Z", "checkInRequired": true,
  "teams": [{ "id": "team_1", "name": "Time Aizen", "players": ["…"], "seed": 1, "checkedIn": true, "eliminated": false }],
  "rounds": [{ "round": 1, "matches": [{ "id": "r1m1", "teamA": "team_1", "teamB": "team_8",
     "status": "PLAYING", "winner": null, "walkover": false, "room": "room_Q2hX9aK1Lm0p" }] }],
  "champion": null
}
status do campeonatoSignificado
SCHEDULEDAguardando startsAt; check-in aberto.
RUNNINGEm andamento: salas sendo criadas e resultados avançando a chave.
FINISHEDTerminou; champion tem o id do time campeão.
CANCELLEDCancelado por você.
status do confrontoSignificado
PENDINGAguardando os dois times ou uma vaga livre do plano.
CREATING / PLAYINGSala sendo criada ou partida em andamento (room aponta a sala na API).
DONEVencedor definido (walkover: true quando foi W.O. ou bye).
BYEConfronto vazio, sem times.
REVIEWPrecisa de você: resultado pendente ou sala que falhou três vezes.

Criar campeonato

POST/v1/tournaments

Disponível nos planos com campeonatos.

{
  "name": "Copa Semanal",
  "mode": "2x2",
  "startsAt": "2026-10-26T22:00:00Z",
  "checkInRequired": true,
  "joinTimeoutMinutes": 10,
  "reference": "copa-42",
  "teams": [
    { "name": "Time Aizen", "players": ["123456789", "223456789"] },
    { "name": "Time Lobo",  "players": ["323456789", "423456789"] }
  ]
}
CampoDescrição
name *Até 80 caracteres.
mode *1x1 a 4x4.
teams *De 2 a 64 times. Cada um com name (até 40 caracteres) e exatamente N IDs do Free Fire em players. A ordem define as sementes (o primeiro é a semente 1) e os ids team_1, team_2…
startsAtData ISO nos próximos 60 dias. Padrão: agora.
checkInRequiredSe true, só jogam os times que fizerem check-in antes de startsAt.
joinTimeoutMinutesPrazo para entrar em cada sala, de 2 a 30. Padrão: 10.
referenceAté 100 caracteres.

Como o campeonato roda sozinho

  1. A chave mata-mata é montada com sementes. Quando o número de times não é potência de 2, as melhores sementes avançam direto (bye).
  2. Em startsAt, os times sem check-in (se exigido) são eliminados e o campeonato vira RUNNING.
  3. Cada confronto com os dois times definidos ganha uma sala com início e resultado automáticos, respeitando o limite de salas ao mesmo tempo do seu plano. Você recebe tournament.match_ready com ID e senha para avisar os times.
  4. Com o resultado confirmado, o vencedor avança. Se um time não entrar a tempo, vence por W.O. quem tiver mais jogadores na sala; no empate, a melhor semente.
  5. A final define o champion e dispara tournament.finished.

Check-in

POST/v1/tournaments/{id}/teams/{teamId}/check-in

Marca o check-in de um time enquanto o campeonato está SCHEDULED. Chame quando o capitão confirmar presença no seu bot.

Conferência de confrontos

Se a sala do confronto terminar com resultado PENDING, confirme pela sala com POST /v1/rooms/{roomId}/result: o campeonato avança sozinho. Se o confronto estiver em REVIEW por falha de criação, defina o vencedor direto:

POST/v1/tournaments/{id}/matches/{matchId}/result
{ "winnerTeamId": "team_3" }

Cancelar campeonato

POST/v1/tournaments/{id}/cancel

Para de criar salas. Salas já em andamento seguem até o fim e continuam aparecendo em /v1/rooms.

GET/v1/tournaments/{id}
GET/v1/tournaments?limit=20

Webhooks

Cadastre no painel uma URL https pública do seu bot ou site. A API envia um POST JSON para cada evento:

{
  "id": "evt_9aZ1kQ3mX0pL",
  "type": "room.finished",
  "createdAt": "2026-10-25T18:24:02.000Z",
  "data": { /* objeto sala ou campeonato */ }
}

Eventos

EventoQuandodata
room.readySala criada no jogo, com ID e senha.sala
room.startedPartida iniciada.sala (sem senha)
room.finishedResultado confirmado (automático ou manual).sala
room.result_pendingPartida terminou e precisa de conferência.sala
room.cancelledCancelada por você, por ausência ou porque a sala sumiu.sala
room.failedNão foi possível criar a sala.sala
tournament.createdCampeonato criado.campeonato
tournament.startedChegou startsAt.campeonato
tournament.match_readySala de um confronto pronta.{ tournamentId, match, room }
tournament.match_finishedConfronto decidido (inclui W.O. e bye).{ tournamentId, match }
tournament.finishedCampeão definido.campeonato
tournament.cancelledCampeonato cancelado.campeonato
subscription.activatedPagamento confirmado e plano ativo.{ plan, validUntil }
webhook.testTeste pedido por você.{ message }

Conferir a assinatura

Cada envio traz:

X-Lobbito-Event: room.finished
X-Lobbito-Delivery: evt_9aZ1kQ3mX0pL
X-Lobbito-Signature: t=1792950242,v1=5d41402abc4b2a76b9719d911017c592…

v1 é o HMAC-SHA256, em hexadecimal, de t + "." + corpo cru usando o seu segredo whsec_…. Rejeite envios com assinatura diferente ou com t mais de 5 minutos fora do seu relógio.

import crypto from 'node:crypto';
import express from 'express';

const app = express();
app.post('/lobbito', express.raw({ type: 'application/json' }), (req, res) => {
  const [, t, v1] = /^t=(\d+),v1=([a-f0-9]{64})$/.exec(req.get('X-Lobbito-Signature') ?? '') ?? [];
  const expected = crypto.createHmac('sha256', process.env.LOBBITO_WEBHOOK_SECRET)
    .update(`${t}.${req.body}`).digest('hex');
  const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300;
  if (!v1 || !fresh || !crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected))) return res.sendStatus(401);
  const event = JSON.parse(req.body);
  if (event.type === 'room.finished') pagarVencedor(event.data.reference, event.data.result.winner);
  res.sendStatus(200);
});

Conta e modos

GET/v1/me
{
  "object": "account", "id": "acct_…", "name": "Apostados FF", "active": true,
  "plan": { "id": "pro", "name": "Pro", "roomsPerMonth": 5000, "concurrentRooms": 10, "tournaments": true, "requestsPerMinute": 300 },
  "validUntil": "2026-11-24T18:00:00.000Z",
  "usage": { "rooms": 212, "roomsLimit": 5000, "activeRooms": 2, "concurrentLimit": 10, "periodStart": "2026-10-25T18:00:00.000Z" }
}
GET/v1/modes

Modos com o número de jogadores por time, mapas disponíveis (mapId) e catálogo settings com grupos, presets, defaults por formato e opções indisponíveis. O catálogo não expõe blobs ou campos brutos do protocolo.

POST/v1/webhooks/test

Assinaturas e Pix

Boas práticas

Mudanças

VersãoMudança
v1 · outubro de 2026Lançamento: salas, resultado automático, campeonatos, webhooks e assinaturas por Pix.

Mudanças incompatíveis só entram em uma nova versão (/v2), com aviso prévio. Campos novos podem aparecer nas respostas a qualquer momento: ignore os que você não conhece.