Incorporação (iframe)
O sportsbook roda em um iframe na sua página. O SDK de incorporação cria o iframe, passa o launch token, ajusta o tamanho, confere a origem de cada mensagem e oferece callbacks para o que acontece lá dentro. Não tem dependências e pesa cerca de 5 KB.
Com o SDK
Seção intitulada “Com o SDK”<div id="sportsbook"></div><script src="https://sportsbook.example.com/embed/v1.js"></script><script> const sb = BookmakerSportsbook.mount('#sportsbook', { url: 'https://sportsbook.example.com', tenant: 'seu-tenant', launchToken: '<launch token vindo do seu servidor>', // omita para navegação anônima height: matchMedia('(max-width: 899px)').matches ? 'fill' : 'auto', onLoginRequired: () => abrirSeuLogin(), onDepositRequested: () => abrirSeuCaixa(), onBalanceChanged: ({ balance, currency }) => atualizarSeuCabecalho(balance, currency), onSessionExpired: () => buscarLaunchTokenNoSeuServidor(), // uma string, uma promise de string, ou null });</script>/embed/v1.js é o SDK da versão 1 do protocolo. Ele recebe correções
compatíveis na mesma URL e é servido com Cache-Control: public, max-age=3600, stale-while-revalidate=86400 e Access-Control-Allow-Origin: *.
Não use o atributo integrity: a próxima atualização compatível o quebraria.
npm install @bookmaker/embed-sdkimport { mount, type SportsbookInstance } from '@bookmaker/embed-sdk';// só os tipos e helpers do protocolo:import type { SportsbookEvents, HostCommands } from '@bookmaker/embed-sdk/protocol';
const sb: SportsbookInstance = mount(document.getElementById('sportsbook')!, { url: 'https://sportsbook.example.com', tenant: 'seu-tenant', launchToken, onBetPlaced: ({ betId, stake, currency }) => analytics.track('bet', { betId, stake, currency }),});Módulo ES com declarações de tipo, sem dependências em tempo de execução.
| Opção | Tipo | |
|---|---|---|
url |
string | URL base do sportsbook. A origem dela é a única com que o SDK conversa. Obrigatória. |
tenant |
string | O id do seu tenant. Obrigatório. |
launchToken |
string | Vindo do seu servidor (Sessões de jogador). Sem ele, o jogador navega anônimo. |
path |
string | Primeira rota, veja links diretos. |
locale |
'en' | 'pt-BR' |
Idioma; padrão: o do tenant. |
height |
'auto' | 'fill' |
Modo de tamanho. Padrão 'fill'. |
minHeight |
number | Modo auto: altura em px até o primeiro evento resize. Padrão 600. |
scrollOffset |
number | false |
Modo auto: quando o jogador abre outra página do sportsbook com o topo do iframe fora da tela, o SDK rola a sua página de volta até ele, deixando esta quantidade de pixels para o seu cabeçalho fixo. Padrão 0; false desliga. |
title |
string | Nome acessível do iframe. Padrão Sportsbook. |
onReady, onLoginRequired, onDepositRequested, onBalanceChanged, onBetPlaced, onBetSettled, onRouteChange, onResize, onError |
function | Um callback por evento, chamado com o payload dele. |
onSessionExpired |
function | Devolva um launch token novo (ou uma promise dele) e o SDK envia set_launch_token; devolva null para manter o jogador deslogado. Uma chamada por vez. |
onEvent |
function | (type, payload) para todo evento, depois do callback específico. |
Um callback que lança exceção é reportado com console.error e não impede os
demais.
A instância
Seção intitulada “A instância”| Membro | |
|---|---|
setLaunchToken(token) |
Faz o login do jogador, ou substitui uma sessão expirada, sem recarregar o iframe. |
navigate(path) |
Vai para um link direto. |
setLocale(locale) |
en ou pt-BR. |
refreshBalance() |
Relê o saldo da sua carteira, por exemplo depois de um depósito no seu caixa. O iframe responde com balance_changed. |
logout() |
Encerra a sessão do sportsbook (chame quando o jogador sair do seu site). |
on(type, handler) |
Assina um tipo de evento; devolve a função para cancelar. |
ready |
Promise do payload de ready. |
iframe, origin |
O elemento iframe e a origem do sportsbook. |
destroy() |
Remove o iframe e todos os listeners. |
Comandos enviados antes de o sportsbook estar pronto ficam em fila e são
enviados depois do ready.
Sem o SDK
Seção intitulada “Sem o SDK”Qualquer página pode enquadrar o sportsbook e falar o protocolo
postMessage diretamente. Use a launchUrl devolvida
por integration/sessions, ou monte a URL:
https://sportsbook.example.com/?tenant=<tenant>&launch=<launchToken>&path=/live&locale=pt-BR&height=fill&origin=https%3A%2F%2Fwww.seu-site.example| Parâmetro | |
|---|---|
tenant |
Obrigatório. Também diz ao servidor qual frame-ancestors enviar. |
launch |
O launch token de uso único. Removido do endereço do iframe na hora. |
path |
Primeira rota (links diretos). Um caminho inválido é ignorado e reportado com um evento error. |
locale |
en ou pt-BR. |
height |
auto ou fill (padrão). Em auto a página não pode depender da altura da viewport, por isso informe ao sportsbook. |
origin |
A origem da sua página. Navegadores sem location.ancestorOrigins (Firefox) usam este valor, ou o Referer, para saber quem é o pai. É conferida contra as suas origens permitidas como qualquer outra. |
token |
Obsoleto: o próprio token de sessão na URL. Ainda aceito em integrações existentes; use launch. |
<iframe id="sb" title="Sportsbook" style="width: 100%; height: 100%; border: 0" src="https://sportsbook.example.com/?tenant=seu-tenant&launch=lt_…&origin=https%3A%2F%2Fwww.seu-site.example"></iframe><script> const SB = 'https://sportsbook.example.com'; const frame = document.getElementById('sb');
window.addEventListener('message', (e) => { // só o nosso iframe, só a origem do sportsbook, só o protocolo v1 if (e.source !== frame.contentWindow || e.origin !== SB) return; const m = e.data; if (!m || m.source !== 'bookmaker-sportsbook' || m.v !== 1) return; if (m.type === 'login_required') abrirSeuLogin(); if (m.type === 'balance_changed') atualizarSeuCabecalho(m.payload.balance, m.payload.currency); });
function send(type, payload = {}) { // sempre a origem exata do sportsbook, nunca '*' frame.contentWindow.postMessage({ source: 'bookmaker-host', v: 1, type, payload }, SB); } // por exemplo, depois do seu login: send('set_launch_token', { launchToken });</script>Modos de tamanho
Seção intitulada “Modos de tamanho”auto |
fill |
|
|---|---|---|
| Altura | O iframe cresce com o conteúdo: o SDK aplica a altura de cada evento resize. |
O iframe preenche o contêiner (height: 100%); dê uma altura ao contêiner. |
| Rolagem | A sua página rola; o iframe não tem barra de rolagem. | O sportsbook rola dentro do iframe. |
| Indicado para | Páginas de desktop com o seu cabeçalho e rodapé em volta do sportsbook. | Celulares e layouts no estilo de app. |
| Partes fixas | O cabeçalho e o boletim do sportsbook rolam junto com a página. | Cabeçalho, boletim e navegação inferior ficam sempre à vista. |
/* fill: o sportsbook ocupa a tela abaixo do seu cabeçalho */#sportsbook { height: calc(100dvh - var(--altura-do-seu-cabecalho)); }Celular
Seção intitulada “Celular”Em telas com menos de 900 px o sportsbook muda para o layout móvel: uma barra
de navegação inferior e um boletim em bottom sheet, ambos fixos na base da
viewport do iframe. No modo auto essa viewport tem a altura do sportsbook
inteiro, então eles ficariam muito abaixo da tela. Use fill em celulares,
com altura em dvh para considerar as barras do navegador. O operador de
referência escolhe por dispositivo:
height: matchMedia('(max-width: 899px)').matches ? 'fill' : 'auto',Links diretos
Seção intitulada “Links diretos”| Caminho | Abre |
|---|---|
/ |
Início: ao vivo agora e cupons em destaque |
/live, /live/{sportId} |
Ao vivo, todos os esportes ou um (football, basketball, tennis) |
/sport/{sportId} |
Competições e eventos de um esporte |
/competition/{competitionId} |
Uma competição, por exemplo /competition/br-serie-a |
/event/{eventId} |
Um evento com todos os mercados |
/my-bets |
As apostas abertas e liquidadas do jogador (anônimo: login_required) |
Abra um deles na inicialização com path e depois com navigate(path). O
iframe informa cada navegação com um evento route ({path, title}); espelhe
no seu próprio endereço para tornar as páginas do sportsbook compartilháveis,
e devolva como path no próximo carregamento:
onRouteChange: ({ path, title }) => { const url = new URL(location.href); url.searchParams.set('sb', path); history.replaceState(null, '', url); document.title = `${title} · Seu Cassino`;},path: new URLSearchParams(location.search).get('sb') ?? undefined,Hoje estão disponíveis en e pt-BR. Passe locale ao montar, ou troque a
qualquer momento com setLocale(); o sportsbook é redesenhado no lugar e
mantém a rota e o boletim. Sem nenhum dos dois, vale o idioma padrão do
tenant.
Origens permitidas
Seção intitulada “Origens permitidas”Só os seus sites podem enquadrar o sportsbook e conversar com ele. Liste as
origens exatas (esquema, host e porta, sem caminho, sem curingas) no
embedOrigins do seu tenant:
- A API envia
Content-Security-Policy: frame-ancestors 'self' <suas origens>em toda página do sportsbook do seu tenant (só'self'quando a lista está vazia), e os navegadores se recusam a exibi-lo dentro de qualquer outro site. - O iframe lê a mesma lista em
GET /api/v1/config(tenant.embedOrigins), só aceita comandos de uma página pai em uma dessas origens e só envia eventos para essa origem verificada, nunca para'*'. - A própria origem do sportsbook é sempre permitida (para pré-visualizações e esta documentação).
Configure no back office em Configurações → Integração, ou pela API (token de staff):
PUT /api/v1/admin/tenantAuthorization: Bearer <token de staff>Content-Type: application/json
{"embedOrigins": ["https://www.seu-cassino.example", "https://m.seu-cassino.example"]}A CSP da sua página
Seção intitulada “A CSP da sua página”Se o seu site envia uma Content Security Policy, libere a origem do sportsbook para o script e para o frame:
script-src 'self' https://sportsbook.example.com; frame-src https://sportsbook.example.comO que muda no modo incorporado
Seção intitulada “O que muda no modo incorporado”| No sportsbook | Quando incorporado |
|---|---|
| Cadastro, login, conta, depósitos, saques | Ocultos: são seus. |
| Saldo no cabeçalho | O saldo da sua carteira, identificado como tal. |
| Botão Depositar | Envia deposit_requested; abra o seu caixa. |
| Botão Entrar, Entre para apostar, Minhas Apostas anônimo | Enviam login_required com um reason; abra o seu login. |
| Fim da sessão | session_expired; nenhum diálogo dentro do iframe. |