Skip to content

Round replay

An operator can request a link (POST /v1/operator/rounds/replay, documented in the operator docs) that opens a page replaying one of your game's rounds — reels spinning, balance updating, in the sequence the player originally saw. The platform brokers the link and verifies the operator actually owns the round; everything about recording and rendering the replay itself is your responsibility. The platform never sees your game's visual outcome, only the money movements (BET/WIN/ROLLBACK) you submit — there's nothing for it to replay from.

This means replay support is opt-in, and only rounds played after you add recording are replayable — there's no way to retroactively reconstruct a round whose visual data was never captured.

What you need to build

  1. Record, at spin time, an ordered event timeline for the round, keyed by the same roundId you submit transactions under. Persist it (a DB table, object storage, ...) — not just in memory, unless you're fine with replay links only working until your process restarts.
  2. Configure a replay page base URL for your game with the platform team (GameSummary.replayBaseUrl) — the same way launchBaseUrl is configured. A game with no replayBaseUrl configured makes the operator's replay-link request fail with 400.
  3. Implement a GET route at that URL. It receives a ?replay= query parameter — resolve it with verifyReplay, look up the resulting roundId in your own storage, and render a page that plays the recorded timeline back.

Resolving the token

ts
import { ProviderClient } from '@moose/provider-sdk'

const client = new ProviderClient({
  baseUrl: process.env.PLATFORM_URL!,
  tenantId: 'acme-studio',
  secret: process.env.PLATFORM_SECRET!,
})

app.get('/replay', async (req, res) => {
  const replayToken = req.query.replay as string
  let verified
  try {
    verified = await client.verifyReplay(replayToken)
  } catch (err) {
    // PlatformApiError with status 401 (unknown/expired token) or 403
    // (token minted for a different provider — shouldn't happen in
    // practice, but don't trust the token blindly either way).
    return res.status((err as { status?: number }).status ?? 502).send('replay link invalid or expired')
  }

  const log = await replayStore.get(verified.roundId)
  if (!log) return res.status(404).send('replay not found')

  res.send(renderReplayPage({ roundId: verified.roundId, locale: verified.language, log }))
})

verifyReplay is a signed, retried call just like verifySession — see the ProviderClient reference. A 401 means the token is unknown or past its expiry window (15 minutes by default) — surface that as "this replay link has expired," not a generic error, since it's an expected outcome for an old link, not a bug.