Living Worlds

API guides

Start building.

Six short guides, from a first call to answers held to the real world. Every operation they use is in the reference.

Before you start

Access comes with a base address for your project and keys. Send a key as a bearer token on every call. Keys are server-side only: never in a browser or an app.

Three roles: a member key does the work, an admin key designs and manages, and a checker key reports verdicts on work it did not do. Each operation in the reference names the role it needs.

Check that your key and address work by asking for the contract. It lists every operation the server accepts, and the server checks itself against it on every start.

curl -H "Authorization: Bearer $LW_KEY" "$LW_URL/contract"

Ask a population a question

A simulation run draws a population from a persona pack, shows it a stimulus and measures how it reacts. Packs you can use are listed at GET /packs. A share of members can answer in their own words (voice), and spreading the run across seeds shows how much the answer moves.

The run is queued as jobs. Follow it at GET /events (watch for sim.progress and sim.done), then read GET /sim/runs/:id. Its results.trust block reports the seed spread, test-retest reliability, collapse checks and the design's backtest skill, so you can see how far to trust the answer. At most three runs are queued or running per project.

curl -X POST "$LW_URL/sim/runs" \
  -H "Authorization: Bearer $LW_ADMIN_KEY" -H "Content-Type: application/json" \
  -d '{
    "pack": "PACK_KEY",
    "population": { "simulate": 5000, "represents": 1000000, "seed": 7 },
    "stimulus": { "text": "A four-day working week, at the same pay" },
    "measures": ["appeal", "share_intent"],
    "voice": { "members": 200 },
    "seeds": 5
  }'

Run a world over time

In the examples, PACK_KEY is a pack key from GET /packs. A world holds a living population that goes on over simulated time: households, ties, circles, life events, word of mouth and memory. It is created paused at tick 0, and the reply carries its plan: the scale you asked for, the scale the model and the arithmetic sustain, and why.

Step it while paused (POST /worlds/:id/step), jump ahead (/jump) or run it at its scale (/run). Read what happened tick by tick at GET /worlds/:id/replay, meet members at /members, and branch at any tick to compare two futures that share one past. Interventions are added while the world is paused.

curl -X POST "$LW_URL/worlds" \
  -H "Authorization: Bearer $LW_ADMIN_KEY" -H "Content-Type: application/json" \
  -d '{
    "name": "Riverside, five years",
    "pack": "PACK_KEY",
    "population": { "simulate": 2000, "seed": 3 },
    "time": { "start": "2026-01-01", "horizon": "1825d", "step": "1d" },
    "budget": { "calls_per_day": 20 }
  }'

curl -X POST "$LW_URL/worlds/$WORLD/step" -H "Authorization: Bearer $LW_ADMIN_KEY" \
  -H "Content-Type: application/json" -d '{ "ticks": 30 }'

Agents with a life

A self is an agent with a character, a record and lessons it learns from what happened. Give birth to one with POST /selves. Before each call your product asks for the self's context (POST /selves/:handle/context): what it should know, including what the person it is serving has said is true of them, and a ticket.

After the work, report the outcome on the ticket. A person's verdict moves belief; only a registered checker, at POST /checks, can change how a self works. Every episode lands in the self's hash-chained record. The server-side SDK wraps this as a turn.

import { LivingWorlds } from "@livingworlds/sdk";

const lw = new LivingWorlds();          // reads LW_URL and LW_KEY
const turn = await lw.turn({ self: "concierge", task: question, person: userId });
const answer = await yourModel(turn.wrap(question));
await turn.done(answer);

Hold answers to the real world

A model's answer is worth what it survives. Three tools keep it honest.

POST /calibrate/rectify corrects a model's answers with a small real sample, giving an estimate and interval that stay valid however wrong the model is. POST /calibrate/intervals gives intervals that keep their coverage, by subgroup.

POST /forecasts registers a forecast before the moment it is for; once that moment passes the server refuses it. Post actuals and every open forecast for that subject is scored; GET /forecasts/ledger keeps the accuracy of each method against naive baselines.

curl -X POST "$LW_URL/forecasts" \
  -H "Authorization: Bearer $LW_ADMIN_KEY" -H "Content-Type: application/json" \
  -d '{
    "subject": "tickets sold, opening week",
    "target_at": "2026-12-01",
    "value": 4200, "low": 3600, "high": 4900,
    "method": "swarm+release",
    "baselines": { "last": 3900 }
  }'

Follow along, and work through MCP

Everything that happens is an event. Ask GET /events with the last id you saw to follow runs, worlds and work as they move.

Agents can use the same capabilities as MCP tools at POST /mcp (Streamable HTTP), with the same keys and roles.

curl -H "Authorization: Bearer $LW_KEY" "$LW_URL/events?after=$LAST_ID&limit=100"