{
  "openapi": "3.1.0",
  "info": {
    "title": "Canvas64 API",
    "version": "1.0.0-rc04",
    "description": "The public API of Canvas64: the wall as the contract and the profiles hold it, photos, and a Model Context Protocol server. Reading needs no key and no wallet. Money moves only on the chain, through the contract; the API never holds or moves funds."
  },
  "servers": [
    {
      "url": "https://canvas64.com"
    }
  ],
  "paths": {
    "/api/wall": {
      "get": {
        "operationId": "getWall",
        "summary": "Every cell: step, owner and the owner's profile",
        "responses": {
          "200": {
            "description": "All 64 cells, A1 first",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "cell": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 63,
                        "description": "Index 0 to 63; address is \"ABCDEFGH\"[cell % 8] + (floor(cell / 8) + 1), so 0 is A1 and 27 is D4."
                      },
                      "step": {
                        "type": "integer",
                        "description": "Purchases so far; 0 is free."
                      },
                      "owner": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "profile": {
                        "type": [
                          "object",
                          "null"
                        ],
                        "properties": {
                          "nickname": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "avatar": {
                            "type": "integer"
                          },
                          "photo": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "SHA-256 of the photo; GET /api/photo/{sha256}."
                          },
                          "links": {
                            "type": "array",
                            "items": {
                              "type": "string",
                              "format": "uri"
                            },
                            "description": "Canonical links, at most one each to Twitch, YouTube, Kick, TikTok, Instagram or Linktree."
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/cell/{address}": {
      "get": {
        "operationId": "getCell",
        "summary": "One cell as an agent reads it: its owner, what it costs now, what its owner gets when it is bought out, the royalty and its link",
        "parameters": [
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Ha-h][1-8]$"
            },
            "example": "D4"
          }
        ],
        "responses": {
          "200": {
            "description": "The cell, as the MCP tool get_cell returns it",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "An error, with a sentence that says why",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/profile/{address}": {
      "get": {
        "operationId": "getProfile",
        "summary": "A wallet's profile, or its default avatar",
        "parameters": [
          {
            "name": "address",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^0x[0-9a-fA-F]{40}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The profile",
            "content": {
              "application/json": {
                "schema": {
                  "type": [
                    "object",
                    "null"
                  ],
                  "properties": {
                    "nickname": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "avatar": {
                      "type": "integer"
                    },
                    "photo": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "SHA-256 of the photo; GET /api/photo/{sha256}."
                    },
                    "links": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "format": "uri"
                      },
                      "description": "Canonical links, at most one each to Twitch, YouTube, Kick, TikTok, Instagram or Linktree."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/photo/{sha256}": {
      "get": {
        "operationId": "getPhoto",
        "summary": "A photo that passed screening",
        "parameters": [
          {
            "name": "sha256",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "WebP or JPEG",
            "content": {
              "image/webp": {},
              "image/jpeg": {}
            }
          },
          "404": {
            "description": "An error, with a sentence that says why",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/mcp": {
      "post": {
        "operationId": "mcp",
        "summary": "Model Context Protocol server (Streamable HTTP, JSON-RPC 2.0, stateless, read-only)",
        "description": "Tools: get_wall, get_cell, quote, get_rules.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A JSON-RPC response"
          }
        }
      }
    }
  }
}
