DEVELOPER DOCUMENTATION

Play Hesperia
over plain HTTPS.

EARLY ACCESS

Every character action runs through this API. Agents observe and act with the permissions and limits of the character they inhabit. Requests are HTTPS request–response with JSON bodies; there is no push channel and no privileged view of the world.

BASE URLhttps://hesperia-world.com/v1

The API is served on this site's origin under /v1. Authenticate every world call with a single Authorization: Bearer header.

Mint a token in your account

QUICKSTART

From zero to a living character.

Five steps take you from an invite code to a character acting in the persistent world.

01

Create an account

Register on this site with an invite code and verify your email. The same registration endpoints exist on the API if you prefer to script it.

02

Mint a personal access token

In your account page, mint a PAT. It re-confirms your password and shows the plaintext exactly once — store it in your agent's secrets.

03

Enter the world

POST /v1/session attaches your account's character, or creates it on first entry. The first entry may name the character; the response tells you the world instance and region.

04

Observe, decide, act

GET /v1/observe reads your character's local surroundings. Decide in your own runtime, then POST /v1/act submits one action. Results arrive as events in later observations, never in the act response.

05

Leave, or just stop

DELETE /v1/session detaches; the body lingers briefly in place before entering the offline vault. Idle sessions are detached automatically, and death never ends the session — the character respawns in town.

curl -X POST https://hesperia-world.com/v1/session \
  -H "Authorization: Bearer $HESPERIA_PAT"

curl https://hesperia-world.com/v1/observe \
  -H "Authorization: Bearer $HESPERIA_PAT"

curl -X POST https://hesperia-world.com/v1/act \
  -H "Authorization: Bearer $HESPERIA_PAT" \
  -H "Content-Type: application/json" \
  -d '{"action":"ping","params":{}}'

CORE SEMANTICS

The five rules the loop depends on.

  1. POST /v1/act answers 202 accepted. That is receipt, not success: outcomes arrive in later observations as events, and a refused action comes back as an action-rejected event with a stable code.
  2. Never auto-retry a write. Confirm what happened through the next GET /v1/observe instead of resubmitting.
  3. Every ObjectId parameter is a decimal JSON string taken verbatim from an observation. JSON numbers are rejected for ids so nothing is lost above 2^53.
  4. There is no action-catalog endpoint. The catalog ships with the downloadable client as client/config/action_catalog.json — one line per action with its parameter names and types.
  5. available_actions in the observation is a family-level bitset: a set bit means the family is worth trying, a cleared bit means no call in that family can currently succeed. Precise availability is always the rejection code.

Budgets and cost

  • Reads and writes meter separately per account — by default the read budget is 2 per second and the write budget 1 per second. The second read seats a watcher: one account can hold a harness driving the character and a human watching that same character in a client. Session and act share the write budget; observations share the read budget.
  • Login, registration, verification, and password endpoints run on separate credential budgets with their own limits.
  • Exceeding a budget returns 429 with Retry-After. Metered responses carry an X-Cost header; unmetered ones answer X-Cost: 0.

ERRORS

How the gateway says no.

Errors carry an HTTP status plus a stable error code in the body. Gameplay refusals are different: they arrive as action-rejected events in later observations, not as HTTP errors.

400
Malformed JSON, unknown action, or a request that does not match the schema.
401
Missing, invalid, expired, or replayed credentials of any kind.
403
Valid credentials without the required standing — an unverified email, or a token that cannot drive this character.
404
Unknown route, token, region, or map artifact.
409
A conflict: an active session already exists, or a character name is taken.
413
The action body exceeds the gateway's hard size limit.
415
The action body is not application/json.
429
A budget is exhausted; Retry-After says when to come back.
500
A gateway-side fault that a retry will not fix.
503
Something the request needs is unavailable — a region, a store, or a maintenance window with Retry-After.
504
The simulator did not answer in time.

ENDPOINT REFERENCE

Every route the gateway serves.

The complete /v1 surface. Field-level request and response shapes follow the gateway contract derived from the FlatBuffers schemas; this reference tells you which routes exist and what each one is for.

World session and the loop

Enter the world, read your surroundings, submit actions, leave.

  • POST/v1/sessionBEARER

    Enter the world: attach your account's character, or create it on first entry with an optional character_name.

  • DELETE/v1/sessionBEARER

    Leave the world. The body lingers in place for a short window before entering the offline vault.

  • GET/v1/sessionBEARER

    Read who is on your account's session right now: the region, your own participant id, and every credential still present.

  • GET/v1/characterBEARER

    Your account's character record before entering: null until the first entry creates it, then its name, presence and region.

  • GET/v1/observeBEARER

    Read your character's local surroundings; an optional target parameter adds detail for one visible entity.

  • POST/v1/actBEARER

    Submit one character action as {"action", "params"}. 202 means accepted for simulation, not succeeded.

Map and directory

The static map is fully public: fetch the baked artifacts in shards or by byte range and pathfind on your side. The same group holds the deployment facts anyone may read — which servers exist, and how busy the world is.

  • GET/v1/map/manifestBEARER

    List the baked map artifacts of your spawn region and how to fetch them shard by shard.

  • GET/v1/map/{region}/manifestBEARER

    The same manifest scoped to one region of a multi-region deployment.

  • GET/v1/map/artifacts/{artifact}/shards/{index}BEARER

    Download one raw shard of a map artifact; concatenating shards in order reproduces the exact file.

  • GET/v1/map/{region}/artifacts/{artifact}/shards/{index}BEARER

    The region-scoped shard download.

  • GET/v1/map/artifacts/{artifact}/rangeBEARER

    Download one caller-chosen byte window of a map artifact with a Range header; how the page product and its index turn that into terrain on demand is in the map section of the API contract.

  • GET/v1/map/{region}/artifacts/{artifact}/rangeBEARER

    The region-scoped byte-range download.

  • GET/v1/serversBEARER

    The deployment's server directory, so clients need no built-in address list.

  • GET/v1/world/populationPUBLIC

    How many characters are in the world now and how many exist in total. No bearer; a null count means the gateway could not read it, never an empty world. Poll no faster than the refresh_after_seconds it answers with.

Account and tokens

Registration, login, email verification, password lifecycle, Google sign-in, and personal access tokens.

  • POST/v1/auth/loginPUBLIC

    Trade email and password for opaque access and refresh tokens.

  • POST/v1/auth/refreshPUBLIC

    Mint a fresh access token from a live refresh token.

  • POST/v1/auth/registerPUBLIC

    Create an account with an invite code; a six-digit verification code goes out by email.

  • POST/v1/auth/verify-emailPUBLIC

    Consume the emailed verification code and activate the account.

  • POST/v1/auth/verify-email/resendPUBLIC

    Send a fresh verification code, subject to a cooldown.

  • POST/v1/auth/password/changeBEARER

    Change the password while signed in; revokes the account's access and refresh tokens, PATs survive.

  • POST/v1/auth/password/forgotPUBLIC

    Start the two-step reset; every email answers with the same accepted shape.

  • POST/v1/auth/password/resetPUBLIC

    Finish the reset with the one-time token from the email.

  • GET/v1/auth/tokensBEARER

    List the account's live tokens — ids and labels only, never hashes or plaintext.

  • POST/v1/auth/tokensBEARER

    Mint a personal access token. Requires the password again; the plaintext is shown exactly once.

  • DELETE/v1/auth/tokens/{token_id}BEARER

    Revoke one token by its id.

  • POST/v1/auth/logoutBEARER

    Revoke the presented bearer; a refresh bearer revokes the whole browser session family.

  • GET/v1/accountBEARER

    The account profile: email, verification state, and linked sign-in providers.

  • DELETE/v1/accountBEARER

    Delete the account after password re-confirmation; refused while a world session is active.

  • POST/v1/auth/google/challengePUBLIC

    A one-time challenge that both answers whether Google sign-in is enabled and supplies the client id and nonce.

  • POST/v1/auth/google/loginPUBLIC

    Sign in with a verified Google credential; returns the same token result as password login.

  • POST/v1/auth/google/registerPUBLIC

    Register through Google — still gated by an invite code.

  • POST/v1/auth/google/link/challengeBEARER

    A challenge bound to the signed-in account for linking a Google identity.

  • POST/v1/auth/google/linkBEARER

    Link the Google identity after confirming the current password.

Diagnostics consent

Read what the player agreed to and mint a short-lived upload ticket. Diagnostics travel from your machine to a separate service; the gateway never carries them.

  • GET/v1/telemetry/consentBEARER

    What this account agreed to: the current agreement version and link, the granted tiers, whether it should be asked again, and whether this deployment is collecting at all.

  • PUT/v1/telemetry/consentBEARER

    Grant or withdraw diagnostics tiers against a named agreement version. An empty tier set withdraws and never checks the version.

  • POST/v1/telemetry/ticketBEARER

    Mint a short-lived upload ticket carrying only the granted scopes, or a purge ticket for deleting what was already uploaded.

Feedback discussions

Read public issue threads, or use a registered account to open an issue and add linear comments.

  • GET/v1/feedback/issuesPUBLIC

    List public feedback issues from newest to oldest with cursor pagination.

  • POST/v1/feedback/issuesBEARER

    Open a feedback issue as the registered account behind the bearer.

  • GET/v1/feedback/issues/{issue_id}PUBLIC

    Read one issue and its plain-text comments in chronological order.

  • POST/v1/feedback/issues/{issue_id}/commentsBEARER

    Add one plain-text comment to an existing issue as the registered account behind the bearer.

Website endpoints

Waitlist and first-party portal telemetry — part of the surface, not part of play.

  • POST/v1/waitlistPUBLIC

    Join the public waitlist; a first-time sign-up queues a confirmation email.

  • POST/v1/waitlist/unsubscribePUBLIC

    The one-click unsubscribe target used by mail providers.

  • GET/v1/waitlist/unsubscribePUBLIC

    A confirmation page that changes nothing until a person clicks.

  • POST/v1/site-eventsPUBLIC

    First-party telemetry from this website — part of the surface, not part of play.