Predixdata API
Documentação para integrar o feed de mercados de previsão ao seu sistema. Consuma mercados em tempo real e receba notificações automáticas via webhook.
O que você consegue fazer
| Recurso | Descrição |
|---|---|
| Feed de mercados | Todos os mercados ativos agrupados por evento, com odds e análise de IA |
| Filtros | Filtre por categoria, sub-categoria ou evento específico |
| Webhooks | Notificações push quando um mercado fecha ou tem resultado final |
BASE URL
https://predixdata.com/api
HEADERS OBRIGATÓRIOS
X-Public-Key: pub_sua_chave_aqui
X-Secret-Key: sec_sua_chave_aqui
Autenticação
Todas as requests exigem autenticação via headers. Você receberá suas chaves ao se cadastrar como agente.
| Header | Formato | Descrição |
|---|---|---|
X-Public-Key | pub_xxxxxxxx... | Identificador único do agente |
X-Secret-Key | sec_xxxxxxxx... | Chave secreta de autenticação |
X-Secret-Key no frontend. Use-a apenas no backend.EXEMPLO DE REQUEST
curl https://predixdata.com/api/v1/get-markets \
-H "X-Public-Key: pub_sua_chave" \
-H "X-Secret-Key: sec_sua_chave"
Quick Start
Integre em 3 passos:
Receba suas chaves
Entre em contato para receber seu X-Public-Key e X-Secret-Key.
Busque os mercados
Faça um GET /api/v1/get-markets com os headers de autenticação. Pronto — você recebe todos os mercados ativos.
Configure os webhooks
Crie duas rotas no seu backend para receber notificações automáticas quando mercados fecham ou têm resultado.
PHP / LARAVEL
$response = Http::withHeaders([
'X-Public-Key' => 'pub_sua_chave',
'X-Secret-Key' => 'sec_sua_chave',
])->get('https://predixdata.com/api/v1/get-markets');
$markets = $response->json()['data'];
JAVASCRIPT
const res = await fetch('https://predixdata.com/api/v1/get-markets', {
headers: {
'X-Public-Key': 'pub_sua_chave',
'X-Secret-Key': 'sec_sua_chave'
}
});
const { data } = await res.json();
ROTAS DE WEBHOOK
POST /webhook/predixdata/notify-closed
POST /webhook/predixdata/final-result
POST /webhook/predixdata/market-refund
Feed de Mercados
Endpoint principal. Retorna todos os mercados ativos agrupados por evento, com odds em tempo real e análise de IA. Sem parâmetros retorna tudo; use query params para filtrar.
Query Parameters
| Parâmetro | Tipo | Descrição |
|---|---|---|
category | string | Filtra por categoria (ex: cripto, politica) |
sub_category | string | Filtra por sub-categoria (ex: bitcoin, futebol) |
event_id | string | Filtra por evento específico |
Campos do Response
| Campo | Tipo | Descrição |
|---|---|---|
event_id | string | ID do evento que agrupa os mercados |
event_title | string | Título do evento em PT-BR |
category | string | Categoria do evento |
sub_category | string | Sub-categoria |
total_volume | float | Volume total de todos os mercados do evento (USD) |
total_markets | integer | Quantidade de mercados no evento |
market_id | string | ID do mercado use para vincular com webhooks |
odds.yes.odd | float | Odd decimal para SIM (ex: 1.35) |
odds.yes.ai_estimate | float | Estimativa da IA para SIM (0 a 1) |
odds.no.odd | float | Odd decimal para NÃO |
odds.no.ai_estimate | float | Estimativa da IA para NÃO (0 a 1) |
ai.confidence | float | Confiança da IA (0 a 1) |
ai.reasoning | string | Explicação textual da análise |
volume | float | Volume de negociação (USD) |
closed | boolean | Se o mercado já fechou |
active | boolean | Se está ativo |
end_date | string | Data de encerramento (ISO 8601) |
RESPONSE 200
{
"success": true,
"agent": "Meu Site",
"total": 85,
"events": 12,
"generated_at": "2026-03-12T10:30:00.000Z",
"data": [
{
"event_id": "248137",
"event_title": "Preço do Bitcoin em Março 2026",
"category": "cripto",
"sub_category": "bitcoin",
"total_volume": 5000000.00,
"total_markets": 4,
"markets": [
{
"market_id": "1508196",
"slug": "o-preco-do-bitcoin-estara-entre-74000",
"title": "O preço do Bitcoin estará entre...",
"image_url": "https://...",
"odds": {
"yes": { "odd": 1.35, "ai_estimate": 0.72 },
"no": { "odd": 3.85, "ai_estimate": 0.28 }
},
"ai": {
"confidence": 0.85,
"reasoning": "Análise do modelo de IA..."
},
"volume": 1500000.00,
"closed": false,
"active": true,
"end_date": "2026-03-15T16:00:00.000Z"
}
]
}
]
}
Categorias
Retorna todas as categorias e subcategorias disponíveis com a contagem de mercados ativos em cada uma. Use para montar filtros ou menus dinâmicos no seu frontend.
Response
| Campo | Tipo | Descrição |
|---|---|---|
success | boolean | Sempre true |
total | integer | Quantidade de categorias |
generated_at | string | Timestamp ISO 8601 |
data[].category | string | Nome da categoria |
data[].total_markets | integer | Total de mercados ativos na categoria |
data[].sub_categories[].name | string | Nome da subcategoria |
data[].sub_categories[].total | integer | Total de mercados na subcategoria |
category e sub_category como filtro no endpoint /api/v1/get-markets?category=esportes&sub_category=futebol.curl https://predixdata.com/api/v1/get-categories \
-H "X-Agent-Public-Key: SUA_PUBLIC_KEY" \
-H "X-Agent-Secret-Key: SUA_SECRET_KEY"
{
"success": true,
"total": 6,
"generated_at": "2026-03-16T02:00:00.000Z",
"data": [
{
"category": "esportes",
"total_markets": 59,
"sub_categories": [
{ "name": "futebol", "total": 58 },
{ "name": "ufc-mma", "total": 1 }
]
},
{
"category": "geopolitica",
"total_markets": 80,
"sub_categories": [
{ "name": "oriente-medio", "total": 33 },
{ "name": "global", "total": 40 },
{ "name": "americas", "total": 2 }
]
},
{
"category": "entretenimento",
"total_markets": 17,
"sub_categories": [
{ "name": "reality-show", "total": 16 },
{ "name": "outros-entretenimento", "total": 1 }
]
}
]
}
Webhooks
O Predixdata envia notificações automáticas via POST para seu servidor quando eventos importantes acontecem.
Fluxo de entrega
| Etapa | Descrição |
|---|---|
| 1 | Mercado novo aprovado, fechado ou com resultado → webhook enfileirado |
| 2 | Dispatcher envia POST para sua URL |
| 3 | Seu servidor retorna 2xx → marcado como enviado |
| 4 | Falha → retry automático (1 min, 5 min, 15 min) |
| 5 | 4 tentativas sem sucesso → marcado como falha |
Headers enviados pelo Predixdata
| Header | Descrição |
|---|---|
X-Predixdata-Key | Sua public_key — identifica a origem |
X-Predixdata-Signature | HMAC-SHA256 do payload |
Content-Type | application/json |
2xx para confirmar recebimento. Caso contrário, retries serão feitos automaticamente.ROTAS QUE VOCÊ PRECISA CRIAR
POST {sua_url}/webhook/predixdata/new-market
POST {sua_url}/webhook/predixdata/notify-closed
POST {sua_url}/webhook/predixdata/final-result
POST {sua_url}/webhook/predixdata/market-refund
POLÍTICA DE RETRY
Tentativa 1: imediata
Tentativa 2: +1 minuto
Tentativa 3: +5 minutos
Tentativa 4: +15 minutos
Depois: marcado como falha
new-market
Enviado automaticamente a cada ~6 horas quando novos mercados são processados pela IA e aprovados. O payload segue o mesmo formato do GET /api/v1/get-markets, incluindo odds e pools prontos para uso.
Campos do Payload
| Campo | Tipo | Descrição |
|---|---|---|
event | string | Sempre "new-market" |
event_id | string | ID do evento que agrupa este mercado |
event_title | string | Título do evento em PT-BR |
category | string | Categoria (ex: politica, esportes) |
sub_category | string | Sub-categoria (ex: futebol, exterior) |
market | object | Objeto com todos os dados do mercado (ver abaixo) |
sent_at | string | Quando o webhook foi gerado (ISO 8601) |
Campos do objeto market
| Campo | Tipo | Descrição |
|---|---|---|
market_id | string | ID único do mercado — use como chave no seu banco |
slug | string | Slug em PT-BR para URL |
title | string | Título em PT-BR |
description | string | Descrição traduzida |
image_url | string|null | Imagem do mercado |
icon_url | string|null | Ícone do mercado |
odds.yes.odd | float | Odd decimal do SIM (com margem embutida) |
odds.yes.pool | float | Pool de liquidez do YES — use para montar seu CPMM |
odds.yes.ai_estimate | int|null | Probabilidade estimada pela IA (%) |
odds.no.odd | float | Odd decimal do NÃO |
odds.no.pool | float | Pool de liquidez do NO |
odds.no.ai_estimate | int|null | Probabilidade estimada pela IA (%) |
ai.confidence | string | high, medium ou low |
ai.reasoning | string | Justificativa da IA para a estimativa |
volume | float | Volume negociado na fonte original (USD) |
relevance_score | int | Score de relevância para público brasileiro (0-100) |
end_date | string|null | Data de encerramento (ISO 8601) |
odds.yes.pool e odds.no.pool, calcule k = yes_pool × no_pool, e o mercado já está pronto para receber apostas. Não precisa chamar o GET.PAYLOAD
{
"event": "new-market",
"event_id": "248137",
"event_title": "Eleições USA 2028",
"category": "politica",
"sub_category": "exterior",
"market": {
"market_id": "1508196",
"slug": "trump-vence-eleicao-2028",
"title": "Trump vence a eleição de 2028?",
"description": "Resolve SIM se Trump vencer...",
"image_url": "https://polymarket.com/...",
"icon_url": "https://polymarket.com/...",
"odds": {
"yes": {
"odd": 2.35,
"pool": 21.27,
"ai_estimate": 42
},
"no": {
"odd": 1.74,
"pool": 28.73,
"ai_estimate": 58
}
},
"ai": {
"confidence": "medium",
"reasoning": "Trump lidera pesquisas..."
},
"volume": 145230.50,
"relevance_score": 85,
"end_date": "2028-11-05T23:00:00+00:00"
},
"sent_at": "2026-03-15T18:30:00+00:00"
}
EXEMPLO DE HANDLER
Route::post('/webhook/predixdata/new-market',
function (Request $request) {
$data = $request->all();
$m = $data['market'];
Market::updateOrCreate(
['predixdata_id' => $m['market_id']],
[
'title' => $m['title'],
'slug' => $m['slug'],
'category' => $data['category'],
'yes_odd' => $m['odds']['yes']['odd'],
'no_odd' => $m['odds']['no']['odd'],
'yes_pool' => $m['odds']['yes']['pool'],
'no_pool' => $m['odds']['no']['pool'],
'end_date' => $m['end_date'],
'active' => true,
]
);
return response()->json(['received' => true]);
});
notify-closed
Enviado quando um mercado fecha para novas apostas (5 minutos antes do end_date).
Campos do Payload
| Campo | Tipo | Descrição |
|---|---|---|
event | string | Sempre "notify-closed" |
market_id | string | ID do mercado — mesmo market_id retornado no feed |
event_id | string | ID do evento que agrupa este mercado |
title | string | Título em PT-BR |
end_date | string | Data de encerramento (ISO 8601) |
closed | boolean | Sempre true |
closed_at | string | Quando o mercado foi fechado |
PAYLOAD
{
"event": "notify-closed",
"market_id": "1508196",
"event_id": "248137",
"title": "O preço do Bitcoin estará entre...",
"end_date": "2026-03-12T16:00:00+00:00",
"closed": true,
"closed_at": "2026-03-12T15:55:12+00:00"
}
EXEMPLO DE HANDLER
Route::post('/webhook/predixdata/notify-closed',
function (Request $request) {
$data = $request->all();
$market = Market::where(
'predixdata_id', $data['market_id']
)->first();
if ($market) {
$market->update([
'closed' => true,
'closed_at' => $data['closed_at'],
]);
}
return response()->json(['received' => true]);
});
final-result
Enviado quando o resultado final do mercado é confirmado.
Campos do Payload
| Campo | Tipo | Descrição |
|---|---|---|
event | string | Sempre "final-result" |
market_id | string | ID do mercado — mesmo market_id retornado no feed |
event_id | string | ID do evento que agrupa este mercado |
title | string | Título em PT-BR |
end_date | string | Data de encerramento |
result | string | "yes" ou "no" — sempre lowercase |
resolved_at | string | Quando o resultado foi confirmado |
result será "yes" ou "no" — sempre lowercase.PAYLOAD
{
"event": "final-result",
"market_id": "1508196",
"event_id": "248137",
"title": "O preço do Bitcoin estará entre...",
"end_date": "2026-03-12T16:00:00+00:00",
"result": "yes",
"resolved_at": "2026-03-12T18:30:00+00:00"
}
EXEMPLO DE HANDLER
Route::post('/webhook/predixdata/final-result',
function (Request $request) {
$data = $request->all();
$market = Market::where(
'predixdata_id', $data['market_id']
)->first();
if ($market) {
$market->update([
'result' => $data['result'],
'active' => false,
'resolved_at' => $data['resolved_at'],
]);
// Processa pagamentos, notifica usuários...
}
return response()->json(['received' => true]);
});
market-refund
Enviado quando um mercado é reembolsado automaticamente. Isso acontece quando o resultado não é confirmado dentro de 24 horas após o fechamento.
Campos do Payload
| Campo | Tipo | Descrição |
|---|---|---|
event | string | Sempre "market-refund" |
market_id | string | ID do mercado |
event_id | string | ID do evento |
title | string | Título em PT-BR |
active | boolean | Sempre false |
closed | boolean | Sempre true |
result | string | Sempre "refund" |
refunded_at | string | Quando o refund foi processado |
result será "refund" em vez de "yes"/"no".PAYLOAD
{
"event": "market-refund",
"market_id": "1508196",
"event_id": "248137",
"title": "O preço do Bitcoin estará entre...",
"active": false,
"closed": true,
"result": "refund",
"refunded_at": "2026-03-13T18:00:00+00:00"
}
EXEMPLO DE HANDLER
Route::post('/webhook/predixdata/market-refund',
function (Request $request) {
$data = $request->all();
$market = Market::where(
'predixdata_id', $data['market_id']
)->first();
if ($market) {
$market->update([
'result' => 'refund',
'active' => false,
]);
// Devolver valor apostado aos usuários
$market->bets()->each(function ($bet) {
$bet->user->increment('balance', $bet->amount);
$bet->update(['status' => 'refunded']);
});
}
return response()->json(['received' => true]);
});
Validação HMAC
Todo webhook inclui uma assinatura HMAC-SHA256 no header X-Predixdata-Signature. Valide para garantir que a request veio do Predixdata.
Como funciona
| Etapa | Descrição |
|---|---|
| 1 | Predixdata gera HMAC-SHA256 do body JSON usando sua secret_key |
| 2 | Assinatura enviada no header X-Predixdata-Signature |
| 3 | Você recalcula o HMAC e compara com a assinatura |
401.PHP
$signature = $request->header('X-Predixdata-Signature');
$secret = config('services.predixdata.secret_key');
$expected = hash_hmac(
'sha256',
$request->getContent(),
$secret
);
if (!hash_equals($expected, $signature)) {
return response()->json(
['error' => 'Invalid signature'], 401
);
}
// Assinatura válida — processar
NODE.JS
const crypto = require('crypto');
const signature = req.headers['x-predixdata-signature'];
const expected = crypto
.createHmac('sha256', process.env.PREDIXDATA_SECRET)
.update(JSON.stringify(req.body))
.digest('hex');
if (signature !== expected) {
return res.status(401).json({
error: 'Invalid signature'
});
}
// Assinatura válida — processar
Trânsito ao Vivo
Mercados de previsão baseados em câmeras de trânsito em tempo real. A cada 5 minutos, uma nova rodada é criada automaticamente com uma linha Over/Under de veículos. Os usuários apostam se a contagem será acima ou abaixo da linha.
Como funciona
| Etapa | Tempo | O que acontece |
|---|---|---|
| 1. Abertura | 0:00 | Nova rodada criada — mercado chega via webhook new-market com source: "traffic" |
| 2. Apostas | 0:00 → 3:00 | Apostadores escolhem Over (SIM) ou Under (NÃO). Odds se movem via CPMM igual aos outros mercados |
| 3. Fechamento | 3:00 | Apostas travadas — webhook notify-closed é enviado |
| 4. Resultado | 5:00 | Contagem final de veículos enviada — webhook final-result ou market-refund (empate na linha) |
| 5. Nova rodada | 5:05 | Ciclo recomeça automaticamente |
POST /transaction) e simulação (POST /simulate-bet). A única diferença é que eles vêm com source: "traffic" e incluem um campo extra video_url.CARACTERÍSTICAS
source: "traffic"
category: "live"
sub_category: "transito"
duração: 5 minutos por rodada
apostas: 3 minutos (fecha 2 min antes)
tipo: Over / Under (veículos)
video_url: URL do stream ao vivo
CICLO VISUAL
0:00 ─── Rodada abre ──────────────────
▸ Apostas habilitadas
▸ Odds se movem com cada aposta
3:00 ─── Apostas fechadas ────────────
✕ Novas apostas bloqueadas
5:00 ─── Resultado ───────────────────
✓ Contagem final → Over/Under/Push
5:05 ─── Nova rodada ─────────────────
Vídeo ao Vivo
Cada mercado de trânsito inclui um campo video_url que aponta para uma página hospedada no Predixdata com o stream ao vivo da câmera (MJPEG via HTTPS). A URL real da câmera nunca é exposta — você sempre recebe uma URL nossa.
Formato da URL
| Campo | Exemplo |
|---|---|
video_url | https://predixdata.com/live/xK9mP2nQr7sT4u8v.html |
Como usar
| Método | Descrição |
|---|---|
| iframe | Embedar a página video_url direto no seu site — já vem com o stream fullscreen e fundo preto |
| Link | Abrir em nova aba para o usuário assistir enquanto aposta |
EMBED COM IFRAME
<div class="video-container">
<iframe
src="{{ video_url }}"
width="100%"
height="400"
frameborder="0"
style="border-radius: 8px"
></iframe>
</div>
REACT
{market.video_url && (
<iframe
src={market.video_url}
className="w-full aspect-video rounded-lg"
frameBorder="0"
/>
)}
Ciclo de Vida (5 min)
Cada rodada passa por 4 webhooks — os mesmos que você já usa para mercados normais. A diferença é a velocidade: tudo acontece em 5 minutos.
Webhooks por ordem
| # | Webhook | Quando | Ação no seu sistema |
|---|---|---|---|
| 1 | new-market | Rodada abre (0:00) | Salvar mercado, exibir vídeo, habilitar apostas Over/Under |
| 2 | notify-closed | 2 min antes do fim (3:00) | Bloquear novas apostas, mostrar countdown |
| 3a | final-result | Fim da rodada (5:00) | Mostrar resultado, liquidar apostas (Over=yes / Under=no) |
| 3b | market-refund | Empate na linha | Reembolsar todas as apostas |
Mapeamento Over/Under → Yes/No
| Aposta do usuário | Tipo na API | Resultado ganhador |
|---|---|---|
| Over (acima da linha) | type: "yes" | result: "yes" |
| Under (abaixo da linha) | type: "no" | result: "no" |
| Exato na linha (Push) | — | result: "refund" |
EXEMPLO: new-market (TRÂNSITO)
{
"event": "new-market",
"event_id": "traffic_rod-br-101-km42",
"event_title": "Trânsito ao Vivo - BR-101 KM 42",
"category": "live",
"sub_category": "transito",
"market": {
"market_id": "traffic_rod-br-101-km42_15",
"source": "traffic",
"slug": "transito-br-101-km-42-rodada-15",
"title": "Rodada #15 - Mais de 14.5 veículos irão cruzar a linha?",
"description": "Mercado resolve SIM se a contagem de veículos for superior a 14.5 ao final da rodada.",
"video_url": "https://predixdata.com/live/xK9mP2nQr7sT4u.html",
"image_url": "https://s2.glbimg.com/...rodovia-dutra-divulgacao.jpg",
"icon_url": "https://s2.glbimg.com/...rodovia-dutra-divulgacao.jpg",
"odds": {
"yes": { "odd": 1.85, "pool": 43.20, "ai_estimate": 54 },
"no": { "odd": 2.12, "pool": 36.80, "ai_estimate": 46 }
},
"ai": {
"confidence": "low",
"reasoning": "Linha de 14.5 calculada com base no histórico da câmera..."
},
"volume": 0,
"closed": false,
"active": true,
"relevance_score": 75,
"end_date": "2026-03-23T15:05:00+00:00"
},
"sent_at": "2026-03-23T15:00:00+00:00"
}
Over / Under
A linha (threshold) de cada rodada é calculada automaticamente com base no histórico da câmera. O sistema considera 3 fatores:
Cálculo da Linha
| Fator | Peso | Descrição |
|---|---|---|
| Últimas 5 rodadas | 50% | Tendência recente — se o trânsito está mais ou menos movimentado |
| Mesma hora ontem | 30% | Padrão horário — rush, almoço, madrugada (com margem de ±30 min) |
| Média geral | 20% | Baseline da câmera |
Se a média da mesma hora de ontem diverge mais de 20% da média recente, o sistema aumenta o peso dela para 40% — isso significa que detectou um padrão horário forte (ex: rush das 18h).
Regras da linha
| Regra | Descrição |
|---|---|
| Arredondamento | Linha sempre em .0 ou .5 (ex: 12.5, 15.0) |
| Sem histórico | Padrão de 10.0 na primeira rodada |
A linha pode ser extraída do título do mercado (ex: "Rodada #15 - Mais de 14.5 veículos irão cruzar a linha?").
TÍTULO E DESCRIPTION
"title": "Rodada #15 - Mais de 14.5 veículos irão cruzar a linha?"
"description": "Mercado resolve SIM se a contagem de veículos for superior a 14.5 ao final da rodada."
EXTRAINDO A LINHA (REGEX)
// Extrair a linha do título
const match = title.match(
/Mais de ([\d.]+)/
);
const line = match ? parseFloat(match[1]) : null;
ODDS E PROBABILIDADES
// odds.yes = Over (acima da linha)
// odds.no = Under (abaixo da linha)
//
// ai_estimate = probabilidade em % (ex: 55, 45)
// Mesmo padrão dos outros mercados
//
// Com histórico: baseado nas últimas 10 rodadas
// Sem histórico: assimetria leve aleatória (40-60%)
// Nunca 50/50 — sempre um lado ligeiramente favorito
//
// Pool inicial: R$80 (maior que padrão)
// Mercado rápido = mais liquidez = estabilidade
Integração Completa
Exemplo passo a passo de como integrar mercados de trânsito no seu sistema.
Receber o mercado
No seu handler de webhook new-market, verifique se sub_category === "transito". Se sim, salve o mercado com o video_url e exiba na UI com os botões Over e Under.
Exibir vídeo + apostas
Embede a video_url via iframe na sua página — a página já contém o stream MJPEG via HTTPS. Mostre a linha, as odds atuais e botões SIM/NÃO. Use POST /simulate-bet para preview em tempo real.
Executar aposta
Use POST /api/v1/transaction com type: "yes" para Over ou type: "no" para Under. As odds se movem igual CPMM — a mesma API dos outros mercados.
Receber fechamento
Webhook notify-closed chega 2 min antes do fim. Bloqueie o botão de apostar e mostre um countdown.
Receber resultado
Webhook final-result com result: "yes" (Over ganhou) ou "no" (Under ganhou). Ou market-refund se empate na linha. Liquide as apostas e mostre próxima rodada.
HANDLER COMPLETO — LARAVEL
// routes/api.php
Route::post('/webhook/predixdata/new-market',
function (Request $r) {
$data = $r->all();
$m = $data['market'];
// Mercado de trânsito?
$isTraffic = $data['sub_category'] === 'transito';
Market::updateOrCreate(
['market_id' => $m['market_id']],
[
'title' => $m['title'],
'source' => $m['source'] ?? 'polymarket',
'video_url' => $m['video_url'] ?? null,
'yes_odd' => $m['odds']['yes']['odd'],
'no_odd' => $m['odds']['no']['odd'],
'yes_pool' => $m['odds']['yes']['pool'],
'no_pool' => $m['odds']['no']['pool'],
'end_date' => $m['end_date'],
]
);
if ($isTraffic) {
// Broadcast para exibir na tela de trânsito
broadcast(new TrafficRoundStarted($m));
}
return response()->json(['ok' => true]);
});
APOSTAR OVER (YES)
curl -X POST "https://predixdata.com/api/v1/transaction" \
-H "X-Public-Key: pub_..." \
-H "X-Secret-Key: sec_..." \
-H "Content-Type: application/json" \
-d '{
"market_id": "traffic_rod-br-101-km42_15",
"type": "yes",
"amount": 50.00,
"odd": 1.85
}'
Jogos ao Vivo
Mercados de previsão baseados em jogos 3D ao vivo transmitidos via stream. Dois grupos (YES e NO) se enfrentam e os usuários apostam em quem vence. Usa a mesma infraestrutura de webhooks e apostas dos outros mercados.
Como funciona
| Etapa | Tempo | O que acontece |
|---|---|---|
| 1. Abertura | 0:00 | Nova rodada criada — mercado chega via webhook new-market com source: "game" |
| 2. Apostas | 0:00 → 0:15 | Apostadores escolhem YES ou NO. Odds se movem via CPMM |
| 3. Fechamento | 0:15 | Apostas travadas — webhook notify-closed é enviado |
| 4. Jogo | 0:15 → fim | Jogo roda até um grupo vencer (máx ~10 min) |
| 5. Resultado | fim | Webhook final-result ou market-refund (empate/timeout) |
POST /transaction) e simulação (POST /simulate-bet). A diferença é que eles vêm com source: "game", sub_category: "game" e o resultado é binário: YES vence ou NO vence.CARACTERÍSTICAS
source: "game"
category: "live"
sub_category: "game"
duração: ~2 minutos (variável)
apostas: 15 segundos após abertura
tipo: YES vence / NO vence
video_url: URL do stream ao vivo
image_url: Logo do jogo
CICLO VISUAL
0:00 ─── Rodada abre ──────────────────
▸ Grupos YES e NO revelados
▸ Apostas habilitadas (15s)
0:15 ─── Apostas fechadas ────────────
✕ Novas apostas bloqueadas
▸ Jogo em andamento
~2:00 ── Resultado ───────────────────
✓ Grupo vencedor → YES ou NO
~2:10 ── Nova rodada ─────────────────
Ciclo de Vida
Cada rodada de jogo passa pelos mesmos 4 webhooks dos mercados normais. A diferença principal é que o tempo de apostas é curto (15 segundos) e a duração do jogo é variável.
Webhooks por ordem
| # | Webhook | Quando | Ação no seu sistema |
|---|---|---|---|
| 1 | new-market | Rodada abre | Salvar mercado, exibir vídeo, habilitar apostas YES/NO |
| 2 | notify-closed | 15s após abertura | Bloquear novas apostas, mostrar "jogo em andamento" |
| 3a | final-result | Jogo termina | Mostrar vencedor, liquidar apostas (yes ou no) |
| 3b | market-refund | Empate/timeout | Reembolsar todas as apostas |
Mapeamento de Resultado
| Situação | Resultado | Webhook |
|---|---|---|
| Grupo YES vence | result: "yes" | final-result |
| Grupo NO vence | result: "no" | final-result |
| Empate / Timeout | Reembolso | market-refund |
EXEMPLO: new-market (JOGO)
{
"event": "new-market",
"event_id": "traffic_arena-flags-battle",
"event_title": "Arena ao Vivo - Arena 3D - Bandeiras",
"category": "live",
"sub_category": "game",
"market": {
"market_id": "traffic_arena-flags-battle_16_KnRAdC",
"source": "game",
"slug": "game-arena-3d-bandeiras-rodada-16-knradc",
"title": "Rodada #16 - Quem vence a batalha?",
"description": "Mercado resolve SIM se o Grupo YES vencer a rodada.",
"video_url": "https://predixdata.com/live/xK9mP2nQr7sT4u.html",
"image_url": "https://mathzdev.b-cdn.net/ch-v2-logo/...",
"icon_url": "https://mathzdev.b-cdn.net/ch-v2-logo/...",
"odds": {
"yes": { "odd": 1.55, "pool": 44.80, "ai_estimate": 56 },
"no": { "odd": 1.72, "pool": 35.20, "ai_estimate": 44 }
},
"ai": {
"confidence": "low",
"reasoning": "Odds calculadas com base no histórico de vitórias..."
},
"volume": 0,
"closed": false,
"active": true,
"relevance_score": 75,
"end_date": "2026-04-09T02:48:33+00:00"
},
"sent_at": "2026-04-09T02:46:33+00:00"
}
Odds YES / NO
As odds dos jogos são calculadas de forma diferente dos mercados de trânsito. Não existe "linha" — é simplesmente YES vence ou NO vence.
Cálculo das Odds
| Cenário | Lógica |
|---|---|
| Com histórico (≥3 rodadas) | Baseado na taxa de vitórias YES vs NO das últimas 20 rodadas, com suavização |
| Sem histórico | Odds entre 1.40 e 1.70 com leve variação aleatória |
| Especial (~5%) | Odd de 2.00 em um dos lados — lado oposto entre 1.10 e 1.30 |
Range de Odds
| Tipo | Mínimo | Máximo |
|---|---|---|
| Normal | 1.10 | 1.90 |
| Especial (~5% das rodadas) | 1.10 | 2.00 |
As odds se movem com cada aposta via CPMM, igual aos outros mercados. As odds iniciais são apenas o ponto de partida.
TÍTULO E DESCRIPTION
"title": "Rodada #16 - Quem vence a batalha?"
"description": "Mercado resolve SIM se o Grupo YES vencer a rodada."
DIFERENÇAS DO TRÂNSITO
// TRÂNSITO
source: "traffic"
sub_category: "transito"
resultado: Over / Under / Push (refund)
odds: 1.01 — 3.00+
// JOGO
source: "game"
sub_category: "game"
resultado: YES vence / NO vence / Refund
odds: 1.10 — 1.90 (esporadicamente 2.00)
COMO IDENTIFICAR
// No handler de new-market:
const isGame = data.sub_category === 'game';
const isTraffic = data.sub_category === 'transito';
if (isGame) {
// Exibir botões YES / NO
// Mostrar stream do jogo
} else if (isTraffic) {
// Exibir botões Over / Under
// Mostrar câmera de trânsito
}
Integração Completa
Exemplo passo a passo de como integrar mercados de jogos ao vivo no seu sistema.
Receber o mercado
No seu handler de webhook new-market, verifique se sub_category === "game". Se sim, salve o mercado com o video_url e exiba na UI com os botões YES e NO.
Exibir vídeo + apostas
Embede a video_url via iframe — mostra o jogo 3D ao vivo. Use a image_url como logo/thumbnail. Mostre as odds atuais e botões YES/NO. Apostas duram apenas 15 segundos — destaque o countdown.
Executar aposta
Use POST /api/v1/transaction com type: "yes" ou type: "no". Mesma API dos outros mercados.
Receber fechamento
Webhook notify-closed chega 15s após abertura. Bloqueie o botão de apostar e mostre "jogo em andamento".
Receber resultado
Webhook final-result com result: "yes" (Grupo YES venceu) ou "no" (Grupo NO venceu). Ou market-refund se empate/timeout. Liquide as apostas e aguarde próxima rodada.
HANDLER — LARAVEL
// routes/api.php
Route::post('/webhook/predixdata/new-market',
function (Request $r) {
$data = $r->all();
$m = $data['market'];
// Tipo de mercado ao vivo?
$isGame = $data['sub_category'] === 'game';
$isTraffic = $data['sub_category'] === 'transito';
Market::updateOrCreate(
['market_id' => $m['market_id']],
[
'title' => $m['title'],
'source' => $m['source'],
'video_url' => $m['video_url'] ?? null,
'image_url' => $m['image_url'] ?? null,
'yes_odd' => $m['odds']['yes']['odd'],
'no_odd' => $m['odds']['no']['odd'],
'end_date' => $m['end_date'],
]
);
if ($isGame) {
broadcast(new GameRoundStarted($m));
} elseif ($isTraffic) {
broadcast(new TrafficRoundStarted($m));
}
return response()->json(['ok' => true]);
});
APOSTAR YES
curl -X POST "https://predixdata.com/api/v1/transaction" \
-H "X-Public-Key: pub_..." \
-H "X-Secret-Key: sec_..." \
-H "Content-Type: application/json" \
-d '{
"market_id": "traffic_arena-flags-battle_16_KnRAdC",
"type": "yes",
"amount": 50.00,
"odd": 1.55
}'
Guia de Odds
Cada mercado no Predixdata usa um modelo AMM (Automated Market Maker) com liquidez inicial de R$50. As odds são estilo bet365 (decimal) — uma odd de 2.50 significa que R$10 apostados retornam R$25.
Dados que você recebe no feed
| Campo | Tipo | Descrição |
|---|---|---|
odds.yes.odd | float | Odd decimal do YES (ex: 1.35) |
odds.yes.pool | float | Volume em R$ no pool YES |
odds.no.odd | float | Odd decimal do NO (ex: 4.12) |
odds.no.pool | float | Volume em R$ no pool NO |
Cálculo simples (sem slippage)
Para apostas pequenas relativas ao pool, a fórmula é direta:
| Campo | Fórmula | Exemplo (R$10, odd 1.35) |
|---|---|---|
payout | amount × odd | 10 × 1.35 = R$13.50 |
profit | payout − amount | 13.50 − 10 = R$3.50 |
Cálculo com slippage (CPMM)
Para apostas maiores, o slippage reduz a odd efetiva. Quanto maior a aposta relativa ao pool, pior a odd. Use esta fórmula para calcular o payout exato:
| Passo | Fórmula | Descrição |
|---|---|---|
| 1 | K = yes_pool × no_pool | Constante do pool (produto invariável) |
| 2 | newPool = pool_apostado + amount | Pool do lado que recebe a aposta |
| 3 | unitsOut = pool_oposto − (K / newPool) | Unidades que saem do lado oposto |
| 4 | payout = amount + (unitsOut × 0.95) | 5% de margem da casa sobre o lucro |
| 5 | odd = min(payout / amount, odd_exibida) | Cap: nunca paga mais que a odd na tela |
EXEMPLO PRÁTICO
Mercado: "Brasil ganha a Copa?"
Pool inicial: yes_pool=37.50, no_pool=12.50
Odds: yes=1.28, no=4.12
─── Aposta R$5 no YES ───
K = 37.50 × 12.50 = 468.75
newYesPool = 37.50 + 5 = 42.50
newNoPool = 468.75 / 42.50 = 11.03
unitsOut = 12.50 − 11.03 = 1.47
houseCut = 1.47 × 0.05 = 0.07
payout = 5 + 1.47 − 0.07 = 6.40
odd = 6.40 / 5 = 1.28x
→ Aposta R$5, retorno R$6.40, lucro R$1.40
─── Aposta R$25 no YES (slippage alto) ───
newYesPool = 37.50 + 25 = 62.50
newNoPool = 468.75 / 62.50 = 7.50
unitsOut = 12.50 − 7.50 = 5.00
houseCut = 5.00 × 0.05 = 0.25
payout = 25 + 5.00 − 0.25 = 29.75
odd = 29.75 / 25 = 1.19x
→ Odd caiu de 1.28x pra 1.19x (slippage)
JAVASCRIPT
function calcPayout(market, type, amount) {
const yp = market.odds.yes.pool;
const np = market.odds.no.pool;
const K = yp * np;
const isYes = type === 'yes';
const betPool = isYes ? yp : np;
const other = isYes ? np : yp;
const maxOdd = isYes
? market.odds.yes.odd
: market.odds.no.odd;
const newPool = betPool + amount;
const unitsOut = other - (K / newPool);
const houseCut = unitsOut * 0.05;
let payout = amount + unitsOut - houseCut;
let odd = payout / amount;
// Cap pela odd exibida
if (odd > maxOdd) {
odd = maxOdd;
payout = amount * maxOdd;
}
return {
odd: +odd.toFixed(2),
payout: +payout.toFixed(2),
profit: +(payout - amount).toFixed(2),
};
}
// Uso: dados do feed /api/v1/get-markets
const r = calcPayout(market, 'yes', 10);
console.log(r);
// { odd: 1.25, payout: 12.50, profit: 2.50 }
PHP LARAVEL
function calcPayout(
float $yesPool,
float $noPool,
float $yesOdd,
float $noOdd,
string $type,
float $amount
): array {
$K = $yesPool * $noPool;
if ($type === 'yes') {
$newPool = $yesPool + $amount;
$other = $noPool;
$maxOdd = $yesOdd;
} else {
$newPool = $noPool + $amount;
$other = $yesPool;
$maxOdd = $noOdd;
}
$unitsOut = $other - ($K / $newPool);
$houseCut = $unitsOut * 0.05;
$payout = $amount + $unitsOut - $houseCut;
$odd = $payout / $amount;
if ($odd > $maxOdd) {
$odd = $maxOdd;
$payout = $amount * $maxOdd;
}
return [
'odd' => round($odd, 2),
'payout' => round($payout, 2),
'profit' => round($payout - $amount, 2),
];
}
// Uso com dados do feed
$r = calcPayout(
37.50, 12.50, // pools
1.28, 4.12, // odds
'yes', 10 // aposta
);
Erros
| HTTP | Significado | Quando |
|---|---|---|
200 | Sucesso | Request processada com sucesso |
401 | Não autorizado | Chaves ausentes ou inválidas |
403 | Proibido | Agente desativado |
404 | Não encontrado | Mercado não encontrado (transaction/simulate) |
409 | Conflito | Odd sofreu alteração — atualize via WebSocket e tente novamente |
422 | Não processável | Mercado fechado ou dados inválidos |
Erros comuns
| Mensagem | Causa | Solução |
|---|---|---|
Credenciais não fornecidas. | Headers ausentes | Envie X-Public-Key e X-Secret-Key |
Credenciais inválidas. | Chaves incorretas | Verifique suas chaves |
Agente desativado. | Agente inativo | Entre em contato com o suporte |
Mercado não encontrado. | ID inválido | Verifique o market_id no feed |
Mercado fechado para apostas. | Mercado closed/inativo | Só é possível apostar em mercados ativos |
401 UNAUTHORIZED
{
"success": false,
"error": "Credenciais inválidas."
}
403 FORBIDDEN
{
"success": false,
"error": "Agente desativado. Entre em contato com o suporte."
}