Player saves

Saved data for each player, kept per environment: a level's state, a profile, settings, anything your game can write as JSON. Switch on the Player saves service for the project to use it.

Slots

A player's saves are slots, each a JSON value under a key you choose:

  • profile for what follows the player everywhere
  • settings for their options
  • level:ARCTIC:DUNGEON for one level in one mode

A key is 1 to 120 characters of letters, digits and . _ : -, so it goes into a URL as it is. The platform never looks inside a value: its shape is yours, and so is reading an old shape after your game changes it. A slot that has never been written answers not-found, which your game treats as "start fresh".

Limits

Limit Value Refusal
One slot 256 KB invalid-request, naming body.data
One player, every slot 5 MB quota-exceeded (details.quota: playerDataBytesPerPlayer), until the player has room
One environment, every player Your org's plan: 25 MB on Free quota-exceeded (details.quota: playerDataBytes)
A request body, as a whole 512 KB 413 payload-too-large, before the body is read

Sizes are measured on the value written compactly, as JSON without spaces. null is not a save: delete the slot instead. A write that makes a slot smaller always lands, however full the player or the environment is.

Writing without losing a write

Every slot has a version, which starts at 1 and goes up by one with every write. Send the version you read as expectedVersion, and the write lands only if nobody has written the slot since:

curl -X PUT https://api.greenmindmedia.com/api/platform/v1/players/me/data/profile \
  -H "Authorization: Bearer <access token>" \
  -H "Content-Type: application/json" \
  -d '{"data":{"level":8,"coins":120},"expectedVersion":7}'

A write that made the slot answers 201, and one that replaced it 200; both carry the slot's new version. If another machine wrote version 8 in between, this answers 409 conflict and changes nothing. Read the slot again, merge or choose, and write with the new version. expectedVersion: 0 means "only if the slot does not exist yet". Leave expectedVersion out and the write always lands, replacing whatever is there: fine for settings, risky for progress a player could make on two devices.

Who writes

  • The player's client, with its access token, reads and writes its own slots at /players/me/data. It cannot name another player.
  • Your game server, with its server key, reads and writes any of its environment's players at /players/:playerId/data. A player of another environment is not-found.

A client can write anything to its own slots, so a player who edits their client can edit their saves. For anything that must be trusted (currency, unlocks bought with it, ranked progress), use a slot whose key starts with server:, such as server:wallet: your server writes it with the server key, and a player's own token can read it but gets forbidden if it tries to write or delete it.

In the console

Open a player from the environment's Players page to see their saved slots, each with its version, size and when it was last written, and to read any slot's JSON. Reading saves needs the View players permission. Deleting a slot, which is how support fixes a save that will not load, needs Player saves.

Deleting a player (DELETE /players/:playerId) deletes their saves too.

Routes

Method Path Credential Answers
GET /players/me/data player A page of slots (key, version and size), with the player's totalBytes and limitBytes
GET /players/me/data/:key player One slot, with its value
PUT /players/me/data/:key player Writes one slot; { data, expectedVersion? }. 201 when it made the slot
DELETE /players/me/data/:key player 204, whether or not the slot held anything
GET /players/:playerId/data server As above, for the named player
GET /players/:playerId/data/:key server
PUT /players/:playerId/data/:key server
DELETE /players/:playerId/data/:key server

Request fields and answers are in the API reference, under Player saves.