Skip to content
GEMSARCADIA
▸ MANUAL CONTENTS(Coin flow)
GEMS ARCADIA · COIN-OP SERVICE MANUAL · FORM GA-DEV-1SEC. 1.2

Coin flow

Your game asks for a coin; the arcade takes it. The game never touches money, cookies or accounts, so the most a buggy (or hostile) game can do is ask.

Coin flow sequence diagram1. game to sdk: GemsArcadia.insertCoin(). 2. sdk to host: postMessage {__ga:1, type:"insertCoin"}. 3. host to host: check event.source + validate. 4. host to api: POST /api/play/sessions/:id/insert-coin. 5. api to wallet: $transaction: debit + 70% earning. 6. wallet to api: new balance. 7. api to host: 200 {insertionId, balance}. 8. host to sdk: response {ok:true, data}. 9. sdk to game: resolve {ok:true, insertionId}. 10. game to server: insertionId (receipt, support). 11. server to api: GET /api/v1/insertions/:id (API key). 12. api to server: {valid:true, coins, playerRef}.IFRAME SANDBOX · NO COOKIESYOUR GAMEsandboxed iframeSDK/sdk/v1.jsARCADE HOSTGameBridge pageCOIN API/api/play · /api/v1WALLETappend-only ledgerYOUR SERVERoptionalGemsArcadia.insertCoin()1postMessage {__ga:1, type:"insertCoin"}2check event.source + validate3POST /api/play/sessions/:id/insert-coin4$transaction: debit + 70% earning5new balance6200 {insertionId, balance}7response {ok:true, data}8resolve {ok:true, insertionId}9insertionId (receipt, support)10GET /api/v1/insertions/:id (API key)11{valid:true, coins, playerRef}12
Figure 1. One coin, from your game's button to the wallet ledger and back. Dashed arrows are replies. Steps 10–12 are optional server-side verification.

Step by step#

  1. YOUR GAME → SDK: GemsArcadia.insertCoin()
  2. SDK → ARCADE HOST: postMessage {__ga:1, type:"insertCoin"}
  3. ARCADE HOST: check event.source + validate
  4. ARCADE HOST → COIN API: POST /api/play/sessions/:id/insert-coin
  5. COIN API → WALLET: $transaction: debit + 70% earning
  6. WALLET → COIN API: new balance
  7. COIN API → ARCADE HOST: 200 {insertionId, balance}
  8. ARCADE HOST → SDK: response {ok:true, data}
  9. SDK → YOUR GAME: resolve {ok:true, insertionId}
  10. YOUR GAME → YOUR SERVER: insertionId (receipt, support)
  11. YOUR SERVER → COIN API: GET /api/v1/insertions/:id (API key)
  12. COIN API → YOUR SERVER: {valid:true, coins, playerRef}

Who does what#

Your game (sandboxed iframe)#

Runs in <iframe sandbox="allow-scripts allow-pointer-lock allow-fullscreen"> without allow-same-origin. It has an opaque origin, no access to the player's cookies, and a Content-Security-Policy that only lets it load its own files. It talks to the outside world through one channel: postMessage to the arcade page, wrapped by the SDK.

The SDK#

Wraps each call in an envelope { __ga: 1, id, type, payload }, posts it to the arcade's origin only, and matches the reply by id. It ignores messages from anything but its parent window and the arcade origin. Calls that get no answer time out after 10 seconds.

The arcade host page#

Accepts messages only when event.source is the game's iframe, validates every payload, and allows one insertion in flight at a time. It then calls the play API with the player's session cookie, adding an idempotency key so a retried request can never charge twice.

The coin API and wallet#

POST /api/play/sessions/{id}/insert-coin runs one database transaction that appends a debit to the player's coin ledger, records the insertion and records your 70% earning. Balances are derived from the append-only ledger, never edited in place.

Steps 10–12: server verification (optional)#

Every successful insertion has an insertionId. If your own backend needs to trust a purchase (a support request quoting the receipt code your game showed, an unlock you store yourself), it can confirm the id with your API key. See server verification.

REV 1.0 · KEEP THIS MANUAL WITH THE CABINET · QUESTIONS? ASK GLINT