Crux SDK Quickstart
Pick curl or your engine SDK. Authenticate a player, save state, and submit a leaderboard score in about two minutes. Every call on this page matches the real, current Crux API.
Before you start (2 minutes)
- Sign up at crux.supercraft.host/signup/ โ a project and a
devenvironment are created for you automatically. - Open your project dashboard and copy your project ID, environment ID, and publishable API key. The publishable key is safe for player clients; never substitute the secret API key in client code.
- Use
Authorization: ApiKey YOUR_PUBLISHABLE_KEYonly to log the player in. Follow-on player calls use the returnedBearertoken. Server-side administration uses a separate secret key.
๐ Coming from PlayFab
The hard part of leaving PlayFab is rarely the backend. It is the thousand call
sites. crux-playfab-compat keeps them. It takes PlayFab’s request
shapes, returns PlayFab’s { code, status, data } envelope, and works
with callbacks or promises, so the diff is which client you construct.
npm install crux-playfab-compat
const PlayFabClientAPI = new PlayFabClientCompat(
CruxClient.forPlayer(baseUrl, projectId, environmentId, apiKey),
);
// unchanged from your PlayFab codebase
PlayFabClientAPI.GetUserData({ Keys: ["save"] }, (res, err) => { /* ... */ }); Available for JavaScript/TypeScript, Unity (C#) and Godot (GDScript). It covers the calls an ordinary title makes every session: login, user data, title data, leaderboards, statistics, inventory, virtual currency and friends.
Anything outside that set throws a named error instead of quietly doing
nothing, and it tells you what to use instead. That is deliberate: a stub that
looks like it worked is worse than a failure, and on a currency call it is somebody’s
money. ExecuteCloudScript is not supported. Crux does not run customer
code, so that logic moves behind your own endpoint.
Full method-by-method coverage, the methods with no Crux equivalent, and the three behaviours that differ on purpose are in the migration guide.
๐ curl - your first authenticated call
The single call that proves your key works. It mints a guest player and
returns a player_id plus a player token. Works from any HTTP
client, CI, or a C++ dedicated server.
# First authenticated call - mint a guest player. Proves your API key works.
curl -X POST https://crux.supercraft.host/v1/auth/anonymous \
-H "Authorization: ApiKey YOUR_PUBLISHABLE_KEY" \
-H "Content-Type: application/json" \
-d '{"anonymous_id":"device-abc-123","display_name":"Ada"}'
# 200 OK
# {
# "player_id": "7f3c1e2a-...",
# "access_token": "eyJhbGciOi...", # a player JWT (Bearer)
# "token_type": "Bearer",
# "expires_in": 86400,
# "refresh_token": "...",
# "refresh_token_expires_in": 2592000
# } Now the three calls every game needs - a saved document and a leaderboard. These use the returned player token against the real nested routes:
# Values you copy once from your project dashboard:
CRUX=https://crux.supercraft.host
PROJECT=YOUR_PROJECT_ID # project ID
ENV=YOUR_ENV_ID # environment ID (a "dev" env is created on signup)
TOKEN=PLAYER_ACCESS_TOKEN # access_token returned by /v1/auth/anonymous
PLAYER=7f3c1e2a-... # the player_id returned by /v1/auth/anonymous
BOARD=YOUR_LEADERBOARD_ID # create a leaderboard in the dashboard, copy its ID
# 1. Save a player document (JSON whose shape you own). "save" is the document key.
curl -X PUT "$CRUX/v1/projects/$PROJECT/environments/$ENV/players/$PLAYER/documents/save" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"value":{"level":4,"coins":250,"unlocks":["sword","shield"]}}'
# 1b. Read it back with GET on the same URL.
# Reading a key you have never written returns 404, and that is the correct
# answer, not a broken token - a bad credential is 401 or 403. Treat it as
# "no save yet" and fall back to your defaults. The JS SDK already does this
# for you: getPlayerDocument() returns null instead of throwing.
curl "$CRUX/v1/projects/$PROJECT/environments/$ENV/players/$PLAYER/documents/save" \
-H "Authorization: Bearer $TOKEN"
# 2. Submit a leaderboard score
curl -X POST "$CRUX/v1/projects/$PROJECT/environments/$ENV/leaderboards/$BOARD/scores" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"player_id":"7f3c1e2a-...","score":12750}'
# 3. Read the top of the board
curl "$CRUX/v1/projects/$PROJECT/environments/$ENV/leaderboards/$BOARD/top?limit=10" \
-H "Authorization: Bearer $TOKEN"
# [ {"player_id":"7f3c1e2a-...","score":12750,"rank":1}, ... ] ๐ฆ JavaScript / TypeScript - crux-sdk
Fetch-based, zero dependencies. Works in Node 18+, browsers, Electron,
and Cloudflare Workers. Install: npm install crux-sdk · source on GitHub
import { CruxClient } from "crux-sdk";
// Copy projectId, environmentId, and a PUBLISHABLE key from your
// dashboard. A "dev" environment is created for you on signup.
const gsb = CruxClient.forPlayer(
"https://crux.supercraft.host",
"YOUR_PROJECT_ID",
"YOUR_ENV_ID",
"YOUR_PUBLISHABLE_KEY",
);
// 1. Create or sign in a player. (Email shown; OAuth + guest also supported.)
const auth = await gsb.registerEmail("player@example.com", "a-strong-password");
console.log("player:", auth.player_id);
// 2. Save player data - any JSON shape you like
await gsb.setPlayerDocument(auth.player_id, "save", { level: 4, coins: 250 });
// 3. Submit and read a leaderboard. leaderboardId is the board's ID
// (create a board in the dashboard and copy its ID).
await gsb.submitScore("YOUR_LEADERBOARD_ID", auth.player_id, 12750);
const top = await gsb.getTop("YOUR_LEADERBOARD_ID", 10);
top.forEach(e => console.log("#" + e.rank + " " + e.player_id + ": " + e.score)); ๐ค Godot 4 (GDScript)
Drop the addons/crux autoload into your project. Same API,
idiomatic GDScript. Great for migrating a leaderboard off a shuttered
Godot backend โ see the
SilentWolf migration guide.
# Copy the addon into res://addons/crux and autoload it
# (Project -> Project Settings -> Autoload) as "Crux".
Crux.init_player("https://crux.supercraft.host",
"YOUR_PROJECT_ID", "YOUR_ENV_ID", "YOUR_PUBLISHABLE_KEY")
# Create or sign in a player (email; OAuth + guest also supported)
var auth = await Crux.register_email("player@example.com", "a-strong-password")
print("player: ", auth.player_id)
# Save player data
await Crux.set_player_document(auth.player_id, "save", { "level": 4, "coins": 250 })
# Submit a leaderboard score (leaderboard_id is the board's ID from the dashboard)
await Crux.submit_score("YOUR_LEADERBOARD_ID", auth.player_id, 12750.0) Want a complete project instead of snippets? Relay Zero is an open-source Godot 4 co-op demo wired to Crux end to end: an authoritative headless server that verifies player tokens, versioned live-config bundles with a last-known-good fallback, and server-owned rewards and leaderboards, with Docker deploy files included.
๐ฏ Unity (C#)
UPM package under Supercraft.Crux. async/await
throughout; works in the editor, standalone, dedicated server builds, and WebGL.
using Supercraft.Crux;
// Copy projectId, environmentId, and a PUBLISHABLE key from your dashboard.
var gsb = ServerToolkitClient.ForPlayer(
"https://crux.supercraft.host", "YOUR_PROJECT_ID", "YOUR_ENV_ID", "YOUR_PUBLISHABLE_KEY");
// Create or sign in a player
var auth = await gsb.RegisterEmailAsync("player@example.com", "a-strong-password");
Debug.Log($"player: {auth.player_id}");
// Save player data (raw JSON string)
await gsb.SetPlayerDocumentAsync(auth.player_id, "save", "{\"level\":4,\"coins\":250}");
// Submit + read a leaderboard (leaderboardId is the board's ID from the dashboard)
await gsb.SubmitScoreAsync("YOUR_LEADERBOARD_ID", auth.player_id, 12750);
var top = await gsb.GetTopAsync("YOUR_LEADERBOARD_ID", 10);
foreach (var e in top) Debug.Log($"#{e.rank} {e.player_id}: {e.score}"); ๐ฎ Roblox & any other engine
Roblox talks to Crux from a ServerScriptService script over
HttpService using a server token โ walk through it in the
Roblox quickstart. Any engine that can
make an HTTPS request works the same way: the API is plain HTTP + JSON, and the
curl block above is the whole contract.