{
  "openapi": "3.1.0",
  "info": {
    "title": "OneMoreDay API",
    "version": "0.2.0",
    "description": "Public, read-focused API for OneMoreDay. Every request is scoped to the authenticated user; the API never returns another user's data or platform content libraries. The mobile app is the source of truth for writes; this surface is designed for reading your own progress (profile/HP, goals, workouts, territory, badges, challenges, summaries). Per-user API keys and a hosted MCP server are rolling out — see https://onemoreday.fit/developers.",
    "contact": {
      "name": "OneMoreDay",
      "url": "https://onemoreday.fit/developers"
    }
  },
  "servers": [
    {
      "url": "https://onemoreday-api.onrender.com/api",
      "description": "Production API"
    }
  ],
  "tags": [
    {
      "name": "health",
      "description": "Service health"
    },
    {
      "name": "auth",
      "description": "Authentication & current user"
    },
    {
      "name": "profile",
      "description": "User profile, avatar & weekly summary"
    },
    {
      "name": "goals",
      "description": "Goals, completions & XP history"
    },
    {
      "name": "game",
      "description": "Avatar game state, revive & lives"
    },
    {
      "name": "territory",
      "description": "Run territory, map & leaderboard"
    },
    {
      "name": "badges",
      "description": "Earned & available badges"
    },
    {
      "name": "avatar",
      "description": "Avatar generation"
    },
    {
      "name": "waitlist",
      "description": "Waitlist"
    }
  ],
  "paths": {
    "/healthz": {
      "get": {
        "operationId": "healthCheck",
        "tags": [
          "health"
        ],
        "summary": "Health check",
        "responses": {
          "200": {
            "description": "Healthy",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthStatus"
                }
              }
            }
          }
        }
      }
    },
    "/auth/me": {
      "get": {
        "operationId": "getMe",
        "tags": [
          "auth"
        ],
        "summary": "Get the current user's profile",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Current user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProfileResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/profile/weekly-summary": {
      "get": {
        "operationId": "getWeeklySummary",
        "tags": [
          "profile"
        ],
        "summary": "Get the current user's weekly summary",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Weekly summary",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WeeklySummary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/goals": {
      "get": {
        "operationId": "listGoals",
        "tags": [
          "goals"
        ],
        "summary": "List the current user's goals",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Goals",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Goal"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/goals/{id}": {
      "get": {
        "operationId": "getGoal",
        "tags": [
          "goals"
        ],
        "summary": "Get a single goal by id",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Goal",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Goal"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/goals/xp-history": {
      "get": {
        "operationId": "getGoalXpHistory",
        "tags": [
          "goals"
        ],
        "summary": "Get the current user's XP history from goal completions",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "XP history",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/XpEvent"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/game/state": {
      "get": {
        "operationId": "getGameState",
        "tags": [
          "game"
        ],
        "summary": "Get the current avatar game state (HP, level, coins, etc.)",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Game state",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GameState"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/territory/me": {
      "get": {
        "operationId": "getMyTerritory",
        "tags": [
          "territory"
        ],
        "summary": "Get the current user's captured territory as GeoJSON",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "GeoJSON FeatureCollection of the user's territories",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GeoJSONFeatureCollection"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/territory/map": {
      "get": {
        "operationId": "getTerritoryMap",
        "tags": [
          "territory"
        ],
        "summary": "Get territories within a bounding box as GeoJSON",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "bbox",
            "in": "query",
            "required": true,
            "description": "Comma-separated west,south,east,north",
            "schema": {
              "type": "string",
              "example": "-122.5,37.7,-122.3,37.8"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "GeoJSON FeatureCollection",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GeoJSONFeatureCollection"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/territory/leaderboard": {
      "get": {
        "operationId": "getTerritoryLeaderboard",
        "tags": [
          "territory"
        ],
        "summary": "Get the territory leaderboard with the caller's rank",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Leaderboard",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LeaderboardResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/territory/stats": {
      "get": {
        "operationId": "getTerritoryStats",
        "tags": [
          "territory"
        ],
        "summary": "Get the current user's territory statistics",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Territory stats",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TerritoryStats"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/territory/runs/history": {
      "get": {
        "operationId": "getRunHistory",
        "tags": [
          "territory"
        ],
        "summary": "Get the current user's paginated run history",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Runs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Run"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/badges/me": {
      "get": {
        "operationId": "getMyBadges",
        "tags": [
          "badges"
        ],
        "summary": "Get the current user's earned badges",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Earned badges",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Badge"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/badges/all": {
      "get": {
        "operationId": "getAllBadges",
        "tags": [
          "badges"
        ],
        "summary": "Get all available badges",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "All badges",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Badge"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/auth/login": {
      "post": {
        "operationId": "login",
        "tags": [
          "auth"
        ],
        "summary": "Log in with email and password",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoginRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Logged in",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/waitlist": {
      "post": {
        "operationId": "joinWaitlist",
        "tags": [
          "waitlist"
        ],
        "summary": "Join the waitlist",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WaitlistRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Joined",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WaitlistResponse"
                }
              }
            }
          },
          "409": {
            "description": "Already on waitlist"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Unauthorized",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "BadRequest": {
        "description": "Bad request",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "NotFound": {
        "description": "Not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    },
    "schemas": {
      "HealthStatus": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string"
          }
        },
        "required": [
          "status"
        ]
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "error",
          "message"
        ]
      },
      "ProfileResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "displayName": {
            "type": "string"
          },
          "avatarUrl": {
            "type": "string",
            "nullable": true
          },
          "avatarThumbUrl": {
            "type": "string",
            "nullable": true
          },
          "healthCurrent": {
            "type": "integer"
          },
          "healthMax": {
            "type": "integer"
          },
          "healthState": {
            "type": "string",
            "enum": [
              "thriving",
              "struggling",
              "critical",
              "flatline"
            ]
          },
          "streak": {
            "type": "integer"
          },
          "totalDaysAlive": {
            "type": "integer"
          },
          "totalDeaths": {
            "type": "integer"
          },
          "level": {
            "type": "integer"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "displayName",
          "healthCurrent",
          "healthMax",
          "healthState",
          "streak",
          "level"
        ]
      },
      "Goal": {
        "type": "object",
        "description": "A user-defined goal and its schedule. Open schema; core fields listed.",
        "additionalProperties": true,
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "schedule": {
            "type": "object",
            "additionalProperties": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "XpEvent": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "xp": {
            "type": "integer"
          },
          "source": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "GameState": {
        "type": "object",
        "description": "Avatar game state. Open schema; core fields listed.",
        "additionalProperties": true,
        "properties": {
          "healthCurrent": {
            "type": "integer"
          },
          "healthMax": {
            "type": "integer"
          },
          "healthState": {
            "type": "string",
            "enum": [
              "thriving",
              "struggling",
              "critical",
              "flatline"
            ]
          },
          "level": {
            "type": "integer"
          },
          "coins": {
            "type": "integer"
          },
          "xp": {
            "type": "integer"
          },
          "streak": {
            "type": "integer"
          }
        }
      },
      "WeeklySummary": {
        "type": "object",
        "description": "Weekly progress recap. Open schema.",
        "additionalProperties": true
      },
      "Badge": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "icon": {
            "type": "string"
          },
          "conditionType": {
            "type": "string"
          },
          "conditionValue": {
            "type": "number"
          },
          "earnedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "required": [
          "id",
          "name"
        ]
      },
      "TerritoryStats": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "totalTerritorySqm": {
            "type": "number"
          },
          "totalDistanceM": {
            "type": "number"
          },
          "runCount": {
            "type": "integer"
          }
        }
      },
      "Run": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "distanceM": {
            "type": "number"
          },
          "areaSqm": {
            "type": "number"
          },
          "capturedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "LeaderboardResponse": {
        "type": "object",
        "properties": {
          "leaderboard": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true,
              "properties": {
                "userId": {
                  "type": "string"
                },
                "displayName": {
                  "type": "string"
                },
                "totalArea": {
                  "type": "number"
                },
                "rank": {
                  "type": "integer"
                }
              }
            }
          },
          "myRank": {
            "type": "integer",
            "nullable": true
          },
          "myTotalArea": {
            "type": "number"
          }
        },
        "required": [
          "leaderboard"
        ]
      },
      "GeoJSONFeatureCollection": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "FeatureCollection"
            ]
          },
          "features": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        },
        "required": [
          "type",
          "features"
        ]
      },
      "LoginRequest": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "password": {
            "type": "string"
          }
        },
        "required": [
          "email",
          "password"
        ]
      },
      "AuthResponse": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string"
          },
          "user": {
            "$ref": "#/components/schemas/ProfileResponse"
          }
        },
        "required": [
          "token",
          "user"
        ]
      },
      "WaitlistRequest": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          }
        },
        "required": [
          "email"
        ]
      },
      "WaitlistResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          }
        },
        "required": [
          "message"
        ]
      }
    }
  }
}