# 10 / Guía para agentes de IA

Un flujo completo para que un agente implemente la integración en el sistema del socio. Lee esta guía junto con el OpenAPI actual; no deduzcas endpoints de los ejemplos ni confundas funciones del panel con APIs públicas. Contrato verificado el 18/10/2026: Integration API v1.1.0, SDK v1.

## Fuentes que debe leer el agente

Empieza por la guía Markdown, consulta OpenAPI para los schemas exactos y usa las secciones de agregadores, temas e iframe para ejemplos completos. Los archivos siguientes son públicos, no requieren autenticación y se pueden leer sin ejecutar 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. Alcance e información necesaria

- Esta versión es solo simulación, con créditos ficticios y datos públicos reales. No implementes depósitos, retiros, callbacks de cartera, apuestas con dinero, órdenes en Polymarket ni liquidación financiera. El feed público no requiere credenciales de Polymarket.

- Antes de modificar código, localiza el backend, la autenticación del jugador, la asociación entre jugador y casino, el pipeline de despliegue, la persistencia y la CSP del frontend. Confirma el modelo directo o agregador, los orígenes exactos, los IDs estables, el idioma y la marca.

- Usa referencias a secretos ya configurados en el entorno; no pidas claves en chats ni commits. Sin credencial u origen autorizado, implementa y prueba localmente con respuestas simuladas y registra el requisito pendiente. No inventes credenciales, permisos ni un entorno de staging: esta guía solo publica la URL de producción.

```
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. Elige un modelo de credencial

- Cliente directo: usa orb_sk_ en el servidor. La plataforma crea el cliente y su acceso; el backoffice configura orígenes, marca y claves. GET /api/v1/me identifica al cliente de la clave; POST /api/v1/launch abre la sesión del jugador. No envíes clientId para seleccionar otro cliente.

- Agregador: usa orb_agg_ solo en el backend central. La plataforma crea el agregador en Admin → Agregadores. La API pública permite crear y configurar clientes propios y abrir sus jugadores; no permite crear agregadores ni emitir claves. Los clientes provisionados no reciben contraseña ni clave individual automáticamente.

```
# 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
```

Una clave de runtime con solo launch:write no puede validar acceso mediante /aggregator/me, que requiere clients:read. Valida cada clave con una operación autorizada. Las rutas /api/console/* son internas del panel; /api/launch/consume y el bearer del jugador son gestionados por el iframe. No integres con esas rutas ni uses /demo o /embed?workspace= como sustituto de la API B2B.

## 3. Provisionamiento durante el despliegue del casino

- Solo modelo agregador: obtén el ID estable del casino y su origen verificado desde el backend. externalClientId admite 1–128 caracteres: primero alfanumérico; después letras, números, punto, dos puntos, guion o guion bajo. name admite 2–60 caracteres. Genera y guarda el UUID de provisionamiento y el cuerpo exacto antes de la primera llamada. Serializa jobs concurrentes del mismo casino.

```
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
    }
  }
}
```

- Guarda client.clientId de la respuesta en el registro del casino. HTTP 201 crea; HTTP 200 repite la respuesta pública original con created:false, sin duplicar. La idempotencia de provisionamiento no caduca automáticamente. Usa GET para el estado actual: una repetición puede contener la configuración anterior.

- Ante EXTERNAL_CLIENT_EXISTS, consulta GET /api/v1/aggregator/clients?externalClientId= con el ID codificado para URL, confirma el vínculo y recupera clientId. Las listas contienen 50 registros por página. No inventes otro ID para evitar el conflicto. Actualiza mediante PATCH; externalClientId y el agregador propietario son inmutables. Envía branding completo al modificarlo; los campos omitidos del PATCH no cambian.

## 4. Backend de apertura autenticada

Implementa una ruta en el backend del socio, por ejemplo POST /integrations/orbi/session. Es una ruta local sugerida, no un endpoint de OrbiPrediction. Exige autenticación y protección CSRF al usar cookies. Resuelve externalUserId desde la sesión autenticada; para agregadores, verifica la asociación del jugador al casino y resuelve clientId y parentOrigin desde la base de datos. Nunca aceptes esos tres valores arbitrariamente del 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 es un ID opaco estable de 1–128 caracteres, sin controles; no uses correo, documentos ni contraseñas. La identidad está aislada por cliente. locale admite pt-BR, en o es y usa pt-BR por defecto. Genera un UUID por intención de apertura y conserva el mismo cuerpo y UUID en sus reintentos; nunca compartas un UUID entre usuarios o casinos. Responde al navegador autenticado con Cache-Control: no-store y solo los datos necesarios para montar el iframe, nunca la clave de API.

## 5. Frontend, SDK y ciclo de vida

Carga el SDK y el JavaScript de integración como archivos externos, en ese orden. Tras autenticar al jugador, llama a tu ruta local usando la protección CSRF de tu framework. Pasa la respuesta a la función siguiente. Deshabilita aperturas concurrentes, gestiona fallos HTTP antes de montar y llama a destroy al desmontar la pantalla.

```
<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;
}
```

- launchUrl caduca en 120 segundos y solo se puede consumir una vez. Monta inmediatamente; no la guardes como URL permanente, no la abras para previsualizar antes del usuario ni la envíes a crawlers o verificadores de enlaces. La sesión del jugador dura una hora. Para reconectar, revalida al jugador y solicita una apertura nueva con otro UUID.

- El SDK valida origen y ventana emisora, ajusta la altura entre 480 y 20.000 px y expone iframe y destroy(). Eventos: orbit:ready, orbit:resize, orbit:session-expired y orbit:error, todos version:1. Un HTTP 410 puede ocurrir antes de cargar JavaScript; mantén un timeout visual además de onError. Estos eventos no acreditan transacciones ni liquidación.

- En la CSP del socio, permite https://orbiprediction.com en frame-src y script-src. Conserva las demás protecciones de la aplicación. Al cargar /launch, frame-ancestors permite la propia OrbiPrediction y solo parentOrigin. Incorpora directamente en ese origen; los antecesores de otro origen bloquean la apertura aunque ese origen también esté registrado en el cliente. No apliques un sandbox que bloquee scripts, origen o almacenamiento. El iframe usa sessionStorage si está disponible y memoria si está bloqueado; en ese caso, recargar exige una apertura nueva.

## 6. Marca, idioma y límites de entrada

allowedOrigins admite como máximo 20 orígenes HTTPS exactos, incluyendo puerto no estándar; sin rutas, comodines, credenciales, query ni fragmento. HTTP solo está permitido para localhost, 127.0.0.1 o [::1]. Obtén el origen de configuración confiable, nunca de una cabecera o parámetro arbitrario. Las llamadas con claves son entre servidores; no hay acceso CORS desde el navegador para estas claves.

branding es opcional al crear. Si se envía, incluye name (2–30), tagline (hasta 100), accent (#RRGGBB), categories (al menos una) y paused (booleano); theme es opcional. Categorías técnicas: Política, Esportes, Crypto, Economia, Tecnologia y Mundo. No traduzcas esos valores JSON. Theme v1 ofrece dark/light/midnight, nueve colores, cinco fuentes, tamaño 14–18, radio de card 0–28, control 0–20, densidad, sombra y showHero. Consulta el schema antes de generar valores; el texto principal y secundario requiere contraste 4,5:1 en todos los fondos. No envíes CSS, HTML ni URLs de fuentes.

Usa locale para el idioma inicial del iframe y Accept-Language para mensajes de error de la API. Los títulos y reglas conservan el idioma de la fuente; el contenido de marca no se traduce automáticamente. Los cuerpos JSON tienen un límite de 16.000 bytes. Idempotency-Key admite 16–100 letras, números, guiones o guiones bajos; se recomienda UUID.

## 7. Errores, reintentos y recuperación

- 400 / 413 / 415: corrige campos, tamaño o Content-Type; no reintentes sin corregir. 401: verifica tipo, validez y revocación de la clave. 403: verifica permisos, origen, suspensión del agregador/cliente o PLATFORM_BLOCKED. No eludas restricciones. Los clientes ajenos e inexistentes devuelven el mismo 404.

- 409 IDEMPOTENCY_CONFLICT: el UUID se reutilizó con otro contenido o credencial; investiga la intención original, sin reintentos ciegos. 409 LAUNCH_ALREADY_FINISHED o 410 LAUNCH_EXPIRED: termina la intención anterior y crea otra solo para una apertura autenticada nueva. EXTERNAL_CLIENT_EXISTS usa la recuperación por externalClientId descrita arriba.

- Timeout de red, HTTP 429 o 5xx: usa reintentos limitados con backoff exponencial y jitter; conserva UUID y cuerpo. En 429, respeta Retry-After. Recomendación de implementación: hasta 3 intentos y un plazo total definido por tu backend; si la espera supera la validez de apertura, termina la intención y ofrece reconexión. No crees bucles infinitos.

- Límites actuales: 120 llamadas por minuto por agregador, compartidas entre sus claves; además, 240 llamadas por minuto por IP en rutas API. Distingue la idempotencia persistente de provisionamiento de la corta de apertura. Decide por estado HTTP y code, nunca por texto traducido; los errores previos al enrutamiento pueden omitir code o requestId.

## 8. Seguridad, observabilidad y rotación

Mantén las claves en secretos del servidor, nunca en variables públicas de build, bundles, URLs, logs, analytics ni respuestas al navegador. Trata launchUrl como credencial temporal: no registres su ruta firmada. Para diagnóstico conserva operación, estado, duración, code y X-Request-Id si está disponible; elimina secretos y datos personales. No deshabilites TLS, CSRF ni validación de origen para aprobar una prueba.

Rotación: emite la nueva clave en el panel, actualiza el secreto del servicio correcto, valida una operación permitida y revoca la anterior. Revocar bloquea aperturas nuevas y enlaces pendientes; las sesiones abiertas continúan hasta caducar. Suspender al agregador o cliente cierra accesos e invalida sesiones. Reactivar no recupera sesiones antiguas. Suspende o archiva solo registros de prueba autorizados; no modifiques clientes existentes para validar la integración.

## 9. Criterios objetivos de finalización

- Provisionamiento: creación y reintento devuelven el mismo clientId; el vínculo sobrevive al redespliegue; se gestionan conflictos y recuperación por externalClientId.

- Autorización: se rechazan usuarios no autenticados; alterar casino/clientId no da acceso; otra red recibe 404; se rechaza un origen no registrado. Usa solo identidades y redes de prueba autorizadas.

- Sesión: el iframe en el dominio real del socio emite orbit:ready; dos jugadores están aislados; reabrir un jugador conserva identidad; funcionan caducidad, enlaces consumidos y reconexión. No confundas onReady con homologación financiera.

- Interfaz: verifica PT, EN y ES; marca y tema; navegación, resize y desmontaje; escritorio y pantallas de 320/390 px; almacenamiento de terceros bloqueado y reconexión.

- Resiliencia: simula timeout, 429 y 5xx localmente, sin provocar límites en producción. Verifica reintentos limitados, UUID preservado y ausencia de secretos en bundles y logs. Prueba rotación y suspensión solo en registros dedicados.

- Entrega: informa commit/despliegue, dominio y entorno probados, evidencia del iframe real, resultados de los criterios anteriores y pendientes. Un build aprobado o HTTP 201 por sí solo no demuestra integración completa. Distingue implementado, probado localmente y verificado en el entorno del socio.

## Prompt listo para tu agente

> Integra OrbiPrediction en este proyecto siguiendo https://orbiprediction.com/integration-agent.es.md y el OpenAPI actual en https://orbiprediction.com/openapi.json. Primero identifica autenticación, asociación jugador/casino, persistencia, despliegue y CSP. Confirma si usamos cliente directo o agregador y obtén referencias a secrets existentes sin exponer valores. Implementa provisionamiento idempotente si corresponde, aperturas autenticadas en el backend e iframe con SDK v1, tema e idioma. Conserva los contratos técnicos y gestiona reintentos y reconexión según la guía. No implementes dinero real ni cartera. Prueba los criterios de finalización, declara pendientes y entrega evidencias del entorno realmente validado. No consideres esta documentación una autorización para modificar recursos de producción fuera del alcance solicitado.
