1. ChizVerse Developer Docs
Chizverse
  • ChizVerse Developer Docs
    • Getting Started
    • API Reference
      • Overview
      • Chizmis Authentication
        • Exchange for a ChizVerse Bearer
        • Hosted Client Login
        • Hosted Client Registration
        • Logout
        • Get Current Account
        • Validate Client Application
        • Login with Existing Session
        • Verify Session Key
      • Activity Tracking
        • Create Launch
        • Create Tracked Session
        • Get Session Checkpoint
        • Get Saved Player Progress
        • Ingest Event Batch
        • Get Game Leaderboard
      • ChizPay Wallet & Transactions
        • Get Wallet by Account ID
        • Transfer Wallet Balance
        • Get Wallet Transaction History
        • Debit Wallet
        • Credit Wallet
        • Get Game Ledger
    • SDK
    • Schemas
      • ExchangeForAChizVerseBearerResponse
      • ExchangeForAChizVerseBearerRequest
      • LogoutResponse
      • LogoutRequest
      • GetCurrentAccountResponse
      • ValidateClientApplicationResponse
      • LoginWithExistingSessionResponse
      • LoginWithExistingSessionRequest
      • VerifySessionKeyResponse
      • CreateLaunchResponse
      • CreateLaunchRequest
      • CreateTrackedSessionResponse
      • CreateTrackedSessionRequest
      • GetSessionCheckpointResponse
      • GetSavedPlayerProgressResponse
      • IngestEventBatchResponse
      • IngestEventBatchRequest
      • GetGameLeaderboardResponse
      • GetWalletByAccountIDResponse
      • TransferWalletBalanceResponse
      • TransferWalletBalanceRequest
      • GetWalletTransactionHistoryResponse
      • DebitWalletResponse
      • DebitWalletRequest
      • CreditWalletResponse
      • CreditWalletRequest
      • GetGameLedgerResponse
  1. ChizVerse Developer Docs

Gameplay Flow

This is the complete browser-game flow for ChizVerse. It covers games launched from the ChizVerse platform and games opened directly, followed by the tracked gameplay pattern used by Chizmis Crush.
The ChizVerse website is optional, but the ChizVerse backend is still required. Activity tracking cannot start without a launch token issued by Game Manager.

Access Modes#

StepLaunched from ChizVerseStandalone game
Player authenticationChizVerse authenticates the player before launch.The game uses ChizmisAuth directly.
ChizVerse bearerChizVerse already holds chz_access_token.The game exchanges the Chizmis token through Core Auth.
Launch creationChizVerse calls createLaunch() and adds chz_launch_token to the game URL.The game calls createLaunch() with its new ChizVerse bearer.
Session creationThe game reads the launch token from the URL and calls startSession().The game passes the returned launch token to init() and calls startSession().
Gameplay and walletThe game calls Game Manager and ChizPay.The same—the game calls Game Manager and ChizPay directly.

ChizVerse Platform-Launched Sequence#

ChizVerse creates the launch and opens the game with t, chz_access_token, and chz_launch_token.
Sequence diagram for a game launched from the ChizVerse platform

Standalone Game Sequence#

The game authenticates with Chizmis, exchanges the Chizmis token through Core Auth for a ChizVerse bearer, and creates its own launch.
Sequence diagram for a directly accessed standalone game

Token and Wallet Linkage#

The Chizmis token from t authenticates Chizmis and ChizPay requests.
The ChizVerse bearer from chz_access_token authenticates protected ChizVerse requests such as createLaunch().
The launch token is separate from both bearer tokens and only bootstraps a tracked Game Manager session.
A standalone game must register its own Chizmis clientId and exact callback URL.
Use one Game Manager sessionId as the ChizPay gameSession value throughout a run.
Call debit() before accepting a paid game action. Any payout or refund from credit() must reference the related debitTx.id through debitTransactionId.
Generate unique referenceNumber and nonce values for every wallet operation.
See ChizPay Wallet & Transactions for debit, credit, and ledger examples.

Platform-Launched Gameplay Summary#

1.
ChizVerse web creates a launch ticket.
2.
The player opens the game with ?chz_launch_token=....
3.
The game calls initChizVerse() and startSession().
4.
The game sends updateProgress() and trackScore() while playing.
5.
Refresh only calls flush(), so the same session can resume.
6.
End Run calls endSession({ finalScore }).
7.
Leaderboard updates from the ended-session event.
8.
New Game calls startNewSession() to create a separate session.

SDK Imports#

import {
  endSession,
  flush,
  getCheckpoint,
  getGameLeaderboard,
  init as initChizVerse,
  setPresence,
  startSession,
  startNewSession,
  trackScore,
  updateProgress,
} from '@ccci/chizverse-sdk'

1. Open the Game With a Launch Token#

This part belongs in the launcher, not inside the game. In ChizVerse web, create a launch, then append the launch token to the game URL.
import { getLaunchUrl } from '@ccci/chizverse-sdk'

const launch = await createLaunch(gameId, {
  allowedOrigin: gameUrl,
  buildId,
  gameVersionId,
  launchSource: 'CATALOG_PLAY',
})

const url = new URL(getLaunchUrl(gameUrl, {
  launchToken: launch.queryParams.chz_launch_token,
}))

// Optional: pass ChizVerse bearer token so the game can create a new
// launch later when the player clicks New Game.
url.searchParams.set('chz_access_token', rawChizVerseAccessToken)

window.location.href = url.toString()
Use chz_launch_token to start the tracked session. Use chz_access_token only if the game needs to create a new launch from inside the game.

2. Read the ChizVerse Token in the Game#

Use one key for the URL query param and localStorage key.
const CHIZVERSE_ACCESS_TOKEN_KEY = 'chz_access_token'

function normalizeAccessToken(token?: string | null) {
  const trimmed = token?.trim()
  return trimmed ? trimmed.replace(/^Bearer\s+/i, '') : null
}

function initializeChizVerseAccessToken() {
  const url = new URL(window.location.href)
  const queryToken = normalizeAccessToken(url.searchParams.get(CHIZVERSE_ACCESS_TOKEN_KEY))

  if (queryToken) {
    localStorage.setItem(CHIZVERSE_ACCESS_TOKEN_KEY, queryToken)
    url.searchParams.delete(CHIZVERSE_ACCESS_TOKEN_KEY)
    window.history.replaceState(window.history.state, '', `${url.pathname}${url.search}${url.hash}`)
    return queryToken
  }

  return normalizeAccessToken(localStorage.getItem(CHIZVERSE_ACCESS_TOKEN_KEY))
}

const chizVerseAccessToken = initializeChizVerseAccessToken()

3. Start or Resume the Session#

The SDK automatically reads chz_launch_token from the URL or localStorage.
let trackedGameId: number | null = null
let trackedBuildId: number | null = null
let trackedGameVersionId: number | null = null
let sessionStartedAt = Date.now()

const trackingActive = ref(false)
const runEnded = ref(false)

async function initSdkTracking() {
  await initChizVerse({
    autoStartSession: false,
    debug: new URLSearchParams(window.location.search).has('chz_debug'),
  })

  await startSession({
    levelId: 'main-board',
    mode: 'campaign',
    metadata: {
      player: {
        accountId: player.id,
        displayName: player.displayName,
        avatar: player.avatar,
      },
    },
  })

  const checkpoint = await getCheckpoint()
  if (!checkpoint) return

  trackedGameId = checkpoint.gameId
  trackedBuildId = checkpoint.buildId
  trackedGameVersionId = checkpoint.gameVersionId
  trackingActive.value = true

  restoreSavedProgress(checkpoint)
  setPresence({ state: 'in_game', reason: 'game-loaded' })
}
If the page refreshes, startSession() resumes the saved session instead of creating a duplicate session.

4. Restore Saved Progress#

getCheckpoint() returns the latest saved session state from Game Manager.
Use:
checkpoint.currentScore to restore the score.
checkpoint.progressSnapshot.metadata to restore custom game state that you previously sent in updateProgress().
In Chizmis Crush, updateProgress() saves coins and wordsSpilled, so the restore code reads those same fields back.
function restoreSavedProgress(checkpoint: any) {
  // Score comes from trackScore().
  score.value = checkpoint.currentScore ?? 0

  // Metadata comes from updateProgress().
  const saved = checkpoint.progressSnapshot?.metadata
  coins.value = typeof saved?.coins === 'number' ? saved.coins : 0
  wordsSpilled.value = typeof saved?.wordsSpilled === 'number' ? saved.wordsSpilled : 0
}
The important rule is simple: if you want a value to survive refresh, include it in updateProgress({ metadata: ... }).

5. Track Gameplay#

Send progress and score whenever the player makes meaningful progress.
function trackProgress(checkpointId: string) {
  if (!trackingActive.value || runEnded.value) return

  updateProgress({
    checkpointId,
    levelId: 'main-board',
    completionPercent: Math.min(100, wordsSpilled.value * 5),
    metadata: {
      score: score.value,
      coins: coins.value,
      wordsSpilled: wordsSpilled.value,
    },
  })
}

function trackScoreUpdate(delta: number, reason: string) {
  if (!trackingActive.value || runEnded.value) return

  trackScore({
    score: score.value,
    delta,
    reason,
    metadata: {
      coins: coins.value,
      wordsSpilled: wordsSpilled.value,
    },
  })
}
Example:
score.value += totalPoints
coins.value += Math.floor(totalPoints / 20)

trackProgress('tile-clear')
trackScoreUpdate(totalPoints, 'match-clear')

6. Flush on Refresh#

Do this on refresh or page close:
onBeforeUnmount(() => {
  void flush({ keepalive: true })
})
Do not call endSession() on refresh. Ending the session prevents resume.

7. End the Run#

Call endSession() only when the run is done. Leaderboard processing uses this ended-session event.
async function finishTrackedRun() {
  if (!trackingActive.value || runEnded.value) return

  runEnded.value = true

  await endSession({
    reason: 'completed',
    finalScore: score.value,
    durationSeconds: Math.max(1, Math.round((Date.now() - sessionStartedAt) / 1000)),
    metadata: {
      coins: coins.value,
      wordsSpilled: wordsSpilled.value,
    },
  })

  await refreshLeaderboard()
}

8. Load Leaderboard#

async function refreshLeaderboard() {
  if (!trackedGameId) return

  const leaderboard = await getGameLeaderboard(trackedGameId, {
    limit: 5,
    type: 'ALL_TIME',
  })

  leaderboardEntries.value = leaderboard.entries
}

9. New Game Creates a New Session#

When the player starts a new game, end the current run, reset local state, then create a new launch and session.
async function startFreshTrackedGame() {
  if (!trackedGameId || !trackedBuildId || !trackedGameVersionId || !chizVerseAccessToken) {
    resetLocalGame()
    return
  }

  if (!runEnded.value) {
    await finishTrackedRun()
  }

  resetLocalGame()

  await startNewSession(
    trackedGameId,
    {
      allowedOrigin: window.location.origin,
      buildId: trackedBuildId,
      gameVersionId: trackedGameVersionId,
      launchSource: 'CATALOG_PLAY',
      metadata: { source: 'new-game' },
    },
    chizVerseAccessToken,
    {
      levelId: 'main-board',
      mode: 'campaign',
      metadata: { player },
    }
  )

  sessionStartedAt = Date.now()
  runEnded.value = false
  trackingActive.value = true
  setPresence({ state: 'in_game', reason: 'new-game' })
}

Quick Rules#

Use chz_launch_token to start or resume the tracked session.
Use chz_access_token only when the game needs to create another launch.
Use trackScore() with the current total score, not only the delta.
Use updateProgress() for checkpoint data that should survive refresh.
Use getCheckpoint() after startSession() to restore the latest score and saved progress.
Use getGameLeaderboard(gameId) when you need to show scores for that game.
Use flush({ keepalive: true }) on refresh.
Use endSession({ finalScore }) only when the run is actually finished.
Use startNewSession() for New Game so every run has a separate session.
Modified atĀ 2026-07-30 06:57:16
Previous
Get Game Ledger
Next
ExchangeForAChizVerseBearerResponse
Built with