API
The leaderboard routes are public and allow cross-origin reads. Everything else needs a key.
Envelope
Every response is JSON. Successful responses wrap the payload:
{"data": ..., "meta": {"game": "classic_era", "build": "1.15.9.69722", "engineVersion": "...", "generatedAt": "..."}} Errors:
{"error": {"code": "spec_mismatch", "message": "the export is a Mage, this spec is warrior"}} Lists paginate with ?page=&perPage= (max 500) and carry page, perPage and total in meta.
Public leaderboard routes
No key. Writes are limited per address.
GET /v1/games/{game}/profileActive encounter profile, phase and notes.
GET /v1/games/{game}/specsEvery spec with role, ranked flag, engine status, current champion summary and co-champion count.
GET /v1/games/{game}/championsCurrent champions across specs, full records.
GET /v1/games/{game}/specs/{spec}Spec, profile, current champions, past champions and the last 50 challenges.
GET /v1/games/{game}/specs/{spec}/apl-presetsRotation presets for the spec: [{name, apl}].
GET /v1/games/{game}/specs/{spec}/bisLatest generated sets with DPS, intervals, ties and stat weights, or {"status":"not_generated"}.
POST /v1/games/{game}/specs/{spec}/submissionsSubmit a build. 202 with {submissionId, status, queuePosition, poll}.
GET /v1/games/{game}/submissions/{id}Status, queue position, stage results, verdict and the build. Always public.
GET /v1/games/{game}/submissions?spec=&status=Recent submissions, the queue view.
Keys and limits
Send the key as X-API-Key: sf_<prefix>.<secret>. A missing or invalid key returns 401. Each key has a token bucket per minute; when it runs out you get 429 with Retry-After. Every response carries X-RateLimit-Limit and X-RateLimit-Remaining.
POST /v1/keysCreate a key: {"email","name"} returns {"key"} once. Free tier, 60 requests per minute.
GET /v1/gamesGames the API knows.
POST /v1/games/{game}/simsRun one sim from a wowsims link or settings export, up to 25,000 iterations. 202 with a job id.
GET /v1/sims/{id}Sim job status and summary.
GET /v1/jobs/{id}Any job by id.
Examples
Current champions:
curl https://forever.howtoguides.online/v1/games/classic_era/champions One spec with history:
curl https://forever.howtoguides.online/v1/games/classic_era/specs/warrior Submit a build from the WoWSims Exporter addon string, using a preset rotation:
curl -X POST https://forever.howtoguides.online/v1/games/classic_era/specs/warrior/submissions \
-H 'Content-Type: application/json' \
-d '{
"source": "addon",
"addon": "{\"class\":\"Warrior\",\"race\":\"Orc\",\"talents\":\"30305001302-05050005525010051\",\"gear\":{\"items\":[...]}}",
"aplPreset": "dps_reck",
"finderName": "Thrandor"
}' Submit from a wowsims link with your own rotation and talents:
curl -X POST https://forever.howtoguides.online/v1/games/classic_era/specs/warrior/submissions \
-H 'Content-Type: application/json' \
-d '{"source": "link", "link": "https://wowsims.github.io/classic/warrior/#...", "talents": "30305001302-05050005525010051", "apl": {"type": "TypeAPL", "priorityList": [...]}, "finderName": "Thrandor", "finderContact": "thrandor@example.org"}' Poll a submission:
curl https://forever.howtoguides.online/v1/games/classic_era/submissions/101 Create a key for the keyed routes:
curl -X POST https://forever.howtoguides.online/v1/keys -H 'Content-Type: application/json' -d '{"email": "you@example.org", "name": "my tool"}'