In-game economy
- Written for
- + Written for
- Deprecated
- + Deprecated
- Applies to
- + Applies to
In-game economy
You can sell items inside your game for coins, the platform-wide virtual currency players earn on Cool GPT Games. You define a small store of items (SKUs) for your game. Players buy them from inside the game with GameSDK.economy.purchase(sku), and the platform records a permanent entitlement: "this player owns this SKU in this game."
Coins are a virtual currency with no real-money value. Players can't buy coins with money, and neither players nor creators can cash coins out, exchange them, or redeem them for anything outside the platform. Don't describe coins, items or prizes as having monetary value in your game.
For exact signatures and failure modes, see GameSDK reference: ads, economy & tournaments.
How it fits together
Piece | Who | How |
|---|---|---|
Define items | You (creator) | Your game's dashboard page (Store), the REST API, or the Publisher SDK |
Show the store | Your game |
|
Buy an item | Signed-in player, from your game |
|
Check what a player owns | Your game |
|
Receive the coins | You | Each paid sale credits the item's price in coins to your coin balance |
Where players get coins
Players earn coins across the whole platform, not per game. For example, they earn coins when XP is granted, from level-up bonuses and daily rewards, from friends' gifts, and from tournament prizes. See XP, achievements & social and Tournaments. Your game can't grant coins directly. It can only spend a player's coins through purchase.
There's no coin top-up or coin purchase. If a player is short of coins, tell them so, and don't send them to buy coins.
Items and SKUs
Each item belongs to one game and is identified by its SKU.
Field | Type | Rules |
|---|---|---|
| string | 1–64 characters: letters, digits, |
| string | 1–80 characters |
| string | Optional, up to 300 characters |
| integer | 0 to 1,000,000. |
| boolean | Optional, defaults to |
A game can have up to 200 items. Editing an existing SKU always works, even at the limit. Only new SKUs count toward it.
Durable only: there are no consumables
Every item is a permanent, one-time unlock per player. Buying a SKU the player already owns doesn't charge them again. It returns alreadyOwned: true. There's no quantity, no stacking and no "use up" operation.
Good fits: skins, cosmetic themes, level packs, a permanent ability, "remove a feature limit".
Not supported: "5 extra lives", "100 gems", repeatable boosts. You can't sell the same SKU to the same player twice.
Defining items
Dashboard: open your game in the creator dashboard and use the Store section to add, edit, deactivate or delete items.
REST (API key with the economy scope; you must own the game):
Method and path | Body | Returns |
|---|---|---|
|
|
|
| none |
|
| none |
|
:id is your game's id, not its slug.
curl -X POST https://api.coolgptgames.com/v1/dev/games/$GAME_ID/items \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/json" \
-d '{"sku":"skin_gold","name":"Gold Skin","description":"Shiny.","priceCoins":250}'await client.upsertItem(gameId, { sku: "skin_gold", name: "Gold Skin", priceCoins: 250 });
const items = await client.listItems(gameId); // all items, including inactive
await client.deleteItem(gameId, "skin_gold");See Publisher SDK for client setup and API keys & scopes for the economy scope.
Upserts replace the whole item. A POST for an existing SKU overwrites name, description, priceCoins and active:
Leaving out
descriptionclears it.Leaving out
activesets the item back to active.
Always send every field you want to keep.
Changing, deactivating and deleting items
Price changes take effect for the next purchase. Players who already own the item aren't affected. - Deactivating (
active: false) hides the item fromlistItemsand makespurchasefail withnot_found. Players who already own it keep the entitlement. It still appears ingetEntitlements.Deleting removes the item definition only. Existing entitlements aren't removed. Players keep owning the SKU. If you later re-create the same SKU, those players already own it.
Use deactivation, not deletion, to retire an item, and keep honouring owned SKUs in your game code.
Using the store in your game
async function openStore() {
const [items, ent] = await Promise.all([
GameSDK.economy.listItems(),
GameSDK.economy.getEntitlements(),
]);
const owned = new Set((ent && ent.owned) || []);
renderStore((items || []).map(function (it) {
return { sku: it.sku, name: it.name, price: it.priceCoins, owned: owned.has(it.sku) };
}));
}
async function buy(sku, button) {
button.disabled = true; // never fire two purchases at once
const r = await GameSDK.economy.purchase(sku);
button.disabled = false;
if (r && r.ok) {
unlock(sku); // purchased or alreadyOwned
showBalance(r.coins);
} else if (r && r.error === "sign_in_required") {
showMessage("Sign in to buy items.");
} else if (r && r.error === "insufficient_coins") {
showMessage("Not enough coins yet. Keep playing to earn more!");
} else if (r === null) {
// Timed out or no answer. The purchase MAY have gone through, so re-check ownership.
const ent = await GameSDK.economy.getEntitlements();
if (ent && ent.owned.indexOf(sku) !== -1) unlock(sku);
} else {
showMessage("Purchase failed. Please try again.");
}
}Unlocking on load
Call getEntitlements() when the game starts and unlock everything in owned. That way, ownership follows the player across devices and sessions without any save data. Don't store "owned" flags in your own save as the source of truth. The entitlement list is authoritative.
Purchase semantics
When a signed-in player calls purchase(sku):
The platform looks up an active item with that SKU on this game. If there isn't one, the result is
{ error: "not_found" }.Everything else happens in one atomic transaction: - The entitlement is recorded first. If the player already owns the SKU, nothing else happens and the result is
{ ok: true, alreadyOwned: true, coins }. They aren't charged.If the price is above 0, the price is debited from the player's coins and the same number of coins is credited to the game's creator. If the balance is too low, the result is
{ error: "insufficient_coins" }and the whole transaction is undone: nothing is charged and no entitlement is recorded.If the price is 0, there's no coin movement.
Either all of it happens or none of it does.
The result is
{ ok: true, purchased: sku, coins }, wherecoinsis the player's balance after the purchase.
The SDK fires the purchase event only when the purchase succeeded (ok: true, including alreadyOwned: true). It doesn't fire for { error } results or a null timeout. See the reference.
Purchases need the player's own signed-in session. Spending a player's coins is only allowed from the player's signed-in session on Cool GPT Games. Inside the game page that's automatic: the page makes the request with the player's session, and your game never handles it. The purchase endpoint refuses API keys (403 session_required), so you can't buy items on a player's behalf from your own server.
Double-purchase protection and idempotency
Repeats are safe. Buying an owned SKU returns
alreadyOwned: trueand charges nothing, so a "Buy" button that the player taps again after success is harmless.Concurrent purchases of the same SKU can't double-charge. Only one of them records the entitlement and is charged. The others resolve
alreadyOwned: true.Disable the Buy button until the promise settles anyway, as in the example above, so the player sees one clear result. - There's no idempotency key for purchases. A
nullresult (timeout) doesn't mean the purchase failed. CheckgetEntitlements()before offering a retry. Retrying is safe: if the first attempt went through, the retry returnsalreadyOwned: truewithout charging again.
Refunds
There's no refund or revoke operation for item purchases, neither for players nor through the creator API. Deleting or deactivating an item doesn't return coins to anyone. Describe items accurately before sale.
Limits
Limit | Value |
|---|---|
Items per game | 200 |
Purchases | 60 per minute per player (exceeding it returns |
SDK response timeout | 6 seconds per call; after that the promise resolves |
SDK messages to the page | 30 per second across all SDK calls; extras are silently dropped |
Guests
Call | Guest result |
|---|---|
| Works normally, since the store is public |
|
|
|
|
Show guests the store with prices, but prompt them to sign in when they try to buy.
What you earn from sales
Each paid sale credits the item's full price, in coins, to your own coin balance. That's the same balance you can spend as a player or use to fund tournament prize pools (see Tournaments). Coins from sales are not money and aren't part of your ad-revenue earnings or payouts. See Ads and rewarded ads for how creator payouts work.
Related
Tournaments: funding prize pools with coins - XP, achievements & social: how players earn coins - Publisher SDK, REST API overview, API keys & scopes