---
title: "Game developers: the Play API · OpenVibe.Games"
canonical: "https://openvibe.games/developers"
updated: null
---

# Game developers: the Play API · OpenVibe.Games

HTML: [Game developers: the Play API · OpenVibe.Games](https://openvibe.games/developers)

GAME DEVELOPERS

# The Play API

 Achievements, leaderboards and cloud saves for your game, on the OpenVibe network. One API, one player account, nothing to host yourself. This is the same API the boards and achievements on this site are drawn from. 

 [Make a project](https://openvibe.services/projects) [Browse the public titles JSON](https://play.openvibe.network/api/v1/titles) 

## Base address and errors

 Every call is under `https://play.openvibe.network/api/v1`. The API stays on that host; this page is the documentation, moved here with the rest of the player pages. 

 Errors are RFC 9457 `problem+json` with a stable `code`. 

## Reading: anyone, any site

- `GET /titles`: every game, with its achievements and boards.
- `GET /titles/:title`: one game.
- `GET /titles/:title/boards/:board?period=week|all&page=1`: 25 entries a page, `rank`, `name`, `score`, never a player id.
- `GET /people/:subject/achievements`: a person's unlocks in every game, what their OpenVibe profile shows.

## Writing: your game's own token

 Your server uses an OpenVibe Network service or app token for audience `openvibe.play`. Only the principal that registered a title writes to it. 

- `PUT /titles/:title` (`play.title.manage`): the name, url, summary, achievements and boards. A definition left out is retired, never deleted.
- `POST /titles/:title/scores` (`play.result.write`): `{ board, ref, entries: [{ player, name, score }] }`. Posting the same `ref` again changes nothing.
- `POST /titles/:title/unlocks` (`play.result.write`): `{ player, achievements: [id] }`, and it answers the new ones.
- `POST /titles/:title/players/:guest/adopt`: a guest signed in, so their unlocks and scores become the person's.
- `GET /titles/:title/players/:player/achievements` (`play.player.read`): what one player unlocked in your game.

## Cloud saves

 Up to 8 slots per player in your game, each any JSON value of at most 64 KB. Every write names the version it read; if another device saved in between, the write is refused with `409 play.save_conflict` so the game can merge instead of losing progress. 

- `PUT /titles/:title/players/:player/saves/:slot` (`play.result.write`): `{ data, version }`.
- `GET /titles/:title/players/:player/saves/:slot` (`play.player.read`): the slot and its version.
- `GET /me/saves`: a signed-in person's slots in every game.

## Start in the sandbox

1. Sign in on [OpenVibe Services](https://openvibe.services/projects) and make a project. New projects are sandbox-only.
2. Add a sandbox app and ask for `play.title.manage`, `play.result.write` and `play.player.read`. A sandbox app gets them without waiting for anyone.
3. Get a token for audience `openvibe.play` and `PUT /titles/sandbox-your-game`. Sandbox titles are never listed, counted or indexed; their players are guests only.

 When the game is ready, staff turn production on for your project and its production app registers the real name. 

## From your game server

 The `openvibe-sdk/play` client wraps the same calls; plain HTTPS works too. 

~~~~
const { createClient } = require('openvibe-sdk/core');
const { createPlayClient } = require('openvibe-sdk/play');

const play = createPlayClient(createClient({ tokenProvider: tokens }));
await play.titles.define('gem-run', {
  name: 'Gem Run',
  achievements: [{ id: 'first-gem', name: 'First Gem' }],
  boards: [{ id: 'high-score', name: 'High score', kind: 'best' }],
});
await play.scores.post('gem-run', {
  board: 'high-score', ref: 'round-42',
  entries: [{ player: 'usr_…', name: 'kim', score: 1200 }],
});
await play.achievements.unlock('gem-run', {
  player: 'usr_…', achievements: ['first-gem'],
});
await play.saves.put('gem-run', 'usr_…', 'main', { data: { level: 3 }, version: 0 });
~~~~

## Where players see it

 Every unlock and board score is on [Achievements](/achievements) and [Leaderboards](/leaderboards) here, and on the player's OpenVibe profile. A guest plays at once; when they sign in, their progress moves to their account. 

 Read more about the service in the [OpenVibe.Play README](https://github.com/OpenVibers/OpenVibe.Play#readme).
