Skip to main content

World HTTP API

Read as Markdown · MCP tools · World schema

Base URL and authentication​

Use https://betworld.gg/api/worlds. All JSON requests use Content-Type: application/json. GLB uploads use Content-Type: model/gltf-binary and raw file bytes.

AccessHow to authenticateUse for
PublicNo credentialBrowse published worlds and download published documents or assets
Owner sessionYour signed-in Betworld session cookieCreate worlds, manage credentials, inspect your library and publish
World tokenAuthorization: Bearer <token>Let your AI read and edit one world draft and upload assets to your library

Sign in with a registered account for owner routes. In the Betworld website, use fetch with credentials: "same-origin"; your browser supplies the session cookie and Origin. Session-based write requests require Origin: https://betworld.gg. For token-based /ai/... requests, a command-line or MCP client can omit Origin. If supplied, it must match the Betworld origin.

Create a token for each world you connect. Tokens remain valid until you revoke or replace them. Store the token in your AI client's secret settings. Owner-session actions, including publishing, are available through your signed-in website session.

Route index​

Paths below are relative to /api/worlds.

MethodPathAccessResult
GET/PublicActive world directory, lobby population and limits
GET/mineOwnerYour worlds, asset library, usage and earnings
POST/OwnerCreate a world with a basic starting layout
GET/:id/documentPublicPublished document and published revision
GET/:id/statusOwnerDraft revision, published revision and entity count
GET/:id/draftOwnerYour editable document and asset library
PUT/:id/draftOwnerReplace your draft using its current revision
POST/:id/publishOwnerPublish a saved revision
POST/:id/ai-tokenOwnerCreate or replace the world's AI credential
DELETE/:id/ai-tokenOwnerRevoke the world's AI credential
POST/assetsOwnerUpload a static GLB to your library
GET/assets/:hash.glbPublicDownload an immutable converted GLB
GET/ai/draft/documentWorld tokenRead the connected draft, catalog, limits and schema
PUT/ai/draft/documentWorld tokenReplace the connected draft
GET/ai/export/worldWorld tokenDownload the draft with asset URLs and Blender references
POST/ai/assets/uploadWorld tokenUpload a static GLB to the connected owner's library
POST/ai/mcpWorld tokenCall the MCP tools using JSON-RPC

Browse and download​

GET /​

Returns:

{
"worlds": [
{"id":"public-2","name":"Pyramids","description":"…","ownerId":null,"revision":1,"players":12,"capacity":50}
],
"hub": {"id":"lobby","name":"Lobby","players":4},
"limits": {"entities":1000000,"memoryBytes":500000000,"worldBytes":100000000}
}

The numbers and description above are examples; limits contains the full current limit object. Worlds are ordered by descending active player count, then ID. Creator worlds have an ownerId; built-in worlds use null. revision here identifies the published version.

GET /:id/document​

Returns { "id", "name", "document", "revision" } for a published world. Use this document to inspect the layout players receive. A missing or unpublished world returns 404. Your newer draft is available through an owner or token draft route.

GET /assets/:hash.glb​

Replace :hash with a returned 64-character lowercase hexadecimal asset hash. The response body is binary model/gltf-binary. Asset URLs are immutable and publicly downloadable; keep private material out of assets you upload. Cache responses for repeat visits. Missing hashes return 404.

Create and manage your worlds​

POST /​

Request:

{"name":"My Desert World","description":"Tables beneath the palms."}

name is trimmed and must contain 3–48 characters. description is optional, trimmed, defaults to an empty string and permits 240 characters. Extra fields are rejected. The JSON request limit is 2 KiB. You can own up to three worlds.

Success: 201 with { "id": "world-<uuid>" }. The new draft starts with the basic layout. Read its draft to get the initial revision before editing.

GET /mine​

Returns:

  • worlds: your worlds, each with id, name, description, revision, published_revision and updated_at.
  • assets: your library entries, each with hash, name, size, triangles, pixels and meshes.
  • usedBytes: total converted bytes in your asset library.
  • earnings.paidCents: earnings already paid to your balance, in cents.
  • earnings.pendingUnits: the fractional remainder as a decimal string; 1,000,000 units equal one cent. Divide by 1,000,000 to display pending cents.
  • limits: current creator and world budgets.

Library entries are ordered by creation time. meshes counts rendered primitive parts and contributes to the estimated memory budget. See publishing and earnings for the earning formula.

GET /:id/status​

Returns { "id", "name", "revision", "publishedRevision", "entities" }. Use this lightweight request to refresh the management page after your AI saves a change. A world you do not own returns 404.

GET /:id/draft​

Returns { "id", "name", "description", "document", "revision", "publishedRevision", "assets" }. document is the complete editable world. Use its revision in your next save.

Save a draft​

Use PUT /:id/draft with your owner session, or PUT /ai/draft/document with the connected world's token. Both accept the same body:

{
"revision": 1,
"document": {
"version": 1,
"floor": "#dad4c4",
"walls": "#e8e1cf",
"entities": [
{"id":"blackjack:0","kind":"game","asset":"blackjack","position":[-8,0,4],"yaw":0,"scale":[1,1,1],"color":"#d7ba7f"},
{"id":"bench-east","kind":"prop","asset":"bench","position":[8,0,4],"yaw":3.141592653589793,"scale":[1,1,1],"color":"#42756b"}
]
}
}

This replaces the complete draft, including entities and optional skins. Preserve every field and entity you want to keep. The body limit is 64,000,000 bytes, including the revision/document envelope. Follow the world format and game skin contract for exact field and placement rules.

Success returns:

{
"revision": 2,
"budget": {
"entities": 2,
"bytes": 25000306,
"manifestBytes": 306,
"memoryBytes": 138667738,
"triangles": 110060,
"pixels": 8000000
}
}

Budget values are illustrative. Use the actual returned values. revision increases after every accepted save; submit that new revision next time. Publishing is a separate step.

If you receive 409, download the current draft, merge your changes into it, and retry using its revision. Keep saves sequential. For smaller edits, use MCP world_edit_entities to upsert/remove up to 1,000 entities per array.

Publish​

POST /:id/publish​

Request: { "revision": 2 }, using your latest saved revision. The JSON request limit is 1 KiB.

The revision must match the saved draft, the draft must contain a supported game station, all referenced assets must belong to your library, and every world budget must pass.

Success returns { "ok": true, "pending": true, "revision": 2 }. The server stores that exact draft as a pending snapshot, blocks new wagers in the world, and waits for existing bets to finish. After at least five seconds of notice and no unsettled wagers, it installs the snapshot. Later draft saves do not change the pending snapshot.

A stale revision or a different update already queued returns 409. Repeating the same queued revision succeeds without replacing or delaying it. Use an authenticated owner session.

GET /:id/update​

Public, uncached metadata for polling publication progress:

{
"revision": 1,
"pending": true,
"pendingRevision": 2,
"requestedAt": "2026-11-01T12:00:00.000Z"
}

revision is the currently published revision, or zero for an unpublished world. pendingRevision and requestedAt become null when no publication is pending. While pending is true, clients show the update notice and disable new-bet controls while keeping active-game actions enabled. When revision increases, download GET /:id/document and reload the world renderer. The website does this automatically without replacing the page.

DELETE /:id/publish​

Authenticated owner session, no body. Cancels a queued update and returns { "ok": true }. The existing published layout and saved draft are retained; new bets reopen. It does not roll back a publication that already completed.

Create, replace or revoke an AI token​

POST /:id/ai-token​

Send an authenticated owner request with no body. Response:

{
"token": "<64 lowercase hexadecimal characters>",
"endpoint": "https://betworld.gg/api/worlds/ai/mcp",
"draftEndpoint": "https://betworld.gg/api/worlds/ai/draft/document",
"expiresIn": null
}

Save the returned token immediately in your client's secret settings. Calling this route again replaces the previous credential for that world. expiresIn: null means the credential has no automatic expiry.

DELETE /:id/ai-token​

Send an authenticated owner request with no body. Returns { "ok": true }. The credential stops working; your saved draft, assets and published world remain available to you.

Read the connected world with a token​

GET /ai/draft/document​

Returns worldId, revision, document, assets, catalog, limits and schema. The token selects your world automatically. catalog.props and catalog.games contain supported built-ins; schema describes the accepted world JSON.

curl --fail-with-body https://betworld.gg/api/worlds/ai/draft/document \
-H "Authorization: Bearer $BETWORLD_TOKEN"

GET /ai/export/world​

Use this when importing a draft into Blender. It returns the same core draft data plus:

  • name: the world name.
  • assets[].url: an immutable download URL for each asset in your library.
  • sources.props, sources.games, sources.shell: GLB authoring references.
  • gameScale: the source-to-world scale for the game library.
  • authoring: URLs for model guides, interfaces, the skin contract, socket catalog and skin schema.

Preserve the supplied game scale when placing reference models. The Blender bridge handles coordinate conversion and reference placement for you.

Upload a prop or game-skin mesh​

Use POST /assets with your owner session or POST /ai/assets/upload with your world token.

curl --fail-with-body https://betworld.gg/api/worlds/ai/assets/upload \
-H "Authorization: Bearer $BETWORLD_TOKEN" \
-H 'Content-Type: model/gltf-binary' \
-H 'X-Model-Name: Palm planter' \
--data-binary @palm-planter.glb

Send one static, self-contained GLB of at most 4,000,000 bytes. The converted result must also fit that limit. X-Model-Name is optional; it defaults to Custom prop and permits 1–80 characters after trimming. Use embedded textures within the asset limits. Your entire converted asset library can use 100,000,000 bytes.

Success: 201 with { "hash", "name", "size", "triangles", "pixels", "meshes" }. size is the converted byte count. Place the prop using asset: "upload:<hash>", or use the plain hash as a skin's body / binding asset. Save the draft after uploading to include the placement or skin.

Re-uploading identical converted content under the same owner reuses its hash and storage. Revised geometry or materials can produce a new hash; update your document to reference the returned asset. Existing assets continue to occupy library storage.

For player characters, use the separate avatar upload API, whose formats and size limits differ.

MCP transport​

Send JSON-RPC requests to POST /ai/mcp with your world token. Start with initialize, honor its returned protocol version, then call tools/list or tools/call. Use Accept: application/json, text/event-stream; parse either response format. The transport is stateless; a persistent GET event stream returns 405.

{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"world_download","arguments":{}}}

The MCP reference documents all seven tools: world_download, world_upload, world_edit_entities, game_skin_contract, game_skin_save, asset_upload and asset_download. Successful tool results contain structuredContent and equivalent JSON text. Check isError on tool results even when HTTP returns 200.

Errors, limits and retrying​

Application validation failures return { "error": "message" }. Read that message before retrying. Rate-limit and proxy errors may use a text body; check the response Content-Type before parsing JSON.

HTTP statusWhat to do
400Correct the request, model, placement, ownership reference or resource budget described by error
401Sign in to a registered account, or reconnect using your current world token
403Use the correct origin and authentication method for the route
404Check the world/asset ID, publication status and world ownership
409Refresh a stale draft revision, or cancel an existing queued update before publishing a different revision
413Reduce the request body to the route's byte limit
429Wait for the rate-limit window indicated by response headers
503Respect Retry-After and retry after the service has capacity
500Retry a read later; refresh the draft before repeating a save whose outcome is uncertain

World API routes allow 120 requests per minute per client IP. Public GLB downloads have a separate 12,000-per-minute limit. Heavy reads and writes are admitted one at a time; queue your AI's changes instead of sending parallel saves. Proxy limits can also apply.

All limits apply together: up to 1,000,000 entities, 100 MB world download, 500 MB estimated runtime memory, 64 MB manifest, 20,000,000 placed triangles, 32,000,000 decoded texture pixels and 50 players per world. Read the live limits response and returned budget while building.

In-game editor integration​

GET /:id/document includes ownerId alongside id, name, document and revision. The site offers Edit this world when it matches the signed-in player. Ownership is checked independently on every draft, asset and publish operation.

GET /:id/draft also returns pendingRevision (an integer or null). The editor uses it to resume displaying a queued publication after reopening. Draft saves continue to use the current revision; queued publication uses its own stored snapshot.

Terrain and panorama routes​

World documents accept optional terrain and background settings. Upload a background with POST /api/worlds/backgrounds using your owner session, or POST /api/worlds/ai/backgrounds/upload using a world Bearer credential. Download canonical WebP bytes from GET /api/worlds/backgrounds/:hash.webp. Draft, library and export responses include backgrounds metadata alongside the existing GLB assets. See terrain and backgrounds for every field, limit, header, response and error code.