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.
| Item | Valor |
|---|---|
| URL base | https://api.lobbito.com.br/v1 |
| Formato | JSON em UTF-8, datas em ISO 8601 (UTC) |
| Autenticação | Authorization: Bearer lbt_live_… |
| Modos | 1x1, 2x2, 3x3, 4x4 (Contra Squad) |
| Rastreio | Toda 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
- Entre no painel com o Discord e assine um plano por Pix.
- Crie uma chave de API e guarde-a no servidor do seu bot (ela aparece uma única vez).
- Cadastre a URL do webhook e guarde o segredo
whsec_…. - 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"}'
const response = await fetch('https://api.lobbito.com.br/v1/rooms', { method: 'POST', headers: { Authorization: `Bearer ${process.env.LOBBITO_KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': 'aposta-8841', }, body: JSON.stringify({ mode: '1x1', teams: { A: ['123456789'], B: ['987654321'] }, reference: 'aposta-8841' }), }); const room = await response.json(); // room.roomId e room.password: mande no privado de cada jogador
import os, requests room = requests.post( "https://api.lobbito.com.br/v1/rooms", headers={"Authorization": f"Bearer {os.environ['LOBBITO_KEY']}", "Idempotency-Key": "aposta-8841"}, json={"mode": "1x1", "teams": {"A": ["123456789"], "B": ["987654321"]}, "reference": "aposta-8841"}, timeout=40, ).json()
- Envie
roomIdepasswordaos jogadores. Quando todos entrarem no time certo e marcarem pronto, a partida começa sozinha. - Receba o webhook
room.finishedcomresult.winnere 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." } }
| HTTP | code | Quando acontece |
|---|---|---|
| 400 | invalid_request, invalid_json | Campo faltando ou inválido. A mensagem diz qual. |
| 401 | unauthorized | Chave ausente, errada, revogada ou conta bloqueada. |
| 402 | plan_required | O recurso solicitado exige assinatura ativa, como campeonatos. |
| 403 | plan_feature | O recurso não faz parte do seu plano (ex.: campeonatos). |
| 404 | not_found | Recurso inexistente ou de outra conta. |
| 409 | invalid_state | Ação fora de hora (ex.: cancelar sala já iniciada). |
| 413 | payload_too_large | Corpo maior que 32 KB. |
| 429 | rate_limited | Requisições por minuto acima do plano. Veja Retry-After. |
| 429 | quota_exceeded | Salas do ciclo esgotadas. |
| 429 | concurrency_limit | Salas ao mesmo tempo acima do plano. |
| 503 | capacity_unavailable | Capacidade momentaneamente esgotada. Tente após Retry-After. |
| 503 | creation_failed | Nã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. |
| 500 | internal | Falha nossa. Tente de novo com a mesma Idempotency-Key. |
Limites e cotas
| Limite | Como funciona |
|---|---|
| Requisições por minuto | Por chave, conforme o plano. Acima disso: 429 rate_limited. |
| Free | Dez 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 ciclo | Conta 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. |
| Reservas | CREATING 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 tempo | Contam 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 corpo | 32 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
}
| Campo | Descrição |
|---|---|
name | Nome 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, password | ID e senha da sala no Free Fire. Só existem depois de WAITING_PLAYERS. |
teams | IDs do Free Fire esperados em cada lado. A é o primeiro time da sala e B, o segundo. |
presence | Quem está na sala, em qual time e se marcou pronto. missing lista quem falta. Atualiza a cada ~10 s enquanto a sala espera. |
result.status | NONE (ainda não há), CONFIRMED (vencedor definido) ou PENDING (precisa de conferência). |
result.winner | "A" ou "B" quando confirmado. |
result.source | AUTO (confirmado automaticamente) ou MANUAL (confirmado por você). |
result.stats | Abates, 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
| status | Significado | Próximo passo |
|---|---|---|
CREATING | Pedido aceito; a sala está sendo criada no jogo. | Vira WAITING_PLAYERS ou FAILED. Evento room.ready. |
CREATION_UNKNOWN | A criação ainda está sendo confirmada. A API resolve sozinha e nunca cria outra sala por cima. | Vira WAITING_PLAYERS ou FAILED. |
WAITING_PLAYERS | Sala pronta, aguardando os jogadores. | Começa sozinha (autoStart) ou com /start. Sem todos até joinDeadline: CANCELLED. |
IN_PROGRESS | Partida em andamento. | Vira FINISHED com o resultado. |
FINISHED | Partida encerrada; veja result. | Se result.status for PENDING, confirme manualmente. |
CANCELLED | Cancelada por você, por ausência ou porque a sala sumiu do jogo. | Final. presence mostra quem estava (útil para W.O.). |
FAILED | Não foi possível criar a sala no momento. Não conta na cota. | Final. Crie outra sala. |
Criar sala
| Campo | Tipo | Descrição |
|---|---|---|
mode * | string | 1x1, 2x2, 3x3 ou 4x4. |
teams | objeto | { "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. |
autoStart | boolean | Inicia quando todos estiverem no time certo e prontos. Padrão: true se houver teams. |
autoResult | boolean | Confirma o vencedor automaticamente ao fim da partida. Padrão: true se houver teams. |
password | string | De 4 a 8 dígitos. Se omitida, a API gera uma senha de 6 dígitos. |
mapId | número | Mapa (veja GET /v1/modes). Padrão: 1. |
joinTimeoutMinutes | número | Prazo para todos entrarem, de 2 a 60. Padrão: 10. |
reference | string | Até 100 caracteres. Seu identificador (aposta, partida, ticket); volta em todos os eventos. |
settings | objeto | Configuraçõ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
Iniciar a partida
Inicia na hora, sem esperar todos marcarem pronto. Só vale em WAITING_PLAYERS.
Cancelar a sala
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
{ "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:
result.status: "CONFIRMED"eresult.winner("A"ou"B");result.stats: abates, mortes e dano de cada jogador, por ID do Free Fire, para placar, MVP e ranking na sua comunidade.
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
{ "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 campeonato | Significado |
|---|---|
SCHEDULED | Aguardando startsAt; check-in aberto. |
RUNNING | Em andamento: salas sendo criadas e resultados avançando a chave. |
FINISHED | Terminou; champion tem o id do time campeão. |
CANCELLED | Cancelado por você. |
| status do confronto | Significado |
|---|---|
PENDING | Aguardando os dois times ou uma vaga livre do plano. |
CREATING / PLAYING | Sala sendo criada ou partida em andamento (room aponta a sala na API). |
DONE | Vencedor definido (walkover: true quando foi W.O. ou bye). |
BYE | Confronto vazio, sem times. |
REVIEW | Precisa de você: resultado pendente ou sala que falhou três vezes. |
Criar campeonato
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"] }
]
}
| Campo | Descriçã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… |
startsAt | Data ISO nos próximos 60 dias. Padrão: agora. |
checkInRequired | Se true, só jogam os times que fizerem check-in antes de startsAt. |
joinTimeoutMinutes | Prazo para entrar em cada sala, de 2 a 30. Padrão: 10. |
reference | Até 100 caracteres. |
Como o campeonato roda sozinho
- 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).
- Em
startsAt, os times sem check-in (se exigido) são eliminados e o campeonato viraRUNNING. - 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_readycom ID e senha para avisar os times. - 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.
- A final define o
champione disparatournament.finished.
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:
{ "winnerTeamId": "team_3" }
Cancelar campeonato
Para de criar salas. Salas já em andamento seguem até o fim e continuam aparecendo em /v1/rooms.
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 */ }
}
- Responda com qualquer status
2xxem até 10 segundos. - Falhas são reenviadas até 8 vezes, com espera crescente (30 s, 1 min, 2 min… até 1 h).
- O mesmo evento pode chegar mais de uma vez: ignore
idrepetido. - Use
POST /v1/webhooks/testou o botão do painel para receber umwebhook.test.
Eventos
| Evento | Quando | data |
|---|---|---|
room.ready | Sala criada no jogo, com ID e senha. | sala |
room.started | Partida iniciada. | sala (sem senha) |
room.finished | Resultado confirmado (automático ou manual). | sala |
room.result_pending | Partida terminou e precisa de conferência. | sala |
room.cancelled | Cancelada por você, por ausência ou porque a sala sumiu. | sala |
room.failed | Não foi possível criar a sala. | sala |
tournament.created | Campeonato criado. | campeonato |
tournament.started | Chegou startsAt. | campeonato |
tournament.match_ready | Sala de um confronto pronta. | { tournamentId, match, room } |
tournament.match_finished | Confronto decidido (inclui W.O. e bye). | { tournamentId, match } |
tournament.finished | Campeão definido. | campeonato |
tournament.cancelled | Campeonato cancelado. | campeonato |
subscription.activated | Pagamento confirmado e plano ativo. | { plan, validUntil } |
webhook.test | Teste 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); });
import hmac, hashlib, os, re, time, json from flask import Flask, request app = Flask(__name__) @app.post("/lobbito") def lobbito(): m = re.fullmatch(r"t=(\d+),v1=([a-f0-9]{64})", request.headers.get("X-Lobbito-Signature", "")) raw = request.get_data() if not m or abs(time.time() - int(m[1])) > 300: return "", 401 expected = hmac.new(os.environ["LOBBITO_WEBHOOK_SECRET"].encode(), m[1].encode() + b"." + raw, hashlib.sha256).hexdigest() if not hmac.compare_digest(expected, m[2]): return "", 401 event = json.loads(raw) if event["type"] == "room.finished": pagar_vencedor(event["data"]["reference"], event["data"]["result"]["winner"]) return "", 200
Conta e modos
{
"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" }
}
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.
Assinaturas e Pix
- Os planos valem 30 dias e são pagos por Pix no painel. A liberação é automática quando o Mercado Pago confirma o pagamento.
- Pagar de novo o mesmo plano antes de vencer soma 30 dias. Pagar outro plano troca na hora e começa um ciclo novo, com a contagem de salas zerada.
- Não há cobrança automática: ao expirar, o acesso volta ao Free com os testes que ainda restarem. Isso não concede outras dez salas. Recursos exclusivos da assinatura deixam de estar disponíveis.
- O código Pix vale 30 minutos. Se expirar, gere outro no painel.
Boas práticas
- Guarde a chave e o segredo do webhook em variáveis de ambiente; troque-os no painel se vazarem.
- Envie
Idempotency-Keyem toda criação; repita a chamada com a mesma chave em caso de timeout. - Prefira webhooks a ficar consultando a sala; se consultar, faça no máximo uma vez a cada 10 segundos.
- Só pague apostas com
result.status === "CONFIRMED". - Peça os IDs do Free Fire no cadastro do jogador e confira se são dele, para o resultado automático funcionar.
Mudanças
| Versão | Mudança |
|---|---|
| v1 · outubro de 2026 | Lanç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.