FAHSWE

Developer documentation

Integrate hosted H5 games into Android, iOS, Flutter and web apps

This guide explains the secure production flow from your trusted backend to a full-screen or voice-room WebView. Game files stay on Fah Swe's global CDN; your app receives only a short-lived launch URL.

Security model

  • Create signed sessions from your backend—not from Flutter, Android, iOS or browser code.
  • Every launch URL is short-lived, single-session and checked against an active subscription and game entitlement.
  • Wallet callbacks are signed and idempotent; verify signatures and reject reused nonces.
  • Validate WebView message origins and accept only documented event types.

Production launch flow

  1. 1Your app authenticates the user with your own login system.
  2. 2Your backend requests a one-time game session using the private app secret.
  3. 3Your backend returns only the launch URL to the mobile app.
  4. 4The app opens the URL in a WebView using full or voice-room layout.
  5. 5Fah Swe validates subscription, entitlement, expiry and session state on the server.

1. Create the session on your backend

Node.js / TypeScript
// Your trusted backend only — never put appSecret in a mobile app
const response = await fetch("https://game-api.fahswe.com/v1/sessions", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-App-Id": process.env.FAHSWE_APP_ID!,
    "X-Timestamp": timestamp,
    "X-Nonce": nonce,
    "X-Signature": createHmacSignature(body, timestamp, nonce),
  },
  body: JSON.stringify({
    gameId: "food-wheel",
    externalUserId: user.id,
    layout: "voice", // "full" or "voice"
  }),
});
const { launchUrl } = await response.json();

2. Open the launch URL in your client

Flutter (Dart)
final controller = WebViewController()
  ..setJavaScriptMode(JavaScriptMode.unrestricted)
  ..addJavaScriptChannel('FahSweGame', onMessageReceived: (event) {
    final message = jsonDecode(event.message);
    if (message['type'] == 'game.close') Navigator.pop(context);
  })
  ..loadRequest(Uri.parse(launchUrl)); // URL received from your backend
Android (Kotlin / Java bridge)
webView.settings.javaScriptEnabled = true
webView.settings.domStorageEnabled = true
webView.addJavascriptInterface(GameBridge(), "FahSweGame")
webView.loadUrl(launchUrl) // one-time URL from your backend

class GameBridge {
  @JavascriptInterface fun postMessage(json: String) {
    // Parse an allow-listed event: game.ready, game.close, wallet.refresh
  }
}
iOS (Swift / WKWebView)
let controller = WKUserContentController()
controller.add(self, name: "FahSweGame")
let config = WKWebViewConfiguration()
config.userContentController = controller
let webView = WKWebView(frame: .zero, configuration: config)
webView.load(URLRequest(url: launchUrl)) // obtained from your backend
React Native
<WebView
  source={{ uri: launchUrl }}
  javaScriptEnabled
  domStorageEnabled
  originWhitelist={["https://games.fahswe.com"]}
  onMessage={({ nativeEvent }) => {
    const event = JSON.parse(nativeEvent.data);
    if (event.type === "game.close") navigation.goBack();
  }}
/>
Web / iframe
<iframe
  src={launchUrl}
  title="Fah Swe game"
  allow="autoplay; fullscreen"
  sandbox="allow-scripts allow-same-origin"
  referrerPolicy="strict-origin-when-cross-origin"
/>
// Validate event.origin === "https://games.fahswe.com" before processing.

Bridge events

Games send versioned JSON messages such as game.ready, game.close, game.result and wallet.refresh. Treat messages as untrusted input, validate the origin, type and payload, and never accept a balance supplied by the WebView.

Subscription and downtime behavior

Only active subscribers can create sessions. During the configured grace period, the game shows a payment warning. After grace expires, new sessions are blocked. A verified paid invoice reactivates service through the backend automatically.

Virtual entertainment only

Fah Swe does not provide gambling, cash wagering, cash redemption or transferable-value credits. Integrators are responsible for age controls, store policies, local law and truthful in-app disclosures.