Betamigos / Desenvolvedores
Referência da API
API do Betamigos
Registre suas apostas no Betamigos a partir do seu próprio sistema: um bot, um script de planilha, uma ferramenta interna. Toda aposta enviada cai no mesmo lugar de uma digitada no app, então CLV, P&L, exposição e o extrato da carteira continuam funcionando igual.
É uma API pequena de propósito. Ela cobre o ciclo que importa (registrar, corrigir, liquidar, reconciliar) e mais nada.
Pegue um token
Abra Perfil > Acesso por API no app e crie um token. O segredo aparece uma única vez, na criação, porque guardamos só o hash dele. Se você perder, revogue aquele token e crie outro.
Mande ele em toda requisição, no header X-Service-Token:
X-Service-Token: bmst_xxxxxxxxxxxxxxxxxxxxxxxxO token age como você: lê e escreve só os seus dados, e nunca enxerga os de outra conta. Revogar vale na hora.
URL base
https://betamigos.ioTodo caminho aqui embaixo já começa com /api, então a URL completa do primeiro endpoint é https://betamigos.io/api/bets. Todos os corpos são JSON. Todas as datas são ISO 8601 em UTC.
Registrar uma aposta
POST /api/bets
Há duas formas de registrar, e a diferença entre elas não é de formato: é o quanto de trabalho fica com você depois.
Aposta solta. Você descreve a aposta em texto e pronto. Serve para qualquer coisa, inclusive mercado que a gente nem acompanha. O preço é que ninguém liquida por você: quando o jogo acabar, você chama o endpoint de liquidação com o resultado, e o CLV só existe se você mandar a odd de fechamento junto.
Aposta ligada ao mercado. Você inclui o selection_id da seleção real. A partir daí a aposta se liquida sozinha quando o jogo termina, e a linha de fechamento é capturada por nós, o que dá CLV sem você fazer nada. Como achar esse id está na seção seguinte.
A recomendação é óbvia: sempre que a aposta existir no nosso catálogo, mande o selection_id. Quando não existir, a aposta solta é o caminho, e nada se perde além da automação.
# Aposta solta: só rótulos. Você liquida depois.
curl -X POST https://betamigos.io/api/bets \
-H "X-Service-Token: $BETAMIGOS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"stake": 25,
"odds": 2.10,
"sport": "Soccer",
"league": "Premier League",
"event_label": "Arsenal vs Chelsea",
"market": "Match winner",
"selection": "Arsenal",
"starts_at": "2026-08-09T19:00:00Z",
"external_source": "meu-bot",
"external_ref": "trade-8814"
}'# Ligada ao mercado: liquida e calcula CLV sozinha.
curl -X POST https://betamigos.io/api/bets \
-H "X-Service-Token: $BETAMIGOS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"account_id": 3,
"stake": 25,
"odds": 2.10,
"blv_odds": 1.96,
"blv_devig": "conservative",
"root_event_id": 45012,
"selection_id": 918273,
"starts_at": "2026-08-09T19:00:00Z",
"sport": "Soccer",
"league": "Premier League",
"event_label": "Arsenal vs Chelsea",
"market": "Asian Handicap -0.5",
"selection": "Arsenal",
"tag_names": ["bot", "valuebet"],
"external_source": "meu-bot",
"external_ref": "trade-8814"
}'Devolve 201 com a aposta criada. Ela nasce pending.
Só stake e odds são obrigatórios. O resto deixa os números mais ricos:
| Campo | Por que enviar |
|---|---|
account_id | Carteira da aposta. Sem ele, cai na sua carteira favorita. |
selection_id, root_event_id | Amarram a aposta ao mercado real. É o que habilita a liquidação automática e a captura da linha de fechamento. |
sport, league, event_label, market, selection | Os rótulos que você vai ler depois no dashboard. Mande mesmo com selection_id: é o que aparece na tabela. |
starts_at | Horário de início. Define quando a linha é considerada fechada. |
odds | A odd que você realmente pegou. Em exchange, mande a líquida, já com a comissão. |
gross_odds, commission_type, commission_pct | A comissão que você pagou, se preferir que a gente faça a conta. Os três juntos ou nenhum: com eles, o servidor calcula a odd líquida a partir da bruta e ignora o odds que você mandou. commission_type é on_profit, on_stake ou on_return. |
blv_odds | A odd justa (sem vig) no momento da aposta, se você calcula. Alimenta a métrica de valor. |
origin | alert, explorer ou manual. Marca de onde a aposta veio. |
tag_names | Anexa suas tags por nome, sem precisar dos ids. Nome inexistente é ignorado. |
external_source, external_ref | Seus identificadores. Veja idempotência abaixo. |
Idempotência
Mande sempre external_source e external_ref. Repetir o POST do mesmo par devolve a aposta que já existe, com status 200 em vez de 201, e não cria nada novo.
Isso pesa mais do que parece: sem esse par, um retry depois de um timeout registra a aposta duas vezes e lança o dinheiro duas vezes no extrato da carteira. Com ele, tentar de novo sai de graça.
Conferência de consistência
Se você mandar root_event_id junto com starts_at, comparamos o horário declarado com o real. Diferença maior que 6 horas é recusada com 400, porque indica que a aposta foi ligada ao jogo errado (o caso clássico são duas partidas entre os mesmos times, com dias de distância). Se a base de odds estiver fora naquele instante, deixamos passar em vez de te travar.
Achar o evento e a seleção
Dois passos: procure o jogo, abra o jogo. O primeiro devolve o id do evento, o segundo devolve os selection_id de dentro dele.
1. Procurar o jogo
GET /api/events/upcoming lista o que ainda não começou, do mais próximo para o mais distante. Filtros: q (texto livre, casa com os nomes dos times), sport, league_id, date_from, date_to, limit (até 200) e offset.
curl "https://betamigos.io/api/events/upcoming?q=arsenal&sport=Soccer&limit=10" \
-H "X-Service-Token: $BETAMIGOS_TOKEN"{
"total": 2,
"limit": 10,
"offset": 0,
"items": [
{ "id": 45012, "home": "Arsenal", "away": "Chelsea",
"starts_at": "2026-08-09T19:00:00Z",
"league_id": 1, "league": "Premier League", "sport": "Soccer", "n_markets": 74 }
]
}Esse id é o root_event_id da aposta. As irmãs /api/events/pending (em andamento) e /api/events/settled (encerrados, com placar) têm os mesmos filtros, e /api/events/leagues devolve o catálogo de ligas se você preferir filtrar por league_id em vez de texto.
Se o seu sistema fala em nomes de casa de aposta, o passo de casar nome com evento é seu, e vale desconfiar: duas partidas entre os mesmos times, com dias de distância, são o erro clássico. Por isso conferimos o starts_at contra o kickoff real e recusamos divergência acima de 6 horas.
2. Abrir o jogo e escolher a seleção
GET /api/events/{id} devolve o evento com todos os mercados e, dentro de cada um, as seleções.
curl "https://betamigos.io/api/events/45012" -H "X-Service-Token: $BETAMIGOS_TOKEN"{
"id": 45012, "home": "Arsenal", "away": "Chelsea", "sport": "Soccer",
"starts_at": "2026-08-09T19:00:00Z", "status": "open",
"markets": [
{
"market_id": 8801, "code": "spread", "period": 0, "unit": "regular",
"period_name": "Match", "unit_label": "Goals",
"team_side": null, "bet_type": null, "status": "open", "settleable": true,
"selections": [
{ "selection_id": 918273, "label": "Arsenal", "line": -0.5, "price": 2.10,
"status": "open", "max_limit": 2500,
"no_vig": { "conservative": 1.96, "equal_margin": 1.95,
"log": 1.95, "odds_ratio": 1.94 },
"margin": 0.038 },
{ "selection_id": 918274, "label": "Chelsea", "line": 0.5, "price": 1.80 }
]
}
]
}Como ler para mapear:
| Campo | Para que serve |
|---|---|
code, period, unit | Identificam o mercado. period: 0 é o jogo todo; unit distingue gols de escanteios, sets de games, e por aí. period_name e unit_label são os rótulos humanos dos mesmos valores. |
line, label | Identificam a seleção dentro do mercado. Em handicap e total, a linha é parte da identidade: Arsenal -0.5 e Arsenal -1 são seleções diferentes. |
selection_id | O que você manda no POST. |
price | A odd atual com margem, do jeito que a casa publica. |
no_vig | A odd justa nos quatro métodos de de-vig. Escolha o seu e mande em blv_odds, com o nome do método em blv_devig. |
max_limit | Quanto a fonte aceita nessa linha. Bom termômetro de quão confiável é o preço. |
settleable | false significa que a fonte nunca publica resultado desse mercado (acontece em kills de e-sports, pontos de vôlei). A aposta é aceita, mas quem informa o resultado é você. |
O gráfico de movimento de linha não está aberto ao token, e não faz falta aqui: para mapear uma seleção, o detalhe do evento basta.
Liquidar uma aposta
POST /api/bets/{id}/settle
curl -X POST https://betamigos.io/api/bets/1234/settle \
-H "X-Service-Token: $BETAMIGOS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"outcome": "won"}'outcome é um de won, lost, void, half_won, half_lost. Liquidar calcula o P&L, lança no saldo da carteira e captura o CLV.
Linha de fechamento: se a aposta tem selection_id e o evento já começou, buscamos a odd de fechamento sozinhos. Se você preferir informar a sua odd justa de fechamento, mande closing_odds e a sua prevalece.
Liquidar de novo com outro resultado é seguro. O extrato estorna o lançamento antigo e lança o novo, então o saldo continua certo.
Registrar uma aposta já decidida
POST /api/bets/settled
Mesmo corpo do POST /api/bets. Tentamos gradear na hora pela base de resultados. Se ainda não der, a aposta fica pendente e nosso worker liquida depois. Este endpoint também é idempotente pelo par external_source e external_ref.
Corrigir uma aposta
PATCH /api/bets/{id}
Mande só o que mudou, por exemplo {"stake": 12.5}. Stake e odd são editáveis enquanto a aposta está pendente; depois de liquidada elas congelam e você recebe 409. Rótulos e métricas de valor seguem editáveis.
Reconciliar
GET /api/bets
curl "https://betamigos.io/api/bets?external_ref=trade-8814" \
-H "X-Service-Token: $BETAMIGOS_TOKEN"Filtros: account_id, status (pending ou settled), external_ref, mais limit (até 5000) e offset. Mais recentes no topo. Buscar pela sua própria external_ref é o jeito mais barato de responder "essa aqui entrou?".
GET /api/bets/{id} devolve uma aposta só.
Valor da aposta: EV e CLV
As duas métricas saem da mesma conta, odd que você pegou ÷ odd justa − 1, em dois momentos diferentes. O que muda é qual odd justa entra no denominador.
EV no momento da aposta (chamamos de BLV). Mande blv_odds no POST: a odd justa, sem margem, do mercado quando você apostou. É o número que responde "esta aposta tinha valor quando eu a fiz?", e é a única das duas que depende de você, porque só o seu sistema sabe qual linha ele leu naquele instante. Sem blv_odds, tentamos calcular no servidor quando a aposta traz selection_id; sem os dois, a aposta entra sem EV e nada preenche isso depois.
CLV, na linha de fechamento. Se a aposta tem selection_id, não faça nada: buscamos a odd justa de fechamento sozinhos e gravamos o CLV quando ela liquida. Sem selection_id (aposta em casa que a gente não acompanha, mercado montado por você), mande closing_odds no settle, e a sua prevalece sempre, inclusive sobre a automática.
O GET devolve as duas prontas, junto do que você precisa para conferir:
| Campo | O que é |
|---|---|
blv_odds, blv | A odd justa que você enviou, e o EV que ela produziu. 0.05 = 5% de valor. |
closing_odds, clv | A odd justa de fechamento (sua ou nossa) e o CLV. |
clv_status | ok tem CLV; closed a linha já estava fechada quando a aposta foi feita, então não inventamos um número; none não houve fechamento. Fica nulo enquanto a aposta está pendente. |
pnl | Resultado líquido, preenchido na liquidação. |
Uma consequência que costuma surpreender: se a sua carteira cobra comissão, mande em odds a odd líquida, e aí EV e CLV também saem líquidos. É o número honesto do seu bolso, mas não é comparável com CLV bruto publicado por terceiros.
Leituras de apoio
| Endpoint | O que devolve |
|---|---|
GET /api/accounts | Suas carteiras, com ids, saldos e qual é a favorita. |
GET /api/tags | Suas tags, de sistema e custom, com ids. |
GET /api/events/upcoming, /pending, /settled | Busca de eventos por texto, esporte, liga e data. Veja "Achar o evento e a seleção". |
GET /api/events/leagues | Catálogo de ligas, para filtrar por league_id. |
GET /api/events/{id} | O evento com mercados, seleções, selection_id e odds justas. |
GET /api/alerts/rules | As regras de alerta de valor que você configurou no app, para o seu bot filtrar igual a você. |
GET /api/alerts | Os 30 alertas de valor mais recentes que batem com suas regras. Cada leg já traz o selection_id, então dá para apostar direto do alerta sem passar pela busca. |
O que um token não faz
Excluir aposta, reabrir aposta liquidada, mover aposta entre carteiras, depósito e saque, e qualquer coisa que toque sua conta, seu plano ou o pagamento continuam exigindo login normal. Um token vazado consegue escrever aposta no seu próprio tracker. Não consegue mover dinheiro, apagar seu histórico nem te trancar para fora.
Erros
| Status | Significado |
|---|---|
400 | Corpo inválido, carteira que não é sua, ou jogo incompatível. |
401 | Token ausente, inválido, expirado ou revogado. |
402 | Sua assinatura não está mais ativa, então o token parou de valer. Ele volta a funcionar assim que ela voltar, sem precisar criar outro. |
404 | A aposta não existe, ou não é sua. |
409 | Edição de aposta já liquidada. |
429 | Escritas demais no último minuto. |
Todo erro traz um campo detail com a mensagem legível.
Limites
Escritas são limitadas a 30 por minuto por ação, por conta: registrar aposta é um balde, liquidar é outro, editar é outro. Leituras por token são limitadas a 120 por minuto por grupo de endpoint. As duas janelas são deslizantes, então um 429 se resolve em menos de um minuto; tente de novo com um respiro em vez de martelar.
Duas coisas que valem desenhar com cuidado. Ficar pollando GET /api/alerts em loop apertado é o jeito mais rápido de bater o teto de leitura, e não traz dado mais fresco: os alertas chegam no ritmo deles, então de poucos em poucos segundos já basta.
Toda recusa se explica no detail. Trate 429 como "tenta daqui a pouco", não como bug.
Conselho prático
Guarde o token como senha, no seu gerenciador de segredos, nunca no repositório. Rotacionar é fácil: crie o segundo token, publique, e só então revogue o primeiro. Nada quebra no meio, porque os tokens são independentes.
Mande a odd que você realmente pegou, não a que você viu. Se a sua casa cobra comissão, a odd líquida é a honesta, e toda métrica lá na frente herda essa honestidade.
Dúvida, ou falta algo para o seu caso? Fale com a gente e conte o que você está construindo.