LiaDevelopers

Guides

Pay players in $LIA from your app's reward pool, from your server. A daily bonus as the example, safe to retry and within your limits.

Your app needs a reward pool, funded by the Lia team (see Reward pools). Rewards only ever come from your server, with your key.

#A daily bonus

Each player can claim 2 LIA once a day, after finishing a level.

server.js
import { lia } from "./lia.js";

app.post("/api/daily-bonus", async (req, res) => {
  const playerId = await playerFrom(req.body.session); // see Verify on your server
  if (!playerId) return res.status(401).end();
  if (!(await db.finishedALevelToday(playerId))) return res.status(403).json({ error: "play_first" });

  const day = new Date().toISOString().slice(0, 10); // 2026-11-01
  try {
    const result = await lia("POST", "/rewards", {
      playerId,
      amount: 2,
      key: `daily:${day}:${playerId}`, // one a day per player, however often this runs
      reason: "Daily bonus",
    });
    res.json({ paid: result.status === "paid", amount: result.amount });
  } catch (error) {
    if (error.data?.error === "pool_empty") return res.status(503).json({ error: "bonus_paused" });
    if (error.data?.error === "daily_limit") return res.status(429).json({ error: "come_back_tomorrow" });
    throw error;
  }
});

In the page:

JavaScript
const { paid, amount } = await api("/api/daily-bonus", {});
if (paid) {
  Lia.haptic("success");
  Lia.toast("+" + amount + " LIA");
}

#Choosing keys

The key is what makes a reward safe. The same key never pays twice, so make it name the reason for the reward, not the request:

RewardKey
A daily bonusdaily:2026-11-01:p_3f9c…
A tournament placetournament-44:place-1:p_3f9c…
A finished questquest-7:p_3f9c…
A watched videoad:ad_8e1c…

A retry with the same key after a timeout answers { "status": "duplicate" } and pays nothing more, so retrying is always safe. Never retry with a new key.

#Keep an eye on the pool

JavaScript
const { balance, dailyCapPerPlayer } = await lia("GET", "/pool");
if (balance < 100) alertTheTeam(`Reward pool is down to ${balance} LIA`);

When the pool can't cover a reward, POST /rewards answers 409 pool_empty. Tell players kindly and ask the Lia team to top it up. When a player has had your app's daily limit, it answers 429 daily_limit (the limit is per player per UTC day, set by the team).

#In test

With your test key, rewards are pretend: recorded, with their webhook, but no $LIA moves, and the pool and daily limit aren't used. Try your keys and your error handling there first.

#Make rewards fair

  • Decide on the server. What someone earned should come from what your server saw (a finished game, a verified video), not from the page saying so.
  • Mind your own limits too, per player and per day, so one player can't drain the pool.
  • Say why. The reason shows in the player's activity under your app's name.

Type to search every page, method and endpoint.