API
Public HTTP endpoints for the wiki. Validate world JSON against the live V33 schema, fetch section docs and schema fragments, or pull the full wiki as JSON or Markdown. Designed for AI agents authoring Voyage worlds, but you can hit them from any script or terminal too.
Last updated:
Overview
All endpoints share the same base URL and conventions:
-
Base URL:
https://voyagewiki.pages.dev - CORS: open to all origins — safe to call from any web page, terminal, or agent runtime.
- Auth: none. The wiki is a public reference.
-
Rate limits: the endpoint is rate-limited to protect the shared free-tier budget. If you exceed the limit you'll get
HTTP 429with aRetry-Afterheader indicating how long to wait. Slow your loop down and retry — legitimate validate-fix-revalidate workflows won't bump into it. -
Versioning: every endpoint serves the currently deployed wiki. The validator endpoint returns its
validatorVersionin the response body.
Quick reference
| Endpoint | Method | Purpose |
|---|---|---|
/api/validate
|
POST | Validate a world JSON. Returns errors, warnings, and recommendations. |
/api/index.json
|
GET | Manifest of every API endpoint. |
/api/sections.json
|
GET | Lightweight index of every documented section. |
/api/sections/<section>.json
|
GET | One section — prose, field notes, schema fragment. |
/api/sections/<section>.md
|
GET | Same as above, formatted as Markdown. |
/api/wiki.json
|
GET | Entire wiki, all sections in one payload (JSON). |
/api/wiki.md
|
GET | Entire wiki concatenated as Markdown. |
/api/schema.json
|
GET | Raw V33 codec schema. |
POST /api/validate
Validates a world JSON against the live V33 schema plus every semantic check the in-browser Validator performs — cross-references, enum validity, size limits, runtime-affecting authoring patterns. Output is byte-for-byte identical to the in-browser tool.
Request
Content-Type: application/json- Body: the world JSON object (same JSON you would paste into the Voyage editor).
- Max body size: 10 MB. Realistic worlds top out around 4–5 MB; the cap is twice that for headroom and to reject abuse payloads.
- Rate-limited. Exceeding the threshold returns
HTTP 429with aRetry-Afterheader (seconds until you can retry). Generous for validate-fix-revalidate loops — if you hit it, slow the loop down.
Response
JSON object with:
counts—{ errors, warnings, recommendations }totals.errors— array of{ path, message, affectedKeys? }. Will break at runtime — broken references, invalid enums, codec shape violations, hard schema misconfigurations. The Voyage editor still publishes worlds with these intact; the engine then silently drops fields, breaks lookups, or throws when the affected code path runs.warnings— array of{ path, message, affectedKeys? }. Might break at runtime — data that the engine may tolerate today but where behaviour is degraded, fragile, or silently wrong (broken area paths, invalid item slots, quest fields whose absence may prevent completion).recommendations— array of{ path, message, affectedKeys? }. Might improve quality — missing optional context the AI would benefit from (emptyhiddenInfo, sparsepersonality, undocumented fields). Safe to ignore by design.validatorVersion— ISO-8601 timestamp of the currently deployed validator.
Issues in each array are sorted by path for stable diffs. Messages embed backtick-wrapped field names and values for easy parsing.
affectedKeys is present only on grouped checks that aggregate many entities (e.g. "71 NPCs have visualDescription set"). The human message truncates the list to a 4 or 5-name preview followed by "(+N more)"; affectedKeys carries the complete array of entity keys so an agent can iterate every affected entity without re-scanning the world JSON. Absent on per-entity issues where the entity is already in path.
Example (curl)
curl -X POST https://voyagewiki.pages.dev/api/validate \
-H 'Content-Type: application/json' \
--data-binary @MyWorld.json
Example (JavaScript)
const result = await fetch('https://voyagewiki.pages.dev/api/validate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(world),
}).then(r => r.json());
console.log(result.counts);
result.errors.forEach(({ path, message }) => console.log(path, message));
Example (Python)
import json, urllib.request
with open('MyWorld.json', 'rb') as f:
body = f.read()
req = urllib.request.Request(
'https://voyagewiki.pages.dev/api/validate',
data=body,
headers={'Content-Type': 'application/json'},
)
result = json.loads(urllib.request.urlopen(req).read())
print(result['counts'])
Endpoint discovery
Issuing GET /api/validate instead of POST returns a machine-readable contract describing the endpoint — useful when an agent encounters the URL and wants to verify its shape before posting.
GET /api/index.json
Manifest listing every API endpoint with its purpose. Use this as an entry point when an agent discovers the wiki and wants to enumerate available data.
curl https://voyagewiki.pages.dev/api/index.json
GET /api/sections.json
Lightweight index of every documented section — section key, title, tab, summary, last-updated timestamp. No body content. Good for an agent to enumerate before fetching specific sections.
curl https://voyagewiki.pages.dev/api/sections.json
GET /api/sections/<section>.json or .md
One section, fully self-contained. The .json form returns structured data; the .md form returns Markdown formatted for direct ingestion by an LLM. Both contain the same content:
- Section metadata (title, summary, editor location, related sections).
- Full prose body of the wiki page.
- Per-field notes pulled from the V33 schema.
- The V33 schema fragment for that section (io-ts codec definition).
Section keys match the URL slug under /world, /mechanics, /ai, /other. Examples: npcs, locations, traits, aiInstructions, storySettings.
curl https://voyagewiki.pages.dev/api/sections/npcs.json
curl https://voyagewiki.pages.dev/api/sections/locations.md
GET /api/wiki.json or .md
The entire wiki in one payload. Useful when an agent wants the full V33 reference loaded into its context window in a single request.
curl https://voyagewiki.pages.dev/api/wiki.json
curl https://voyagewiki.pages.dev/api/wiki.md
The Markdown form is typically the better fit for LLM ingestion — tokenizes cleanly and preserves heading structure.
GET /api/schema.json
Raw V33 codec schema as JSON. The same schema fragments embedded in the section endpoints, aggregated. Useful when an agent wants to validate field types without going through /api/validate.
curl https://voyagewiki.pages.dev/api/schema.json
Mirror the wiki for an offline agent
Some agents (notably ChatGPT and Codex in long-running threads) intermittently fail to fetch live URLs they should be able to reach. Mirroring the wiki to local disk once sidesteps that entirely — the agent reads from files instead of fetching. This pulls the top-level payloads plus every section, driving the section loop from sections.json so it never goes stale when sections are added or removed:
set -e
base='https://voyagewiki.pages.dev'
out='./voyage-wiki' # change to your docs folder
mkdir -p "$out/sections"
curl -sSL "$base/llms.txt" -o "$out/llms.txt"
curl -sSL "$base/api/index.json" -o "$out/api-index.json"
curl -sSL "$base/api/sections.json" -o "$out/api-sections.json"
curl -sSL "$base/api/schema.json" -o "$out/api-schema.json"
curl -sSL "$base/api/wiki.json" -o "$out/api-wiki.json"
curl -sSL "$base/api/wiki.md" -o "$out/api-wiki.md"
# Drive the per-section loop from the live manifest (requires jq) so it never goes stale
curl -sSL "$base/api/sections.json" | jq -r '.[].section' | while read -r s; do
curl -sSL "$base/api/sections/$s.md" -o "$out/sections/$s.md"
done
On Windows, the bash version needs Git Bash or WSL. PowerShell does the same thing natively with no jq dependency, since it parses JSON for you:
$base = 'https://voyagewiki.pages.dev'
$out = './voyage-wiki' # change to your docs folder
New-Item -ItemType Directory -Force -Path "$out/sections" | Out-Null
Invoke-WebRequest "$base/llms.txt" -OutFile "$out/llms.txt"
Invoke-WebRequest "$base/api/index.json" -OutFile "$out/api-index.json"
Invoke-WebRequest "$base/api/sections.json" -OutFile "$out/api-sections.json"
Invoke-WebRequest "$base/api/schema.json" -OutFile "$out/api-schema.json"
Invoke-WebRequest "$base/api/wiki.json" -OutFile "$out/api-wiki.json"
Invoke-WebRequest "$base/api/wiki.md" -OutFile "$out/api-wiki.md"
# Section loop driven from the live manifest, so it never goes stale
Invoke-RestMethod "$base/api/sections.json" | ForEach-Object {
Invoke-WebRequest "$base/api/sections/$($_.section).md" -OutFile "$out/sections/$($_.section).md"
}
If you only need the full reference in one file, skip the loop entirely and fetch /api/wiki.md — it bundles every section into a single Markdown document. The per-section mirror is for agents that want to open one topic at a time.
Agent prompt snippet
Drop this into your agent's system prompt or task instructions so it validates as it works:
You are authoring or editing a Voyage Heroes V33 world JSON.
Reference docs: every wiki section is available as a self-contained
endpoint at https://voyagewiki.pages.dev/api/sections/<section>.md
or .json. Fetch only the sections you need, or pull the whole wiki
from /api/wiki.md in one request.
Verification: to verify the world, POST the JSON to
https://voyagewiki.pages.dev/api/validate. The response groups issues
by severity:
- errors: runtime-affecting problems. Fix these. The Voyage editor
publishes worlds with errors intact, but the engine silently drops
fields or breaks lookups at runtime.
- warnings: quality issues. Many are intentional design choices;
read the "Safe to ignore when..." line in each message before
acting.
- recommendations: best-practice suggestions, same rule as warnings.
Validate after each batch of changes. Do not declare work complete
until counts.errors is 0.
Conventions and notes
-
Backtick chips in messages. Validator messages use backtick-wrapped tokens (
`House Smallwood`,`currentArea`) to mark field names and values. Agents can parse these as code-like literals for diff/edit reasoning. -
Path notation. Validator
pathvalues use dot/bracket notation into the world JSON — e.g.locations.Acorn Hall.factions[0],npcs.Bran Stark.type,traits.Archer.startingItems[3].item. The path locates the exact field that produced the issue. -
Newlines in messages. Validator messages occasionally embed
\nas a structural separator (the in-browser tool renders these as line breaks). Treat them as paragraph boundaries when parsing. - Identical surfaces. The in-browser validator and this endpoint share the same engine. Output is identical across both.
- No write endpoints. The wiki is read-only. Validation does not modify the submitted JSON.