Reliability: retries, idempotency and offline
How the SDK survives dropped connections and retries: the durable outbox, idempotency keys, and the error contract.
Games run on flaky mobile networks and tabs that sleep. The SDK is built so a dropped connection or a retried request never corrupts state: you write calls the obvious way and the durability is automatic.
Automatic retries with backoff
Transient failures (429 rate limited, 5xx, and network errors) are retried automatically with exponential backoff that honors a Retry-After header. A 401 on a player call triggers exactly one silent token refresh, then retries. You only see an error once retries are exhausted, and it's always a typed TriggairError.
The durable outbox
Analytics events and cloud saves flow through a durable outbox persisted in local storage. If the connection drops they replay on reconnect (and on an interval, and on the browser's `online` event). Events coalesce by name (counts summed) and saves coalesce by slot (last-write-wins), so a backlog flushes compactly. The flush is best-effort background work: it never throws into your game loop.
tg.track('level_complete'); // queued; survives a reload or offline spell
tg.saves.queue('slot1', data); // durable save — replays on reconnect Idempotency keys
Every outbox item carries a stable Idempotency-Key, so a replay after a failure resends the identical request under the identical key and the server dedupes it, so a batch is applied at most once. For grants you trigger directly (a purchase, a loot open, a gift), pass your own idem key so a double-tap or a client retry can't double-charge or double-grant.
await tg.economy.buy('main_store', listingId, { idem: uuid });
await tg.economy.loot.open('bronze_box', { idem: uuid }); At-least-once vs exactly-once
Analytics events are at-least-once: coalesced counts can over-deliver slightly, so never derive currency from a raw event count. Anything that grants value is exactly-once: it flows through the inbox and is granted only when the player claims it (see the Inbox and rewards guide). The split is deliberate: cheap telemetry is lossy-safe; money is audited.
The error contract
Every failure is a TriggairError with { code, message, agentHint, requestId }. code is stable and machine-checkable; agentHint tells you (or your AI) how to fix the call; requestId is what you quote in a bug report. Branch on code, never on message text.
try {
await tg.economy.buy('main_store', id, { idem });
} catch (e) {
if (e.code === 'insufficient_funds') promptTopUp();
} - Getting started
Keys, anonymous identity, and the one-import integration loop.
- Player accounts and login
Optional email/password login on top of anonymous-first, so a player keeps one identity across devices.
- Customizing account emails
Override the HTML of the emails Triggair sends your players (confirm signup, reset password, and more), per game, from the dashboard, API, or MCP.
- Built for coding agents
llms.txt, an MCP server, self-fixing errors, and a one-command self-test, so an agent can integrate the backend itself.
- Game engines and raw HTTP
Integrate from Unity, Godot, or any HTTP client. The SDK is JavaScript, but the API is plain REST with header auth and a full OpenAPI spec.