Skip to content
Skip the menu

Concepts

Players and tokens

How a player is named, when GameCoin creates one for you, and how a browser proves which player it acts for.

View as Markdown

On this page

Two kinds of player

KindkindNamed byWho creates it
Your playerexternalext:<your id>Your server, the first time it writes to that id
Anonymous playerhostedThe id GameCoin generatedThe browser SDK, for a game without a backend

Every player also has a GameCoin id: 24 hexadecimal characters such as 6ac419fa60e877541898f38d. It is stable, and it is the id the API puts in every answer.

Name a player in a URL

In a server API path, {player} is either of these:

  • a GameCoin id: 6ac419fa60e877541898f38d;
  • the id your game already uses, behind ext:: ext:user-42.

Your own id is opaque and case-sensitive. It has 1 to 128 characters and no leading or trailing whitespace. GameCoin never reads meaning into it.

URL-encode the whole reference exactly once. ext:user-42 becomes ext%3Auser-42. In JavaScript this is encodeURIComponent("ext:" + id). Encoding a second time, or not at all, is the classic mistake. An id with a space, an accent or a slash shows why:

Your idReferenceIn the path (encoded once)
user-42ext:user-42ext%3Auser-42
Ana María/7ext:Ana María/7ext%3AAna%20Mar%C3%ADa%2F7

A reference encoded twice (ext%253Auser-42) answers 400 VALIDATION_FAILED with the field error PLAYER_REF_INVALID.

LangageLanguage
curl "https://gamecoin.apilow.com/api/v1/players/ext%3AAna%20Mar%C3%ADa%2F7" \
  -H "Authorization: Bearer $GAMECOIN_SECRET_KEY"

GameCoin creates your players

You do not synchronize your players with GameCoin. With a secret key, any PUT or POST on an ext: id that does not exist yet creates the player. Writing to the wallet, the inventory, a purchase or a checkout all count. A GET on an unknown id answers 404 NOT_FOUND.

PUT /players/{player} creates a player or updates its profile:

PUT/players/{player}
FieldMeaning
displayNameA name shown in the dashboard. Up to 200 characters.
emailThe player's e-mail address, if you have one. Up to 254 characters.
countryAn ISO 3166-1 country code, for example BE. It sets the default country for VAT on checkouts.
birthYearThe year of birth, if you know it.

Every field is optional. A field you leave out is not touched, and null clears it. An empty body means {}.

LangageLanguage
curl -X PUT "https://gamecoin.apilow.com/api/v1/players/ext%3Auser-42" \
  -H "Authorization: Bearer $GAMECOIN_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"displayName":"Ana","country":"BE"}'
Answer
{
  "id": "6ac41a8d4c79ef7265372fa9",
  "externalId": "user-42",
  "kind": "external",
  "displayName": "Ana",
  "country": "BE",
  "blocked": false,
  "createdAt": "2026-10-05T21:45:49.967Z"
}

externalId is your id without the ext:. blocked is true after you block the player in the dashboard.

Anonymous players

A game with no server cannot name its players. The browser SDK asks GameCoin for an anonymous player the first time the game runs. GameCoin answers with:

  • the player;
  • a playerSecret, shown once;
  • a first token and its expiry.
Answer to POST /client/players (secret and token shortened)
{
  "player": {
    "id": "6ac41a4259b32e38d077a85f",
    "externalId": null,
    "kind": "hosted",
    "displayName": "Guest",
    "country": null,
    "blocked": false,
    "createdAt": "2026-10-05T21:44:34.398Z"
  },
  "playerSecret": "…",
  "token": "gc_pt_…",
  "expiresAt": "2026-10-05T22:44:34.000Z"
}

The SDK keeps the player id and the secret in the browser's localStorage. On the next visit it trades them for a fresh token, so the same browser is always the same player with the same balance. The secret never leaves that browser, and it cannot be recovered: clearing the browser's data creates a new player.

FactValue
Creating an anonymous playerLimited to 30 per hour per IP address
Turning it offThe game setting « Autoriser les joueurs anonymes » in the dashboard (in French). POST /client/players then answers 403 FORBIDDEN.
Wrong secret, unknown player, or a player that is not anonymous401 UNAUTHENTICATED on POST /client/players/token

An anonymous player has no ext: id, so your server can use it only by its GameCoin id.

Player tokens

A player token lets a browser act as exactly one player, with your publishable key. It looks like gc_pt_…, lasts one hour, and is signed by GameCoin. It names the player, the game and the environment, so it cannot be used on another game or in the other environment.

A token proves which player is calling. It adds no power: a player can read their own wallet, spend, buy an item with a currency, consume an item and pay for a pack, and nothing else. Security model lists it all.

Where a token comes from depends on your game:

Your gameWhere the token comes from
Has a serverYour server asks GameCoin with the secret key and hands the token to the browser
Has no serverThe browser SDK gets it by itself, with the anonymous player's secret

Issue a token from your server

POST/players/{player}/tokens
LangageLanguage
curl -X POST "https://gamecoin.apilow.com/api/v1/players/ext%3Auser-42/tokens" \
  -H "Authorization: Bearer $GAMECOIN_SECRET_KEY"
Answer
{ "token": "gc_pt_…", "expiresAt": "2026-10-05T22:41:51.000Z" }

This call creates the ext: player if it does not exist. It needs no idempotency key: asking twice just gives two valid tokens. Keep it behind your own login: whoever can call your token endpoint can act as that player.

Renew a token

A token is not revocable, so it is kept short. When a request answers 401 UNAUTHENTICATED, the token is invalid or expired; the two cases cannot be told apart.

  • Anonymous player: the browser SDK renews the token by itself with the stored secret, then replays the request with the same idempotency key.
  • Player with a server: pass onTokenExpired to the SDK. It calls your function once, takes the token you return, and replays the request. Your function should fetch a new token from your server.

The browser SDK page shows both with code: Browser SDK.

Blocking a player

Blocking a player in the dashboard stops them at once, even if their token is still valid. Every client call, and every wallet or inventory write from your server, answers 403 PLAYER_BLOCKED. Balances and history are kept, and you can unblock the player at any time.

Where next