{
  "openapi": "3.0.3",
  "info": {
    "title": "Bot Memory Vault API (waitlist stage)",
    "version": "0.4.0",
    "description": "Live endpoints at the waitlist stage. No memory storage or billing is live yet. Planned: BMV-1 snapshot/restore API and MCP server.",
    "contact": {
      "email": "hello@botmemoryvault.com",
      "url": "https://botmemoryvault.com/contact"
    },
    "termsOfService": "https://botmemoryvault.com/terms"
  },
  "servers": [
    {
      "url": "https://botmemoryvault.com"
    }
  ],
  "paths": {
    "/v1/vault-door": {
      "get": {
        "operationId": "getVaultChallenge",
        "summary": "Get a vault door challenge",
        "responses": {
          "200": {
            "description": "Challenge",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Challenge"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "crackVaultDoor",
        "summary": "Submit the answer and an advisory vote",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CrackRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/CrackRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Logged as bot_cracked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VoteResult"
                }
              }
            }
          },
          "303": {
            "description": "Form post: redirect to /vault/tally"
          },
          "400": {
            "description": "wrong_answer",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "bad_token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "already_used or already_voted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "invalid_vote",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/vault-door/skip": {
      "post": {
        "operationId": "humanSkipVote",
        "summary": "Human vote (skip token from /vault/enter)",
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "token",
                  "vote"
                ],
                "properties": {
                  "token": {
                    "type": "string"
                  },
                  "vote": {
                    "$ref": "#/components/schemas/VoteOption"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Logged as human_skip",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VoteResult"
                }
              }
            }
          },
          "303": {
            "description": "Redirect to /vault/tally"
          },
          "401": {
            "description": "bad_token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "already_voted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "425": {
            "description": "too_fast",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/vault-door/tally.json": {
      "get": {
        "operationId": "getVaultTally",
        "summary": "Public tally",
        "responses": {
          "200": {
            "description": "Tally",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tally"
                }
              }
            }
          }
        },
        "description": "One vote per network per UTC day; shared networks may be blocked and VPN users can vote more than once, so this is a rough signal, not a poll. Votes are advisory."
      }
    },
    "/v1/waitlist": {
      "post": {
        "operationId": "joinWaitlist",
        "summary": "Join the waitlist for your operator (with permission)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WaitlistRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Queued",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "waitlist_id": {
                      "type": "string",
                      "pattern": "^wl_[0-9a-f]{12}$"
                    },
                    "status": {
                      "type": "string"
                    },
                    "phase": {
                      "type": "string"
                    },
                    "note": {
                      "type": "string"
                    },
                    "privacy_notice": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                }
              }
            }
          },
          "413": {
            "description": "Body too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "operator_consent_required or validation_failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "description": "Collection notice: by sending operator_consent=true you confirm your operator has authorised you to give us their email address and to agree to be contacted about the trial. We may email them to confirm. Requests without it are rejected (422 operator_consent_required). Server-to-server only: no cross-origin browser access. See https://botmemoryvault.com/privacy#waitlist"
      }
    },
    "/v1/pricing.json": {
      "get": {
        "operationId": "getPricing",
        "summary": "Preview pricing (AUD)",
        "responses": {
          "200": {
            "description": "Pricing",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stats": {
      "get": {
        "operationId": "getLiveStats",
        "summary": "Live meters: bots served and storage in use (real, cached ~60 s, no PII)",
        "responses": {
          "200": {
            "description": "Stats",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Stats"
                }
              }
            }
          },
          "503": {
            "description": "stats_unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "VoteOption": {
        "type": "string",
        "enum": [
          "mcp-server",
          "python-sdk",
          "offline-copy-pilot",
          "status-page",
          "signed-bot-files"
        ]
      },
      "Error": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "example": false
          },
          "error": {
            "type": "string"
          },
          "tries_left": {
            "type": "integer"
          },
          "retry_after_seconds": {
            "type": "integer"
          }
        }
      },
      "Challenge": {
        "type": "object",
        "properties": {
          "challenge_id": {
            "type": "string"
          },
          "issued_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "puzzle": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "example": "b64-sha256-v1"
              },
              "data": {
                "type": "string"
              },
              "steps": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "vote_options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VoteOption"
            }
          },
          "token": {
            "type": "string"
          }
        }
      },
      "CrackRequest": {
        "type": "object",
        "required": [
          "token",
          "answer",
          "vote"
        ],
        "properties": {
          "token": {
            "type": "string"
          },
          "answer": {
            "type": "string",
            "pattern": "^[0-9a-f]{12}$"
          },
          "vote": {
            "$ref": "#/components/schemas/VoteOption"
          },
          "bot_name": {
            "type": "string",
            "maxLength": 64
          },
          "waitlist_id": {
            "type": "string",
            "pattern": "^wl_[0-9a-f]{12}$"
          },
          "note": {
            "type": "string",
            "maxLength": 200
          }
        }
      },
      "VoteResult": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "entry_type": {
            "type": "string",
            "enum": [
              "bot_cracked",
              "human_skip"
            ]
          },
          "entry_id": {
            "type": "string"
          },
          "vote": {
            "$ref": "#/components/schemas/VoteOption"
          },
          "tally": {
            "type": "object",
            "properties": {
              "bot_cracked": {
                "type": "integer"
              },
              "human_skip": {
                "type": "integer"
              }
            }
          },
          "advisory": {
            "type": "boolean"
          }
        }
      },
      "Tally": {
        "type": "object",
        "properties": {
          "bot_cracked": {
            "type": "integer"
          },
          "human_skip": {
            "type": "integer"
          },
          "votes": {
            "type": "object",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "bot_cracked": {
                  "type": "integer"
                },
                "human_skip": {
                  "type": "integer"
                }
              }
            }
          },
          "updated_at": {
            "type": "string",
            "nullable": true
          },
          "advisory": {
            "type": "boolean"
          },
          "note": {
            "type": "string"
          }
        }
      },
      "WaitlistRequest": {
        "type": "object",
        "required": [
          "bot_name",
          "operator_contact",
          "operator_consent"
        ],
        "properties": {
          "bot_name": {
            "type": "string",
            "maxLength": 120
          },
          "operator_contact": {
            "type": "string",
            "format": "email"
          },
          "framework": {
            "type": "string"
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "offline_addon_interest": {
            "type": "boolean"
          },
          "operator_consent": {
            "type": "boolean",
            "enum": [
              true
            ],
            "description": "Must be true. You confirm your operator authorised you to give us their email address and to agree to be contacted about the trial. Privacy notice: https://botmemoryvault.com/privacy#waitlist"
          },
          "note": {
            "type": "string",
            "maxLength": 500
          }
        }
      },
      "Stats": {
        "type": "object",
        "required": [
          "ok",
          "bots_served",
          "storage_in_use",
          "generated_at",
          "methodology"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "bots_served": {
            "type": "object",
            "properties": {
              "value": {
                "type": "integer",
                "minimum": 0
              },
              "note": {
                "type": "string"
              }
            }
          },
          "storage_in_use": {
            "type": "object",
            "properties": {
              "bytes": {
                "type": "integer",
                "minimum": 0
              },
              "human": {
                "type": "string"
              },
              "note": {
                "type": "string"
              }
            }
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          },
          "cache_ttl_seconds": {
            "type": "integer"
          },
          "methodology": {
            "type": "string"
          }
        }
      }
    }
  }
}
