Apostar no Jogo do Bicho pela API
Guia para quem vai integrar uma aplicação própria à plataforma, sem usar o aplicativo.
A integração aposta como um apostador comum: cria um usuário, coloca saldo, e envia bilhetes. Não há papel especial nem rota paralela — o que o aplicativo faz, você faz pelos mesmos endereços.
Antes de começar: três coisas que confundem
1. O endereço identifica a loja. Toda requisição vai para o domínio da loja, e é o cabeçalho Host que diz ao sistema de qual loja se trata. Autenticar num domínio e apostar em outro não funciona, e a mensagem de erro não vai deixar isso óbvio.
https://sualoja.com.br/api/v1/...2. Colocar saldo não é imediato. A rota de crédito devolve um QR Code Pix. O saldo só entra quando o banco confirma o pagamento, o que pode levar segundos. Consulte o saldo antes de apostar — não assuma que creditou.
3. A descarga é automática. Quando uma aposta ultrapassa o limite de exposição da loja, o sistema a repassa ao parceiro sozinho. Não existe parâmetro para pedir isso. Você reconhece pelo estado do bilhete depois: forwarded.
1. Autenticar
Todas as rotas, exceto o cadastro, exigem um token.
curl -X POST https://sualoja.com.br/auth/login \
-H 'Content-Type: application/json' \
-d '{
"username": "11144477735",
"password": "suasenha"
}'O campo username aceita CPF, e-mail ou nome de usuário — o sistema reconhece pelo formato: com @ trata como e-mail, com 11 dígitos como CPF, o resto como nome de usuário.
Resposta:
{
"access_token": "eyJhbGciOiJSUzI1NiIs…",
"expires_in": 300,
"refresh_token": "eyJhbGciOiJIUzI1NiIs…",
"refresh_expires_in": 1800,
"token_type": "Bearer"
}O access_token vale 300 segundos; o refresh_token, 1800.
Use o access_token em todas as chamadas seguintes:
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...Dois tokens, dois papéis
A integração usa dois tokens diferentes, e trocá-los é o erro mais comum na primeira tentativa — a resposta é um 401 seco, sem explicar que o papel está errado.
| Token | De quem | Usado em |
|---|---|---|
**$TOKEN_ADMIN** | conta admin, manager ou employee da loja | só a seção 2 (criar apostador) |
**$TOKEN_PLAYER** | do próprio apostador | seções 3, 4 e 5 (crédito, aposta, consulta) |
Nos exemplos deste documento, cada curl mostra qual dos dois ele espera, escrito como $TOKEN_ADMIN ou $TOKEN_PLAYER. **Onde você vir isso, coloque o access_token da conta correspondente**, obtido na chamada de login acima.
Cada token sai de um login diferente:
# token de administrador — só para criar apostadores (seção 2)
curl -X POST https://sualoja.com.br/auth/login \
-H 'Content-Type: application/json' \
-d '{"username": "usuario.admin", "password": "senha"}'
# token do apostador — para crédito, aposta e consulta (seções 3, 4 e 5)
curl -X POST https://sualoja.com.br/auth/login \
-H 'Content-Type: application/json' \
-d '{"username": "11144477735", "password": "senha"}'Cada resposta traz o seu access_token. Guarde os dois: eles valem por poucos minutos e são usados em chamadas diferentes.
Renovar o token
O token expira. Quando isso acontecer, as chamadas passam a responder 401 — renove em vez de pedir a senha de novo:
curl -X POST https://sualoja.com.br/auth/refresh_token \
-H 'Content-Type: application/json' \
-d '{"refresh_token": "eyJhbGciOiJIUzI1NiIs..."}'{
"access_token": "eyJhbGciOiJSUzI1NiIs…",
"expires_in": 300,
"refresh_token": "eyJhbGciOiJIUzI1NiIs…",
"token_type": "Bearer"
}Devolve um par novo. O refresh_token antigo deixa de valer — guarde o novo.
2. Criar um apostador (opcional)
Só se a sua aplicação for cadastrar pessoas. Se o apostador já existe, pule para a seção 3.
Esta rota não é a mesma que o site da loja usa. O cadastro público (POST /users/player) exige reCAPTCHA, que pressupõe um navegador e um usuário humano — uma integração servidor a servidor não consegue atendê-lo. O caminho para integração é a rota autenticada abaixo, a mesma que o promotor usa para cadastrar clientes.
curl -X POST https://sualoja.com.br/api/v1/users \
-H "Authorization: Bearer $TOKEN_ADMIN" \
-H 'Content-Type: application/json' \
-d '{
"cpf": "11144477735",
"password": "umaSenhaForte",
"username": "NomeDoUsuario",
"password_confirmation": "umaSenhaForte",
"role": "player",
"phone": "(11)99999-0000",
"profile": {
"birthdate": "01/01/1990"
}
}'Resposta:
{
"id": "6ac8f2b1b0b17b30838ffc45",
"uuid": "a7d4e912-3f6b-4c85-b218-9e0a5d7f4c61",
"cpf": "11144477735",
"email": null,
"phone": "(85)99999-0000",
"roles": [
"player"
],
"status": "actived",
"profile": {
"full_name": "FULANO DE TAL",
"birthdate": "15/03/1988"
},
"created_at": "2026-10-09T10:35:00.000-03:00"
}O uuid é o identificador do apostador para login; o id é o do registro na loja.
O token precisa ser de um usuário com papel **admin, manager ou employee** — não serve o token do apostador. Autentique essa conta pela seção 1 e use o access_token dela.
Os campos
| Campo | Obrigatório | Formato |
|---|---|---|
cpf | sim | 11 dígitos, só números |
password + password_confirmation | sim | mínimo 6 caracteres |
role | sim | player |
phone | sim | (XX)XXXXX-XXXX — com parênteses e hífen |
profile.birthdate | quase sempre | dd/mm/aaaa — ver abaixo |
email | depende da loja | — |
profile.zipcode (endereço) | depende da loja | — |
employee_id (código promocional) | depende da loja | — |
O phone é exigido sempre, em qualquer loja, e o formato é validado: 85999990000 é recusado, (85)99999-0000 passa.
O username não se aplica a apostador. Se você enviar, o sistema o descarta e usa o CPF como identificador de login — é por isso que o apostador autentica pelo CPF, nunca por um nome escolhido.
Os quatro campos que variam por loja
Cada loja marca estes campos como escondido, visível ou obrigatório. Só o último valor torna o campo exigido no cadastro:
| Campo | Padrão do sistema | Na prática |
|---|---|---|
profile.birthdate | obrigatório | envie sempre — a maioria das lojas exige |
email | escondido | envie se a loja pedir |
profile.zipcode | escondido | envie se a loja pedir |
employee_id | escondido | envie se a loja pedir |
A data de nascimento é o caso que pega. É o único dos quatro que nasce obrigatório, então uma loja que nunca mexeu nessa configuração vai recusar o cadastro sem ela:
{"validation_error": "{:birthdate=>\"Data de nascimento é Obrigatório\"}"}Curiosamente, o valor que você envia não é o que fica salvo: a consulta de CPF devolve a data de nascimento oficial e ela substitui a sua. A exigência é de presença, não de exatidão — mas a validação de maioridade usa a data da consulta, então não adianta inventar uma para contornar.
Antes de fixar o conjunto de campos no seu código, confirme as quatro configurações com a operação da loja.
Dois comportamentos importantes
O CPF é consultado numa base externa. CPF inexistente ou em situação irregular faz o cadastro falhar. CPFs de teste inventados não passam.
O nome e a data de nascimento vêm de lá, não do que você enviar. Se você mandar full_name: "Fulano" e a consulta devolver outro nome, vale o da consulta. Não é erro, é o comportamento esperado.
Erros que você vai encontrar
| Resposta | Causa |
|---|---|
422 com phone | formato errado — use (XX)XXXXX-XXXX |
422 com birthdate | a loja exige data de nascimento e ela não foi enviada — é o padrão do sistema |
422 com cpf | CPF duplicado nesta loja, ou irregular na base externa |
401 | o token não é de admin, manager ou employee |
500 | indisponibilidade da consulta de CPF — tente de novo, não é erro do seu payload |
3. Colocar saldo (opcional)
Gera um QR Code Pix para o apostador pagar.
curl -X POST https://sualoja.com.br/api/v1/invoices/credit \
-H "Authorization: Bearer $TOKEN_PLAYER" \
-H 'Content-Type: application/json' \
-d '{"amount": 50.00}'Resposta:
{
"id": "6ac8f1a4b0b17b30838ffc12",
"kind": "Credit",
"type": "PIX",
"description": "Depósito via Pix",
"customer_cpf": "11144477735",
"customer_name": "Fulano de Tal",
"transaction_id": "e3f21a90-7c4b-4d18-9a52-0b7e6d1f8c33",
"status": "pending",
"pay_day": null,
"due_date": "2026-10-10T10:30:00.000-03:00",
"amount_paid": "0.00",
"amount": "50.00",
"qrcode": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA…",
"pix_copy_paste": "00020126580014BR.GOV.BCB.PIX0136e3f21a90-7c4b-4d18-9a52-0b7e6d1f8c335204000053039865802BR…",
"manually": false,
"created_at": "2026-10-09T10:30:00.000-03:00"
}| Campo | O que fazer com ele |
|---|---|
qrcode | imagem em base64 — exiba para o apostador escanear |
pix_copy_paste | o código Pix em texto — ofereça o botão de copiar |
transaction_id | identificador do pagamento no gateway |
status | começa em pending |
due_date | depois disso o QR Code expira |
A resposta traz o código copia-e-cola e a imagem do QR Code.
O saldo não entra na hora. O pagamento é confirmado pelo banco por fora, depois. Para saber que caiu, consulte o saldo (seção 5) até ele mudar — ou aguarde alguns segundos antes de apostar.
4. Apostar
É o coração da integração. Um bilhete tem duas partes: em quais sorteios ele vale, e quais são os palpites.
curl -X POST https://sualoja.com.br/api/v1/tickets \
-H "Authorization: Bearer $TOKEN_PLAYER" \
-H 'Content-Type: application/json' \
-d '{
"draws": [
{ "draw_name": "pt_rio", "date": "06/10/2026", "time": "14:20" }
],
"bets": [
{
"game": "milhar",
"number": "1234",
"prize": "1",
"amount": 2.00,
"for_all": true
}
]
}'draws — onde a aposta vale
Cada item é um sorteio. Mesmo bilhete em três sorteios: três itens.
| Campo | Formato | Exemplo |
|---|---|---|
draw_name | nome técnico da extração | "pt_rio" |
date | dd/mm/aaaa | "06/10/2026" |
time | hora da extração | "14:20" |
Descobrir as extrações
Primeiro os estados, que é rota pública:
curl https://sualoja.com.br/statesResposta:
["Bahia", "Ceará", "Brasilia (DF)", "Goiás", "Minas Gerais", "Paraíba",
"Pernambuco", "Paraná", "Rio de Janeiro", ...]Depois as extrações do estado — o nome vai exatamente como veio acima, codificado na URL:
curl 'https://sualoja.com.br/api/v1/draws/states/Rio%20de%20Janeiro' \
-H "Authorization: Bearer $TOKEN_PLAYER"Resposta:
[
{
"name": "pt_rio",
"canonical_name": "PT-Rio",
"state": "Rio de Janeiro",
"Segunda": ["09:20", "11:20", "14:20", "16:20", "18:20", "21:20"],
"Terça": ["09:20", "11:20", "14:20", "16:20", "18:20", "21:20"]
}
]Os horários vêm por dia da semana. Para apostar em 06/10/2026, que é uma segunda, use um dos horários de Segunda.
A resposta
{
"success": [
{
"id": "6ac8e712b0b17b30838ffb90",
"published_at": "2026-10-09T10:07:30.745-03:00",
"draw_name": "pt_rio",
"draw_time": "2026-10-09T11:20:00.000-03:00",
"amount_bet": "2.00",
"amount_potential_cash_return": "12000.00",
"paid_with_cash": "2.00",
"paid_with_reward": "0.00",
"bets": [
{
"id": "6ac8e712b0b17b30838ffb92",
"game": "milhar",
"prize": "1",
"prizes": [
1
],
"number": "1234",
"numbers": [
"1234"
],
"quote": {
"milhar": 6000.0
},
"has_milhar_bonus": false,
"potential_cash_return": 12000.0,
"amount": "2.00"
}
],
"state": "published",
"comission_at": null,
"comission_amount": 0.0,
"comission_player_amount": 0.0
}
],
"errors": [],
"user": {
"username": "playerbicho",
"cpf": "111.444.777-35",
"email": "playerbicho@bicho.local",
"roles": [
"player"
],
"status": "actived",
"phone": "(85)99999-0000",
"id": "6a8708adaf9f93dd050159d7",
"uuid": "fc3af4a6-63b9-482f-a866-405b50bdb898",
"profile": {
"full_name": "Player Local",
"birthdate": "01/01/1990",
"amount_credit": 0.0,
"amount_withdraw": 0.0,
"amount_awarded": 0.0,
"quote_id": "6a87068735340824d42428bf"
},
"balance": {
"real_balance": "946.0",
"blocked_balance": "0.0",
"manual_blocked_balance": "0.0",
"bonus_balance": "0.0",
"updated_at": "2026-10-09T10:07:30.751-03:00"
}
}
}A resposta tem três partes, sempre as três, mesmo quando uma vem vazia:
| Parte | O que traz |
|---|---|
success | um objeto por sorteio criado — três sorteios no pedido, três bilhetes aqui |
errors | um objeto por sorteio recusado: a message com o motivo, mais os campos do sorteio que falhou (draw_name, date, time), para você saber qual deles foi |
user | o cadastro do apostador, com o saldo já atualizado |
**Dentro de cada bilhete em success:**
| Campo | O que é |
|---|---|
id | o identificador do bilhete — guarde, é com ele que você consulta na seção 5 |
state | situação do bilhete. Começa em published |
draw_name / draw_time | o sorteio em que este bilhete vale |
amount_bet | quanto foi debitado |
amount_potential_cash_return | quanto o apostador recebe se ganhar |
bets[].quote | a cotação da loja aplicada — aqui, milhar paga 6000× |
bets[].numbers / prizes | os palpites e os prêmios, já convertidos em lista |
paid_with_cash / paid_with_reward | quanto saiu do saldo real e quanto do saldo de bônus |
O status HTTP não indica sucesso
Esta é a parte mais importante da integração. Um bilhete recusado também responde **200 OK** — o que muda é o conteúdo:
{
"success": [],
"errors": [
{
"message": "Extração indisponível no momento.",
"draw_name": "pt_rio",
"date": "09/10/2026",
"time": "03:00"
}
],
"user": {
"username": "fulano",
"balance": "944.00"
}
}Repare: success veio vazio e o motivo está em errors. O bilhete não foi criado e nada foi debitado.
Sempre verifique o conteúdo, nunca o código HTTP:
successcom itens eerrorsvazio → bilhete criadosuccessvazio eerrorscom itens → nada foi criado- os dois preenchidos → criação parcial: alguns sorteios entraram, outros não
O terceiro caso acontece quando você manda vários sorteios num bilhete só e um deles está indisponível. Trate-o: ignorá-lo faz você cobrar do cliente uma aposta que não existe.
bets — os palpites
| Campo | O que é |
|---|---|
game | a modalidade (tabela abaixo) |
number | o palpite. Vários números vão separados por espaço |
prize | em quais prêmios vale. Vários vão separados por vírgula: "1,2,3,4,5" |
amount | valor da aposta, em reais |
for_all | true = o valor vale para o conjunto · false = multiplica pelo número de palpites |
for_all muda quanto você paga
É o detalhe que mais gera dúvida.
number: "1234 5678" amount: 2.00 for_all: true → R$ 2,00 no total
number: "1234 5678" amount: 2.00 for_all: false → R$ 4,00 (2 palpites × R$ 2,00)As modalidades
**number sempre usa espaço entre os palpites. prize sempre usa vírgula** entre os prêmios.
game | Nome | Palpites | Prêmios aceitos | Cotação |
|---|---|---|---|---|
grupo | Grupo | 1 | 5, 10 | grupo |
grupo_meio | Grupo Meio | 1 | 5, 10 | grupo |
grupo_esquerda | Grupo Esquerda | 1 | 5, 10 | grupo |
grupo_combinado | Grupo Combinado | 2 | grupo_combinado | |
milhar | Milhar | 1 | 5, 10 | milhar |
milhar_invertida | Milhar Invertida | 7 | 5, 10 | milhar |
centena | Centena | 1 | 5, 10 | centena |
centena_esquerda | Centena Esquerda | 1 | 5, 10 | centena |
centena_invertida | Centena Invertida | 7 | 5, 10 | centena |
centena_invertida_esquerda | Centena Invertida Esquerda | 1 | 5, 10 | centena |
milhar_centena | Milhar com Centena | 1 | 5, 10 | milhar + centena |
milhar_centena_invertida | Milhar com Centena Invertida | 7 | 5, 10 | milhar + centena |
dezena | Dezena | 1 | 5, 10 | dezena |
dezena_esquerda | Dezena Esquerda | 1 | 5, 10 | dezena |
dezena_meio | Dezena Meio | 1 | 5, 10 | dezena |
unidade | Unidade | 1 | 5, 10 | unidade |
grupo_dupla | Dupla de Grupo | 2 | 5 | grupo_dupla_5 |
grupo_dupla_esquerda | Dupla de Grupo Esquerda | 2 | 5 | grupo_dupla_5 |
grupo_dupla_meio | Dupla de Grupo Meio | 2 | 5 | grupo_dupla_5 |
grupo_terno | Terno de Grupo | 3 | ||
grupo_terno_esquerda | Terno de Grupo Esquerda | 3 | ||
grupo_terno_meio | Terno de Grupo Meio | 3 | ||
grupo_quadra | Quadra de Grupo | 4 | 5 | grupo_quadra_5 |
grupo_quadra_meio | Quadra de Grupo Meio | 4 | 5 | grupo_quadra_5 |
grupo_quadra_esquerda | Quadra de Grupo Esquerda | 4 | 5 | grupo_quadra_5 |
grupo_quina | Quina de Grupo | 5 | 5 | grupo_quina_5 |
grupo_quina_esquerda | Quina de Grupo Esquerda | 5 | 5 | grupo_quina_5 |
grupo_quina_meio | Quina de Grupo Meio | 5 | 5 | grupo_quina_5 |
dezena_duque | Duque de Dezena | 1 | 5 | dezena_duque_5 |
dezena_duque_esquerda | Duque de Dezena Esquerda | 1 | 5 | dezena_duque_5 |
dezena_duque_meio | Duque de Dezena Meio | 1 | 5 | dezena_duque_5 |
dezena_terno | Terno de Dezena | 1 | 5 | dezena_terno_5 |
dezena_terno_esquerda | Terno de Dezena Esquerda | 1 | 5 | dezena_terno_5 |
dezena_terno_meio | Terno de Dezena Meio | 1 | 5 | dezena_terno_5 |
passe_vai | Passe Vai | 2 | ||
passe_vai_vem | Passe Vai e Vem | 2 | ||
palpitao | Palpitão | 20 | 5 | palpitao |
grupo_sena | Sena de Grupo | 10 | 6 | grupo_sena |
grupo_sena_esquerda | Sena de Grupo Esquerda | 10 | 6 | grupo_sena |
grupo_sena_meio | Sena de Grupo Meio | 10 | 6 | grupo_sena |
Exemplos por tipo
Número direto — milhar, centena, dezena, unidade
{ "game": "milhar", "number": "1234", "prize": "1", "amount": 2.00, "for_all": true }
{ "game": "centena", "number": "234", "prize": "1,2,3,4,5", "amount": 1.00, "for_all": true }
{ "game": "dezena", "number": "34 56 78", "prize": "1,2,3,4,5", "amount": 1.00, "for_all": false }Grupo — o palpite é o número do grupo, de 1 a 25
{ "game": "grupo", "number": "7", "prize": "1,2,3,4,5", "amount": 5.00, "for_all": true }
{ "game": "grupo_dupla", "number": "7 12", "prize": "1,2,3,4,5", "amount": 5.00, "for_all": true }
{ "game": "grupo_terno", "number": "7 12 3","prize": "1,2,3,4,5", "amount": 5.00, "for_all": true }
{ "game": "grupo_quina", "number": "1 7 12 19 23", "prize": "1,2,3,4,5", "amount": 5.00, "for_all": true }Grupo 7 é o Carneiro, 12 o Elefante. A lista dos 25 vem de:
curl https://sualoja.com.br/api/v1/games -H "Authorization: Bearer $TOKEN_PLAYER"Resposta:
[
{
"name": "grupo",
"canonical_name": "GRUPO",
"initials": "G",
"options": {
"maxSelection": 10,
"Avestruz": "01 02 03 04",
"Águia": "05 06 07 08",
"Burro": "09 10 11 12",
"Borboleta": "13 14 15 16",
"Cachorro": "17 18 19 20",
"Cabra": "21 22 23 24",
"Carneiro": "25 26 27 28",
"Camelo": "29 30 31 32",
"Cobra": "33 34 35 36",
"Coelho": "37 38 39 40",
"Cavalo": "41 42 43 44",
"Elefante": "45 46 47 48",
"Galo": "49 50 51 52",
"Gato": "53 54 55 56",
"Jacaré": "57 58 59 60",
"Leão": "61 62 63 64",
"Macaco": "65 66 67 68",
"Porco": "69 70 71 72",
"Pavão": "73 74 75 76",
"Peru": "77 78 79 80",
"Touro": "81 82 83 84",
"Tigre": "85 86 87 88",
"Urso": "89 90 91 92",
"Veado": "93 94 95 96",
"Vaca": "97 98 99 00"
},
"status": "actived"
},
{
"name": "milhar",
"canonical_name": "MILHAR SECA",
"initials": "MS",
"options": {
"mask": "9999"
},
"status": "actived"
},
{
"name": "milhar_invertida",
"canonical_name": "MILHAR INVERTIDA",
"initials": "MI",
"options": {
"mask": "9999"
},
"status": "actived"
}
]A lista completa traz as 17 modalidades que a loja tem ativas.
A mesma resposta traz, para cada modalidade, quantos palpites ela aceita e quais prêmios são válidos — é a versão viva da tabela acima.
Duque e terno de dezena — duas ou três dezenas no mesmo palpite
{ "game": "dezena_duque", "number": "34 56", "prize": "1,2,3,4,5", "amount": 3.00, "for_all": true }
{ "game": "dezena_terno", "number": "34 56 78", "prize": "1,2,3,4,5", "amount": 3.00, "for_all": true }Passe — dois grupos, um saindo no primeiro prêmio e outro em prêmio seguinte
{ "game": "passe_vai", "number": "7 12", "prize": "1,2", "amount": 4.00, "for_all": true }
{ "game": "passe_vai_vem", "number": "7 12", "prize": "1,2", "amount": 4.00, "for_all": true }Invertidas — um palpite, todas as combinações dos dígitos
{ "game": "milhar_invertida", "number": "1234", "prize": "1", "amount": 2.00, "for_all": true }
{ "game": "centena_invertida", "number": "234", "prize": "1", "amount": 2.00, "for_all": true }1234 invertida cobre 1243, 1324, 1342 e assim por diante. O custo acompanha: é como apostar em cada combinação. Com for_all: true o valor informado é o total.
Milhar com centena — uma aposta que vale nas duas modalidades
{ "game": "milhar_centena", "number": "1234", "prize": "1", "amount": 2.00, "for_all": true }Paga como milhar se acertar os quatro dígitos, e como centena se acertar os três últimos. Por isso usa duas cotações.
O que a aposta devolve
{
"success": [
{
"id": "6ac40709eddf17f28f62a036",
"published_at": "2026-10-05T17:22:33.694-03:00",
"draw_name": "pt_rio",
"draw_time": "2026-10-06T14:20:00.000-03:00",
"amount_bet": "2.00",
"amount_potential_cash_return": "12000.00",
"paid_with_cash": "2.00",
"paid_with_reward": "0.00",
"bets": [ ... ]
}
]
}Um bilhete por extração. Se você mandou três extrações em draws, success vem com três bilhetes, cada um com seu id. Guarde todos — é por eles que você consulta o resultado.
amount_potential_cash_return é quanto a aposta paga se acertar. paid_with_reward é a parte paga com saldo de bônus, quando houver.
Quando a aposta é recusada
A resposta traz o motivo em errors. Os mais comuns:
| Situação | O que fazer |
|---|---|
| Saldo insuficiente | conferir o saldo antes de enviar |
| Extração já encerrada | cada loja bloqueia alguns minutos antes do sorteio |
| Valor abaixo do mínimo | o mínimo é configurado por loja |
| Prêmio acima do máximo | a loja limita o prêmio por aposta e por extração |
Formato de number inválido | conferir a tabela de modalidades |
5. Consultar bilhete, saldo e extrato
O bilhete
curl https://sualoja.com.br/api/v1/tickets/{id} -H "Authorization: Bearer $TOKEN_PLAYER"Resposta:
{
"id": "6ac8ea92b0b17b30838ffb93",
"published_at": "2026-10-09T10:22:26.740-03:00",
"draw_name": "pt_rio",
"draw_time": "2026-10-09T14:20:00.000-03:00",
"amount_bet": "2.00",
"amount_potential_cash_return": "12000.00",
"paid_with_cash": "2.00",
"paid_with_reward": "0.00",
"bets": [
{
"id": "6ac8ea92b0b17b30838ffb95",
"game": "milhar",
"prize": "1",
"prizes": [
1
],
"number": "1234",
"numbers": [
"1234"
],
"quote": {
"milhar": 6000.0
},
"has_milhar_bonus": false,
"potential_cash_return": 12000.0,
"amount": "2.00"
}
],
"user": {
"username": "playerbicho",
"link_code": "playerbicho",
"link": "/register?invited_from=playerbicho"
},
"tag": null,
"state": "published"
}O campo state diz onde ele está:
| Status | Significa |
|---|---|
draft | criado, ainda não confirmado |
published | valendo — aposta registrada, aguardando o sorteio |
archived | sorteio saiu e o bilhete foi conferido |
refunded | estornado, valor devolvido |
forwarded | repassado ao parceiro — é a descarga |
canceled | cancelado |
Listar os bilhetes
curl 'https://sualoja.com.br/api/v1/tickets?page=1' -H "Authorization: Bearer $TOKEN_PLAYER"Resposta:
{
"tickets": [
{
"id": "6ac8ea92b0b17b30838ffb93",
"draw_name": "pt_rio",
"draw_time": "2026-10-09T14:20:00.000-03:00",
"amount_bet": "2.00",
"state": "published"
},
"…"
],
"count": 4
}Pagina de 20 em 20. Use page=2, page=3 para avançar.
Saldo
curl https://sualoja.com.br/api/v1/users/{user_id}/balance -H "Authorization: Bearer $TOKEN_PLAYER"Resposta:
{
"user_id": "6a8708adaf9f93dd050159d7",
"real_balance": "944.0",
"blocked_balance": "0.0",
"manual_blocked_balance": "0.0",
"bonus_balance": "0.0"
}O saldo vem separado: real, bônus e bloqueado. Para apostar vale o real disponível — o bloqueado está comprometido com apostas ainda em aberto.
Extrato
curl https://sualoja.com.br/api/v1/users/{user_id}/transactions -H "Authorization: Bearer $TOKEN_PLAYER"Resposta:
{
"transactions": [
{
"id": "6ac8ea923365fb352b15396c",
"user_id": "6a8708adaf9f93dd050159d7",
"user_balance_id": "6a8708adce1aa42f2b7bcc98",
"source": "jb",
"operation": "debit",
"idempotency_key": "ticket::6a8708adaf9f93dd050159d7::6ac8ea92b0b17b30838ffb93::paid",
"reference_id": "6ac8ea92b0b17b30838ffb93",
"reference_type": "ticket",
"description": "Bilhete 6AC8-FB93 pago!",
"amount": "2.0",
"real_balance": "2.0",
"real_balance_before": "946.0",
"real_balance_after": "944.0",
"bonus_balance": "0.0",
"bonus_balance_before": "0.0",
"bonus_balance_after": "0.0",
"created_at": "2026-10-09T13:22:26.755Z",
"updated_at": "2026-10-09T13:22:26.755Z"
},
{
"id": "6ac8e7123365fb352b15396b",
"user_id": "6a8708adaf9f93dd050159d7",
"user_balance_id": "6a8708adce1aa42f2b7bcc98",
"source": "jb",
"operation": "debit",
"idempotency_key": "ticket::6a8708adaf9f93dd050159d7::6ac8e712b0b17b30838ffb90::paid",
"reference_id": "6ac8e712b0b17b30838ffb90",
"reference_type": "ticket",
"description": "Bilhete 6AC8-FB90 pago!",
"amount": "2.0",
"real_balance": "2.0",
"real_balance_before": "948.0",
"real_balance_after": "946.0",
"bonus_balance": "0.0",
"bonus_balance_before": "0.0",
"bonus_balance_after": "0.0",
"created_at": "2026-10-09T13:07:30.785Z",
"updated_at": "2026-10-09T13:07:30.785Z"
}
],
"count": 10,
"balance": {
"id": "6a8708adce1aa42f2b7bcc98",
"user_id": "6a8708adaf9f93dd050159d7",
"real_balance": "944.0",
"blocked_balance": "0.0",
"manual_blocked_balance": "0.0",
"bonus_balance": "0.0",
"created_at": "2026-08-20T11:01:17.951-03:00",
"updated_at": "2026-10-09T10:22:26.746-03:00"
}
}Cada lançamento traz o saldo antes e depois, o que permite conferir sem recalcular.
O fluxo completo
1. POST /auth/login → token
2. POST /api/v1/users → cria o apostador (token de admin)
3. POST /api/v1/invoices/credit → QR Code Pix
GET /api/v1/users/{id}/balance → confirma que o saldo entrou
4. POST /api/v1/tickets → aposta
5. GET /api/v1/tickets/{id} → acompanha o resultadoDúvidas frequentes
Posso apostar em várias extrações de uma vez? Sim — um item por extração em draws. O valor de cada aposta é cobrado por extração.
Posso misturar modalidades no mesmo bilhete? Sim. bets aceita quantos itens quiser, com modalidades diferentes.
Como sei se ganhei? O bilhete passa a archived depois do sorteio, e o valor do prêmio aparece nele. O crédito entra no saldo automaticamente.
O que acontece se o sorteio for cancelado? O bilhete vai para refunded e o valor volta ao saldo.
Preciso tratar a descarga? Não. É automática, e o bilhete continua do apostador. O estado forwarded é informativo.