{
  "openapi": "3.1.0",
  "info": {
    "title": "XE Node API",
    "version": "0.4.0",
    "description": "HTTP API exposed by every XE node. All endpoints return JSON; large numeric values (balances, hashes) are returned as strings to avoid JavaScript number precision loss."
  },
  "servers": [
    {
      "url": "https://ldn.test.network",
      "description": "Public testnet bootstrap node"
    },
    {
      "url": "http://localhost:8080",
      "description": "Local node"
    }
  ],
  "tags": [
    { "name": "Accounts", "description": "Balances and per-account chain reads" },
    { "name": "Blocks", "description": "Block submission, lookup, and proof-of-work" },
    { "name": "Chat", "description": "Peer-to-peer messaging" },
    { "name": "Directory", "description": "Account-to-peer directory" },
    { "name": "Leases", "description": "Compute lease lifecycle and providers" },
    { "name": "VMs", "description": "Provider-side VM management" },
    { "name": "Node", "description": "Node health, frontiers, and conflicts" },
    { "name": "State Chain", "description": "Governance state chain reads and writes" }
  ],
  "components": {
    "schemas": {
      "Address": {
        "type": "string",
        "description": "Hex-encoded ed25519 public key (64 chars)",
        "example": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
      },
      "Hash": {
        "type": "string",
        "description": "Hex-encoded SHA-256 (64 chars)",
        "example": "f2a3b4c5d6e7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3"
      },
      "BalanceString": {
        "type": "string",
        "description": "String-encoded unsigned integer (avoids JS number precision loss)",
        "example": "1000000"
      },
      "Asset": {
        "type": "string",
        "enum": ["XE", "XUSD"]
      },
      "Account": {
        "type": "object",
        "properties": {
          "address": { "$ref": "#/components/schemas/Address" },
          "balances": {
            "type": "object",
            "description": "Map of asset name to string-encoded balance",
            "additionalProperties": { "$ref": "#/components/schemas/BalanceString" },
            "example": { "XE": "1000000", "XUSD": "500000" }
          },
          "block_count": { "type": "integer", "example": 42 },
          "frontier": { "$ref": "#/components/schemas/Hash" }
        },
        "required": ["address", "balances", "block_count", "frontier"]
      },
      "BalanceMap": {
        "type": "object",
        "additionalProperties": { "$ref": "#/components/schemas/BalanceString" },
        "example": { "XE": "1000000", "XUSD": "500000" }
      },
      "Block": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": ["send", "receive", "claim", "lease", "lease_accept", "lease_settle", "multisig_open", "multisig_update"]
          },
          "account": { "$ref": "#/components/schemas/Address" },
          "previous": { "$ref": "#/components/schemas/Hash" },
          "balance": { "$ref": "#/components/schemas/BalanceString" },
          "asset": { "$ref": "#/components/schemas/Asset" },
          "representative": { "$ref": "#/components/schemas/Address" },
          "timestamp": { "type": "integer", "format": "int64", "example": 1709500000000000000 },
          "signature": { "type": "string", "description": "Hex ed25519 signature (128 chars)" },
          "hash": { "$ref": "#/components/schemas/Hash" },
          "pow_nonce": { "type": "integer", "format": "int64", "example": 12345 },
          "destination": { "$ref": "#/components/schemas/Address" },
          "amount": { "$ref": "#/components/schemas/BalanceString" },
          "source": { "$ref": "#/components/schemas/Hash" },
          "vcpus": { "type": "integer", "minimum": 1, "example": 4 },
          "memory_mb": { "type": "integer", "minimum": 512, "example": 8192 },
          "disk_gb": { "type": "integer", "minimum": 5, "example": 100 },
          "duration": { "type": "integer", "minimum": 60, "maximum": 31536000, "example": 86400 },
          "access_pub_key": { "$ref": "#/components/schemas/Address" },
          "certificate_hash": { "$ref": "#/components/schemas/Hash" },
          "attestations": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Attestation" }
          },
          "keyset": { "$ref": "#/components/schemas/Keyset" },
          "signatures": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/MultisigSignature" }
          }
        },
        "required": ["type", "account", "previous", "balance", "asset", "timestamp", "hash"]
      },
      "Attestation": {
        "type": "object",
        "properties": {
          "public_key": { "$ref": "#/components/schemas/Address" },
          "timestamp": { "type": "integer", "format": "int64" },
          "signature": { "type": "string" }
        },
        "required": ["public_key", "timestamp", "signature"]
      },
      "Keyset": {
        "type": "object",
        "properties": {
          "keys": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Address" },
            "example": ["a1b2c3d4...", "e5f6a7b8...", "c9d0e1f2..."]
          },
          "threshold": { "type": "integer", "minimum": 1, "example": 2 }
        },
        "required": ["keys", "threshold"]
      },
      "MultisigSignature": {
        "type": "object",
        "properties": {
          "public_key": { "$ref": "#/components/schemas/Address" },
          "signature": { "type": "string" }
        },
        "required": ["public_key", "signature"]
      },
      "BlockHashResponse": {
        "type": "object",
        "properties": {
          "hash": { "$ref": "#/components/schemas/Hash" }
        },
        "required": ["hash"]
      },
      "OkResponse": {
        "type": "object",
        "properties": { "ok": { "type": "boolean", "example": true } },
        "required": ["ok"]
      },
      "ChatMessage": {
        "type": "object",
        "properties": {
          "from": { "$ref": "#/components/schemas/Address" },
          "to": { "$ref": "#/components/schemas/Address" },
          "message": { "type": "string", "example": "Hello, world!" },
          "timestamp": { "type": "integer", "format": "int64" },
          "signature": { "type": "string" }
        },
        "required": ["from", "to", "message", "timestamp", "signature"]
      },
      "DirectoryRegistration": {
        "type": "object",
        "properties": {
          "account": { "$ref": "#/components/schemas/Address" },
          "node_peer": {
            "type": "string",
            "description": "libp2p peer ID",
            "example": "12D3KooWAbCdEfGhIjKlMnOpQrStUvWxYz"
          },
          "timestamp": { "type": "integer", "format": "int64" },
          "signature": { "type": "string" }
        },
        "required": ["account", "node_peer", "timestamp", "signature"]
      },
      "Provider": {
        "type": "object",
        "properties": {
          "account": { "$ref": "#/components/schemas/Address" },
          "total": {
            "type": "object",
            "properties": {
              "vcpus": { "type": "integer" },
              "memory_mb": { "type": "integer" },
              "disk_gb": { "type": "integer" }
            }
          },
          "free": {
            "type": "object",
            "properties": {
              "vcpus": { "type": "integer" },
              "memory_mb": { "type": "integer" },
              "disk_gb": { "type": "integer" }
            }
          },
          "active_leases": { "type": "integer" }
        }
      },
      "Lease": {
        "type": "object",
        "properties": {
          "lease_hash": { "$ref": "#/components/schemas/Hash" },
          "consumer": { "$ref": "#/components/schemas/Address" },
          "provider": { "$ref": "#/components/schemas/Address" },
          "vcpus": { "type": "integer" },
          "memory_mb": { "type": "integer" },
          "disk_gb": { "type": "integer" },
          "duration": { "type": "integer" },
          "cost": { "$ref": "#/components/schemas/BalanceString" },
          "stake": { "$ref": "#/components/schemas/BalanceString" },
          "start_time": { "type": "integer", "format": "int64" },
          "certificate_hash": { "$ref": "#/components/schemas/Hash" },
          "settled": { "type": "boolean" }
        }
      },
      "VM": {
        "type": "object",
        "properties": {
          "lease_hash": { "$ref": "#/components/schemas/Hash" },
          "status": {
            "type": "string",
            "enum": ["provisioning", "running", "stopped", "error"]
          },
          "resources": {
            "type": "object",
            "properties": {
              "vcpus": { "type": "integer" },
              "memory_mb": { "type": "integer" },
              "disk_gb": { "type": "integer" }
            }
          },
          "created_at": { "type": "integer", "format": "int64" },
          "error": { "type": "string" }
        }
      },
      "ExecRequest": {
        "type": "object",
        "properties": {
          "command": { "type": "string", "example": "uname -a" }
        },
        "required": ["command"]
      },
      "ExecResult": {
        "type": "object",
        "properties": {
          "exit_code": { "type": "integer" },
          "stdout": { "type": "string" },
          "stderr": { "type": "string" }
        }
      },
      "PendingSend": {
        "type": "object",
        "properties": {
          "send_hash": { "$ref": "#/components/schemas/Hash" },
          "source": { "$ref": "#/components/schemas/Address" },
          "destination": { "$ref": "#/components/schemas/Address" },
          "amount": { "$ref": "#/components/schemas/BalanceString" },
          "asset": { "$ref": "#/components/schemas/Asset" }
        }
      },
      "Conflict": {
        "type": "object",
        "properties": {
          "account_address": { "$ref": "#/components/schemas/Address" },
          "previous_hash": { "$ref": "#/components/schemas/Hash" },
          "block_hashes": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Hash" }
          },
          "detected_at": { "type": "string", "format": "date-time" }
        }
      },
      "NodeInfo": {
        "type": "object",
        "properties": {
          "version": { "type": "string", "example": "0.4.0" },
          "peer_id": { "type": "string", "example": "12D3KooW..." },
          "account": { "$ref": "#/components/schemas/Address" },
          "uptime_seconds": { "type": "integer" }
        }
      },
      "StateChainBlock": {
        "type": "object",
        "properties": {
          "index": { "type": "integer" },
          "previous": { "$ref": "#/components/schemas/Hash" },
          "operation": { "type": "string", "enum": ["set", "delete", "update_keyset"] },
          "key": { "type": "string" },
          "value": { "type": "string" },
          "timestamp": { "type": "integer", "format": "int64" },
          "signatures": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/MultisigSignature" }
          },
          "hash": { "$ref": "#/components/schemas/Hash" }
        }
      },
      "ResourceRequest": {
        "type": "object",
        "properties": {
          "vcpus": { "type": "integer", "example": 2 },
          "memory_mb": { "type": "integer", "example": 4096 },
          "disk_gb": { "type": "integer", "example": 50 },
          "duration": { "type": "integer", "example": 3600 }
        },
        "required": ["vcpus", "memory_mb", "disk_gb", "duration"]
      },
      "PoWRequest": {
        "type": "object",
        "properties": { "hash": { "$ref": "#/components/schemas/Hash" } },
        "required": ["hash"]
      },
      "PoWResponse": {
        "type": "object",
        "properties": { "nonce": { "type": "integer", "format": "int64", "example": 67890 } },
        "required": ["nonce"]
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string", "example": "invalid signature" }
        }
      }
    }
  },
  "paths": {
    "/accounts": {
      "get": {
        "tags": ["Accounts"],
        "summary": "List all accounts",
        "description": "Returns every account known to the node.",
        "operationId": "listAccounts",
        "responses": {
          "200": {
            "description": "Array of accounts",
            "content": {
              "application/json": {
                "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Account" } }
              }
            }
          }
        }
      }
    },
    "/accounts/{address}/balance": {
      "get": {
        "tags": ["Accounts"],
        "summary": "Get account balances",
        "description": "Returns per-asset balances for a single account. Only assets with non-zero balances are included.",
        "operationId": "getAccountBalance",
        "parameters": [
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": { "$ref": "#/components/schemas/Address" }
          }
        ],
        "responses": {
          "200": { "description": "Balance map", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BalanceMap" } } } },
          "404": { "description": "Account not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/accounts/{address}/chain": {
      "get": {
        "tags": ["Accounts"],
        "summary": "Get account chain",
        "description": "Returns the full block chain for an account, ordered oldest to newest.",
        "operationId": "getAccountChain",
        "parameters": [
          { "name": "address", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/Address" } }
        ],
        "responses": {
          "200": { "description": "Block array", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Block" } } } } },
          "404": { "description": "Account not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/accounts/{address}/keyset": {
      "get": {
        "tags": ["Accounts"],
        "summary": "Get multisig keyset",
        "description": "Returns the multisig keyset for an account. 404 if not a multisig account.",
        "operationId": "getAccountKeyset",
        "parameters": [
          { "name": "address", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/Address" } }
        ],
        "responses": {
          "200": { "description": "Keyset", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Keyset" } } } },
          "404": { "description": "Not a multisig account" }
        }
      }
    },
    "/blocks/send": {
      "post": {
        "tags": ["Blocks"],
        "summary": "Submit send block",
        "description": "Creates a send block that debits the sender and creates a pending entry for the recipient.",
        "operationId": "submitSend",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Block" } } }
        },
        "responses": {
          "200": { "description": "Block accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BlockHashResponse" } } } },
          "400": { "description": "Invalid block" }
        }
      }
    },
    "/blocks/receive": {
      "post": {
        "tags": ["Blocks"],
        "summary": "Submit receive block",
        "description": "Creates a receive block that credits a pending send to the recipient.",
        "operationId": "submitReceive",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Block" } } } },
        "responses": {
          "200": { "description": "Block accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BlockHashResponse" } } } },
          "400": { "description": "Invalid block" }
        }
      }
    },
    "/blocks/claim": {
      "post": {
        "tags": ["Blocks"],
        "summary": "Submit claim block",
        "description": "Mints 100 XUSD from the testnet faucet. Rate limited to once per 24 hours per account.",
        "operationId": "submitClaim",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Block" } } } },
        "responses": {
          "200": { "description": "Block accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BlockHashResponse" } } } },
          "400": { "description": "Invalid claim or rate-limited" }
        }
      }
    },
    "/blocks/lease": {
      "post": {
        "tags": ["Blocks"],
        "summary": "Submit lease block",
        "description": "Creates a lease block requesting compute resources from the network.",
        "operationId": "submitLease",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Block" } } } },
        "responses": {
          "200": { "description": "Block accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BlockHashResponse" } } } },
          "400": { "description": "Invalid lease block" }
        }
      }
    },
    "/blocks/lease_accept": {
      "post": {
        "tags": ["Blocks"],
        "summary": "Submit lease_accept block",
        "description": "Provider accepts a lease request. Requires timekeeper attestations.",
        "operationId": "submitLeaseAccept",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Block" } } } },
        "responses": {
          "200": { "description": "Block accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BlockHashResponse" } } } },
          "400": { "description": "Invalid lease_accept block" }
        }
      }
    },
    "/blocks/lease_settle": {
      "post": {
        "tags": ["Blocks"],
        "summary": "Submit lease_settle block",
        "description": "Settles a completed lease. Requires timekeeper attestations.",
        "operationId": "submitLeaseSettle",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Block" } } } },
        "responses": {
          "200": { "description": "Block accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BlockHashResponse" } } } },
          "400": { "description": "Invalid lease_settle block" }
        }
      }
    },
    "/blocks/multisig_open": {
      "post": {
        "tags": ["Blocks"],
        "summary": "Open multisig account",
        "description": "Opens a new multisig account with a hash-derived address and registers the keyset on the ledger.",
        "operationId": "submitMultisigOpen",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Block" } } } },
        "responses": {
          "200": { "description": "Block accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BlockHashResponse" } } } },
          "400": { "description": "Invalid keyset or signatures" }
        }
      }
    },
    "/blocks/multisig_update": {
      "post": {
        "tags": ["Blocks"],
        "summary": "Rotate multisig keyset",
        "description": "Rotates the keyset on an existing multisig account. Must be signed by the current keyset's threshold.",
        "operationId": "submitMultisigUpdate",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Block" } } } },
        "responses": {
          "200": { "description": "Block accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BlockHashResponse" } } } },
          "400": { "description": "Invalid update" }
        }
      }
    },
    "/blocks/{hash}": {
      "get": {
        "tags": ["Blocks"],
        "summary": "Get block by hash",
        "operationId": "getBlock",
        "parameters": [
          { "name": "hash", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/Hash" } }
        ],
        "responses": {
          "200": { "description": "Block", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Block" } } } },
          "404": { "description": "Block not found" }
        }
      }
    },
    "/blocks/recent": {
      "get": {
        "tags": ["Blocks"],
        "summary": "Recent blocks",
        "description": "Returns recently processed blocks across all accounts, newest first.",
        "operationId": "getRecentBlocks",
        "parameters": [
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 500, "default": 20 } }
        ],
        "responses": {
          "200": { "description": "Block array", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Block" } } } } }
        }
      }
    },
    "/pow": {
      "post": {
        "tags": ["Blocks"],
        "summary": "Compute proof of work",
        "description": "Computes a PoW nonce for a block hash. Convenience endpoint — clients may also compute PoW locally.",
        "operationId": "computePoW",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PoWRequest" } } } },
        "responses": {
          "200": { "description": "Nonce", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PoWResponse" } } } }
        }
      }
    },
    "/chat/send": {
      "post": {
        "tags": ["Chat"],
        "summary": "Send chat message",
        "description": "Sends a signed message from one account to another.",
        "operationId": "sendChat",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChatMessage" } } } },
        "responses": {
          "200": { "description": "Accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } } },
          "400": { "description": "Invalid message" }
        }
      }
    },
    "/chat/messages": {
      "get": {
        "tags": ["Chat"],
        "summary": "List chat messages",
        "description": "Retrieves messages for an account, newest first. Optionally filter by timestamp.",
        "operationId": "listChat",
        "parameters": [
          { "name": "account", "in": "query", "required": true, "schema": { "$ref": "#/components/schemas/Address" } },
          { "name": "since", "in": "query", "schema": { "type": "integer", "format": "int64" } }
        ],
        "responses": {
          "200": { "description": "Message array", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ChatMessage" } } } } }
        }
      }
    },
    "/chat/contacts": {
      "get": {
        "tags": ["Chat"],
        "summary": "List chat contacts",
        "operationId": "listContacts",
        "responses": {
          "200": { "description": "Address array", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Address" } } } } }
        }
      }
    },
    "/chat/events": {
      "get": {
        "tags": ["Chat"],
        "summary": "Subscribe to chat (SSE)",
        "description": "Server-Sent Events stream of new chat messages.",
        "operationId": "chatEvents",
        "parameters": [
          { "name": "account", "in": "query", "schema": { "$ref": "#/components/schemas/Address" } }
        ],
        "responses": {
          "200": {
            "description": "SSE stream",
            "content": {
              "text/event-stream": {
                "schema": { "type": "string", "example": "event: message\ndata: {\"from\":\"...\",\"to\":\"...\",\"message\":\"...\",\"timestamp\":1709500120000000000,\"signature\":\"...\"}\n\n" }
              }
            }
          }
        }
      }
    },
    "/directory/register": {
      "post": {
        "tags": ["Directory"],
        "summary": "Register account",
        "description": "Registers an account in the directory, associating it with a libp2p peer ID.",
        "operationId": "registerDirectory",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DirectoryRegistration" } } } },
        "responses": {
          "200": { "description": "Accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } } },
          "400": { "description": "Invalid registration" }
        }
      }
    },
    "/directory": {
      "get": {
        "tags": ["Directory"],
        "summary": "List all registrations",
        "operationId": "listDirectory",
        "responses": {
          "200": { "description": "Registration array", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/DirectoryRegistration" } } } } }
        }
      }
    },
    "/directory/{account}": {
      "get": {
        "tags": ["Directory"],
        "summary": "Lookup account registration",
        "operationId": "getDirectoryEntry",
        "parameters": [
          { "name": "account", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/Address" } }
        ],
        "responses": {
          "200": { "description": "Registration", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DirectoryRegistration" } } } },
          "404": { "description": "Not registered" }
        }
      }
    },
    "/leases": {
      "get": {
        "tags": ["Leases"],
        "summary": "List all leases",
        "operationId": "listLeases",
        "responses": {
          "200": { "description": "Lease array", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Lease" } } } } }
        }
      }
    },
    "/leases/{hash}": {
      "get": {
        "tags": ["Leases"],
        "summary": "Get lease by hash",
        "operationId": "getLease",
        "parameters": [
          { "name": "hash", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/Hash" } }
        ],
        "responses": {
          "200": { "description": "Lease", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Lease" } } } },
          "404": { "description": "Lease not found" }
        }
      }
    },
    "/providers": {
      "get": {
        "tags": ["Leases"],
        "summary": "List providers",
        "operationId": "listProviders",
        "responses": {
          "200": { "description": "Provider array", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Provider" } } } } }
        }
      }
    },
    "/lease/request": {
      "post": {
        "tags": ["Leases"],
        "summary": "Request lease quote",
        "description": "Asks providers for offers matching the requested resources.",
        "operationId": "requestLease",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResourceRequest" } } } },
        "responses": {
          "200": { "description": "Offer or marketplace acknowledgement", "content": { "application/json": { "schema": { "type": "object" } } } }
        }
      }
    },
    "/attestation/request": {
      "post": {
        "tags": ["Leases"],
        "summary": "Request timekeeper attestation",
        "operationId": "requestAttestation",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": { "lease_hash": { "$ref": "#/components/schemas/Hash" } },
                "required": ["lease_hash"]
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Attestation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Attestation" } } } }
        }
      }
    },
    "/vms": {
      "get": {
        "tags": ["VMs"],
        "summary": "List VMs",
        "operationId": "listVMs",
        "responses": {
          "200": { "description": "VM array", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/VM" } } } } }
        }
      }
    },
    "/vms/{leaseHash}": {
      "get": {
        "tags": ["VMs"],
        "summary": "Get VM",
        "operationId": "getVM",
        "parameters": [
          { "name": "leaseHash", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/Hash" } }
        ],
        "responses": {
          "200": { "description": "VM", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VM" } } } },
          "404": { "description": "VM not found" }
        }
      }
    },
    "/vms/{leaseHash}/exec": {
      "post": {
        "tags": ["VMs"],
        "summary": "Execute command in VM",
        "operationId": "execVM",
        "parameters": [
          { "name": "leaseHash", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/Hash" } }
        ],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExecRequest" } } } },
        "responses": {
          "200": { "description": "Exec result", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExecResult" } } } }
        }
      }
    },
    "/tunnel/{leaseHash}/tcp": {
      "post": {
        "tags": ["VMs"],
        "summary": "Open TCP tunnel to VM",
        "description": "Opens a TCP tunnel to the VM behind a lease via libp2p.",
        "operationId": "tunnelTCP",
        "parameters": [
          { "name": "leaseHash", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/Hash" } }
        ],
        "responses": {
          "101": { "description": "Switching protocols (raw TCP stream)" },
          "404": { "description": "Lease not found" }
        }
      }
    },
    "/node": {
      "get": {
        "tags": ["Node"],
        "summary": "Get node info",
        "operationId": "getNodeInfo",
        "responses": {
          "200": { "description": "Node info", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodeInfo" } } } }
        }
      }
    },
    "/pending": {
      "get": {
        "tags": ["Node"],
        "summary": "List all pending sends",
        "operationId": "listPending",
        "responses": {
          "200": { "description": "Pending sends", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/PendingSend" } } } } }
        }
      }
    },
    "/pending/{address}": {
      "get": {
        "tags": ["Node"],
        "summary": "Pending sends for account",
        "operationId": "getPendingForAccount",
        "parameters": [
          { "name": "address", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/Address" } }
        ],
        "responses": {
          "200": { "description": "Pending sends", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/PendingSend" } } } } }
        }
      }
    },
    "/frontiers": {
      "get": {
        "tags": ["Node"],
        "summary": "Get frontier hashes",
        "description": "Map of account address → frontier (latest) block hash. Used for sync.",
        "operationId": "getFrontiers",
        "responses": {
          "200": {
            "description": "Frontier map",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": { "$ref": "#/components/schemas/Hash" }
                }
              }
            }
          }
        }
      }
    },
    "/conflicts": {
      "get": {
        "tags": ["Node"],
        "summary": "List active conflicts",
        "operationId": "listConflicts",
        "responses": {
          "200": { "description": "Conflicts", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Conflict" } } } } }
        }
      }
    },
    "/conflicts/{account}": {
      "get": {
        "tags": ["Node"],
        "summary": "Conflicts for account",
        "operationId": "conflictsForAccount",
        "parameters": [
          { "name": "account", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/Address" } }
        ],
        "responses": {
          "200": { "description": "Conflicts", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Conflict" } } } } }
        }
      }
    },
    "/statechain/tip": {
      "get": {
        "tags": ["State Chain"],
        "summary": "Get tip block",
        "operationId": "getStateChainTip",
        "responses": {
          "200": { "description": "Latest state-chain block", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StateChainBlock" } } } }
        }
      }
    },
    "/statechain/blocks/{index}": {
      "get": {
        "tags": ["State Chain"],
        "summary": "Get block by index",
        "operationId": "getStateChainBlockByIndex",
        "parameters": [
          { "name": "index", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "responses": {
          "200": { "description": "Block", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StateChainBlock" } } } },
          "404": { "description": "Block not found" }
        }
      }
    },
    "/statechain/blocks": {
      "get": {
        "tags": ["State Chain"],
        "summary": "Get block range",
        "operationId": "getStateChainBlockRange",
        "parameters": [
          { "name": "from", "in": "query", "schema": { "type": "integer" } },
          { "name": "to", "in": "query", "schema": { "type": "integer" } }
        ],
        "responses": {
          "200": { "description": "Block array", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/StateChainBlock" } } } } }
        }
      },
      "post": {
        "tags": ["State Chain"],
        "summary": "Submit state chain block",
        "description": "Submits a state-chain operation block (set/delete key, update keyset).",
        "operationId": "submitStateChainBlock",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StateChainBlock" } } } },
        "responses": {
          "200": { "description": "Block accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BlockHashResponse" } } } },
          "400": { "description": "Invalid block" }
        }
      }
    },
    "/statechain/kv/{key}": {
      "get": {
        "tags": ["State Chain"],
        "summary": "Get state value",
        "operationId": "getStateValue",
        "parameters": [
          { "name": "key", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Value", "content": { "application/json": { "schema": { "type": "object" } } } },
          "404": { "description": "Key not found" }
        }
      }
    },
    "/statechain/kv": {
      "get": {
        "tags": ["State Chain"],
        "summary": "List all KV entries",
        "operationId": "listStateValues",
        "responses": {
          "200": {
            "description": "Map of key → value",
            "content": {
              "application/json": {
                "schema": { "type": "object", "additionalProperties": true }
              }
            }
          }
        }
      }
    },
    "/statechain/keyset": {
      "get": {
        "tags": ["State Chain"],
        "summary": "Get DAO keyset",
        "operationId": "getDaoKeyset",
        "responses": {
          "200": { "description": "Keyset", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Keyset" } } } }
        }
      }
    }
  }
}
