Jumbo. INTEGRATION API v1

Jumbo · jogo de crash

API de Integração v1

As duas direções

IntegraçãoSentidoO que carrega
Catálogo e lançamentooperador → provedorquais jogos existem, e abrir uma partida para um jogador
Carteiraprovedor → operadorresolver a sessão, saldo, débito, crédito, estorno

As oito que quebram integração

Todas contrariam uma convenção comum, e é por isso que estão juntas e antes das rotas: são os pontos em que implementar o que costuma ser produz um cliente que compila, passa no teste feliz e erra em produção.

o palpiteo contrato
Recusa vem em 4xxErro de negócio vem em HTTP 200, com status:"error" e error_code. Ramifique em status, nunca no status HTTP. Um cliente que teste response.ok lê uma recusa como sucesso.
Um código de erro desconhecido é finalA regra padrão é retentar, até 20 vezes. São finais só sete: INSUFFICIENT_FUNDS, TOKEN_EXPIRED, TOKEN_INVALID, PLAYER_NOT_FOUND, BET_NOT_FOUND, CURRENCY_MISMATCH e PLAYER_BLOCKED. Inventar um nome para recusar em definitivo produz 20 tentativas idênticas contra a sua carteira.
Assinar o JSONAssine os bytes exatos do corpo. Desserializar e serializar de novo antes do HMAC muda espaçamento e ordem de chaves, e a assinatura deixa de bater com um conteúdo idêntico.
<code>request_id</code> é a chave de idempotênciaA chave é o transaction_id. O request_id nomeia a tentativa e muda a cada uma, junto com o timestamp. Deduplicar por request_id não deduplica nada; comparar o corpo inteiro rejeita toda retentativa.
<code>/balance</code> sempre traz <code>player_id</code>A primeira chamada de cada sessão vai só com o token: é ela que descobre o jogador. Exigir player_id ali recusa a entrada de todo mundo.
Valor monetário é decimalÉ inteiro, em centavos. R$ 3,56 é 356. O bundle do jogo já mandou 114.99999999999999 para uma aposta de R$ 1,15 quando o campo era decimal.
As duas direções seguem a mesma convençãoNão seguem. A regra do 200 vale para a carteira; as duas rotas do jogo respondem 4xx, porque ali não há decisão de negócio, só pedido inválido. Os dois conjuntos de error_code quase não se tocam, e a exceção importa: INTERNAL_ERROR e INVALID_SIGNATURE estão nos dois, então o código sozinho não diz de que lado veio a falha.
<code>freebet_id</code> só vem quando é brindeO campo existe sempre, valendo null na aposta comum. Ramifique em freebet_id !== null, nunca na presença da chave.

Autenticação: um esquema só, nas duas direções

X-Signature: hex(HMAC-SHA256(corpo_da_requisição, segredo))
Authorization: Bearer <chave>

Assine os bytes exatos do corpo, e confira sobre esses mesmos bytes. Decodificar o JSON e serializá-lo de novo antes do HMAC muda o espaçamento e a ordem das chaves, e a assinatura deixa de bater com um conteúdo idêntico. É o erro mais comum, nos dois lados.

O timestamp vai dentro do corpo assinado, em milissegundos, sem cabeçalho próprio. Fora de uma janela de 5 minutos o pedido é recusado, nos dois sentidos: é o que impede reenviar um pedido capturado.

Todo pedido leva operator e timestamp; os que saem daqui levam também request_id, currency e game_id. O request_id nomeia a tentativa, não o movimento: duas tentativas do mesmo transaction_id têm ids diferentes, e é assim que você acha uma delas no seu log.

O Bearer vale só na direção que sai daqui. Nas duas rotas que expomos não há chave nossa, e a assinatura autentica sozinha: por isso o jogo recusa subir em modo operador sem segredo. Sem segredo configurado, o X-Signature não é enviado e a janela não se aplica.

Gere as credenciais

Os dois valores saem do crypto.getRandomValues do seu navegador e não saem dele: esta página não faz uma única requisição. Letras e números, sem palavra de dicionário, 32 e 48 caracteres. O mínimo que o jogo aceita é 24, e ele recusa subir abaixo disso.

Chave (Bearer)
Segredo (HMAC)

O que nós expomosoperador → provedor

Duas rotas, sobre https://jumbo.aircrash.net, que é também a base das URLs de lançamento que o /v1/launch devolve. Uma instalação em outro endereço publica o dela.

POST/v1/gamestodos os jogos habilitados para o operador
→
{"operator":"casa-do-norte", "timestamp":1755680000000,
 "currency":"BRL"}
←
{
  "status": "ok",
  "operator": "casa-do-norte",
  "currencies": ["BRL", "USD"],
  "games": [
    {
      "game_id": "jumbo-crash",
      "name": "Jumbo",
      "studio": "jumbo",
      "category": "CRASH",
      "demo": false, "mobile": true, "desktop": true, "freebet": true,
      "currency": "BRL",
      "min_bet": 100, "max_bet": 50000, "max_win": 5000000
    }
  ]
}

freebet diz se o jogo aceita rodadas grátis concedidas pelo operador.

Os três limites

Só aparecem quando você envia currency, valem para aquela moeda, e são centavos inteiros.

CampoSignificado
min_betmenor aposta aceita
max_betmaior aposta aceita
max_winteto de pagamento; prêmio maior é pago no teto

currencies é o conjunto de moedas habilitadas para você. É daí que sai em que moedas você pode conceder freebet: uma concessão numa moeda que a mesa não aceita é uma promessa que nunca se cumpre.

POST/v1/launchabre uma partida para um jogador

Devolve a URL para carregar em iframe ou redirecionar.

→
{
  "operator": "casa-do-norte", "timestamp": 1755680000000,
  "game_id": "jumbo-crash",
  "player_id": "618004",
  "token": "e7c1f0a9d3b84e2f95a6",
  "currency": "BRL",
  "language": "pt",
  "demo": false, "mobile": true,
  "lobby_url": "https://seu-site/lobby",
  "deposit_url": "https://seu-site/deposito"
}
CampoObrigatórioNotas
game_idsimtem de ser o jogo desta instalação
tokensalvo em demovai em toda chamada de carteira
player_idsalvo em demoo identificador do jogador no seu sistema
currencyrecomendadoa moeda da sessão
languagenãopt, en ou es
player_namenãoapelido ou nome; é ofuscado ao exibir
themenãoo skin: JUMBO ou SUPERAVIATOR (com 5 no fim, cinco caixas); a url já sai no domínio do skin
demo, mobilenãodemo não precisa de token nem de jogador
lobby_url, deposit_urlnãoguardados na sessão; a mesa ainda não os exibe
←
{"status":"ok",
 "url":"https://jumbo.aircrash.net/?sid=v3Nq8Lm2&lang=pt&cur=BRL"}

Erros: MISSING_GAME_ID, MISSING_TOKEN, MISSING_PLAYER_ID, INVALID_TOKEN (400), GAME_NOT_FOUND (404), DEMO_NOT_AVAILABLE (400).

Moedas e idiomas

Todo dinheiro é centavo inteiro. 1500 quer dizer 15,00 na moeda da sessão. Um campo monetário em unidades da moeda, ou em ponto flutuante, é inválido.

As moedas habilitadas para um operador voltam em currencies no POST /v1/games. Não há lista fixa aqui de propósito: a lista é a configuração da sua instalação, e publicá-la em dois lugares é garantir que um dia divirjam.

Idiomas

pt, en e es. Qualquer outro valor, e a ausência do campo, caem no idioma padrão da instalação, e não em en. A divergência com a referência é deliberada: cair num idioma que a maioria da base não lê, por causa de um campo esquecido, é pior do que cair no idioma da casa.

O que o operador expõeprovedor → operador

Quatro rotas.

POST {wallet_url}/balance     token → jogador, saldo, moeda
POST {wallet_url}/bet         débito
POST {wallet_url}/win         crédito
POST {wallet_url}/rollback    estorno

Formato da resposta

←
{"status":"ok", "balance":98500, "currency":"BRL",
 "player_id":"618004", "transaction_id":"w-77120"}
←
{"status":"error", "error_code":"INSUFFICIENT_FUNDS",
 "error_message":"saldo insuficiente"}

balance é centavo inteiro, depois da operação, e é obrigatório no sucesso.

currency é a moeda da conta. Mande em toda resposta.

transaction_id na resposta é o seu número para o movimento, não o nosso. Ele existe para a conciliação: é o que se cita ao abrir um chamado sobre um movimento específico.

Campos por rota

→ /bet
{
  "operator": "casa-do-norte", "timestamp": 1755680000000,
  "request_id": "req-9f1464ae0da0664c",
  "game_id": "jumbo-crash", "currency": "BRL",
  "token": "e7c1f0a9d3b84e2f95a6", "player_id": "618004",
  "transaction_id": "b-4471902", "round_id": "88213",
  "amount": 1500
}
RotaCampos
/balanceplayer_id, token
/betplayer_id, token, amount, transaction_id, round_id
/winplayer_id, token, amount, transaction_id, bet_id, round_id, type
/rollbackplayer_id, token, amount, transaction_id, bet_id, round_id

Mais operator, timestamp, request_id e currency em todas, e game_id quando o jogo é conhecido. O ciclo de freebet acrescenta freebet_id ao /bet e ao /win; o estorno acrescenta reason, que é diagnóstico e não muda nada do lado de lá.

Códigos de erro

CódigoSignificadoRetentamos?
INSUFFICIENT_FUNDSsaldo insuficientenão
TOKEN_EXPIREDsessão expiradanão
TOKEN_INVALIDsessão que nunca existiunão
PLAYER_NOT_FOUNDjogador desconhecidonão
BET_NOT_FOUNDa aposta referenciada não existenão
CURRENCY_MISMATCHmoeda errada para esta contanão
PLAYER_BLOCKEDjogador impedido de apostarnão
INTERNAL_ERRORfalha do seu ladosim

Jumbo · crash game

Integration API v1

The two directions

IntegrationDirectionWhat it carries
Catalogue and launchoperator → providerwhich games exist, and opening a game for a player
Walletprovider → operatorresolve the session, balance, debit, credit, rollback

The eight that break integrations

Every one of them contradicts a common convention, which is why they sit together and before the routes: these are the points where implementing what usually holds yields a client that compiles, passes the happy-path test, and is wrong in production.

the guessthe contract
A refusal comes as 4xxBusiness errors come as HTTP 200, with status:"error" and an error_code. Branch on status, never on the HTTP status. A client testing response.ok reads a refusal as success.
An unknown error code is finalThe default is to retry, up to 20 times. Only seven are final: INSUFFICIENT_FUNDS, TOKEN_EXPIRED, TOKEN_INVALID, PLAYER_NOT_FOUND, BET_NOT_FOUND, CURRENCY_MISMATCH and PLAYER_BLOCKED. Inventing a name to refuse for good produces 20 identical attempts against your wallet.
Sign the JSONSign the exact bytes of the body. Deserialising and serialising again before the HMAC changes whitespace and key order, and the signature stops matching identical content.
<code>request_id</code> is the idempotency keyThe key is transaction_id. The request_id names the attempt and changes on each one, together with the timestamp. Deduplicating by request_id deduplicates nothing; comparing the whole body rejects every retry.
<code>/balance</code> always carries <code>player_id</code>The first call of each session carries only the token: it is the call that discovers the player. Requiring player_id there refuses everyone at the door.
Money is a decimalIt is an integer, in cents. R$ 3.56 is 356. The game bundle once sent 114.99999999999999 for a R$ 1.15 bet, back when the field was decimal.
Both directions follow the same conventionThey do not. The 200 rule is for the wallet; the two game routes answer 4xx, because there is no business decision there, only an invalid request. The two error_code sets barely overlap, and the exception matters: INTERNAL_ERROR and INVALID_SIGNATURE are in both, so the code alone does not say which side failed.
<code>freebet_id</code> only shows up on a freebetThe field is always there, and is null on an ordinary bet. Branch on freebet_id !== null, never on the key being present.

Authentication: one scheme, both directions

X-Signature: hex(HMAC-SHA256(request_body, secret))
Authorization: Bearer <key>

Sign the exact bytes of the body, and verify over those same bytes. Decoding the JSON and serialising it again before the HMAC changes whitespace and key order, and the signature stops matching identical content. It is the most common mistake, on both sides.

The timestamp goes inside the signed body, in milliseconds, with no header of its own. Outside a 5 minute window the request is refused, in both directions: that is what stops a captured request from being replayed.

Every request carries operator and timestamp; the ones leaving here also carry request_id, currency and game_id. The request_id names the attempt, not the movement: two attempts of the same transaction_id carry different ids, and that is how you find one of them in your log.

The Bearer applies only on the direction leaving here. On the two routes we expose there is no key of ours, and the signature authenticates on its own: that is why the game refuses to start in operator mode without a secret. With no secret configured, X-Signature is not sent and the window does not apply.

Generate the credentials

Both values come from your browser's crypto.getRandomValues and never leave it: this page makes no requests at all. Letters and digits, no dictionary words, 32 and 48 characters. The game accepts a minimum of 24 and refuses to start below that.

Key (Bearer)
Secret (HMAC)

What we exposeoperator → provider

Two routes, on https://jumbo.aircrash.net, which is also the base of the launch URLs /v1/launch returns. An installation at another address publishes its own.

POST/v1/gamesevery game enabled for the operator
→
{"operator":"casa-do-norte", "timestamp":1755680000000,
 "currency":"BRL"}
←
{
  "status": "ok",
  "operator": "casa-do-norte",
  "currencies": ["BRL", "USD"],
  "games": [
    {
      "game_id": "jumbo-crash",
      "name": "Jumbo",
      "studio": "jumbo",
      "category": "CRASH",
      "demo": false, "mobile": true, "desktop": true, "freebet": true,
      "currency": "BRL",
      "min_bet": 100, "max_bet": 50000, "max_win": 5000000
    }
  ]
}

freebet says whether the game accepts free rounds granted by the operator.

The three limits

They appear only when you send currency, hold for that currency, and are integer cents.

FieldMeaning
min_betsmallest accepted stake
max_betlargest accepted stake
max_winpayout ceiling; a bigger prize is paid at the ceiling

currencies is the set of currencies enabled for you. It is where you read which currencies you may grant freebets in: a grant in a currency the table does not accept is a promise that never comes due.

POST/v1/launchopens a game for one player

Returns the URL to load in an iframe or redirect to.

→
{
  "operator": "casa-do-norte", "timestamp": 1755680000000,
  "game_id": "jumbo-crash",
  "player_id": "618004",
  "token": "e7c1f0a9d3b84e2f95a6",
  "currency": "BRL",
  "language": "pt",
  "demo": false, "mobile": true,
  "lobby_url": "https://seu-site/lobby",
  "deposit_url": "https://seu-site/deposito"
}
FieldRequiredNotes
game_idyesmust be this installation’s game
tokenunless demosent on every wallet call
player_idunless demoyour player identifier
currencyrecommendedthe session currency
languagenopt, en or es
player_namenonickname or name; masked before display
themenothe skin: JUMBO or SUPERAVIATOR (a trailing 5 means five bet boxes); the url comes back on the skin’s domain
demo, mobilenodemo needs neither token nor player
lobby_url, deposit_urlnostored on the session; the table does not surface them yet
←
{"status":"ok",
 "url":"https://jumbo.aircrash.net/?sid=v3Nq8Lm2&lang=pt&cur=BRL"}

Errors: MISSING_GAME_ID, MISSING_TOKEN, MISSING_PLAYER_ID, INVALID_TOKEN (400), GAME_NOT_FOUND (404), DEMO_NOT_AVAILABLE (400).

Currencies and languages

All money is integer cents. 1500 means 15.00 in the session currency. A monetary field in currency units, or in floating point, is invalid.

The currencies enabled for an operator come back in currencies from POST /v1/games. There is no fixed list here on purpose: the list is your installation’s configuration, and publishing it in two places guarantees they diverge one day.

Languages

pt, en and es. Any other value, and an absent field, fall back to the installation’s default language, not to en. The divergence from the market reference is deliberate: falling back to a language most of the player base cannot read, because of a forgotten field, is worse than falling back to the house language.

What the operator exposesprovider → operator

Four routes.

POST {wallet_url}/balance     token → player, balance, currency
POST {wallet_url}/bet         debit
POST {wallet_url}/win         credit
POST {wallet_url}/rollback    refund

Response format

←
{"status":"ok", "balance":98500, "currency":"BRL",
 "player_id":"618004", "transaction_id":"w-77120"}
←
{"status":"error", "error_code":"INSUFFICIENT_FUNDS",
 "error_message":"saldo insuficiente"}

balance is integer cents, after the operation, and is required on success.

currency is the currency of the account. Send it on every response.

transaction_id in the response is your number for the movement, not ours. It exists for reconciliation: it is what you quote when opening a ticket about one specific movement.

Fields per route

→ /bet
{
  "operator": "casa-do-norte", "timestamp": 1755680000000,
  "request_id": "req-9f1464ae0da0664c",
  "game_id": "jumbo-crash", "currency": "BRL",
  "token": "e7c1f0a9d3b84e2f95a6", "player_id": "618004",
  "transaction_id": "b-4471902", "round_id": "88213",
  "amount": 1500
}
RouteFields
/balanceplayer_id, token
/betplayer_id, token, amount, transaction_id, round_id
/winplayer_id, token, amount, transaction_id, bet_id, round_id, type
/rollbackplayer_id, token, amount, transaction_id, bet_id, round_id

Plus operator, timestamp, request_id and currency on every one, and game_id when the game is known. The freebet cycle adds freebet_id to /bet and /win; the rollback adds reason, which is diagnostic and changes nothing on your side.

Error codes

CodeMeaningWe retry?
INSUFFICIENT_FUNDSnot enough balanceno
TOKEN_EXPIREDsession expiredno
TOKEN_INVALIDsession never existedno
PLAYER_NOT_FOUNDunknown playerno
BET_NOT_FOUNDthe referenced bet does not existno
CURRENCY_MISMATCHwrong currency for this accountno
PLAYER_BLOCKEDplayer barred from bettingno
INTERNAL_ERRORyour side failedyes

Jumbo · juego de crash

API de Integración v1

Las dos direcciones

IntegraciónSentidoQué transporta
Catálogo y lanzamientooperador → proveedorqué juegos existen, y abrir una partida para un jugador
Billeteraproveedor → operadorresolver la sesión, saldo, débito, crédito, reverso

Las ocho que rompen integraciones

Todas contradicen una convención común, y por eso están juntas y antes de las rutas: son los puntos en los que implementar lo que suele ser produce un cliente que compila, pasa la prueba feliz y se equivoca en producción.

la suposiciónel contrato
El rechazo llega como 4xxEl error de negocio llega como HTTP 200, con status:"error" y error_code. Ramifique en status, nunca en el estado HTTP. Un cliente que compruebe response.ok lee un rechazo como éxito.
Un código de error desconocido es finalLo predeterminado es reintentar, hasta 20 veces. Solo siete son finales: INSUFFICIENT_FUNDS, TOKEN_EXPIRED, TOKEN_INVALID, PLAYER_NOT_FOUND, BET_NOT_FOUND, CURRENCY_MISMATCH y PLAYER_BLOCKED. Inventar un nombre para rechazar en definitiva produce 20 intentos idénticos contra su cartera.
Firmar el JSONFirme los bytes exactos del cuerpo. Deserializar y volver a serializar antes del HMAC cambia los espacios y el orden de las claves, y la firma deja de coincidir con un contenido idéntico.
<code>request_id</code> es la clave de idempotenciaLa clave es transaction_id. El request_id nombra el intento y cambia en cada uno, junto con el timestamp. Deduplicar por request_id no deduplica nada; comparar el cuerpo entero rechaza todo reintento.
<code>/balance</code> siempre trae <code>player_id</code>La primera llamada de cada sesión va solo con el token: es la que descubre al jugador. Exigir player_id ahí rechaza la entrada de todos.
El importe es decimalEs entero, en céntimos. R$ 3,56 es 356. El bundle del juego llegó a enviar 114.99999999999999 para una apuesta de R$ 1,15 cuando el campo era decimal.
Las dos direcciones siguen la misma convenciónNo la siguen. La regla del 200 vale para la cartera; las dos rutas del juego responden 4xx, porque ahí no hay decisión de negocio, solo petición inválida. Los dos conjuntos de error_code casi no se tocan, y la excepción importa: INTERNAL_ERROR e INVALID_SIGNATURE están en los dos, así que el código por sí solo no dice de qué lado vino el fallo.
<code>freebet_id</code> solo llega cuando es un premioEl campo está siempre, y vale null en la apuesta común. Ramifique en freebet_id !== null, nunca en la presencia de la clave.

Autenticación: un solo esquema, en ambas direcciones

X-Signature: hex(HMAC-SHA256(cuerpo_de_la_petición, secreto))
Authorization: Bearer <clave>

Firme los bytes exactos del cuerpo, y compruebe sobre esos mismos bytes. Decodificar el JSON y volver a serializarlo antes del HMAC cambia los espacios y el orden de las claves, y la firma deja de coincidir con un contenido idéntico. Es el error más común, en ambos lados.

El timestamp va dentro del cuerpo firmado, en milisegundos, sin cabecera propia. Fuera de una ventana de 5 minutos la petición se rechaza, en ambos sentidos: es lo que impide reenviar una petición capturada.

Toda petición lleva operator y timestamp; las que salen de aquí llevan además request_id, currency y game_id. El request_id nombra el intento, no el movimiento: dos intentos del mismo transaction_id llevan ids distintos, y así encuentra uno de ellos en su log.

El Bearer vale solo en la dirección que sale de aquí. En las dos rutas que exponemos no hay clave nuestra, y la firma autentica sola: por eso el juego se niega a arrancar en modo operador sin secreto. Sin secreto configurado, X-Signature no se envía y la ventana no se aplica.

Genere las credenciales

Los dos valores salen del crypto.getRandomValues de su navegador y no salen de él: esta página no hace ni una petición. Letras y números, sin palabras de diccionario, 32 y 48 caracteres. El mínimo que el juego acepta es 24, y se niega a arrancar por debajo de eso.

Clave (Bearer)
Secreto (HMAC)

Lo que exponemosoperador → proveedor

Dos rutas, sobre https://jumbo.aircrash.net, que es también la base de las URLs de lanzamiento que devuelve /v1/launch. Una instalación en otra dirección publica la suya.

POST/v1/gamestodos los juegos habilitados para el operador
→
{"operator":"casa-do-norte", "timestamp":1755680000000,
 "currency":"BRL"}
←
{
  "status": "ok",
  "operator": "casa-do-norte",
  "currencies": ["BRL", "USD"],
  "games": [
    {
      "game_id": "jumbo-crash",
      "name": "Jumbo",
      "studio": "jumbo",
      "category": "CRASH",
      "demo": false, "mobile": true, "desktop": true, "freebet": true,
      "currency": "BRL",
      "min_bet": 100, "max_bet": 50000, "max_win": 5000000
    }
  ]
}

freebet indica si el juego acepta rondas gratis concedidas por el operador.

Los tres límites

Aparecen solo cuando usted envía currency, valen para esa moneda, y son céntimos enteros.

CampoSignificado
min_betapuesta mínima aceptada
max_betapuesta máxima aceptada
max_wintecho de pago; un premio mayor se paga en el techo

currencies es el conjunto de monedas habilitadas para usted. De ahí sale en qué monedas puede conceder freebets: una concesión en una moneda que la mesa no acepta es una promesa que nunca se cumple.

POST/v1/launchabre una partida para un jugador

Devuelve la URL para cargar en un iframe o redirigir.

→
{
  "operator": "casa-do-norte", "timestamp": 1755680000000,
  "game_id": "jumbo-crash",
  "player_id": "618004",
  "token": "e7c1f0a9d3b84e2f95a6",
  "currency": "BRL",
  "language": "pt",
  "demo": false, "mobile": true,
  "lobby_url": "https://seu-site/lobby",
  "deposit_url": "https://seu-site/deposito"
}
CampoObligatorioNotas
game_idsídebe ser el juego de esta instalación
tokensalvo en demose envía en cada llamada de billetera
player_idsalvo en demosu identificador de jugador
currencyrecomendadola moneda de la sesión
languagenopt, en o es
player_namenoapodo o nombre; se ofusca al mostrarlo
themenoel skin: JUMBO o SUPERAVIATOR (con 5 al final, cinco cajas); la url ya sale en el dominio del skin
demo, mobilenodemo no necesita token ni jugador
lobby_url, deposit_urlnoguardados en la sesión; la mesa aún no los muestra
←
{"status":"ok",
 "url":"https://jumbo.aircrash.net/?sid=v3Nq8Lm2&lang=pt&cur=BRL"}

Errores: MISSING_GAME_ID, MISSING_TOKEN, MISSING_PLAYER_ID, INVALID_TOKEN (400), GAME_NOT_FOUND (404), DEMO_NOT_AVAILABLE (400).

Monedas e idiomas

Todo el dinero es céntimo entero. 1500 significa 15,00 en la moneda de la sesión. Un campo monetario en unidades de la moneda, o en coma flotante, es inválido.

Las monedas habilitadas para un operador vuelven en currencies del POST /v1/games. Aquí no hay lista fija a propósito: la lista es la configuración de su instalación, y publicarla en dos sitios garantiza que algún día diverjan.

Idiomas

pt, en y es. Cualquier otro valor, y la ausencia del campo, caen en el idioma por defecto de la instalación y no en en. La divergencia con la referencia del mercado es deliberada: caer en un idioma que la mayoría de la base no lee, por un campo olvidado, es peor que caer en el idioma de la casa.

Lo que expone el operadorproveedor → operador

Cuatro rutas.

POST {wallet_url}/balance     token → jugador, saldo, moneda
POST {wallet_url}/bet         débito
POST {wallet_url}/win         crédito
POST {wallet_url}/rollback    reverso

Formato de la respuesta

←
{"status":"ok", "balance":98500, "currency":"BRL",
 "player_id":"618004", "transaction_id":"w-77120"}
←
{"status":"error", "error_code":"INSUFFICIENT_FUNDS",
 "error_message":"saldo insuficiente"}

balance es céntimo entero, después de la operación, y es obligatorio en el éxito.

currency es la moneda de la cuenta. Envíela en cada respuesta.

transaction_id en la respuesta es su número para el movimiento, no el nuestro. Existe para la conciliación: es lo que se cita al abrir un ticket sobre un movimiento concreto.

Campos por ruta

→ /bet
{
  "operator": "casa-do-norte", "timestamp": 1755680000000,
  "request_id": "req-9f1464ae0da0664c",
  "game_id": "jumbo-crash", "currency": "BRL",
  "token": "e7c1f0a9d3b84e2f95a6", "player_id": "618004",
  "transaction_id": "b-4471902", "round_id": "88213",
  "amount": 1500
}
RutaCampos
/balanceplayer_id, token
/betplayer_id, token, amount, transaction_id, round_id
/winplayer_id, token, amount, transaction_id, bet_id, round_id, type
/rollbackplayer_id, token, amount, transaction_id, bet_id, round_id

Más operator, timestamp, request_id y currency en todas, y game_id cuando el juego se conoce. El ciclo de freebet añade freebet_id al /bet y al /win; el reverso añade reason, que es diagnóstico y no cambia nada de su lado.

Códigos de error

CódigoSignificado¿Reintentamos?
INSUFFICIENT_FUNDSsaldo insuficienteno
TOKEN_EXPIREDsesión expiradano
TOKEN_INVALIDsesión que nunca existióno
PLAYER_NOT_FOUNDjugador desconocidono
BET_NOT_FOUNDla apuesta referenciada no existeno
CURRENCY_MISMATCHmoneda incorrecta para esta cuentano
PLAYER_BLOCKEDjugador impedido de apostarno
INTERNAL_ERRORfallo de su ladosí