Skip to content
NullDevPublic

About

Krunker.io API Wrapper

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

ย 

History

41 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

License pages ci release NPM Version

krapio

Typed client for the READ-ONLY Krunker.io APIs. Zero dependencies, ESM, works on Node 18+ and Bun.
Initially made for Kute Client


โœจ What is it?

krapio is a typed client for the READ-ONLY Krunker.io APIs. Zero dependencies, ESM, works on Node 18+ and Bun.

It aims for 100% API coverage.

It covers three things that live behind different doors:

tier what auth on the client
developer the documented developer API (gapi.svc.krunker.io/api/*) X-Developer-API-Key the root: krunker.player, krunker.market, ...
game what the game itself reads without any auth (market, turf, social, shop, matchmaker, legacy lists) none krunker.game.*
token what the game reads with the player's own FRVR token (wallet, inventory, trades, ranked profile, ...) Authorization: Bearer <jwt> krunker.as(token).*

Warning

Read only. Every write of the game API (buying, listing, trading, posting) is left out on purpose.
Also: game and token API are unofficial. They can break at any time.

This project is not affiliated with Krunker.io or FRVR.


๐Ÿ—’๏ธ Documentation

Living Spec: https://nulldev.github.io/krapio/

Or in the Repo:


๐Ÿ”ง Install

bun add krapio
# or
npm install krapio

Bun runs the TypeScript source directly (bun export condition), Node gets the compiled ESM in dist/ with declarations.

๐Ÿ“ฎ NPM

NPM


โญ Usage

import { Krunker } from "krapio";

const krunker = new Krunker({
    apiKey: process.env.KRUNKER_API_KEY, // developer tier only, optional
    userAgent: "my-bot/1.0 (+https://example.org)",
});

// developer api, needs the key
const profile = await krunker.player.profile("NulPing");
const board = await krunker.leaderboard.ranked(3, { season: 15, page: 1 });
const skin = await krunker.market.skin(1234, { days: 30 });

// game endpoints, no auth
const stats = await krunker.game.market.stats({ sort: "rarity", limit: 50 });
const turf = await krunker.game.turf.status();
const raids = await krunker.game.leaderboards.raidsMonthly(18, "2026-10", "completions");

// a player's own data, with the jwt the game gets from FRVR.auth.getFreshAccessToken()
const me = krunker.as(playerToken);
const wallet = await me.player.wallet();
const ranked = await me.ranked.profile(15, 3);
console.log(me.claims.sub); // the player's frvr id, the one stable key for caching

Every tier is also its own class when you only need one: KrunkerDeveloperApi, KrunkerGameApi, KrunkerTokenApi.

โ“ Resources

Developer (root): player (profile, inventory, listings, matches, posts), match, clan (profile, members), leaderboard (ranked), map (get, featured, leaderboard, leaderboardPlayer), mods (list, get), market (skin), skins (list, get), kpd (latestCalls, needs the kpd scope), events (list, needs an events scope).

Webhooks: verifyWebhook(rawBody, signatureHeader, secret) checks a delivery's Krunker-Signature (HMAC-SHA256 on WebCrypto, 5 minute tolerance) and signWebhook produces one for your own tests. Answer 401 when it returns false, Krunker's signature check sends deliberately bad signatures and expects that.

Game (krunker.game): players, clans, turf, leaderboards, game (maps, mods, titles, creator events), shop, market, items, social, matchmaker, legacy.

Token (krunker.as(token)): player, market, trades, shop, creator, staff (moderator and KPD roles only), ranked.

Response types are exported under the names the API uses (PlayerProfile, MarketStats, Wallet, ...), and every method documents its endpoint in its JSDoc. The APIs themselves are documented in docs/: developer-api.md (Krunker's document, corrected), game-api.md and token-api.md (the undocumented tiers, from the game code and live replies).


โš™๏ธ Options

new Krunker({
    apiKey?: string;    // developer tier; without it those calls throw KrunkerConfigError before any request
    userAgent?: string; // please set one
    timeoutMs?: number; // 20000 (market/skin alone can take seconds on a cold cache)
    retries?: number;   // 1: extra attempts after a network error or a 5xx, never after a 4xx
    fetch?: FetchLike;  // your own fetch (proxy, mock)
    logger?: {          // nothing is logged without one
        debug?: (message: string) => void; // one line per reply and retry
        warn?: (message: string) => void;  // a rate limit window running low
    };
});

โš ๏ธ Errors

Every failure is a KrunkerError subclass, nothing else is thrown:

error when
KrunkerArgumentError an argument the API would reject (empty name, page 0, a bad month); nothing was sent
KrunkerConfigError a developer call without an api key; nothing was sent
KrunkerTokenError as(token) with something that is not a live jwt (malformed, expired within 30 s); nothing was sent
KrunkerNetworkError no http reply, timeout says whether it was the timeout
KrunkerHttpError any other status, with status, url and the parsed body
KrunkerBadRequestError 400
KrunkerUnauthorizedError 401, a token endpoint without a valid token
KrunkerForbiddenError 403, a bad key or a role the player lacks
KrunkerNotFoundError 404
KrunkerRateLimitError 429, with retryAfter seconds; preemptive is true when the client refused to send because it knew the window was empty
KrunkerServerError 5xx

isNotFound, isRateLimited and isTransient are small guards for the common branches.


๐ŸŒ Rate limits

The developer key has 240 requests a minute. gapi also sends per route windows of 5 requests a second. The client mirrors the X-RateLimit-* headers of every reply:

  • a window under 2 s is waited out instead of refused (gapi's per second windows are over before you could react),
  • a longer empty window throws KrunkerRateLimitError with preemptive: true before a request goes out,
  • krunker.rateLimit() returns what the last replies said about the key's window.

One Krunker instance per key: the tracker lives on the instance, two instances cannot see each other's window.


๐Ÿ”’ Tokens

A player token is sent as a bearer header and nothing else: never stored, never logged, never used for a write. The claims are decoded without verifying the signature (Krunker verifies it), only to refuse an expired token locally and to give you sub.


:octocat: Development

bun install
bun run typecheck
bun run lint
bun test      # unit tests against a fake fetch, no network
bun run build # dist/
KRUNKER_API_KEY=... bun run live # a dozen reads against the real api, KRUNKER_TOKEN optional
bun run openapi # regenerates openapi.json, every endpoint of the three tiers as an OpenAPI 3.1 document

The OpenAPI document is generated from the resource classes (paths, parameters, response types) and the exported types, with field descriptions filled in from docs/. It is never edited by hand: run bun run openapi after changing a resource, the test suite fails when the checked in file is stale, and the pages workflow publishes it with the site.

The documentation site (site/, Fumadocs on Next.js, exported statically to GitHub Pages by the pages workflow) renders docs/ plus a library reference TypeDoc generates from src/:

cd site && bun install
bun run dev   # syncs docs/ and the reference into content/, then next dev
bun run build # the static export in site/out, served under /krapio (BASE_PATH="" for a domain of its own)

Releasing. Bump version in package.json, commit, tag it v<version> and push the tag. The release workflow checks that the tag matches the version, runs the pre-publish gate (lint, typecheck, tests, build) and publishes to npm through trusted publishing with provenance, so no npm token lives in the repository or its secrets.

The site serves the OpenAPI document at /openapi.json and offers it for download at /openapi/. Under every endpoint of the three API pages it embeds Scalar's rendering of that operation (parameters, responses, request samples, response example) from a slice of the document.


About

Krunker.io API Wrapper

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages