Kiwi API Documentation

Sign up, mint API tokens, host data, and run calculations.

Overview

Looking to sign up or manage your account and API keys? Use the developer portal. This page is the HTTP reference for calling the API programmatically.

The API is authenticated with API tokens. You create your account and mint tokens in the developer portal - a website you use in your browser - and your programs then send one of those tokens with every request.

WhereWhat you do there
https://dev.aallyn.net
(browser)
Sign up, sign in, and create / manage your API tokens
https://api.aallyn.net
(your code)
The data & calculation API - authenticate with your API token

Signing in happens in the portal, in your browser - never from a program. Your code authenticates only with an API token you generated there. There's no programmatic login endpoint; the token is the credential.

The full, interactive endpoint reference (try-it schemas, every field) lives on the API reference page, generated from the live OpenAPI spec.

Building with an AI assistant? Grab the plain-text reference for LLMs - a single self-contained file you can paste into ChatGPT, Claude, or Cursor as context. The raw machine spec is at /openapi.json.

Get an API token

Everything in this step happens in the developer portal - a website, in your browser. Programs don't sign up or sign in; they only use the token you create here.

  1. Create an account. Open the developer portal and sign up - protected by a captcha and rate limiting. You'll get a verification email; confirm it before creating tokens.
  2. Sign in and open the Tokens tab.
  3. Create a token. Give it a name, choose its scopes (e.g. rotations:read, feeds:read) or grant all access, restrict it to the IP addresses your code runs from, and pick an expiry (30 / 60 / 90 days, or none).
  4. Copy the secret. It looks like kiwi_xxxxxxxx…_xx and is shown exactly once - store it in your secrets manager now. Only a hash is kept server-side, so it can never be shown again (rotate the token if you lose it).

Treat the token like a password. Never commit it to source control - leaked tokens are detected by secret scanning and automatically revoked.

Authenticating

Send your API token as a Bearer credential on every request to the data API. There's no login call and no session to manage - the token is the credential.

export KIWI_TOKEN="kiwi_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# Once data endpoints are published, authenticate them like this:
curl https://api.aallyn.net/v1/<endpoint> \
  -H "Authorization: Bearer $KIWI_TOKEN"

Each request is checked against the token's restrictions:

  • A request from an IP that isn't on the token's allowlist → 403 ip_not_allowed.
  • A token missing a required scope → 403 insufficient_scope.
  • A revoked or expired token → 401 not_authenticated.

Data endpoints

Live Trove game data, grouped by function into nine categories, each with its own scope: rotations (rotations:read) - server time, bonuses, merchants, biomes; feeds (feeds:read) - news, Twitch streams, YouTube / Bilibili videos, and the Trovesaurus event calendar; stats (stats:read) - raw stat tables and class definitions; gems (gems:read) - a gem simulator, evaluator, and build optimizer; misc (misc:read) - a modding-software list and a time converter; mods (mods:read) - decompile and build .tmod files; updates (updates:read) - browse the archived game files (versions, directory tree, single-file download); codexes (codexes:read) - structured game data (allies, mounts, dragons, mementos, recipes, items, fish, badges) parsed from the archive; and btt (btt:read) - BetterTroveTools releases (latest version per platform, per channel) for in-app update checks. Rotations, feeds and stats are GET, read-only (timestamps are real-UTC unix seconds); the gem and mod tools add POST calculators. The API reference has the full field-level schema for each.

rotations, feeds, codexes and btt are public - callable with no token at a stricter per-IP rate limit (30 req/min/IP by default). Send a token carrying the scope to lift it to the full per-token limit (120 req/min). codexes gets 5× both budgets (150 req/min/IP anonymous, 600 req/min/token). Every other category requires a token with the matching scope.

EndpointScopeReturns
/v1/rotations/server-timerotations:readServer time, current in-game day, next daily + weekly resets
/v1/rotations/daily-buffsrotations:readToday's daily buff + the full Mon→Sun rotation
/v1/rotations/weekly-buffsrotations:readThis week's weekly buff + the 4-week rotation
/v1/rotations/corruxionrotations:readCorruxion merchant: live timer + upcoming schedule
/v1/rotations/fluxionrotations:readFluxion merchant: voting/selling timer + schedule
/v1/rotations/gardeningrotations:read2-day / 3-day plant harvest windows + what's next
/v1/rotations/chaos-chestrotations:readWeekly Chaos Chest: featured item (relayed from Trovesaurus) + window + countdown
/v1/rotations/calendarrotations:readYearly calendar: all recurring rotations (buffs, merchants, gardening, biomes) as one ±365-day timeline
/v1/rotations/delves?week=rotations:readA week's delve rotation - floor records relayed from a community delve source (default current week; /delves/weeks lists weeks). Gated behind the feature_delves_enabled admin toggle (default off; 404s when disabled)
/v1/rotations/biomesrotations:readThe 3-hour adventure-world biome rotation (current + upcoming)
/v1/rotations/wild-manarotations:readWeekly Wild Mana biome rotation
/v1/rotations/stampyrotations:readWeekly Stampy event biome (48-hour window)
/v1/feeds/news?limit=feeds:readLatest Trove news relayed from trovegame.com (1–50, default 20); full archive at /v1/misc/news-history
/v1/feeds/twitchfeeds:readLive Trove Twitch streams (channel, title, viewers, thumbnail)
/v1/feeds/youtubefeeds:readRecent Trove YouTube videos
/v1/feeds/bilibilifeeds:readRecent Trove Bilibili videos
/v1/feeds/eventsfeeds:readOngoing Trovesaurus events (filter by ?category=)
/v1/feeds/events/categoriesfeeds:readDistinct event categories (discovered dynamically)
/v1/feeds/events/upcoming · /historyfeeds:readEvents not yet started / already ended (both filterable)
/v1/stats/power-rankstats:readPower Rank stat table - each source and the PR it gives
/v1/stats/magic-findstats:readMagic Find stat table - each source and the MF it gives
/v1/stats/lightstats:readLight stat table - each source and the Light it gives
/v1/stats/classesstats:readAll 18 classes as full objects, keyed by tech_name
/v1/stats/classes/{tech_name}stats:readOne class by its tech_name token (e.g. knight)
GET /v1/gems/lookupsgems:readValid gem field values (tiers, types, elements, stats, augments, abilities)
POST /v1/gems/generategems:readRoll a gem (omit any field for random) → a gem object
POST /v1/gems/augmentgems:readApply a focus augment to a stat by position → updated gem
POST /v1/gems/spark · /flaregems:readReroll a stat type / move a proc, by stat position → updated gem
POST /v1/gems/level-up · /set-levelgems:readRaise or set a gem's level → updated gem
POST /v1/gems/evaluategems:readScore a typed-in gem: quality %, Power Rank, cost to perfect
GET /v1/gems/stat-rangegems:readPlausible (min, max) value a stat can roll at
GET /v1/gems/builds/optionsgems:readValid build-config field values (classes, allies, foods, flags)
POST /v1/gems/builds/calculategems:readTop gem proc layouts for a build, ranked by damage coefficient
GET /v1/misc/news-history?limit=&offset=misc:readFull Trove news archive (never pruned), newest first, paginated
GET /v1/btt/releases?channel=&limit=&offset=btt:readBetterTroveTools GitHub releases (newest first; filter by release / beta channel)
GET /v1/btt/latest?channel=btt:readLatest BTT version per platform (windows/linux/android); each platform walks back to find an asset
GET /v1/btt/latest/{platform}?channel=btt:readLatest BTT version for one platform
GET /v1/btt/check?installed=&platform=&channel=btt:read"Is there an update?" server-side version compare; returns { update_available, latest } so the client just reads a bool
GET /v1/btt/changelog?limit_groups=&commits_per_group=btt:readCommits grouped by git tag (mirrors BTT's "Show changelog" button); newest first with an "Unreleased" group leading; cached so users don't trip GitHub's 60/hr unauth rate limit
GET /v1/misc/softwaremisc:readThird-party Trove modding software, grouped by category
GET /v1/misc/timezonesmisc:readTimezones supported by the converter and clocks
GET /v1/misc/time/nowmisc:readCurrent time across every zone, incl. Trove server (reset) time
POST /v1/misc/time/convertmisc:readConvert a time/zone (or unix) to every zone + Discord timestamp codes
POST /v1/mods/readmods:readDecompile a .tmod (POST raw bytes); ?metadata_only= omits file contents
POST /v1/mods/buildmods:readBuild a .tmod from header fields + files → raw bytes
GET /v1/updates/branchesupdates:readTracked branches (live-us / pts) with current version + file count
GET /v1/updates/{branch}/versionsupdates:readCaptured game version history, newest first
GET /v1/updates/{branch}/tree?prefix=updates:readDirectory listing, one level at a time (latest version)
GET /v1/updates/{branch}/file?path=updates:readDownload a single archived game file (streamed); /file/meta for hash + size
GET /v1/codexes/typescodexes:readCodex types present (ally, mount, dragon, memento, recipe, item, fish, badge) with counts
GET /v1/codexes/search?q=&type=&category=&tradable=&sort=codexes:readCross-type search/filter - the unified search surface; each result carries its type
GET /v1/codexes/{type}?search=&category=&tradable=&sort=codexes:readEntries of one type - filter (name/description, category, tradable), sort, paginate
GET /v1/codexes/{type}/categoriescodexes:readDistinct categories (+ counts) in a type, for filter dropdowns
GET /v1/codexes/{type}/entry?path=codexes:readOne codex entry by its source prefab path

News, streams, videos, and events are relayed from upstream sources and cached/stored server-side (refreshed on a timer), so your code hits one fast, consistent API. Events are kept after they leave the upstream feed, so /events/history and /events/upcoming work alongside what's ongoing; categories are free-form and discovered dynamically. Stat tables and classes are raw game data - transmitted as-is, no calculation. Each class carries a stable tech_name token you can store and look it up by later.

The gem tools are stateless: nothing is stored server-side. generate returns a gem object; you hold it and POST it back to an action endpoint (augment, spark, flare, level-up, set-level) with a stat_position (0, 1 or 2) to mutate it, and it's returned updated. evaluate and builds/calculate are pure calculators; the lookups and builds/options endpoints tell you every valid field value to send.

The mod tools are stateless too. /mods/read takes the raw .tmod bytes as the request body and returns its header properties and file table (paths, sizes, FNV checksums); pass ?metadata_only=true to skip the (base64) file contents. /mods/build takes header fields + files and returns a freshly built .tmod as application/octet-stream - built in memory and discarded once sent. The built mod's modLoader header is stamped KiwiAPI. These two endpoints accept a larger 20 MB body.

Example: a merchant timer

curl https://api.aallyn.net/v1/rotations/fluxion \
  -H "Authorization: Bearer $KIWI_TOKEN"

# → {
#   "active": true,
#   "state": "voting",                 // voting | selling | away
#   "starts_at": 1717326000,
#   "ends_at": 1717585200,
#   "seconds_remaining": 46800,        // to leaving when active, else to arriving
#   "schedule": [                      // upcoming windows, soonest first
#     { "starts_at": …, "ends_at": …, "state": "voting" },
#     { "starts_at": …, "ends_at": …, "state": "selling" }
#   ]
# }

Example: the biome rotation

curl https://api.aallyn.net/v1/rotations/biomes \
  -H "Authorization: Bearer $KIWI_TOKEN"

# → {
#   "current":  { "starts_at": …, "ends_at": …,
#                 "biomes": [ { "name": "Volcanic Fields", "final_name": "Dragonfire Peaks", "icon": "dragon" }, … ] },
#   "upcoming": [ { "starts_at": …, "ends_at": …, "biomes": [ … ] }, … ]
# }

News refreshes on a background timer; everything else is computed on demand. daily-buffs / weekly-buffs return the current buff plus the whole rotation (full game data: name, color, emoji, buff lists, icons).

Rate limits

Limits are enforced per fixed window. Every rate-limited response carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (unix seconds) headers so you can self-throttle. When you exceed a limit you receive 429 with an additional Retry-After header (seconds to wait).

SurfaceDefault limitKeyed by
Signup5 / hourclient IP
Login10 / 5 minclient IP
API requests120 / minuteAPI token

Error responses

Every error returns a consistent JSON envelope with a stable, machine-readable code you can branch on, a human-readable message, and optional details.

{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded. Slow down and try again later.",
    "details": { "limit": 120, "window_seconds": 60 }
  }
}
StatuscodeMeaning
400captcha_failed / bad_requestCaptcha rejected or malformed request
401not_authenticatedMissing, invalid, expired, or revoked credentials
401invalid_credentialsWrong email or password (login)
403email_unverifiedMust verify your email before minting tokens
403forbiddenAuthenticated but not allowed
404not_foundResource missing or not yours
409email_takenEmail already registered
422validation_errorBody failed validation (details lists fields)
429rate_limitedRate limit exceeded (see Retry-After)
500internal_errorUnexpected server error