We recommend referencing our React experience template to see how these concepts work together in practice.
You are free to use any frontend technology you want (React, Vue, Svelte, etc.) to build your experience.
An "experience" is a game embedded on a MoneyPot casino in an <iframe>
.
Here are some examples:
Experiences talk to a @moneypot/hub game server to authenticate MoneyPot users, manage player balances, and implement API endpoints specific to the game.
Experiences are also expected to implement some PostMessage events to communicate with the casino.
Anyone can create an experience at moneypot.com/me/developer where you must provide two things:
Once you create an experience, you can access it at https://moneypot.com/play/{username}/{experienceId}
. You can also set a permanent slug
for the experience to give it a prettier URL like /play/user1/my-game
.
When a player visits that page, MoneyPot creates a userToken
(a JSON Web Token) for them and passes it to the experience through the iframe url:
<iframe src="https://my-game.example.com#userToken={userToken}" />
When the experience loads in the iframe, it parses the userToken
and it derives the casinoBaseUrl
(the url of the MoneyPot casino that embedded it).
This information is sufficient to know which MoneyPot player is playing the game.
The casino shows a loading screen on the /play/{username}/{experienceId}
page until the experience is ready.
The experience posts the status message to the casino when it's ready to be revealed:
parent.postMessage({ type: "status", status: "ready" }, "*");
Or, if the experience hit an error that it can't recover from (like if the hub server is down), then:
parent.postMessage({ type: "status", status: "fatal" }, "*");
More info: PostMessage API docs explain, the experience can tell the casino that it's ready by posting a message to the parent.
Here's a bub server that implements the wheel game: wheel-controller.moneypot.com.
If you add a new mutation, you can see that there's a hubAuthenticate
mutation:
mutation Authenticate { hubAuthenticate( input: { casinoBaseUrl: "https://moneypot.com", userToken: "..." } ) { success { experienceId sessionKey uname userId } } }
The hub server verifies the userToken JWT, extracts the token, and exchanges it with the MoneyPot API to get the player's info.
The hub server then ensures the player exists in its own database and creates its own session for the player.
Now we can store sessionKey
on the client to make authenticated requests to the hub server:
fetch("https://wheel-controller.moneypot.com/graphql", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `session:${sessionKey}`, }, body: JSON.stringify({ query: "..." }), });
(Our React template shows how you can set up graphql codegen and TanStack Query to work with a graphql API in a pleasant, type-safe way.)
Once the player is authenticated (and any time the player's balance changes), the experience is required to post the player's balances to the casino.
parent.postMessage( { type: "playerBalances", balances: { HOUSE: 100, BTC: 123, }, }, "*" );
The hub server offers a graphql subscription that the experience can subscribe to for knowing when to fetch the player's latest balances from the hub server:
subscription PlayerBalanceAlert { hubBalanceAlert { currencyKey } }
Notice that the alert doesn't tell us the player's balance, just that the balance has changed.
The experience is expected to fetch the latest balances from the hub server:
query PlayerBalances { hubCurrentUser { hubBalancesByUserId { nodes { id currencyKey amount hubCurrencyByCurrencyKeyAndCasinoId { key displayUnitScale displayUnitName } } } } }
That will return something like:
{ "data": { "hubCurrentUser": { "hubBalancesByUserId": { "nodes": [ { "id": "0ffaece8-8d94-4592-ba8c-ce20afbd122a", "amount": 123, "hubCurrencyByCurrencyKeyAndCasinoId": { "key": "BTC", "displayUnitScale": 100, "displayUnitName": "bits" } }, { "id": "0ffaece8-8d94-4592-ba8c-ce20afbd122b", "amount": 100, "hubCurrencyByCurrencyKeyAndCasinoId": { "key": "HOUSE", "displayUnitScale": 1, "displayUnitName": "tokens" } } ] } } } }