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:
profilefor what follows the player everywheresettingsfor their optionslevel:ARCTIC:DUNGEONfor 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 isnot-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.