---
name: set-api
title: Set World API
description: A complete fantasy RPG backend for game developers and agents. Procedurally generate characters, items, equipment sets, and full economies (rarity, crafting, salvage, stat boosts, monster drops, derived attributes, trait impacts, status effects, classes). Stateless JSON over HTTP GET, CORS open, no auth. Every generator is seedable and the forge makes one soul per call (single-flight), so a daily dungeon or a forty-character army is reproducible because a client expands one seed into per-soul derived seeds with `deriveSeed`. Progression, combat, and state stay with your game — Set generates, grades, and prices; it never levels. Use these mechanics as the foundation for your own game — every system is deterministic, composable, and ready to build on.
homepage: https://set.world
spec: https://set.world/api/spec
license: MIT
version: 1
methods: [GET]
auth: none
cors: open
content_type: application/json
canonical_paths:
  - https://set.world/skill
  - https://set.world/skill.md
  - https://set.world/.well-known/skill
  - https://set.world/.well-known/skill.md
  - https://set.world/llms.txt
  - https://set.world/api/skill
---

# Set World API

Set is an open fantasy RPG system designed for game developers and agents to build on. It provides a complete, tested mechanical foundation: procedural character generation, weighted item tables, a single-currency economy, 144 character classes, 288 skills, 48 status effects, 23 derived attributes, and a deterministic trait system. Everything is stateless JSON over HTTP GET — no auth, no session, no SDK required.

**Build your game on Set.** Use these APIs as the backend for a roguelike, a MUD, a card game, an idle clicker, a tabletop companion, a narrative engine, or anything else that needs RPG mechanics. Every system is composable: roll items independently, score them, craft toward target tiers, derive attributes from stats, price monster fights, and let equipment influence character power. The formulas are open, the data tables are MIT-licensed, and the API is CORS-enabled for any origin.

This skill is the human-and-agent-readable guide. The machine-readable surface map (every endpoint, query params, summary, and a two-line `scenario`) lives at `GET /api/spec`. When in doubt, fetch `/api/spec` first — it is the single source of truth and never drifts from this page.

## Conventions

- **Method**: `GET` only. Body-less.
- **Encoding**: JSON in, JSON out. Successful responses do not wrap (they return the payload directly).
- **Errors**: a uniform envelope `{ error: { code, message, field? } }`. `400` for validation, `501` for parked surfaces.
- **CORS**: open for `GET`, `POST`, `OPTIONS` from any origin.
- **Statelessness**: items are reconstructable from their roll vector; characters are the only persisted entity (encrypted blob in Postgres).
- **Seeds**: every roll, craft, and drop endpoint takes `seed=` (mulberry32) and returns the same result for that seed forever. A client fans one seed out into an army with `deriveSeed(seed, i) = (seed + i × 0x9E3779B9) >>> 0`, calling once per soul, each derived seed independently reproducible with `seed=<derived>`.
- **Content version**: every seeded envelope carries a `contentVersion` string; same seed + same `contentVersion` ⇒ identical forever; a changed value means a content update moved the roll stream.
- **Single-flight**: the forge makes one soul at a time — no `count=` fan-out; each `/api/roll/*` request returns one object; expand an army with `deriveSeed`, one call per soul.
- **Stat order**: when an endpoint takes `stats=`, the order is fixed: `strength, dexterity, intelligence, wisdom, agility, vitality, perception, resolve, luck` (9 dash-joined integers). Always confirm via `GET /api/stats`.
- **Primary stats**: only 5 of the 9 stats — `strength, dexterity, agility, intelligence, vitality` — power the derived-attribute formulas. The other 4 (`wisdom, perception, resolve, luck`) are still rolled, traited, and displayed, but they don't directly compute derived attributes; that keeps the formula stable when stats are added or renamed.
- **Slot order**: equipment iteration uses `EQUIPMENT_SLOT_ORDER` from `/api/slots`.
- **Grade scale**: items are graded F through S (seven grades), determined solely by material. The UI displays "Grade F" … "Grade S" — no fantasy tier names. Definitions: `GET /api/rarity/tiers`.
- **Material rank**: each material has a numeric `materialRank` (1–23 for tools, 1–30 for wearables) — its rank when sorted by drop weight, `1` = most common. It is NOT the letter grade; the letter grade (`tier`/`tierGrade`) is derived from `materialRank` via cumulative-weight share cutoffs.

## Discovery

Start with `GET /api/spec`. It returns `{ version, endpoints: [{ method, path, query?, summary, scenario: { use, returns }, example? }] }` — every endpoint with the same two-line "Use this when … / Returns …" copy a human reads on the home page.

```sh
curl https://set.world/api/spec
```

Supplementary tables that an agent typically needs once before composing other calls:

| Endpoint | Why |
| --- | --- |
| `/api/stats` | Canonical stat order and `[min, max]` bounds before posting `stats=` anywhere. |
| `/api/slots` | Slot list, per-slot capacity (hand and finger hold two), and the derived-attribute domain each slot influences. |
| `/api/drop/classes` | Encounter classes (`trash`, `veteran`, `elite`, `boss`, `world-boss`) and their drop multipliers (1, 3, 10, 50, 250). |
| `/api/rarity/tiers` | Grade F–S definitions and grade ranges per category (23 tool grades, 30 wearable grades). |
| `/api/salvage` | The disassembly schedule (F–C: 0, B: 2, A: 40, S: 200 orbs) and the strict-sink expectation that keeps it honest. |
| `/api/modifiers/spec` | The item power budget per grade, the 31 theme channels, and the hash rule that derives them. |
| `/api/attributes/spec` | Formula behind every derived attribute so a client can recompute locally. |

## Generators

### Roll a single item

```sh
curl https://set.world/api/roll/item
curl 'https://set.world/api/roll/item?seed=42'        # same item forever
```

Returns a fresh item enriched with `score, materialRank, tier, tierGrade, tierName, orbValue, material: { name, materialRank, tier, tierGrade, tierName }`, `affects` (the slot's derived-attribute domain), a one-row `breakdown` matching the per-slot shape from `/api/roll/set`, the `contentVersion` string, and the `seed` that produced it (`null` when unseeded). `tierName` returns grade labels (`'Grade F'` … `'Grade S'`); `tierGrade` returns the raw letter. The URL form `/roll/item` (no `/api`) renders the same item with the full weighted-table visualization and a permalink encoding the 19-number roll vector.

### Roll a full equipment set

```sh
curl 'https://set.world/api/roll/set?seed=7'
```

Returns `{ equipment, orbValue, orbBreakdown, seed }`. `orbBreakdown` walks `EQUIPMENT_SLOT_ORDER` and emits one row per slot with `affects` and the items inside.

### Roll a character (one at a time)

```sh
curl https://set.world/api/roll/character
curl 'https://set.world/api/roll/character?seed=2026'                  # same character forever
curl 'https://set.world/api/roll/character?seed=2026&equipmentBonus=1'  # fold gear bonuses into finalStats
```

Returns base `stats`, `modifiedStats` (base reconciled with trait deltas, clamped to `[8, 24]`), `equipmentBonus` (bool), `equipmentBonuses`, and `finalStats`. Equipment→stat bonus is opt-in: on a fresh roll `finalStats === modifiedStats`; pass `equipmentBonus=1` to fold the grade-gated per-slot gear bonus into `finalStats`. Also returns `equipment` (enriched), `powerRating` / `powerRatingMax` (the whole-character grade — a roster's salary cap is a sum of these), `equipmentOrbValue`, `equipmentOrbBreakdown`, `traits` (skills carry `flavor`; advantages/disadvantages each carry their FNV-1a-derived `impact`), `class`, the `contentVersion` string, the `seed`, and the twenty-three derived `attributes`. An army is a set of per-soul derived seeds via `deriveSeed` — one call per soul — so a whole roster is shareable and verifiable like an item URL.

## Rarity

### Score a known item

```sh
curl 'https://set.world/api/rarity?indexes=0-1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18'
```

Pass either `indexes=` (preferred — the index-vector form persisted in URLs) or `rolls=` (the raw 19-number roll vector). Returns `score, materialRank, tier, probability, orbValue, material: { name, materialRank, tier, tierGrade, tierName }`, and a `breakdown[]` of per-factor `−log10(p)` contributions sorted descending. The item's letter grade is determined solely by the rolled material — the quality score is informational only.

### Tier definitions

```sh
curl https://set.world/api/rarity/tiers
```

## Economy: orbs

The whole economy is denominated in a single currency (orbs). Every cost is precomputed and deterministic — the same inputs return the same result every time, so you can verify any cost by calling the endpoint (pass `seed=` to pin a roll).

### Crafting (rejection-sample to a target tier)

```sh
curl 'https://set.world/api/craft?tier=5'
curl 'https://set.world/api/craft/cost?tier=5'   # up-front price + budget
```

`craftCost(T) = 5^(T-1)` → `1, 5, 25, 125, 625, 3125, 15625` orbs for Grade F..S. The server rejection-samples until the material grade hits or the budget (`min(1_000_000, 100 × craftCost(T))`) runs out (`capped: true`).

### Best-of-N lottery

```sh
curl 'https://set.world/api/craft?orbs=125'
```

Returns the single highest-tier item across `N` independent rolls (ties broken by quality score) plus `rolls` (the actual `N`) and a `rollsExpected` percentile band keyed off the measured curve.

### Stat boost

```sh
curl 'https://set.world/api/boost/cost?from=14&to=18'
```

`boostCostStep(s) = (s-7)^3` for `8 ≤ s ≤ 20`, then `4096 / 8192 / 32768` for the perfect wall steps `21/22/23`. Total `8 → 24 = 53,337` orbs.

### Monster drops

```sh
curl 'https://set.world/api/drop?stats=12-14-10-11-13-16-12-14-11&class=elite'
```

`baseDrop = round((avgStat - 6)^2 / 4)` × encounter-class multiplier × `uniform(0.75, 1.25)` variance. Optional `override=` and `seed=` parameters are documented in `/api/spec`; `override.guaranteedTier=1..7` now returns a `guaranteedItem` (an enriched item plus its `salvage` value) crafted at that material grade on a derived seed. The seeded response also carries `contentVersion`.

### Salvage (disassembly)

```sh
curl 'https://set.world/api/salvage?tier=6'                  # by grade
curl 'https://set.world/api/salvage?indexes=<19-numbers>'    # appraise a known item
curl 'https://set.world/api/salvage'                         # schedule + sink invariant
```

Destroying an item refunds orbs by grade: F–C return `0`, B returns `2`, A returns `40`, S returns `200`. The schedule is pinned by the strict-sink invariant — the expected salvage per 1-orb roll is ≈ 0.70 orbs, so craft → disassemble → craft always loses ~30% and no spend size escapes the sink. Salvage is grading, not prescription: the endpoint scores the item; whether disassembly exists in your game is your call.

### Leveling is yours (levels are meaningless here)

There is no level curve and no level endpoint, on purpose. Set grants no stat points — how a character or a zone grows is your game's design, and `/api/drop` prices whatever stat block you bring. Because drop income is quadratic in enemy stats while craft and boost prices are geometric and cubic, *any* monotone level → stat mapping you invent inherits sane pacing automatically. Useful arithmetic if you're designing one: the stat space holds 144 grantable points (9 stats on `[8, 24]`), so granting a flat 8 points per level fields a maxed, world-boss-tier enemy after 18 level-ups. Where `level` appears in our envelopes (the character display default, the `/api/power` input) it is your number, weighted but never interpreted.

### Power rating (whole-character grading)

```sh
curl 'https://set.world/api/power?stats=14-12-10-11-13-16-12-14-11&skills=2'
```

One canonical number per character: `level × 100 + (str + int + dex + agi + vit) × 10 + (wis + per + res) × 5 + luck × 2 + skills × 25`, computed from the reconciled (final) stat block. `/api/roll/character` already includes `powerRating` and `powerRatingMax`; use this endpoint to re-grade characters you store yourself. Grading, not prescription — matchmaking rules stay with your game.

### Item power budgets (modifiers)

```sh
curl 'https://set.world/api/modifiers?indexes=<19-numbers>'
curl 'https://set.world/api/modifiers/spec'
```

Items never ship resolved stat modifiers. What Set grades is the **budget** — how much power an item of a given grade is entitled to (`F: 0, E: 1, D: 2, C: 4, B: 8, A: 16, S: 32` — budget doubles per grade while craft price grows 5×) — plus a **themed channel** for each name factor (prefix/quality/material/gear/suffix), hash-derived by the same pinned FNV-1a spec as traits into one of 31 channels (the 23 derived attributes + 8 elemental channels: fire, frost, lightning, poison, shadow, holy, arcane, nature). What a point of budget buys inside your combat math is your tuning knob; two games honoring the same Grade A item at different magnitudes are both correct.

## Traits

```sh
curl 'https://set.world/api/traits/impact?name=Iron%20Will&kind=advantage'
curl 'https://set.world/api/traits/impacts?kind=advantage'   # bulk pre-scored map
```

Every trait name hashes (FNV-1a 32-bit, offset basis `0x811c9dc5`, prime `0x01000193`, UTF-8 NFC) to a deterministic `{primary, primaryDelta, secondary?, secondaryDelta?, tier}`. Tiers 1–4 distribute 60/25/12/3. Magnitude tables: advantages `+5/+10/+15/+25%` primary; disadvantages `-8/-15/-22/-35%` primary.

## Derived attributes

```sh
curl 'https://set.world/api/attributes?stats=14-12-10-11-13-16-12-14-11'
curl https://set.world/api/attributes/spec
```

Twenty-three derived attributes — max health, stamina, physical/magical/action damage, six damage-reduction/resistance/dodge channels, six speed channels, carry capacity, jump height, vision range, crit chance, plus the three combat-utility channels `clarity` (anti-dodge accuracy), `initiative` (cooldown rate), and `reflexes` (counter to surprise hits) — each computed as `base + primaryCoef × (primary - 8) + secondaryCoef × (secondary - 8)` after the 5 primary stats are clamped to `[8, 24]`. Every primary and secondary in the formula table lives in `{strength, dexterity, agility, intelligence, vitality}`, so adding or renaming a non-primary stat can never break the derivation. `/api/attributes/spec` returns the full formula table.

## Recipes

### Build a complete level-1 character

```sh
curl https://set.world/api/roll/character
```

Single call: 9 base stats, modifiedStats, finalStats, traits with impacts, full equipment, orb-equivalent value of the loadout, power rating, twenty-three derived attributes.

### Mint two armies and price the battle

```sh
# side A: base seed 1, 40 souls — one call per derived seed
curl 'https://set.world/api/roll/character?seed=1'   # soul 0
curl 'https://set.world/api/roll/character?seed=<deriveSeed(1,1)>'  # soul 1 … through soul 39
# side B: base seed 2, 40 souls, same fan-out
curl 'https://set.world/api/roll/character?seed=2'   # soul 0 …
```

Each army is described by its base seed + count of souls; anyone re-mints either side by expanding that base seed with `deriveSeed(seed, i)` — one call per soul — and verifies a battle report. Match sides on summed `equipmentOrbValue` or `powerRating`.

### Price a fight

```sh
curl 'https://set.world/api/drop/classes'
curl 'https://set.world/api/drop?stats=...&class=boss'
```

### Craft up to Grade B

```sh
curl 'https://set.world/api/craft/cost?tier=5'   # → 625 orbs
curl 'https://set.world/api/craft?tier=5'        # → returns the Grade B item
```

### Validate a third-party item

A consumer that tracks items by index vector can re-derive everything from the indexes alone:

```sh
curl 'https://set.world/api/rarity?indexes=<19-numbers>'
```

## Reference Codexes

Set exposes its full data tables as queryable endpoints. Use these as codexes when designing your game:

| Endpoint | What you get | Build with it |
| --- | --- | --- |
| `/api/skills` | 288 skills with flavor text | Skill trees, talent systems, character progression |
| `/api/advantages` | Advantage trait pool | Perk systems, character creation bonuses |
| `/api/disadvantages` | Disadvantage trait pool | Flaw systems, challenge modifiers, cursed items |
| `/api/classes` | 144 classes with mainhand weapon binding | Class selection UI, weapon-class gating, NPC archetypes |
| `/api/effects` | 48 status effects with prose descriptions | Combat status systems, buff/debuff mechanics, item enchantments |
| `/api/stats` | 9 base stats with bounds | Character sheets, stat allocation UI, NPC scaling |
| `/api/slots` | 13 equipment slots with capacity and domain | Inventory systems, loadout screens, equipment comparisons |
| `/api/attributes/spec` | 23 derived attribute formulas | Tooltip systems, stat previews, build planners |
| `/api/rarity/tiers` | Grade F-S definitions | Loot filters, item comparison, reward thresholds |
| `/api/drop/classes` | 5 encounter classes with multipliers | Enemy design, encounter balancing, reward scaling |

### What you can build

- **Roguelike / dungeon crawler**: roll characters, roll items per room, price fights with `/api/drop`, craft upgrades between runs. Pass one `seed=` per run — creation is seeded too, so the whole dungeon replays from one integer for daily challenges and shareable ghosts; on permadeath, price the fallen hero's fifteen slots with `/api/salvage` into the next run's starting orbs.
- **Autobattler / mass battle**: mint two armies from two base seeds, expanding each into 40 per-soul derived seeds with `deriveSeed(seed, i)` — one `/api/roll/character` call per soul — and any spectator can re-mint either army from its base seed + count of souls. Match sides on summed `equipmentOrbValue` or `powerRating` as a salary cap, resolve combat with your own layer over the derived attributes (spend each item's `/api/modifiers` budget in your own combat math), then price every fallen enemy with `/api/drop` so victory pays out.
- **Idle / clicker game**: use orb economy (craft costs scale exponentially), stat boosts as prestige currency sinks.
- **Turn-based RPG**: read `initiative`/`reflexes`/`clarity` as turn order, ambush rounds, and hit confirmation; stamina and the cast/action charge speeds as your action economy; the 48 status effects as turn-native crowd control (durations and stacking are yours to define). Attribute units are advisory — the coefficients are the contract, so turn-meter readings are as legitimate as real-time ones.
- **Tactics / isometric board battles**: `walkSpeed` is tiles per turn, `jumpHeight` is obstacle traversal, `visionRange` is fog of war, `carryCapacity` is encumbrance. Movement range is a reading of existing attributes — no new math needed on either side.
- **MUD / text adventure**: character generation + classes + skills + effects give you a full mechanical layer; add your own narrative.
- **Tabletop companion**: roll characters at the table, use the trait impact system for deterministic modifiers, reference the attribute spec for combat resolution.
- **Card game**: each skill, class, or effect is a card; traits modify stats; equipment builds power rating.
- **NPC generator**: roll hundreds of characters via `/api/roll/character` to populate a world with mechanically distinct entities.
- **Build planner / theorycrafting tool**: `/api/attributes/spec` + `/api/boost/cost` + `/api/traits/impacts` give you everything needed for an optimizer.

### Design principles for builders

1. **Deterministic by default.** Trait impacts are hash-derived (same name = same modifier, always). Items are reconstructable from their roll vector. Pass `seed=` to any roll, craft, or drop endpoint for reproducible results — creation and economy alike.
2. **Composable, not coupled.** You can use the item system without characters, the economy without combat, the traits without equipment. Mix and match.
3. **No state on our side.** Items live in URLs, characters live in your database (or ours via the encrypted blob). You own your game state — which also means there is no scale ceiling on ours: one hero or eight hundred NPCs read the same economy.
4. **Extensible.** The grade scale, encounter classes, stat bounds, and formulas are all exposed via spec endpoints — your client can adapt to changes without redeploying.

## Source

The full source, conventions, and architecture: <https://github.com/jimmylee/set>. MIT licensed. Pages Router only. No client SDK.
