Jumbo · jogo de crash
API de Integração v1
As duas direções
| Integração | Sentido | O que carrega |
|---|---|---|
Catálogo e lançamento | operador → provedor | quais jogos existem, e abrir uma partida para um jogador |
Carteira | provedor → operador | resolver 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.
/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.
| Campo | Significado |
|---|---|
min_bet | menor aposta aceita |
max_bet | maior aposta aceita |
max_win | teto 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.
/v1/launchabre uma partida para um jogadorDevolve 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"
}| Campo | Obrigatório | Notas |
|---|---|---|
game_id | sim | tem de ser o jogo desta instalação |
token | salvo em demo | vai em toda chamada de carteira |
player_id | salvo em demo | o identificador do jogador no seu sistema |
currency | recomendado | a moeda da sessão |
language | não | pt, en ou es |
player_name | não | apelido ou nome; é ofuscado ao exibir |
theme | não | o tema visual da mesa |
demo, mobile | não | demo não precisa de token nem de jogador |
lobby_url, deposit_url | não | guardados 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 estornoFormato 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
{
"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
}| Rota | Campos |
|---|---|
/balance | player_id, token |
/bet | player_id, token, amount, transaction_id, round_id |
/win | player_id, token, amount, transaction_id, bet_id, round_id, type |
/rollback | player_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ódigo | Significado | Retentamos? |
|---|---|---|
INSUFFICIENT_FUNDS | saldo insuficiente | não |
TOKEN_EXPIRED | sessão expirada | não |
TOKEN_INVALID | sessão que nunca existiu | não |
PLAYER_NOT_FOUND | jogador desconhecido | não |
BET_NOT_FOUND | a aposta referenciada não existe | não |
CURRENCY_MISMATCH | moeda errada para esta conta | não |
PLAYER_BLOCKED | jogador impedido de apostar | não |
INTERNAL_ERROR | falha do seu lado | sim |
Jumbo · crash game
Integration API v1
The two directions
| Integration | Direction | What it carries |
|---|---|---|
Catalogue and launch | operator → provider | which games exist, and opening a game for a player |
Wallet | provider → operator | resolve 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.
/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.
| Field | Meaning |
|---|---|
min_bet | smallest accepted stake |
max_bet | largest accepted stake |
max_win | payout 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.
/v1/launchopens a game for one playerReturns 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"
}| Field | Required | Notes |
|---|---|---|
game_id | yes | must be this installation’s game |
token | unless demo | sent on every wallet call |
player_id | unless demo | your player identifier |
currency | recommended | the session currency |
language | no | pt, en or es |
player_name | no | nickname or name; masked before display |
theme | no | the table’s visual theme |
demo, mobile | no | demo needs neither token nor player |
lobby_url, deposit_url | no | stored 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 refundResponse 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
{
"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
}| Route | Fields |
|---|---|
/balance | player_id, token |
/bet | player_id, token, amount, transaction_id, round_id |
/win | player_id, token, amount, transaction_id, bet_id, round_id, type |
/rollback | player_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
| Code | Meaning | We retry? |
|---|---|---|
INSUFFICIENT_FUNDS | not enough balance | no |
TOKEN_EXPIRED | session expired | no |
TOKEN_INVALID | session never existed | no |
PLAYER_NOT_FOUND | unknown player | no |
BET_NOT_FOUND | the referenced bet does not exist | no |
CURRENCY_MISMATCH | wrong currency for this account | no |
PLAYER_BLOCKED | player barred from betting | no |
INTERNAL_ERROR | your side failed | yes |
Jumbo · juego de crash
API de Integración v1
Las dos direcciones
| Integración | Sentido | Qué transporta |
|---|---|---|
Catálogo y lanzamiento | operador → proveedor | qué juegos existen, y abrir una partida para un jugador |
Billetera | proveedor → operador | resolver 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.
/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.
| Campo | Significado |
|---|---|
min_bet | apuesta mínima aceptada |
max_bet | apuesta máxima aceptada |
max_win | techo 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.
/v1/launchabre una partida para un jugadorDevuelve 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"
}| Campo | Obligatorio | Notas |
|---|---|---|
game_id | sí | debe ser el juego de esta instalación |
token | salvo en demo | se envía en cada llamada de billetera |
player_id | salvo en demo | su identificador de jugador |
currency | recomendado | la moneda de la sesión |
language | no | pt, en o es |
player_name | no | apodo o nombre; se ofusca al mostrarlo |
theme | no | el tema visual de la mesa |
demo, mobile | no | demo no necesita token ni jugador |
lobby_url, deposit_url | no | guardados 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 reversoFormato 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
{
"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
}| Ruta | Campos |
|---|---|
/balance | player_id, token |
/bet | player_id, token, amount, transaction_id, round_id |
/win | player_id, token, amount, transaction_id, bet_id, round_id, type |
/rollback | player_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ódigo | Significado | ¿Reintentamos? |
|---|---|---|
INSUFFICIENT_FUNDS | saldo insuficiente | no |
TOKEN_EXPIRED | sesión expirada | no |
TOKEN_INVALID | sesión que nunca existió | no |
PLAYER_NOT_FOUND | jugador desconocido | no |
BET_NOT_FOUND | la apuesta referenciada no existe | no |
CURRENCY_MISMATCH | moneda incorrecta para esta cuenta | no |
PLAYER_BLOCKED | jugador impedido de apostar | no |
INTERNAL_ERROR | fallo de su lado | sí |