Home Grids API
Every player gets one free home grid — a personal plot-sized zone (64×64×64) they fully control. Home grids are player-hosted: the owner's own game client runs the world as a listen server, with no dedicated server involved. Blocks persist to the cloud through the standard block endpoints, authorized by the owner's user JWT.
Key properties:
- Free — no credit cost, provisioned lazily on first access
- One per player — enforced by a unique index on
(owner_id)for home zones - Invite-only by default — guests join via invite codes
- Owner has full admin rights — build, moderate, manage roles and invites
- Reserved coordinates — home zones live in a coordinate band far outside the purchasable Grid (
coord_y = 1,000,000) and never appear in discovery queries
Provisioning
Get (or Create) My Home Grid ✅ Auth
GET /api/zones/home
Returns the caller's home zone. If it doesn't exist yet, it is created on the spot — free of charge — along with two default roles: Guest (no permissions) and Builder (zone.build).
Response (200 existing, 201 newly created):
{
"id": "zone_abc123",
"owner_id": "user_xyz",
"name": "willow's Home",
"size_tier": "plot",
"coord_x": 42,
"coord_y": 1000000,
"width": 64, "height": 64, "depth": 64,
"visibility": "invite_only",
"max_players": 8,
"zone_type": "home",
"created": false
}
Resolve Another Player's Home ✅ Auth
GET /api/zones/home/of/:userId
Returns basic info about a player's home zone, including whether it is currently being hosted.
{
"id": "zone_abc123",
"name": "willow's Home",
"owner_id": "user_xyz",
"owner_name": "willow",
"visibility": "invite_only",
"max_players": 8,
"is_hosted": true
}
Errors: 404 (player has no home zone)
Host Sessions
Because home grids have no dedicated server, the owner's client announces a host session while it is hosting. Guests can only join while a session is live.
All three endpoints require the zone owner's user JWT and a zone_type = 'home' zone.
Start Hosting ✅ Auth (Owner Only)
POST /api/zones/:id/host/start
{
"eos_session_id": "abc...", // optional — EOS session for P2P join
"connect_string": "1.2.3.4:7777", // optional — direct connect fallback
"max_players": 8 // optional, capped at the zone's max
}
One session per zone — restarting the host replaces the previous session.
Heartbeat ✅ Auth (Owner Only)
POST /api/zones/:id/host/heartbeat
{ "player_count": 3, "eos_session_id": "abc..." }
Send every ~30 seconds. Sessions with heartbeats older than 2 minutes are considered offline (a cron sweep marks stale sessions offline every 5 minutes).
Errors: 404 (no session — call /host/start first)
Stop Hosting ✅ Auth (Owner Only)
POST /api/zones/:id/host/stop
Marks the session offline immediately.
Joining a Home Grid
The standard Join Zone endpoint branches for home zones:
GET /api/zones/:id/join
Owner — always receives a directive to self-host:
{
"zone_id": "zone_abc123",
"zone_name": "willow's Home",
"connect_method": "host_local",
"width": 64, "height": 64, "depth": 64,
"size_tier": "plot",
"max_players": 8
}
Guest, owner hosting — receives the live session plus a visit token:
{
"zone_id": "zone_abc123",
"connect_method": "eos",
"eos_session_id": "abc...",
"connect_string": "1.2.3.4:7777",
"visit_token": "eyJ...",
"player_count": 2,
"max_players": 8
}
The visit token's can_build claim is resolved from the guest's zone roles — a guest with the Builder role can place and remove blocks; everyone else is visit-only.
Guest, owner offline — 503:
{ "error": "The owner is not hosting this home grid right now" }
Standard ban and visibility checks apply before any of the above (invite-only means guests need a membership from a redeemed invite).
Invites
Invite codes grant membership to non-public zones — including home grids. Schema supports both open codes and codes targeted at a specific player.
Create Invite ✅ Auth (Owner or zone.members)
POST /api/zones/:id/invites
{
"invited_user_id": "user_abc", // optional — restrict to one player
"max_uses": 5, // optional — default unlimited
"expires_in_hours": 24 // optional — default never
}
Response (201):
{
"id": "invite_1",
"zone_id": "zone_abc123",
"invite_code": "7f3kq9xd",
"max_uses": 5,
"expires_in_hours": 24
}
Redeem Invite ✅ Auth
POST /api/zones/invites/:code/accept
Adds the caller to the zone with the Guest role (created on demand if missing).
{ "zone_id": "zone_abc123", "zone_name": "willow's Home", "joined": true }
Errors: 404 (unknown code), 410 (expired or no uses remaining), 403 (targeted at another player, or banned)
List Invites ✅ Auth (Owner or zone.members)
GET /api/zones/:id/invites
Revoke Invite ✅ Auth (Owner or zone.members)
DELETE /api/zones/:id/invites/:inviteId
My Memberships ✅ Auth
GET /api/zones/memberships
Returns the zones the caller has joined — the "places I can visit" list.
{
"zones": [
{
"id": "zone_abc123",
"name": "willow's Home",
"zone_type": "home",
"owner_id": "user_xyz",
"owner_name": "willow",
"size_tier": "plot",
"visibility": "invite_only"
}
]
}
Block Persistence (Owner JWT)
The block endpoints normally require an operator key (dedicated servers only). For home zones, they also accept the owner's user JWT — the owner's client is the hosting authority for their own home:
POST /api/zones/:id/blocks Authorization: Bearer <user JWT>
DELETE /api/zones/:id/blocks/:blockId
PUT /api/zones/:id/blocks/:blockId/faces
GET /api/zones/:id/blocks/all
POST /api/zones/:id/chat
The JWT path is rejected (403) unless both are true:
- The zone's
zone_typeishome - The JWT subject is the zone's owner
Guests' builds are persisted by the hosting owner's client with the guest recorded as placed_by.
Game Client Flow
- Player clicks My Home Grid in the main menu
- Client calls
GET /api/zones/home(creates the zone on first use) - Client opens the home level as a listen server (
AHomeGridGameMode) — the host's PlayerState gets full owner permissions from the local session - Client calls
POST /:id/host/startand heartbeats while hosting - Persisted blocks load via
GET /:id/blocks/all; new builds save through the block endpoints with the owner's JWT - Guests with a redeemed invite call
/joinand connect to the host's session, authenticated by their visit token onPreLogin - When the owner leaves, the client posts
/host/stopand guests are disconnected