API reference

This page lists every module, signature and key type in SDK 1.2.0. Behavior details (runtime modes, offline reconciliation, email binding) live in the Integration guide.

Include and initialize

Platform-hosted games use the CDN bundle with the global Instfun:

<script src="/sdk/v1/instfun.js"></script>
const sdk = await Instfun.init({
  gameId: "my-game",
  gameVersion: "0.1.0",
  mode: "auto"
});
Method / propertySignatureDescription
Instfun.init(config: InstfunConfig, deps?) => Promise<InstfunSdk>Creates and replaces the singleton instance
Instfun.getInstance() => InstfunSdk / nullReturns null before initialization
Instfun.versionstringSDK version (currently 1.2.0)

InstfunConfig:

FieldTypeRequiredDescription
gameIdstringYesMatches ^[a-z0-9][a-z0-9_-]{0,63}$; must match the published package. The upload/submit API additionally requires no underscores, 2–64 characters, and consistency with game-info.json
gameVersionstringNoDefaults to "0.0.0"
debugbooleanNoEnable debug logging
mode"local" / "remote" / "auto"NoDefaults to auto
apiBaseUrlstringNoRemote API prefix; remote defaults to /api/v1
initialBalancePartial<Record<"coins" / "gems", number>>NoInitial balance in local mode
limits{ saveThrottleMs?: number; sessionEvents?: number }NoOverride save throttling and the per-process event cap

InstfunSdk root object:

MemberTypeDescription
sdkVersionstringSDK version
gameIdstringCurrent game identifier
mode"local" / "remote"Resolved runtime mode
host{ kind: "android" / "web" / "browser" }Current host
supports(capability: "ads" / "login" / "payments" / "tracking") => Promise<boolean>Host capability probe
sync() => Promise<{ flushed: number; pending: number }>Flush analytics and replay the offline queue
account / wallet / game / leaderboard / analytics / ads / storageModulesSee below

account

MethodSignatureDescription
getCurrentUser() => Promise<UserProfile>Current guest profile (shared same-origin)
updateProfile(patch: Partial<Pick<UserProfile, "nickname" / "avatarUrl" / "bio">>) => Promise<UserProfile>Update profile fields
hasEmail() => Promise<boolean>Whether an email is bound; always false in local mode
openEmailBindDialog(options?: EmailBindDialogOptions) => Promise<EmailBindResult>Email binding / rebinding dialog
type EmailBindResult =
  | { status: "bound"; email: string; profile: UserProfile }
  | { status: "cancelled" }
  | { status: "unavailable"; reason: "offline" | "already-bound" };

Key UserProfile fields:

FieldTypeDescription
userId / nickname / avatarUrl / biostringBasic profile
isGuestbooleanAlways true for guest accounts
accountCodestring8-character account code for support
emailstring / nullMasked email; null when unbound
accountBoundbooleanWhether an email is bound
createdAtnumberCreation time (millisecond timestamp)
recentGameIdsstring[]Recently played games

wallet

MethodSignatureDescription
get() => Promise<WalletBalance>Balance snapshot { coins, gems, updatedAt }
getBalance(currency?: "coins" / "gems") => Promise<number>Balance for one currency, default coins
reward(input: WalletRewardInput) => Promise<WalletTransaction>Credit and return the transaction
spend(input: WalletSpendInput) => Promise<WalletTransaction>Debit; throws INSUFFICIENT_FUNDS when short
transactions(options?: { limit?: number; currency?: "coins" / "gems" }) => Promise<WalletTransaction[]>Recent transactions, newest first
interface WalletRewardInput {
  amount: number;
  reason: string;
  currency?: "coins" | "gems";
  type?: WalletTransactionType;
  idempotencyKey?: string;
}

interface WalletSpendInput {
  amount: number;
  reason: string;
  currency?: "coins" | "gems";
  idempotencyKey?: string;
}

interface WalletTransaction {
  id: string;
  userId: string;
  currency: "coins" | "gems";
  amount: number;        // signed: positive is a credit, negative a debit
  balanceAfter: number;
  type: WalletTransactionType;
  reason: string;
  gameId: string;
  idempotencyKey?: string;
  createdAt: number;
}

WalletTransactionType: "REWARD" | "SPEND" | "PURCHASE" | "AD_REWARD" | "MISSION_REWARD" | "ACHIEVEMENT_REWARD" | "ADMIN_ADJUST".

Amounts must be integers in [1, 10000] or the call throws INVALID_AMOUNT. Local mode uses a local ledger; remote mode is server-authoritative and supports idempotencyKey.

game

MethodSignatureDescription
getInfo() => Promise<GameInfo>First/recent play times and open count
start(meta?: { level?: number; mode?: string }) => Promise<GameSession>Open a session; returns { sessionId, startedAt }
finish(input: GameFinishInput) => Promise<GameFinishResult>Settle: record + stats + optional save/leaderboard
record(input: GameRecordInput) => Promise<GameRecord>Write a record without a session
saveProgress<T>(data: T, options?: { merge?: boolean }) => Promise<GameProgress<T>>Write a save; merge is shallow
loadProgress<T>() => Promise<GameProgress<T> / null>Read the save
getStats() => Promise<GameStats>{ playCount, bestScore, totalDurationMs, lastPlayedAt }
getRecords(options?: { limit?: number }) => Promise<GameRecord[]>Recent records, newest first
interface GameFinishInput {
  result: "complete" | "fail" | "quit";
  score?: number;
  level?: number;
  progress?: Record<string, unknown>;
  mergeProgress?: boolean; // defaults to true
  submitScore?: boolean;   // defaults to false
  boardId?: string;        // defaults to "global"
}

interface GameFinishResult {
  record: GameRecord;
  stats: GameStats;
  leaderboard: LeaderboardSnapshot | null;
}

interface GameProgress<T = Record<string, unknown>> {
  gameId: string;
  data: T;
  revision: number;
  gameVersion: string;
  sdkVersion: string;
  updatedAt: number;
  pendingSync?: boolean; // set in remote mode only
}

The leaderboard is submitted only when submitScore: true and score is a non-negative integer. A save over 256KB throws PAYLOAD_TOO_LARGE.

leaderboard

MethodSignatureDescription
submitScore(input: { boardId?: string; score: number; higherIsBetter?: boolean }) => Promise<LeaderboardEntry>Keeps only the better score
get(options?: { boardId?: string; limit?: number }) => Promise<LeaderboardSnapshot>Local or global board
interface LeaderboardSnapshot {
  boardId: string;
  scope: "local" | "global";
  localOnly: boolean;
  window: "all" | "weekly";
  entries: LeaderboardEntry[];
  self: LeaderboardEntry | null;
  total: number;
  updatedAt: number;
}

interface LeaderboardEntry {
  userId: string;
  nickname: string;
  score: number;
  rank: number;
  updatedAt: number;
}

boardId defaults to "global". Scores must be non-negative integers or the call throws INVALID_SCORE. The SDK currently always requests window: "all".

analytics

MethodSignatureDescription
track(name: string, properties?: Record<string, unknown>) => Promise<AnalyticsEvent>Queue an event; never throws
getQueue() => Promise<AnalyticsEvent[]>Current queue snapshot
flush() => Promise<{ sent: number; pending: number }>Batched upload in remote mode; local reports pending only
clear() => Promise<void>Clear the queue

Event names are 1–64 characters; properties over 8KB serialized are dropped; the queue keeps at most 500 events.

ads

MethodSignatureDescription
showRewarded(options: { placement: string; currency?: "coins" / "gems"; amount?: number; reason?: string }) => Promise<RewardedAdResult>Grants the reward idempotently after a full view
showInterstitial(options?: { placement: string }) => Promise<InterstitialAdResult>Interstitial; browser host returns shown: false
interface RewardedAdResult {
  completed: boolean;
  simulated: boolean;
  rewardGranted: boolean;
  reward?: { currency: "coins" | "gems"; amount: number };
  transactionId?: string;
}

placement defaults to "GAME_OVER" for interstitials. The default reward is 100 coins; never grant currency yourself.

storage (game-level KV)

MethodSignatureDescription
get<T>(key: string) => Promise<T / null>Read
set<T>(key: string, value: T) => Promise<void>Write a JSON-serializable value
remove(key: string) => Promise<void>Delete
keys() => Promise<string[]>Keys for the current game
persistentbooleanWhether storage is durable (false after memory fallback)

Keys are namespaced per gameId; identical keys in different games do not collide.

Module cheat sheet

ModuleMethodsDescription
accountgetCurrentUser() / updateProfile(patch)Guest profile (with accountCode / email / accountBound); shared same-origin
accounthasEmail()Whether an email is bound; always false locally
accountopenEmailBindDialog(options?)Email binding/rebinding dialog (bilingual, 60s resend countdown by default)
walletget() / getBalance(currency?)Balance snapshot; coins by default
walletreward({ amount, reason, currency?, type?, idempotencyKey? })Credit and return the transaction
walletspend({ amount, reason, currency?, idempotencyKey? })Debit; throws INSUFFICIENT_FUNDS when short
wallettransactions({ limit?, currency? })Recent transactions, newest first
gamegetInfo()First/recent play times and open count
gamestart(meta?) / finish(input)Session start and settlement (record + stats + optional save/leaderboard)
gamerecord(input)Write a record without a session
gamesaveProgress(data, { merge? }) / loadProgress()Save read/write; merge is shallow
gamegetStats() / getRecords({ limit? })Stats and recent records
leaderboardsubmitScore({ boardId?, score, higherIsBetter? }) / get(...)Keeps only the better score; local or global board
analyticstrack(name, properties?)Queue an event; never throws
analyticsgetQueue() / flush() / clear()Remote flush() uploads in batches; local reports pending
adsshowRewarded({ placement, currency?, amount?, reason? })Grants the reward idempotently after a full view
adsshowInterstitial({ placement })Interstitial; browser host returns shown: false
storageget/set/remove/keys + persistentGame-level KV
rootsdkVersion / gameId / mode / host / supports(capability) / sync()Version, mode and host capability probing

Type index

GroupKey types
Host and basicsHostKind, HostCapability, Currency
ConfigInstfunConfig, InstfunMode
AccountUserProfile, AccountModule, EmailBindDialogOptions, EmailBindResult
WalletWalletTransactionType, WalletTransaction, WalletRewardInput, WalletSpendInput, WalletBalance, WalletModule
GameGameProgress, GameSession, GameResult, GameRecord, GameStats, GameInfo, GameFinishInput, GameFinishResult, GameModule, SyncResult
LeaderboardLeaderboardEntry, LeaderboardSnapshot, LeaderboardModule
AnalyticsAnalyticsEvent, AnalyticsModule
AdsShowRewardedOptions, RewardedAdResult, ShowInterstitialOptions, InterstitialAdResult, AdsModule
StorageGameStorageModule
AggregateInstfunSdk

The complete TypeScript definitions live in the SDK package's types module.