Connect your game to Realm GameOps.
Authenticate players, track achievements, fetch live configuration, read leaderboard standings, and synchronize save data from a game client. Every request is scoped to the app environment attached to its API key.
Base URL
https://www.realmgames.com/v1
Content type
application/json
All responses, including errors, use JSON.
Before you make a request
- 01Create or select an active app environment.
- 02Create a game-client key under Manage → API Keys.
- 03Create and activate a leaderboard for that same environment.
Authentication
Send an API key with every request
Use the X-Realm-API-Key header for the game-client key. Keys begin with rg_client_ and are shown only once when created. Player-authorized requests also send the session returned by player login.
Game client · every request
X-Realm-API-Key: rg_client_YOUR_KEY
Player · when required
Authorization: Bearer rg_player_SESSION
| Service | Read · GET/HEAD | Write · POST/PUT/DELETE |
|---|---|---|
| Player Auth | player-auth:read | player-auth:write |
| Leaderboards | leaderboards:read | leaderboards:write |
| Achievements | achievements:read | achievements:write |
| Remote Config | remote-config:read | Not used by public API |
| Cloud Saves | cloud-saves:read | cloud-saves:write |
Write permission always includes read permission for the same service; write-only service access is not valid.
Treat game-client keys as environment credentials. Use separate keys for development, staging, and production, rotate exposed keys, and never commit production keys to source control.
/v1/player-auth/device
Login with device
Creates or resolves an anonymous player using a stable device identifier, then returns a new player session token. The endpoint must be enabled under Operate → Player Auth for the API key’s environment.
| JSON field | Required | Description |
|---|---|---|
| deviceId | Platform strategy | Stable device identifier, maximum 512 characters |
| displayName | No | Initial or updated player-facing name, maximum 80 characters |
| platform | No | Client platform such as ios, android, or windows |
With the Realm-generated strategy, omit deviceId on the first request. Store the returned device.deviceId securely and send it on later logins to recover the same player.
curl --request POST \
--url 'https://www.realmgames.com/v1/player-auth/device' \
--header 'Content-Type: application/json' \
--header 'X-Realm-API-Key: rg_client_YOUR_KEY' \
--data '{
"deviceId": "ios-vendor-device-id",
"displayName": "Nova",
"platform": "ios"
}'
[System.Serializable]
public class DeviceLoginRequest
{
public string deviceId;
public string displayName;
public string platform;
}
IEnumerator LoginWithDevice(string deviceId)
{
var payload = new DeviceLoginRequest {
deviceId = deviceId,
displayName = "Nova",
platform = Application.platform.ToString().ToLowerInvariant()
};
byte[] body = Encoding.UTF8.GetBytes(JsonUtility.ToJson(payload));
string url = BaseUrl + "/v1/player-auth/device";
using (var request = new UnityWebRequest(url, "POST"))
{
request.uploadHandler = new UploadHandlerRaw(body);
request.downloadHandler = new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
request.SetRequestHeader("X-Realm-API-Key", ApiKey);
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
Debug.Log(request.downloadHandler.text);
else
Debug.LogError(request.downloadHandler.text);
}
}
player.id, session.accessToken, and session.expiresAt. Store the player token securely; a new device login revokes the previous active session for that device.
/v1/leaderboard
List leaderboards
Returns active leaderboards in the API key’s environment. Results are ordered by name.
| Query | Type | Description |
|---|---|---|
| limit | integer | 1–100, default 25 |
| offset | integer | 0–100,000, default 0 |
curl --request GET \
--url 'https://www.realmgames.com/v1/leaderboard?limit=25&offset=0' \
--header 'X-Realm-API-Key: rg_client_YOUR_KEY'
IEnumerator ListLeaderboards()
{
string url = BaseUrl + "/v1/leaderboard?limit=25&offset=0";
using (UnityWebRequest request = UnityWebRequest.Get(url))
{
request.SetRequestHeader("X-Realm-API-Key", ApiKey);
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
Debug.Log(request.downloadHandler.text);
else
Debug.LogError(request.downloadHandler.text);
}
}
/v1/leaderboard/:leaderboardKey
Get leaderboard standings
Returns ranked entries for one active leaderboard. Use its key—not its UUID—in the URL. Ranking direction follows the leaderboard’s ascending or descending configuration.
| Parameter | Location | Description |
|---|---|---|
| leaderboardKey | path | Leaderboard key, such as season-score |
| limit | query | 1–100, default 25 |
| offset | query | 0–100,000, default 0 |
curl --request GET \
--url 'https://www.realmgames.com/v1/leaderboard/season-score?limit=25&offset=0' \
--header 'X-Realm-API-Key: rg_client_YOUR_KEY'
IEnumerator GetLeaderboard(string leaderboardKey)
{
string key = UnityWebRequest.EscapeURL(leaderboardKey);
string url = BaseUrl + "/v1/leaderboard/" + key +
"?limit=25&offset=0";
using (UnityWebRequest request = UnityWebRequest.Get(url))
{
request.SetRequestHeader("X-Realm-API-Key", ApiKey);
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
Debug.Log(request.downloadHandler.text);
else
Debug.LogError(request.downloadHandler.text);
}
}
/v1/leaderboard/:leaderboardKey/players/:playerId
Get a player’s rank
Returns a single player’s score and current rank. A player ID can be up to 128 characters and should be URL encoded.
curl --request GET \
--url 'https://www.realmgames.com/v1/leaderboard/season-score/players/019faa5e-5292-75ae-8c05-e89965aa0d32' \
--header 'X-Realm-API-Key: rg_client_YOUR_KEY'
IEnumerator GetPlayerRank(string leaderboardKey, string playerId)
{
string key = UnityWebRequest.EscapeURL(leaderboardKey);
string player = UnityWebRequest.EscapeURL(playerId);
string url = BaseUrl + "/v1/leaderboard/" + key +
"/players/" + player;
using (UnityWebRequest request = UnityWebRequest.Get(url))
{
request.SetRequestHeader("X-Realm-API-Key", ApiKey);
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
Debug.Log(request.downloadHandler.text);
else
Debug.LogError(request.downloadHandler.text);
}
}
/v1/leaderboard/:leaderboardKey/scores
Submit or improve a score
Requires a player session from device login. The authenticated player ID is used automatically, so a client cannot submit a score for another player. On descending boards, higher wins; on ascending boards, lower wins. A valid but non-improving score returns accepted: false.
Send both credentials: the environment’s rg_client_ key in X-Realm-API-Key and the logged-in player’s rg_player_ token as a Bearer token.
| JSON field | Required | Description |
|---|---|---|
| score | Yes | Finite number; integer and duration boards require whole numbers |
| displayName | No | Player-facing name, maximum 80 characters |
| metadata | No | JSON object, maximum 8 KB |
| playerId | No | Deprecated; if sent, it must match the authenticated player |
curl --request POST \
--url 'https://www.realmgames.com/v1/leaderboard/season-score/scores' \
--header 'Content-Type: application/json' \
--header 'X-Realm-API-Key: rg_client_YOUR_KEY' \
--header 'Authorization: Bearer rg_player_SESSION' \
--data '{
"displayName": "Nova",
"score": 18450,
"metadata": { "season": 4, "character": "mage" }
}'
[System.Serializable]
public class ScoreMetadata
{
public int season;
public string character;
}
[System.Serializable]
public class ScoreSubmission
{
public string displayName;
public long score;
public ScoreMetadata metadata;
}
IEnumerator SubmitScore(string leaderboardKey, string playerAccessToken)
{
var payload = new ScoreSubmission {
displayName = "Nova",
score = 18450,
metadata = new ScoreMetadata { season = 4, character = "mage" }
};
byte[] body = Encoding.UTF8.GetBytes(JsonUtility.ToJson(payload));
string key = UnityWebRequest.EscapeURL(leaderboardKey);
string url = BaseUrl + "/v1/leaderboard/" + key + "/scores";
using (var request = new UnityWebRequest(url, "POST"))
{
request.uploadHandler = new UploadHandlerRaw(body);
request.downloadHandler = new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
request.SetRequestHeader("X-Realm-API-Key", ApiKey);
request.SetRequestHeader("Authorization", "Bearer " + playerAccessToken);
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
Debug.Log(request.downloadHandler.text);
else
Debug.LogError(request.downloadHandler.text);
}
}
using System.Collections;, using System.Text;, and using UnityEngine.Networking;. Define BaseUrl and ApiKey in your client configuration, and pass the player token returned by login when submitting scores.
/v1/achievements
Achievements
List active achievement definitions, load the authenticated player’s progress, and report absolute or incremental progress. Secret achievements remain hidden until unlocked.
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/achievements | List active, non-secret definitions |
| GET | /v1/achievements/:key | Read one non-secret achievement |
| GET | /v1/achievements/player | List the logged-in player’s visible progress |
| POST | /v1/achievements/:key/progress | Set progress or increment it atomically |
Player progress endpoints require both credentials. Send the environment API key with X-Realm-API-Key and the player session with Authorization: Bearer.
curl --request POST \
--url 'https://www.realmgames.com/v1/achievements/monster-hunter/progress' \
--header 'Content-Type: application/json' \
--header 'X-Realm-API-Key: rg_client_YOUR_KEY' \
--header 'Authorization: Bearer rg_player_SESSION' \
--data '{ "increment": 1 }'
{
"environment": "production",
"playerId": "0198...",
"achievement": {
"key": "monster-hunter",
"name": "Monster Hunter",
"points": 50,
"target": 10,
"progress": 7,
"percentComplete": 70,
"unlocked": false,
"unlockedAt": null
}
}
| JSON field | Use | Behavior |
|---|---|---|
| progress | Absolute | Sets a new high-water mark; progress never moves backward |
| increment | Relative | Atomically adds to current progress |
Send exactly one field. Values must be finite, non-negative numbers. Progress is capped at the achievement target, and the first request to reach that target records unlockedAt.
/v1/remote-config
Fetch Remote Config
Returns every enabled key in the API key’s environment as a single JSON object. Values preserve their JSON types, so booleans, numbers, strings, arrays, and objects arrive without client-side conversion.
Store the response’s ETag header and send it as If-None-Match on the next poll. Realm returns 304 Not Modified with no body when configuration has not changed.
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/remote-config | Fetch all enabled values and response metadata |
| GET | /v1/remote-config/:key | Fetch one enabled value, its version, and update time |
curl --request GET \
--url 'https://www.realmgames.com/v1/remote-config' \
--header 'X-Realm-API-Key: rg_client_YOUR_KEY' \
--header 'If-None-Match: "LAST_ETAG"'
{
"environment": "production",
"values": {
"gameplay.double_xp": true,
"economy.daily_coins": 250,
"ui.season_theme": "winter"
},
"meta": {
"count": 3,
"etag": "CONFIG_ETAG",
"updatedAt": "2026-08-04T18:30:00.000Z"
}
}
IEnumerator FetchRemoteConfig(string previousEtag = null)
{
string url = BaseUrl + "/v1/remote-config";
using (UnityWebRequest request = UnityWebRequest.Get(url))
{
request.SetRequestHeader("X-Realm-API-Key", ApiKey);
if (!string.IsNullOrEmpty(previousEtag))
request.SetRequestHeader("If-None-Match", previousEtag);
yield return request.SendWebRequest();
if (request.responseCode == 304)
yield break;
if (request.result == UnityWebRequest.Result.Success)
{
string etag = request.GetResponseHeader("ETag");
Debug.Log(request.downloadHandler.text);
}
else
Debug.LogError(request.downloadHandler.text);
}
}
Key behavior
- Disabled keys are omitted and single-key reads return 404.
- The API key selects the environment; clients cannot override it in a query.
- Keys may use letters, numbers, dots, underscores, and hyphens.
/v1/cloud-saves
Cloud save slots
Store up to 20 JSON save slots per player and environment, with a 1 MB limit per slot. Every endpoint requires both the environment API key and the player’s Bearer session token.
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/cloud-saves | List the authenticated player’s save slot metadata |
| GET | /v1/cloud-saves/:slotKey | Read one slot and its JSON data |
| PUT | /v1/cloud-saves/:slotKey | Create or replace a slot |
| DELETE | /v1/cloud-saves/:slotKey | Permanently delete a slot |
Send expectedVersion: 0 when creating a new slot. For later writes, use the version returned by the previous read or write. A stale version returns 409 cloud_save_conflict instead of overwriting newer progress.
curl --request PUT \
--url 'https://www.realmgames.com/v1/cloud-saves/main' \
--header 'Content-Type: application/json' \
--header 'X-Realm-API-Key: rg_client_YOUR_KEY' \
--header 'Authorization: Bearer rg_player_SESSION' \
--data '{
"data": {
"level": 12,
"checkpoint": "forest-gate",
"inventory": ["map", "key"]
},
"expectedVersion": 0
}'
curl --request GET \
--url 'https://www.realmgames.com/v1/cloud-saves/main' \
--header 'X-Realm-API-Key: rg_client_YOUR_KEY' \
--header 'Authorization: Bearer rg_player_SESSION'
/v1/live-communication/messages
Live Communication
Deliver active, scheduled messages to game clients without releasing a new build. Messages can be grouped into channels, styled by severity, and linked to an HTTPS destination or game deep link.
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/live-communication/messages | List messages that are live now |
| GET | /v1/live-communication/messages/:key | Read one active message |
| POST | /v1/live-communication/messages/:key/acknowledge | Record that the logged-in player saw or dismissed it |
Clients only receive messages with an active publishing status whose optional start and end times include the current server time. Draft, archived, future, and expired messages are excluded automatically.
curl --request GET \
--url 'https://www.realmgames.com/v1/live-communication/messages?channel=news&limit=20' \
--header 'X-Realm-API-Key: rg_client_YOUR_KEY'
{
"environment": "production",
"messages": [{
"key": "double-xp-weekend",
"channel": "news",
"title": "Double XP weekend",
"body": "Earn twice the XP through Sunday.",
"severity": "success",
"action": {
"label": "Play now",
"url": "mygame://events/double-xp"
},
"startsAt": "2026-08-07T17:00:00.000Z",
"endsAt": "2026-08-10T07:00:00.000Z",
"publishedAt": "2026-08-04T18:30:00.000Z",
"updatedAt": "2026-08-04T18:30:00.000Z"
}],
"paging": {
"limit": 20,
"hasMore": false,
"nextCursor": null
}
}
curl --request POST \
--url 'https://www.realmgames.com/v1/live-communication/messages/double-xp-weekend/acknowledge' \
--header 'X-Realm-API-Key: rg_client_YOUR_KEY' \
--header 'Authorization: Bearer rg_player_SESSION'
Client behavior
- Use
channelto populate separate surfaces such as news, inbox, and service status. - Acknowledgement is idempotent. Repeating it preserves the player’s original timestamp.
- Reads need the API key; acknowledgement also needs the player Bearer session.
nextCursor. Pass it back as ?cursor=…. Limits range from 1 to 100.Errors
Consistent JSON errors
Check both the HTTP status and the machine-readable error code. An inactive environment returns a specific message so clients can distinguish configuration problems from invalid credentials.
{
"error": {
"code": "environment_inactive",
"message": "The Production environment is currently maintenance. Activate it before using this API key."
}
}
| Status | Meaning |
|---|---|
| 400 | Invalid request, score, slot key, or version |
| 401 | Missing or invalid API key or player session |
| 403 | Inactive environment, app, player, or insufficient API-key permission |
| 404 | Requested leaderboard, player, or save slot not found |
| 409 | Cloud save version conflict or slot limit reached |
| 413 | Cloud save exceeds 1 MB |
| 500 | Server error |
Ready to connect?