WebView Integration
Complete Example & Troubleshooting
The full backend + client flow end to end, plus troubleshooting and links to related guides
This page brings the previous guides together into one end-to-end flow: a backend that owns the API key, and a client that opens the store.
The full flow
┌────────────┐ 1. request token ┌────────────┐ create-with-uuid ┌───────────┐
│ Your app │ ───────────────────────────▶ │ Your │ ────────────────────▶ │ PlaySuper │
│ (client) │ ◀─────────────────────────── │ backend │ federatedByStudio │ API │
└────────────┘ 2. access_token └────────────┘ └───────────┘
│ ▲
│ 3. open store URL in WebView │ 5. webhook on purchase/refund
▼ │
┌────────────┐ 4. player shops & redeems ┌───────────┐
│ WebView │ ────────────────────────────▶│ PlaySuper │
│ (store) │ │ store │
└────────────┘ └───────────┘- The app asks your backend for a store token.
- The backend find-or-creates the player and runs federated login (Authentication).
- The app builds the store URL (Store URL) and opens it in a configured WebView (WebView Setup, Platform Examples).
- The player browses and redeems rewards inside the store.
- Your backend hears about purchases and refunds via webhooks (Coins & Transactions).
Backend (Node.js / Express)
One service that issues store tokens, distributes coins, and receives webhooks:
const express = require('express');
const app = express();
app.use(express.json());
const API_BASE = process.env.NODE_ENV === 'production'
? 'https://api.playsuper.club'
: 'https://dev.playsuper.club';
const headers = {
'Content-Type': 'application/json',
'x-api-key': process.env.PLAYSUPER_API_KEY,
};
// 1. Issue a store token for the authenticated app user
app.post('/playsuper/token', async (req, res) => {
const uuid = req.user.id; // your app's user ID
// Find-or-create — safe to call every time
await fetch(`${API_BASE}/player/create-with-uuid`, {
method: 'POST',
headers,
body: JSON.stringify({ uuid }),
});
const login = await fetch(`${API_BASE}/player/login/federatedByStudio`, {
method: 'POST',
headers,
body: JSON.stringify({ uuid }),
});
const { access_token } = await login.json();
res.json({ accessToken: access_token });
});
// 2. Award coins when the user completes a rewarded action
app.post('/playsuper/reward', async (req, res) => {
const response = await fetch(
`${API_BASE}/coins/${process.env.PLAYSUPER_COIN_ID}/distribute`,
{
method: 'POST',
headers: { ...headers, 'x-game-uuid': req.user.id },
body: JSON.stringify({ amount: req.body.amount }),
}
);
res.json(await response.json());
});
// 3. React to store purchases and refunds
app.post('/webhooks/playsuper', (req, res) => {
const { reason, user_uuid, delta, new_balance } = req.body;
// Skip events from your own distribute calls
if (reason === 'GAME_CREDIT' || reason === 'GAME_DEBIT') {
return res.status(200).json({ received: true, skipped: true });
}
if (reason === 'PURCHASE_DEBIT') {
// e.g. notify the user, log the purchase, trigger an achievement
console.log(`${user_uuid} spent ${Math.abs(delta)} coins, balance ${new_balance}`);
} else if (reason === 'REFUND_CREDIT') {
console.log(`${user_uuid} was refunded ${delta} coins`);
}
res.status(200).json({ received: true });
});Verify the X-PlaySuper-Signature header on every webhook before trusting it — see Webhook Security.
Client
The client side is thin — fetch the token, then open the store screen for your platform:
// Pseudocode — the platform-specific screen is in Platform Examples
async function openRewardsStore() {
let token = getCachedToken();
if (!token) {
const res = await fetch('https://your-server.com/playsuper/token', { method: 'POST' });
token = (await res.json()).accessToken;
cacheToken(token);
}
showStoreScreen(token); // StoreActivity / StoreViewController / StoreScreen / StorePage
}Full screens for each platform are in Platform Examples.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Blank or broken store page | DOM storage disabled | Enable localStorage/DOM storage in the WebView settings |
| Player shown as logged out in the store | Missing or expired authToken | Re-run the federated login and reopen the store with a fresh token |
| Login works in dev but not production | Environment mismatch | A token from dev.playsuper.club only works with dev-store.playsuper.club — match API and store environments |
| Previous user's data appears after account switch | Stale WebView localStorage | Open the store once with clearSession=true |
404 from federated login | Player was never created | Call /player/create-with-uuid first — it is find-or-create and safe to call every launch |
400 Invalid coin for this game on distribute, or empty rewards | Coin not linked to the game | Link the coin to your game in the console — org-wide coins link automatically |
| Store layout looks wrong | Screen not locked to portrait | The store is portrait-only — lock the hosting screen's orientation |
| No webhook events arriving | Endpoint unreachable or misconfigured | Check the delivery history and confirm your endpoint returns a 2xx within 30 seconds |
Related guides
| Guide | Description |
|---|---|
| Console Setup | Set up your account, game, coins, and API key |
| API Reference | Distribute coins, fetch balances, and manage players via REST |
| Webhooks | Server-side notifications for coin transactions |
| Touchpoints API | Show reward widgets in your own app UI |
| Gift Card API | Purchase and distribute gift card vouchers |
| Unity SDK Guide | If your game is built with Unity, use the SDK instead |
Need help?
- Email: engineering@playsuper.club