JavaScript SDK
You don't need a package to use the API — it's plain HTTP. But this ~40-line client wraps the read calls and the HMAC write signing so you don't hand-roll it. Drop it into your project.
Note
Keep the secret on your server. The read methods are browser-safe with just
the clientId; only earn() needs the secret and must run server-side.
The client¶
import { createHash, createHmac } from "node:crypto";
export function VectorLabz({ clientId, secret, baseUrl = "https://vectorlabz.io" }) {
async function read(path) {
const res = await fetch(baseUrl + path, { headers: { "x-api-key": clientId } });
if (!res.ok) throw await res.json();
return res.json();
}
return {
// ── reads (browser-safe) ──────────────────────────────
hub: (slug) => read(`/api/v1/hub/${slug}`),
leaderboard: (slug, limit = 10) => read(`/api/v1/hub/${slug}/leaderboard?limit=${limit}`),
holder: (slug, wallet) => read(`/api/v1/hub/${slug}/holder/${wallet}`),
stakeStatus: (slug, wallet) => read(`/api/v1/hub/${slug}/stake-status?wallet=${wallet}`),
// ── signed write (server only — needs secret) ─────────
async earn(slug, { wallet, kind, delta, ref }) {
if (!secret) throw new Error("earn() requires a secret — server-side only");
const path = `/api/v1/hub/${slug}/bits/earn`;
const body = JSON.stringify({ wallet, kind, delta, ref });
const ts = String(Math.floor(Date.now() / 1000));
const key = createHash("sha256").update(secret).digest("hex");
const sig = createHmac("sha256", key).update(`${ts}.POST.${path}.${body}`).digest("hex");
const res = await fetch(baseUrl + path, {
method: "POST",
headers: {
"x-api-key": clientId,
"x-api-timestamp": ts,
"x-api-signature": sig,
"content-type": "application/json",
},
body,
});
if (!res.ok) throw await res.json();
return res.json();
},
};
}
Usage¶
const vl = VectorLabz({
clientId: process.env.VL_CLIENT_ID,
secret: process.env.VL_SECRET, // omit in browser builds
});
// Read — anywhere
const board = await vl.leaderboard("aevon", 25);
const me = await vl.holder("aevon", wallet);
// Write — server only, idempotent via ref
await vl.earn("aevon", { wallet, kind: "engage:post", ref: `post-${postId}` });
Browser vs. server¶
-
🌐 Browser
Instantiate with
clientIdonly. Use the read methods to render leaderboards, holder badges and stake status. Never ship the secret. -
🖥️ Server
Instantiate with
clientId+secret. Callearn()when your backend has verified an action worth points. Always pass a stableref.