Leaderboard API

Your game sends a message — a new score, or a rank question — and gets a message back it can print straight on screen. No account, no SDK, one HTTP call.

Base URL  https://game.easytrans.io/api

Submitting a score needs a game key. Send it as an X-Game-Key header — ask the leaderboard owner for the value. Reading (rank, leaderboard) is open to everyone, and the demo board accepts writes with no key so you can experiment.

The 30-second version

Every response contains a ready-to-display message string plus the raw numbers if you want to draw your own UI.

POST https://game.easytrans.io/api/message
{"type":"score","game":"byow","player":"Milo","score":1200}

→ {"ok":true,"message":"New personal best, Milo: 1200 (was 900) — rank 3 of 41.",
   "rank":3,"best":1200,"total_players":41,"top":[...]}

Endpoints

MethodPathWhat it does
POST/api/message One door for everything — type = score, rank, or top
POST/api/score Submit a score
GET/api/rank?player=Milo One player's best score and rank
GET/api/leaderboard?limit=10 Top N players
GET/healthz Returns ok when the server is alive

Fields

FieldTypeNotes
gamestringOptional, defaults to byow. Each value is its own separate leaderboard.
playerstring1–24 chars: letters, digits, space, _ . - #, or Chinese. This is the identity — same name = same player.
scoreintegerHigher is better. −1e9 … 1e9.
notestringOptional free text stored with the submission (seed, level, …).
Only your best score counts for ranking, but every submission is stored. Ties are broken by who got there first. Rank 1 is the top.

JavaScript

Plain fetch, works in a browser or in Node 18+.

const API = "https://game.easytrans.io/api";
const KEY = "YOUR_GAME_KEY";   // only needed for sending scores

async function send(payload) {
  const r = await fetch(API + "/message", {
    method: "POST",
    headers: { "Content-Type": "application/json", "X-Game-Key": KEY },
    body: JSON.stringify(payload)
  });
  return r.json();
}

// 1. game over → send the score
const res = await send({ type: "score", player: "Milo", score: 1200 });
console.log(res.message);   // "New personal best, Milo: 1200 ..."
console.log(res.rank);      // 3

// 2. player asks "where am I?"
const me = await send({ type: "rank", player: "Milo" });
console.log(me.message);    // "Milo: best 1200, rank 3 of 41."

// 3. draw the top 10
const board = await send({ type: "top", limit: 10 });
board.entries.forEach(e => console.log(`${e.rank}. ${e.player} ${e.score}`));

GET version (no JSON body needed)

const me = await (await fetch(API + "/rank?player=Milo")).json();
const top = await (await fetch(API + "/leaderboard?limit=10")).json();

Java

Java 11+ HttpClient, no dependencies. Drop this class into your game.

import java.net.URI;
import java.net.URLEncoder;
import java.net.http.*;
import java.nio.charset.StandardCharsets;

public class Leaderboard {
    private static final String API = "https://game.easytrans.io/api";
    private static final String KEY = "YOUR_GAME_KEY";  // only for sending scores
    private static final HttpClient HTTP = HttpClient.newHttpClient();

    private static String post(String path, String json) throws Exception {
        HttpRequest req = HttpRequest.newBuilder(URI.create(API + path))
                .header("Content-Type", "application/json")
                .header("X-Game-Key", KEY)
                .POST(HttpRequest.BodyPublishers.ofString(json))
                .build();
        return HTTP.send(req, HttpResponse.BodyHandlers.ofString()).body();
    }

    private static String get(String path) throws Exception {
        HttpRequest req = HttpRequest.newBuilder(URI.create(API + path)).GET().build();
        return HTTP.send(req, HttpResponse.BodyHandlers.ofString()).body();
    }

    /** Send a score, get back the sentence to show the player. */
    public static String submit(String player, int score) throws Exception {
        String json = String.format("{\"type\":\"score\",\"player\":\"%s\",\"score\":%d}",
                                    player, score);
        return message(post("/message", json));
    }

    /** Ask for this player's rank. */
    public static String rank(String player) throws Exception {
        return message(get("/rank?player=" + URLEncoder.encode(player, StandardCharsets.UTF_8)));
    }

    /** Top N as raw JSON — parse with Gson/Jackson, or just show .message */
    public static String top(int n) throws Exception {
        return get("/leaderboard?limit=" + n);
    }

    // Tiny extractor so the example stays dependency-free.
    // In real code use Gson: new Gson().fromJson(body, Result.class)
    private static String message(String body) {
        int i = body.indexOf("\"message\":\"");
        if (i < 0) return body;
        int start = i + 11, end = start;
        StringBuilder sb = new StringBuilder();
        while (end < body.length() && body.charAt(end) != '"') {
            if (body.charAt(end) == '\\') end++;
            sb.append(body.charAt(end++));
        }
        return sb.toString();
    }

    public static void main(String[] args) throws Exception {
        System.out.println(submit("Milo", 1200));
        System.out.println(rank("Milo"));
    }
}

curl

curl -s https://game.easytrans.io/api/message \
  -H 'Content-Type: application/json' -H 'X-Game-Key: YOUR_GAME_KEY' \
  -d '{"type":"score","player":"Milo","score":1200}'

curl -s 'https://game.easytrans.io/api/rank?player=Milo'
curl -s 'https://game.easytrans.io/api/leaderboard?limit=10'

Try it now

(the demo leaderboard is game=demo, so it won't touch your real board)

Errors & limits

StatusMeaning
400Bad name, bad score, or unknown type
401A game key is required and yours is missing or wrong
429Too many requests — 120 writes / 600 reads per minute per IP

Every error also returns {"ok":false,"error":"...","message":"Error: ..."}, so the same display code works for the failure path.

The game key

Score writes are locked to a shared key so strangers can't stuff the board. Reads never need it, and game: "demo" writes never need it either.

headers: { "Content-Type": "application/json", "X-Game-Key": "YOUR_GAME_KEY" }
// or: Authorization: Bearer YOUR_GAME_KEY