सीधे सामग्री पर जाएँ

Developers / Docs

Developer docs

Your first game in about five minutes, then everything else: the launch API, events, tables, the network, webhooks and the SDKs.

Your first game in five minutes

Pick your platform: install, ask your server for a launch link, show it. No developer? The last tab needs no code at all.

  1. Install

    npm install playmez-embed

    One script tag, or npm install playmez-embed. Any site, any framework.

  2. Ask your server for a launch link

    Your API key stays on your server. Each link is for one player and works once, within five minutes.

    launch.mjs
    // Node 18+. The API key stays on your server; the page or app only ever sees launchUrl.
    const res = await fetch("https://api.playmez.com/partner/launch", {
      method: "POST",
      headers: { "Content-Type": "application/json", "X-Api-Key": process.env.PLAYMEZ_API_KEY },
      body: JSON.stringify({ game: "ludo", externalUserId: user.id, displayName: user.name }),
    });
    const { launchUrl } = await res.json(); // one use, valid for five minutes
    // Drop-in helper with error handling: https://playmez.com/sdk/server/launch.mjs
  3. Show the game

    index.html
    <!-- launchUrl comes from your server (see step 2). -->
    <script src="https://playmez.com/sdk/playmez.js"></script>
    <div id="ludo-game"></div>
    <script>
      const game = Playmez.mount(document.getElementById("ludo-game"), {
        launchUrl,
        height: 720,
        title: "Ludo",
        onEvent: (e) => {
          if (e.type === "ready") console.log("Ludo open");
          if (e.type === "result") console.log(e.won ? "won" : "lost", e.net, "points"); // one event when the match ends
          if (e.type === "close") showYourOwnScreenAgain();
          if (e.type === "error") console.error(e.code, e.message); // fetch a new launchUrl
        },
      });
      // game.unmount() removes the frame.
    </script>

Testing? Your portal's Try it tab launches a real game with your key and shows the events and the server call side by side.

Code for every game, every platform

Choose a game and a platform. Copy the samples, drop in the file, done.

1 · Pick a game

Every sample below is written for the game you choose. The code beside each name is the `game` value you send.

Ludo · vs computer · Classic Indian Ludo for 2 or 4 players. Bring all four tokens home first; free tables or a points pot. Frame height about 720 px.

2 · Your server gets a launch URL

Server to server, with your API key. The URL works once, for five minutes, and opens the same Playmez account for the same externalUserId every time.

launch.mjs
// Node 18+. The API key stays on your server; the page or app only ever sees launchUrl.
const res = await fetch("https://api.playmez.com/partner/launch", {
  method: "POST",
  headers: { "Content-Type": "application/json", "X-Api-Key": process.env.PLAYMEZ_API_KEY },
  body: JSON.stringify({ game: "ludo", externalUserId: user.id, displayName: user.name }),
});
const { launchUrl } = await res.json(); // one use, valid for five minutes
// Drop-in helper with error handling: https://playmez.com/sdk/server/launch.mjs
Download the full helper (server/launch.mjs)

3 · Show the game

The page or app opens the launch URL. The game runs on Playmez; your side never hosts game code, decides outcomes or holds balances.

npm install playmez-embed
Needs: One script tag, or npm install playmez-embed. Any site, any framework. playmez.js
ludo.html
<!-- launchUrl comes from your server (see step 2). -->
<script src="https://playmez.com/sdk/playmez.js"></script>
<div id="ludo-game"></div>
<script>
  const game = Playmez.mount(document.getElementById("ludo-game"), {
    launchUrl,
    height: 720,
    title: "Ludo",
    onEvent: (e) => {
      if (e.type === "ready") console.log("Ludo open");
      if (e.type === "result") console.log(e.won ? "won" : "lost", e.net, "points"); // one event when the match ends
      if (e.type === "close") showYourOwnScreenAgain();
      if (e.type === "error") console.error(e.code, e.message); // fetch a new launchUrl
    },
  });
  // game.unmount() removes the frame.
</script>

Try the same flow live on the demo page with your key.

4 · Listen for events

Events

Every message is { source: "spinline", type, ...fields }. Websites receive it with postMessage; React Native, Flutter, Android and iOS get the same JSON through their bridge.

typefieldswhen
readygameThe player is seated and the game is on screen.
resultgame, won, netA match, round or reward settled for this player. net is in virtual points.
close—The player tapped Leave or Close. Hide or remove the frame.
errorcode, messageThe game could not open. Fetch a new launch URL.
resizeheightReserved for pages that grow with their content.

Errors

HTTP codes come back from POST /partner/launch. Event codes arrive as an `error` event inside the frame; fetch a new launch URL.

codewheremeaning
INVALID_API_KEY401Unknown, rotated or switched-off key.
INVALID_GAME400game is not one of the ids above.
ACCOUNT_BANNED403This player is banned on Playmez.
LAUNCH_EXPIREDeventThe launch URL was older than five minutes.
LAUNCH_USEDeventThe launch URL was already opened once.
PARTNER_DISABLEDeventGames are switched off for this partner.

Shared tables: your players at one table, talking

Create a table from your server, then launch each player with its code. They sit together, and computer players can fill what is left. Table chat and voice (peer to peer, no audio through any server) switch on per partner; ask us and they appear inside your frames.

1. Create a table (server to server)

The host is one of your players; the table closes itself when nobody is there.

create-table.js
const res = await fetch("https://api.playmez.com/partner/tables", {
method: "POST",
headers: { "Content-Type": "application/json", "X-Api-Key": process.env.PLAYMEZ_API_KEY },
body: JSON.stringify({ game: "callbreak", hostExternalUserId: "user-123", name: "Friday Callbreak", computerFill: false }),
});
const { tableCode } = await res.json(); // e.g. "K7Q2MZ"

2. Launch every player with the code

Same launch call as above, plus tableCode. Each player gets their own one-time link.

launch-at-table.js
const launch = await fetch("https://api.playmez.com/partner/launch", {
method: "POST",
headers: { "Content-Type": "application/json", "X-Api-Key": process.env.PLAYMEZ_API_KEY },
body: JSON.stringify({ game: "callbreak", externalUserId: "user-456", displayName: "Anoop", tableCode }),
}).then((r) => r.json());
// launch.launchUrl -> mount it exactly as before; the player lands at the shared table.
// GET /partner/tables/K7Q2MZ returns { seated, connected, phase, status } while it runs.

Chat and voice in your frames

Both are off until you ask. Chat is the table chat (deleted when the table closes). Voice is peer to peer between the players at a private table; the SDK frame already carries allow="microphone", and native wrappers need the WebView microphone permission (notes in each drop-in README).

Players hear only the people at their table, never strangers; nothing is recorded.

The Playmez network: live people across every app

One game build runs inside every SDK and on playmez.com, talking to one server. So a player in your Flutter app, one in your React Native app, one in another partner's Android app and one in Chrome on playmez.com can sit at the same Ludo table, live, with the same board, chat and notices. Tables fill from the first minute because every partner's audience joins one pool; you never have to find the opponents.

Who meets whom

Decided by how you launch, never by the device or the framework.

  • mode: "online"

    Your players, playmez.com players and every other partner in the network, matched in one pool. Needs the network switched on in your portal.

    Your two stranger switches decide whether your players can talk with people from outside your app.

  • tableCode

    Only the people launched with that code, from any of your apps (web, React Native, Flutter, Android, iOS), plus anyone you give the playmez.com join link to. Another partner's launch is refused.

    Your own-table chat and voice switches.

  • mode: "local"

    Offline on the phone: alone against the computer in every game, or people passing the phone (Ludo, Chess, Carrom, 8-Ball Pool). Nobody from outside, and names stay on the phone.

    Chat and voice off: nobody else is at the table.

  • no mode (default)

    The computer only. Nobody from outside.

    Chat and voice off.

Launch a player into the pool

Same call as a solo launch, plus mode. After 25 seconds without a match the player can switch to the computer.

launch-online.js
const launch = await fetch("https://api.playmez.com/partner/launch", {
method: "POST",
headers: { "Content-Type": "application/json", "X-Api-Key": process.env.PLAYMEZ_API_KEY },
body: JSON.stringify({ game: "ludo", externalUserId: "user-456", displayName: "Anoop", mode: "online" }),
}).then((r) => r.json());
// launch.launchUrl -> mount it as usual. Ludo, Callbreak, Rummy, Chess, Carrom, 8-Ball Pool and Teen Patti are network games.

What stays yours

Your players are your accounts: points, level and history stay under your partner record, and no partner learns which app, or whether playmez.com, another player came from (unless both opted into cross-promotion, below, which shows a vetted brand and nothing more).

Results reach your webhook for your players only, marked network: true when the match was at a public table. Your private tables and tournaments never appear in Playmez's public lists.

A game never ends because of a bad connection or a Playmez update: a player who drops is played by the computer until they are back (up to three minutes), and every live table carries on across our deploys.

Your brand in every app

Optional, off until you ask, and on your terms.

Network tables show where each player came from: your brand inside the other apps and theirs inside yours, in the waiting lobby and in a strip above the board. You choose what your players see (all apps, Playmez only or none), whether they can open other apps, and the apps or kinds of app you never appear with. See it in a game.

Webhooks: results pushed to your server

No polling. Set a URL and Playmez posts every settled result, new player, opened session and closed table to your server. Each delivery is signed with HMAC-SHA256 and retried for about 35 hours until you answer 2xx.

1. Point us at your URL

https only. The signing secret is shown once.

set-webhook.js
// Once, from your server. The secret comes back only this time: store it with your API key.
const res = await fetch("https://api.playmez.com/partner/webhook", {
  method: "PUT",
  headers: { "Content-Type": "application/json", "X-Api-Key": process.env.PLAYMEZ_API_KEY },
  body: JSON.stringify({ url: "https://example.com/playmez/webhook" }),
});
const { url, secret } = await res.json(); // secret: "whsec_…" (first time) or null
// POST /partner/webhook/test sends a webhook.test; GET /partner/webhook/deliveries lists what was sent.

Events

Body: { id, type, createdAt, partner: { id, slug }, data }

  • player.createdplayer { id, externalUserId, displayName }

    One of your user ids opened a game for the first time and got a Playmez account.

  • session.openedplayer, game, tableCode

    A player opened a launch URL and is in the game.

  • player.resultplayer, game, won, net, withBots, matchId, tableCode, network

    A match (turn games) or round (round games) settled for this player. net is in virtual points; network is true for a match on the Playmez network (tableCode is then null).

  • table.closedtableCode, tableId, game

    A table you created with POST /partner/tables closed.

  • tournament.startedtournament { id, name, game, startsAt, endsAt }

    A tournament you created began scoring.

  • tournament.finishedtournament, standings [{ rank, player, netPoints, wins, roundsPlayed, prize }]

    A tournament you created ended; standings are final.

  • tournament.prize_awardedtournament, rank, prize { label, code }, player (your own player) or visitor (anyone else)

    A tournament you sponsor ended and a winner got one of your coupons. player { id, externalUserId, displayName } only for your own players; others are an anonymous visitor tag.

  • mission.completedmission { id, title, kind, game, target, period }, periodKey, player { id, externalUserId, displayName }, completedAt, sandbox

    One of your players finished a mission you set. Give the reward in your app; the same mission, player and period is never sent twice.

  • webhook.test{}

    You asked for a test delivery.

2. Verify every delivery, then answer 2xx

Headers: Playmez-Event, Playmez-Delivery, Playmez-Timestamp, Playmez-Signature (v1=hex), Playmez-Attempt.

webhook.js
import { createHmac, timingSafeEqual } from "node:crypto";

// Express: keep the raw body; the signature covers the exact bytes.
app.post("/playmez/webhook", express.raw({ type: "application/json" }), (req, res) => {
  const ts = req.header("Playmez-Timestamp");
  const expected = createHmac("sha256", process.env.PLAYMEZ_WEBHOOK_SECRET).update(`${ts}.${req.body}`).digest("hex");
  const given = (req.header("Playmez-Signature") ?? "").split(",").map((s) => s.trim()).filter((s) => s.startsWith("v1=")).map((s) => s.slice(3));
  const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
  if (!fresh || !given.some((g) => g.length === expected.length && timingSafeEqual(Buffer.from(g), Buffer.from(expected)))) return res.sendStatus(401);

  const event = JSON.parse(req.body); // { id, type, createdAt, partner: { id, slug }, data }
  if (event.type === "player.result") {
    // data: { player: { id, externalUserId, displayName }, game, won, net, withBots, matchId, tableCode }
  }
  res.sendStatus(200); // retries reuse event.id, so make handling idempotent
});
webhook.py
import hmac, hashlib, time

def verify(raw_body: bytes, signature: str, timestamp: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256).hexdigest()
    given = [p.strip()[3:] for p in signature.split(",") if p.strip().startswith("v1=")]
    fresh = abs(time.time() - int(timestamp or 0)) < 300
    return fresh and any(hmac.compare_digest(g, expected) for g in given)

# Flask: request.get_data() is the raw body; answer 2xx within 10 seconds.

Retries and inspection

  • No 2xx within 10 seconds, a redirect or a connection error: tried again after 1 min, 5 min, 30 min, 2 h, 8 h and 24 h, then marked failed.
  • Retries resend the same body and the same Playmez-Delivery id. Keep handling idempotent.
  • GET /partner/webhook/deliveries lists status, attempts and the last answer; POST /partner/webhook/deliveries/:id/redeliver queues one again. Kept 30 days.
  • The player object carries your externalUserId and the display name only, never the Playmez username or balance.
  • Full copy-paste receivers for Node and Python are in the drop-in files below.

Appearance: the frame looks like your product

Accent, background, text, corners and a Google font, applied before the first paint. Set them once in your portal with a live preview, or per launch.

Language

lang on a launch, or a default in your portal. English and Hindi today, covering every game; BCP 47 tags such as hi-IN are accepted.

launch-in-hindi.js
body: JSON.stringify({ game: "carrom", externalUserId: "user-123", lang: "hi" })
// The embed renders in Hindi from its first paint; the response echoes lang: "hi".

Per launch, or once for the partner

Every field is optional. The background must stay dark; text on the accent flips light or dark by itself.

launch-with-theme.js
const launch = await fetch("https://api.playmez.com/partner/launch", {
method: "POST",
headers: { "Content-Type": "application/json", "X-Api-Key": process.env.PLAYMEZ_API_KEY },
body: JSON.stringify({
  game: "ludo",
  externalUserId: "user-123",
  theme: { accent: "#1e90ff", background: "#101418", radius: "large", googleFont: "Poppins" },
}),
}).then((r) => r.json());
// Fields: accent, background, text (hex), radius (none | small | medium | large),
// font (spinline | system | rounded | serif | mono), googleFont (a fonts.google.com family).
// A bad value answers 400 INVALID_THEME with a problems list naming the field.

Tournaments for your players

One call opens a scored event across your own players. Every match they finish counts, a strip in the embed shows each player their rank, and the standings reach you in the portal, over the API and by webhook when it ends.

Create, then read the standings

Your tournaments never appear in Playmez's public events; only your players score in them.

tournament.js
const cup = await fetch("https://api.playmez.com/partner/tournaments", {
method: "POST",
headers: { "Content-Type": "application/json", "X-Api-Key": process.env.PLAYMEZ_API_KEY },
body: JSON.stringify({ name: "Friday Carrom Cup", game: "carrom", startsAt: "2026-10-30T14:00:00Z", endsAt: "2026-10-30T18:00:00Z" }),
}).then((r) => r.json());
// Later, or on the tournament.finished webhook:
const { standings } = await fetch("https://api.playmez.com/partner/tournaments/" + cup.id, { headers: { "X-Api-Key": process.env.PLAYMEZ_API_KEY } }).then((r) => r.json());
// standings[0] -> { rank: 1, player: { externalUserId: "user-123", displayName: "Asha" }, netPoints: 240, wins: 6, roundsPlayed: 9, prize: 0 }

The games

By default a launch opens the player's own table against the computer; round games open a private one-player table; rewards once a day. Shared tables, chat and voice are the section above.

  • Ludo

    Roll, race, capture.

    Classic Indian Ludo for 2 or 4 players. Bring all four tokens home first; free tables or a points pot.

    vs computergame: "ludo"720 px
  • Callbreak

    Call it. Make it.

    Four players, 13 cards each, spades always trump. Bid your tricks, then make them over 5 rounds.

    vs computergame: "callbreak"720 px
  • Rummy

    Group it. Declare it.

    13-card Indian Rummy for 2 to 6. Make a pure sequence, a second sequence and sets, then declare first. Free points, no cash.

    vs computergame: "rummy"720 px
  • Tambola

    Housie! Mark, claim, win.

    The caller draws 1 to 90, you daub your tickets. Early Five, lines, corners and Full House, up to 100 players a table.

    vs computergame: "tambola"720 px
  • Chess

    Rated games, real clocks.

    Bullet to rapid with increments, Elo ratings, computer opponents at three levels. Free tables or a points pot.

    vs computergame: "chess"720 px
  • Teen Patti

    Blind or seen. Chaal or show.

    Three cards, 2 to 6 players, blind and seen betting, sideshows of nerve. Virtual points only, never cash.

    vs computergame: "teen_patti"720 px
  • Carrom

    Flick. Pocket. Cover the queen.

    Two players, nine coins each and the red queen. Place the striker, flick, pocket your colour; cover the queen or she comes back. Free tables or a points pot.

    vs computergame: "carrom"720 px
  • 8-Ball Pool

    Break. Pot your group. Sink the 8.

    Two players, solids against stripes. Pot your seven, then the black; a foul hands your opponent the cue ball. Free tables or a points pot.

    vs computergame: "pool"720 px
  • Roulette

    Pick a colour, a number, a side.

    European single-zero wheel. Everyone watches the same spin.

    private tablegame: "roulette"640 px
  • Crash

    Cash out before it busts.

    A multiplier climbs from 1.00×. Cash out in time and multiply your stake; hold too long and lose it.

    private tablegame: "crash"640 px
  • Trivia Blitz

    Fast answers pay more.

    One question per round, four options. Correct doubles your stake, speed adds a bonus.

    private tablegame: "trivia"640 px
  • Spin the Wheel

    One free spin a day.

    A prize wheel with a published commitment. Free spins per day are set by Playmez; prizes are virtual points.

    daily rewardgame: "wheel"560 px
  • Scratch Card

    Three of a kind wins.

    A scratch card with a fair, revealed seed. Free cards per day are set by Playmez; prizes are virtual points.

    daily rewardgame: "scratch"560 px

Packages and files

Packages, version 2.1.0

One version for every platform. Install, import, done.

Drop-in files

Generated from the same packages, for projects that cannot add a dependency.

Security

  • The API key is a server secret. Never put it in a page, an app bundle or a public repository.
  • A launch URL works once, within five minutes. Fetch a fresh one every time a player opens a game.
  • Only the web origins you registered may frame the games. Native apps need no origin.
  • Outcomes, balances and timers are decided on Playmez's servers. Every match or round publishes a seed hash first and reveals the seed after.

Limits and rules

  • API base https://api.playmez.com. 600 launches per minute per key.
  • One game per frame. A player holds one seat per turn game at a time.
  • Practice matches against the computer are free. Round games stake virtual points from a welcome bonus and a daily allowance.
  • Virtual points only. No cash value. Points cannot be bought, sold, transferred or redeemed. You must not map points to money, prizes or anything of value.

Create your free account

Your points, history and level come with you. Pick a username and a password; it takes ten seconds.