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

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.

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 tema visual da mesa
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

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.

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 table’s visual theme
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

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.

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_iddebe 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 tema visual de la mesa
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 lado