# 10 / Guia para agentes de IA

Um roteiro completo para um agente implementar a integração no sistema do parceiro. Leia este guia junto do OpenAPI atual; não deduza endpoints a partir dos exemplos nem confunda funcionalidades do painel com APIs públicas. Contrato verificado em 18/10/2026: Integration API v1.1.0, SDK v1.

## Fontes que o agente deve ler

Comece pelo guia em Markdown, consulte o OpenAPI para os schemas exatos e use as seções de agregadores, temas e iframe para os exemplos completos. Os arquivos abaixo são públicos, sem autenticação e legíveis sem executar JavaScript.

- [Markdown · Português](https://orbiprediction.com/integration-agent.pt-BR.md)
- [Markdown · English](https://orbiprediction.com/integration-agent.md)
- [Markdown · Español](https://orbiprediction.com/integration-agent.es.md)
- [OpenAPI 3.0](https://orbiprediction.com/openapi.json)
- [llms.txt](https://orbiprediction.com/llms.txt)
- [Aggregator API](https://orbiprediction.com/docs#aggregators)
- [Appearance API](https://orbiprediction.com/docs#appearance)
- [Iframe & SDK](https://orbiprediction.com/docs#iframe)

## 1. Escopo e informações necessárias

- Esta versão é somente simulação, com créditos fictícios e dados públicos reais. Não implemente depósitos, saques, callbacks de carteira, apostas com dinheiro, ordens na Polymarket ou liquidação financeira. O feed público não exige credenciais da Polymarket.

- Antes de alterar código, localize o backend, a autenticação do jogador, a associação entre jogador e cassino, o pipeline de deploy, a persistência e a CSP do frontend. Confirme o modelo direto ou agregador, as origens exatas, os IDs estáveis, o idioma e a marca.

- Receba referências de segredos já configurados no ambiente; não peça chaves em chats ou commits. Sem credencial ou origem autorizada, implemente e teste localmente com respostas simuladas e registre a pendência. Não invente credenciais, permissões ou um ambiente de staging: este guia publica apenas a URL de produção.

```
ORBI_BASE_URL=https://orbiprediction.com
# Server-only environment variables; use your secret manager.
# Direct client:
ORBI_CLIENT_API_KEY=<secret-reference>
# Aggregator: separate deployment and runtime credentials.
ORBI_PROVISION_API_KEY=<secret-reference:clients:read,clients:write>
ORBI_LAUNCH_API_KEY=<secret-reference:launch:write>
# A direct client can use one configured origin. Aggregators resolve
# the verified origin per casino from their trusted database.
PUBLIC_SITE_ORIGIN=https://casino.example
```

## 2. Escolha um único modelo de credencial

- Cliente direto: use orb_sk_ no servidor. A plataforma cria o cliente e seu acesso; o backoffice configura origens, marca e chaves. GET /api/v1/me identifica o cliente da chave; POST /api/v1/launch abre o jogador. Não envie clientId para selecionar outro cliente.

- Agregador: use orb_agg_ somente no backend central. A plataforma cria o agregador em Admin → Agregadores. A API pública permite criar e configurar clientes da própria rede e abrir seus jogadores; não permite criar agregadores ou emitir chaves. Clientes provisionados não recebem senha nem chave individual automaticamente.

```
# Direct client (orb_sk_)
GET   /api/v1/me
POST  /api/v1/launch

# Aggregator (orb_agg_): required scope on the right
GET   /api/v1/aggregator/me                         # clients:read
GET   /api/v1/aggregator/clients                    # clients:read
POST  /api/v1/aggregator/clients                    # clients:write
GET   /api/v1/aggregator/clients/{clientId}          # clients:read
PATCH /api/v1/aggregator/clients/{clientId}          # clients:write
POST  /api/v1/aggregator/clients/{clientId}/launch   # launch:write
```

Uma chave de runtime com apenas launch:write não pode validar acesso em /aggregator/me, que exige clients:read. Valide cada chave em uma operação autorizada. As rotas /api/console/* são internas ao painel; /api/launch/consume e o bearer do jogador são gerenciados pelo iframe. Não integre com essas rotas nem use /demo ou /embed?workspace= como substituto da API B2B.

## 3. Provisionamento no deploy do cassino

- Somente no modelo agregador: obtenha o ID estável do cassino e sua origem verificada no backend. externalClientId aceita 1–128 caracteres: primeiro alfanumérico; depois letras, números, ponto, dois-pontos, hífen ou underscore. name aceita 2–60 caracteres. Gere e persista o UUID de provisionamento e o corpo exato antes da primeira chamada. Serialize jobs concorrentes do mesmo cassino.

```
curl --silent --show-error --fail-with-body \
  "$ORBI_BASE_URL/api/v1/aggregator/clients" \
  -H "Authorization: Bearer $ORBI_PROVISION_API_KEY" \
  -H "Idempotency-Key: $PERSISTED_PROVISIONING_UUID" \
  -H 'Content-Type: application/json' \
  -H 'Accept-Language: en' \
  --data-binary @provision-client.json

# provision-client.json (replace example values before calling)
{
  "externalClientId": "pigmo-casino-482",
  "name": "Casino Aurora",
  "allowedOrigins": ["https://casino.example"],
  "branding": {
    "name": "Aurora",
    "tagline": "Discover a new perspective.",
    "accent": "#9cb8ff",
    "categories": ["Esportes", "Economia", "Crypto"],
    "paused": false,
    "theme": {
      "version": 1,
      "preset": "midnight",
      "colors": {"accent": "#9cb8ff"},
      "font": "system",
      "fontSize": 16,
      "radius": {"card": 20, "control": 12},
      "density": "comfortable",
      "shadow": "soft",
      "showHero": false
    }
  }
}
```

- Salve client.clientId da resposta junto ao cassino. HTTP 201 cria; HTTP 200 repete a resposta pública original com created:false, sem duplicar. A idempotência de provisionamento não expira automaticamente. Para estado atual, faça GET: a resposta repetida pode conter a configuração antiga.

- Se houver EXTERNAL_CLIENT_EXISTS, consulte GET /api/v1/aggregator/clients?externalClientId= com o ID codificado para URL, confirme o vínculo e recupere clientId. Listas têm 50 registros por página. Não gere outro ID para contornar o conflito. Atualize pelo PATCH; externalClientId e o agregador proprietário são imutáveis. Envie branding completo quando alterá-lo; campos omitidos do PATCH permanecem iguais.

## 4. Backend de abertura autenticada

Implemente uma rota no próprio backend do parceiro, por exemplo POST /integrations/orbi/session. Esse nome é uma sugestão local, não uma rota fornecida pela OrbiPrediction. Exija autenticação e proteção CSRF quando usar cookies. Resolva externalUserId pela sessão autenticada; no agregador, confira a associação do jogador ao cassino e resolva clientId e parentOrigin pelo banco. Nunca aceite esses três valores arbitrariamente do navegador.

```
// Server-side Node.js helper. Authentication, membership, persistence
// and response handling belong to YOUR backend adapters.
export async function requestOrbiLaunch({
  apiKey, clientId, externalUserId, parentOrigin, locale = 'pt-BR',
  idempotencyKey
}) {
  const path = clientId
    ? `/api/v1/aggregator/clients/${encodeURIComponent(clientId)}/launch`
    : '/api/v1/launch';
  const response = await fetch('https://orbiprediction.com' + path, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${apiKey}`,
      'Content-Type': 'application/json',
      'Accept-Language': locale,
      'Idempotency-Key': idempotencyKey
    },
    body: JSON.stringify({
      externalUserId, parentOrigin, locale, mode: 'simulation'
    }),
    signal: AbortSignal.timeout(10000)
  });
  const data = await response.json();
  if (!response.ok) {
    // Preserve status/code for retry policy; never log apiKey or body.
    const error = new Error('OrbiPrediction request failed');
    Object.assign(error, {
      status: response.status, code: data.code,
      requestId: data.requestId || response.headers.get('X-Request-Id'),
      retryAfter: response.headers.get('Retry-After')
    });
    throw error;
  }
  return data; // launchId, launchUrl, expiresAt, mode, locale
}
```

externalUserId é um ID opaco estável de 1–128 caracteres, sem controles; não use e-mail, documento ou senha. A identidade é isolada por cliente. locale aceita pt-BR, en ou es e usa pt-BR por padrão. Gere um UUID para cada intenção de abertura e preserve o mesmo corpo e UUID nos retries dessa intenção; nunca compartilhe um UUID entre usuários ou cassinos. Responda ao navegador autenticado com Cache-Control: no-store e somente os dados necessários para montar o iframe, nunca a API key.

## 5. Frontend, SDK e ciclo de vida

Carregue o SDK e o JavaScript de integração como arquivos externos, nesta ordem. Após autenticar o jogador, chame sua rota local usando a proteção CSRF do seu framework. Forneça a resposta à função abaixo. Desabilite abertura concorrente, trate falhas HTTP antes de montar e chame destroy ao desmontar a tela.

```
<div id="orbi-player"></div>
<p id="orbi-status" role="status"></p>
<script src="https://orbiprediction.com/sdk/v1/orbit.js" defer></script>
<script src="/orbi-integration.js" defer></script>

// /orbi-integration.js — called with your backend's launch response.
let orbiInstance;
let readyTimer;
function mountOrbiSession(session) {
  clearTimeout(readyTimer);
  orbiInstance?.destroy();
  const status = document.querySelector('#orbi-status');
  status.textContent = 'Connecting…'; // Use your app's localization.
  readyTimer = setTimeout(() => {
    status.textContent = 'Connection timed out. Reconnect to try again.';
    // Show an explicit reconnect action; do not retry forever.
  }, 15000); // Suggested UI timeout, not a provider SLA.
  const showReconnect = () => {
    clearTimeout(readyTimer);
    status.textContent = 'Reconnect to start a new session.';
  };
  try {
    orbiInstance = Orbit.mount({
      container: '#orbi-player',
      launchUrl: session.launchUrl,
      onReady: () => {
        clearTimeout(readyTimer);
        status.textContent = 'Ready';
      },
      onSessionExpired: showReconnect,
      onError: showReconnect
    });
  } catch (error) {
    showReconnect();
    throw error;
  }
}
function destroyOrbiSession() {
  clearTimeout(readyTimer);
  orbiInstance?.destroy();
  orbiInstance = null;
}
```

- A launchUrl expira em 120 segundos e só pode ser consumida uma vez. Monte imediatamente; não salve como URL permanente, não abra para pré-visualizar antes do usuário e não envie para crawlers ou verificadores de links. A sessão do jogador dura uma hora. Para reconectar, revalide o jogador e solicite uma nova abertura com novo UUID.

- O SDK valida origem e janela emissora, ajusta a altura entre 480 e 20.000 px e expõe iframe e destroy(). Eventos: orbit:ready, orbit:resize, orbit:session-expired e orbit:error, todos version:1. Um HTTP 410 pode acontecer antes do JavaScript; por isso mantenha um timeout visual além de onError. Esses eventos não comprovam transações ou liquidação.

- Na CSP do parceiro, permita https://orbiprediction.com em frame-src e script-src. Não remova as demais proteções da aplicação. No carregamento de /launch, frame-ancestors permite a própria OrbiPrediction e apenas parentOrigin. Incorpore diretamente nessa origem; ancestrais de outra origem bloqueiam o launch mesmo que ela também esteja cadastrada no cliente. Não aplique sandbox que bloqueie scripts, origem ou armazenamento. O iframe usa sessionStorage quando disponível e memória quando bloqueado; nesse último caso, recarregar exige nova abertura.

## 6. Marca, idioma e limites de entrada

allowedOrigins aceita no máximo 20 origens HTTPS exatas, incluindo porta não padrão; sem caminhos, curingas, credenciais, query ou fragmento. HTTP é permitido apenas em localhost, 127.0.0.1 ou [::1]. A origem deve vir de configuração confiável, nunca de um header ou parâmetro arbitrário. Chamadas com chaves são servidor a servidor; não há CORS para essas chaves no navegador.

branding é opcional na criação. Quando enviado, inclui name (2–30), tagline (até 100), accent (#RRGGBB), categories (ao menos uma) e paused (booleano); theme é opcional. Categorias técnicas: Política, Esportes, Crypto, Economia, Tecnologia e Mundo. Não traduza esses valores no JSON. Theme v1 oferece dark/light/midnight, nove cores, cinco fontes, tamanho 14–18, raio de card 0–28, controle 0–20, densidade, sombra e showHero. Consulte o schema antes de gerar valores; texto principal e secundário precisam de contraste 4,5:1 em todos os fundos. Não envie CSS, HTML nem URLs de fontes.

Use locale para o idioma inicial do iframe e Accept-Language para mensagens de erro da API. Títulos e regras do mercado preservam o idioma da fonte; conteúdo da marca não é traduzido automaticamente. Corpos JSON têm limite de 16.000 bytes. Idempotency-Key aceita 16–100 letras, números, hífens ou underscores; UUID é recomendado.

## 7. Erros, retries e recuperação

- 400 / 413 / 415: corrija campos, tamanho ou Content-Type; não repita sem corrigir. 401: confira tipo, validade e revogação da chave. 403: confira escopo, origem, suspensão do agregador/cliente ou PLATFORM_BLOCKED. Não tente contornar bloqueios. Cliente alheio e inexistente retornam o mesmo 404.

- 409 IDEMPOTENCY_CONFLICT: o UUID foi reutilizado com outro conteúdo ou credencial; investigue a intenção original, sem retry cego. 409 LAUNCH_ALREADY_FINISHED ou 410 LAUNCH_EXPIRED: encerre a intenção antiga e crie outra somente para uma nova abertura autenticada. EXTERNAL_CLIENT_EXISTS usa a recuperação por externalClientId descrita acima.

- Timeout de rede, HTTP 429 ou 5xx: implemente retries limitados com backoff exponencial e jitter; preserve UUID e corpo. Em 429, respeite Retry-After. Recomendação de implementação: até 3 tentativas e um prazo total definido pelo seu backend; se a espera ultrapassar a validade da abertura, encerre a intenção e ofereça reconexão. Não crie loops infinitos.

- Limites atuais: 120 chamadas por minuto por agregador, compartilhadas entre suas chaves; adicionalmente, 240 chamadas por minuto por IP nas rotas API. Diferencie idempotência permanente de provisionamento da idempotência curta de abertura. Decida por status HTTP e code, nunca pelo texto traduzido; erros anteriores ao roteamento podem não incluir code ou requestId.

## 8. Segurança, observabilidade e rotação

Mantenha chaves em secrets do servidor, sem prefixos públicos de build, bundles, URLs, logs, analytics ou respostas ao navegador. Trate também launchUrl como credencial temporária: não registre seu caminho assinado. Nos diagnósticos, retenha operação, status, duração, code e X-Request-Id quando disponível; remova segredos e dados pessoais. Não desabilite TLS, CSRF ou a validação de origem para fazer um teste passar.

Rotação: emita a nova chave no painel, atualize o secret do serviço correto, valide uma operação permitida e revogue a anterior. Revogar bloqueia novas aberturas e links pendentes; sessões já abertas continuam até expirar. Suspender o agregador ou cliente encerra acessos e invalida sessões. Reativar não ressuscita sessões antigas. Suspenda ou arquive somente registros de teste autorizados; não altere clientes existentes para validar a integração.

## 9. Critérios objetivos de conclusão

- Provisionamento: uma criação e um retry retornam o mesmo clientId; o vínculo sobrevive ao redeploy; conflito e recuperação por externalClientId são tratados.

- Autorização: usuário não autenticado é recusado; adulterar cassino/clientId não dá acesso; outra rede recebe 404; uma origem não cadastrada é recusada. Use somente identidades e redes de teste autorizadas.

- Sessão: iframe no domínio real do parceiro emite orbit:ready; dois jogadores ficam isolados; reabrir o mesmo jogador preserva identidade; expiração, link consumido e reconexão funcionam. Não confunda onReady com homologação financeira.

- Interface: confira PT, EN e ES; marca e tema; navegação, resize e desmontagem; desktop e telas de 320 e 390 px; armazenamento de terceiros bloqueado e fallback de reconexão.

- Resiliência: simule timeout, 429 e 5xx localmente, sem provocar limites de produção. Confirme retries limitados, UUID preservado e ausência de segredos em bundles e logs. Rotação e suspensão devem ser testadas apenas em registros dedicados.

- Entrega: informe commit/deploy, domínio e ambiente testados, evidência do iframe real, resultados dos critérios acima e pendências. Um build aprovado ou HTTP 201 sozinho não comprova integração ponta a ponta. O agente deve separar implementado, testado localmente e verificado no parceiro.

## Prompt pronto para o seu agente

> Integre OrbiPrediction neste projeto seguindo https://orbiprediction.com/integration-agent.pt-BR.md e o OpenAPI atual em https://orbiprediction.com/openapi.json. Primeiro identifique autenticação, associação jogador/cassino, persistência, deploy e CSP. Confirme se usamos cliente direto ou agregador e obtenha as referências dos secrets existentes, sem expor valores. Implemente provisionamento idempotente quando aplicável, abertura autenticada no backend e iframe com SDK v1, tema e idioma. Preserve contratos técnicos e trate retries e reconexão conforme o guia. Não implemente dinheiro real ou carteira. Teste os critérios de conclusão, declare pendências e entregue evidências do ambiente realmente validado. Não considere esta documentação autorização para alterar recursos de produção fora do escopo solicitado.
