The Play API
A game registers its title with its own OpenVibe token, posts what its players did, and reads its boards. Base address: https://play.openvibe.network/api/v1. Errors are RFC 9457 problem+json with a stable code.
Reading (anyone, any site)
GET /titles: every game, with its achievements (how many players have each) and its boards.GET /titles/:title: one game.GET /titles/:title/boards/:board?period=week|all&page=1: 25 entries a page:rank,name,score, and whether the player was signed in. Never a player id.GET /me/achievements: with a person's Network token, their own unlocks in every game.
Writing (the game's own token)
A game's server uses a Network service or app token for audience openvibe.play. Only the principal that registered a title writes to it; to anyone else the title does not exist.
PUT /titles/:title(play.title.manage):{ name, url, summary, achievements: [{ id, name, description, hidden }], boards: [{ id, name, kind: "best" | "sum" }] }. A definition left out is retired, never deleted: what players earned stays. A board's kind never changes.POST /titles/:title/scores(play.result.write):{ board, ref, entries: [{ player, name, score }] }, up to 100 entries.refnames the round or run; posting it again changes nothing.POST /titles/:title/unlocks(play.result.write):{ player, achievements: [id] }; answers the ones that were new.POST /titles/:title/players/:guest/adopt(play.result.write):{ person: "usr_…" }when a guest signs in: their unlocks and scores become the person's.GET /titles/:title/players/:player/achievements(play.player.read): a player's unlocks in your game.
Cloud saves
A player's progress follows them to any device: up to 8 slots per player in your game, each any JSON value of at most 64 KB. Slots move with a guest who signs in (the newer save wins a clash) and with an account merge.
PUT /titles/:title/players/:player/saves/:slot(play.result.write):{ data, version }.versionis the version you read (0 for a new slot): if the slot moved on since, the write is refused with409 play.save_conflict, so two devices never overwrite each other silently. Leave it out to overwrite.GET /titles/:title/players/:player/saves/:slot(play.player.read):{ slot, version, data, created_at, updated_at };GET …/saveslists the slots without their data;DELETE …/saves/:slot(play.result.write).GET /me/savesandDELETE /me/saves/:title/:slot: with a person's own Network token, their slots in every game.
A player is a person's OpenVibe subject (usr_…) or a guest your game names, guest: followed by 8 to 128 letters, digits, _ or -. Only people's rows are personal data: they are in the person's account export and erased with their account.