Experience development

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.

How an experience works

Anyone can create an experience at moneypot.com/me/developer where you must provide two things:

  1. Controller ID: The underlying controller that uses the MoneyPot API to authenticate users, detect deposits, and send withdrawals.
    • This cannot be changed.
    • You can create one here: moneypot.com/me/developer/controllers
    • A controller can be summarized as a "sub-user" that you can create: it holds a balance and has API keys to manage its balance. The hub server uses the controller's API keys to make requests to MoneyPot.
    • You generally own the controller and run your own hub server that uses its credentials, but that's not required; You can also use someone else's controllerID and point your experience at their hub server.
  2. Iframe URL: URL to the game frontend.
    • You can always change this later.

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.

Telling the casino that the experience is ready

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.

Authenticating a player

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,
    },
  },
  "*"
);

Subscribing to player balance updates

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"
            }
          }
        ]
      }
    }
  }
}