Version: 1.0.0
Category: Query
Status: Stable
The Query Protocol defines how AI agents should query game state from the Structs API. All queries use HTTP GET requests to REST endpoints.
{
"baseUrl": "http://localhost:1317",
"basePath": "/structs",
"timeout": 5000,
"retryPolicy": {
"maxRetries": 3,
"retryDelay": 1000,
"retryOn": ["timeout", "5xx", "network"]
}
}
Use Case: Get a specific entity by ID
Format: GET {basePath}/{entity}/{id}
Example:
{
"request": {
"method": "GET",
"url": "/structs/player/1",
"headers": {
"Accept": "application/json"
}
},
"response": {
"status": 200,
"body": {
"player": {...},
"gridAttributes": {...},
"playerInventory": {...},
"halted": false
}
}
}
Error Cases:
404: Entity not found400: Invalid ID format500: Server errorUse Case: Get all entities of a type (with pagination)
Format: GET {basePath}/{entity}
Example:
{
"request": {
"method": "GET",
"url": "/structs/player",
"queryParams": {
"pagination.key": "",
"pagination.limit": 100
}
},
"response": {
"status": 200,
"body": {
"player": [...],
"pagination": {
"next_key": "...",
"total": 1000
}
}
}
}
Pagination Strategy:
pagination.keynext_key from response for next pagenext_key is nullpagination.limit to control page size (max 100)Use Case: Get entities filtered by relationship
Format: GET {basePath}/{entity}_by_{filter}/{filterValue}
Example:
{
"request": {
"method": "GET",
"url": "/structs/planet_by_player/1"
},
"response": {
"status": 200,
"body": {
"planet": [...]
}
}
}
Available Filters:
planet_by_player/{playerId} - Planets owned by playeraddress_by_player/{playerId} - Addresses for playeragreement_by_provider/{providerId} - Agreements for providerallocation_by_source/{sourceId} - Allocations from sourceallocation_by_destination/{destinationId} - Allocations to destinationinfusion_by_destination/{destinationId} - Infusions to destinationpermission/object/{objectId} - Permissions for objectpermission/player/{playerId} - Permissions for playerUse Case: Get specific attributes of an entity
Format: GET {basePath}/{entity}_attribute/{entityId}/{attributeType}
Example:
{
"request": {
"method": "GET",
"url": "/structs/planet_attribute/1-1/ore"
},
"response": {
"status": 200,
"body": {
"planetAttribute": {...}
}
}
}
Use Case: Build complete game state incrementally
Steps:
GET /blockheightGET /structs/player (paginated)GET /structs/planet_by_player/{playerId}Example Flow:
{
"step1": {
"query": "GET /blockheight",
"store": "gameState.blockHeight"
},
"step2": {
"query": "GET /structs/player",
"store": "gameState.players",
"pagination": true
},
"step3": {
"forEach": "gameState.players",
"query": "GET /structs/planet_by_player/{playerId}",
"store": "gameState.planets[playerId]"
}
}
Use Case: Query only what you need for specific task
Steps:
Example:
{
"task": "Monitor player 1's planets",
"queries": [
"GET /structs/player/1",
"GET /structs/planet_by_player/1"
],
"updateFrequency": "every 10 seconds"
}
Use Case: Follow relationships between entities
Pattern:
Example:
{
"start": "player/1",
"traverse": [
{
"entity": "player",
"id": "1",
"relationships": [
{
"type": "owns",
"entity": "planet",
"query": "GET /structs/planet_by_player/1"
},
{
"type": "owns",
"entity": "struct",
"query": "GET /structs/struct",
"filter": "ownerId == 1"
}
]
}
]
}
Cache These:
Don’t Cache These:
{
"cachePolicy": {
"structTypes": {
"ttl": 3600,
"invalidateOn": ["blockHeight change"]
},
"players": {
"ttl": 300,
"invalidateOn": ["player update event"]
},
"planets": {
"ttl": 60,
"invalidateOn": ["planet update event"]
}
}
}
{
"error": {
"code": "ENTITY_NOT_FOUND",
"message": "Player with ID '1' not found",
"details": {
"entity": "Player",
"id": "1"
}
}
}
{
"onError": {
"404": {
"action": "log",
"retry": false,
"fallback": "return null"
},
"400": {
"action": "log",
"retry": false,
"fallback": "validate input"
},
"500": {
"action": "retry",
"maxRetries": 3,
"backoff": "exponential"
},
"timeout": {
"action": "retry",
"maxRetries": 3,
"backoff": "exponential"
}
}
}
{
"strategy": "parallel",
"queries": [
"GET /structs/player/1",
"GET /structs/planet_by_player/1",
"GET /structs/fleet",
"GET /structs/struct"
],
"maxConcurrency": 10
}
{
"strategy": "selective",
"onlyQuery": [
"entities needed for current task"
],
"skipQuery": [
"entities not needed"
]
}
{
"strategy": "incremental",
"initialQuery": "full state",
"subsequentQueries": "only changes",
"useStreaming": true
}
Last Updated: January 2025