{
  "openapi": "3.0.1",
  "info": {
    "title": "Hackatime API",
    "version": "v1",
    "description": "Hackatime's API gives access to coding activity data.\n\nWe support the WakaTime spec, allowing you to use existing plugins and tools.\n",
    "contact": {
      "name": "Hack Club",
      "url": "https://github.com/hackclub/hackatime"
    },
    "license": {
      "name": "MIT",
      "url": "https://github.com/hackclub/hackatime/blob/main/LICENSE"
    }
  },
  "externalDocs": {
    "description": "Hackatime documentation",
    "url": "https://hackatime.hackclub.com/docs"
  },
  "paths": {
    "/api/hackatime/v1/users/{id}/heartbeats": {
      "post": {
        "summary": "Push heartbeats (WakaTime compatible)",
        "tags": [
          "WakaTime Compatibility"
        ],
        "description": "Endpoint used by WakaTime plugins to send heartbeat data to the server. This is the core endpoint for tracking time.",
        "security": [
          {
            "Bearer": [],
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "User ID or \"current\" (recommended). The authenticated user is resolved from the API token, not this path segment.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "accepted"
          },
          "400": {
            "description": "no data provided"
          },
          "422": {
            "description": "heartbeat rejected"
          },
          "401": {
            "description": "unauthorized"
          },
          "403": {
            "description": "account pending deletion"
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "description": "Array of heartbeats. The single (non-bulk) variant only processes the first element of the array.",
                "items": {
                  "type": "object",
                  "properties": {
                    "entity": {
                      "type": "string",
                      "example": "app/models/user.rb",
                      "description": "File path or entity being tracked"
                    },
                    "type": {
                      "type": "string",
                      "example": "file",
                      "description": "Entity type, e.g. \"file\""
                    },
                    "time": {
                      "type": "number",
                      "example": 1710946200.0,
                      "description": "Unix timestamp (seconds, float)"
                    },
                    "project": {
                      "type": "string",
                      "example": "hackatime"
                    },
                    "branch": {
                      "type": "string",
                      "example": "main"
                    },
                    "ai_model": {
                      "type": "string",
                      "example": "gpt/5.3-codex"
                    },
                    "ai_session": {
                      "type": "string",
                      "example": "session-123"
                    },
                    "ai_subscription_plan": {
                      "type": "string",
                      "example": "pro"
                    },
                    "ai_input_tokens": {
                      "type": "integer",
                      "format": "int64",
                      "example": 1200
                    },
                    "ai_output_tokens": {
                      "type": "integer",
                      "format": "int64",
                      "example": 350
                    },
                    "ai_prompt_length": {
                      "type": "integer",
                      "example": 240
                    },
                    "ai_line_changes": {
                      "type": "integer",
                      "example": 18
                    },
                    "human_line_changes": {
                      "type": "integer",
                      "example": 7
                    },
                    "language": {
                      "type": "string",
                      "example": "Ruby"
                    },
                    "is_write": {
                      "type": "boolean",
                      "example": true
                    },
                    "lineno": {
                      "type": "integer",
                      "example": 42
                    },
                    "cursorpos": {
                      "type": "integer",
                      "example": 12
                    },
                    "lines": {
                      "type": "integer",
                      "example": 350
                    },
                    "category": {
                      "type": "string",
                      "example": "coding"
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date_time",
                      "example": "2024-03-20T15:30:00Z"
                    },
                    "dependencies": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "example": "rails"
                      },
                      "description": "May also be sent as a string"
                    },
                    "editor": {
                      "type": "string",
                      "example": "VS Code"
                    },
                    "line_additions": {
                      "type": "integer",
                      "example": 8
                    },
                    "line_deletions": {
                      "type": "integer",
                      "example": 3
                    },
                    "machine": {
                      "type": "string",
                      "example": "Orpheus-MacBook-Pro"
                    },
                    "operating_system": {
                      "type": "string",
                      "example": "Mac"
                    },
                    "project_root_count": {
                      "type": "integer",
                      "example": 4
                    },
                    "user_agent": {
                      "type": "string",
                      "example": "wakatime/v1.115.2 (darwin-24.6.0) go1.23 vscode/1.96.0"
                    },
                    "plugin": {
                      "type": "string",
                      "example": "vscode/1.96.0 vscode-wakatime/24.6.0",
                      "description": "Accepted but not persisted"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/hackatime/v1/users/{id}/heartbeats.bulk": {
      "post": {
        "summary": "Push heartbeats in bulk (WakaTime compatible)",
        "tags": [
          "WakaTime Compatibility"
        ],
        "description": "Bulk variant of the heartbeat ingest endpoint, used by WakaTime clients via the \".bulk\" format extension. Resolves to the same controller action (push_heartbeats) which detects params[\"format\"] == \"bulk\". Accepts up to 100 heartbeats per request and returns a per-heartbeat array of [attributes_or_error, status_code] pairs.",
        "security": [
          {
            "Bearer": [],
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "User ID or \"current\" (recommended). The authenticated user is resolved from the API token, not this path segment.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "created"
          },
          "400": {
            "description": "no data or too many heartbeats"
          },
          "401": {
            "description": "unauthorized"
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "description": "Array of heartbeats (max 100). May be sent as a top-level JSON array, a text/plain JSON array, or wrapped as { hackatime: { heartbeats: [...] } }.",
                "items": {
                  "type": "object",
                  "properties": {
                    "entity": {
                      "type": "string",
                      "example": "app/models/user.rb"
                    },
                    "type": {
                      "type": "string",
                      "example": "file"
                    },
                    "time": {
                      "type": "number",
                      "example": 1710946200.0
                    },
                    "project": {
                      "type": "string",
                      "example": "hackatime"
                    },
                    "branch": {
                      "type": "string",
                      "example": "main"
                    },
                    "ai_model": {
                      "type": "string",
                      "example": "gpt/5.3-codex"
                    },
                    "ai_session": {
                      "type": "string",
                      "example": "session-123"
                    },
                    "ai_subscription_plan": {
                      "type": "string",
                      "example": "pro"
                    },
                    "ai_input_tokens": {
                      "type": "integer",
                      "format": "int64",
                      "example": 1200
                    },
                    "ai_output_tokens": {
                      "type": "integer",
                      "format": "int64",
                      "example": 350
                    },
                    "ai_prompt_length": {
                      "type": "integer",
                      "example": 240
                    },
                    "ai_line_changes": {
                      "type": "integer",
                      "example": 18
                    },
                    "human_line_changes": {
                      "type": "integer",
                      "example": 7
                    },
                    "language": {
                      "type": "string",
                      "example": "Ruby"
                    },
                    "is_write": {
                      "type": "boolean",
                      "example": true
                    },
                    "lineno": {
                      "type": "integer",
                      "example": 42
                    },
                    "cursorpos": {
                      "type": "integer",
                      "example": 12
                    },
                    "lines": {
                      "type": "integer",
                      "example": 350
                    },
                    "category": {
                      "type": "string",
                      "example": "coding"
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date_time",
                      "example": "2024-03-20T15:30:00Z"
                    },
                    "dependencies": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "example": "rails"
                      }
                    },
                    "editor": {
                      "type": "string",
                      "example": "VS Code"
                    },
                    "line_additions": {
                      "type": "integer",
                      "example": 8
                    },
                    "line_deletions": {
                      "type": "integer",
                      "example": 3
                    },
                    "machine": {
                      "type": "string",
                      "example": "Orpheus-MacBook-Pro"
                    },
                    "operating_system": {
                      "type": "string",
                      "example": "Mac"
                    },
                    "project_root_count": {
                      "type": "integer",
                      "example": 4
                    },
                    "user_agent": {
                      "type": "string",
                      "example": "wakatime/v1.115.2 (darwin-24.6.0) go1.23 vscode/1.96.0"
                    },
                    "plugin": {
                      "type": "string",
                      "example": "vscode/1.96.0 vscode-wakatime/24.6.0"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/hackatime/v1/users/{id}": {
      "get": {
        "summary": "Get current user (WakaTime compatible)",
        "tags": [
          "WakaTime Compatibility"
        ],
        "description": "Returns profile metadata for the user authenticated by the API key.",
        "security": [
          {
            "Bearer": [],
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "User ID or \"current\" (recommended). The authenticated user is resolved from the API token.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "example": "42"
                        },
                        "username": {
                          "type": "string",
                          "nullable": true,
                          "example": "orpheus"
                        },
                        "display_name": {
                          "type": "string",
                          "example": "Orpheus"
                        },
                        "full_name": {
                          "type": "string",
                          "example": "Orpheus"
                        },
                        "photo": {
                          "type": "string",
                          "example": "https://example.com/orpheus.png"
                        },
                        "timezone": {
                          "type": "string",
                          "example": "America/New_York"
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date_time"
                        },
                        "modified_at": {
                          "type": "string",
                          "format": "date_time"
                        },
                        "plan": {
                          "type": "string",
                          "example": "free"
                        }
                      },
                      "required": [
                        "id",
                        "display_name",
                        "full_name",
                        "photo",
                        "timezone",
                        "created_at",
                        "modified_at",
                        "plan"
                      ]
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "unauthorized"
          }
        }
      }
    },
    "/api/hackatime/v1/users/{id}/summaries": {
      "get": {
        "summary": "Get daily summaries (WakaTime compatible)",
        "tags": [
          "WakaTime Compatibility"
        ],
        "description": "Returns coding activity for an inclusive date range as WakaTime-compatible daily summaries.",
        "security": [
          {
            "Bearer": [],
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "User ID or \"current\" (recommended). The authenticated user is resolved from the API token.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "start",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "required": true,
            "description": "Inclusive start date in YYYY-MM-DD format."
          },
          {
            "name": "end",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "required": true,
            "description": "Inclusive end date in YYYY-MM-DD format. The range may contain at most 366 days."
          },
          {
            "name": "project",
            "in": "query",
            "required": false,
            "description": "Only include activity for this project.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "timezone",
            "in": "query",
            "required": false,
            "description": "Timezone used to segment days. Defaults to the user's timezone.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "grand_total": {
                            "type": "object",
                            "properties": {
                              "total_seconds": {
                                "type": "integer",
                                "example": 7200
                              },
                              "hours": {
                                "type": "integer",
                                "example": 2
                              },
                              "minutes": {
                                "type": "integer",
                                "example": 0
                              },
                              "seconds": {
                                "type": "integer",
                                "example": 0
                              },
                              "digital": {
                                "type": "string",
                                "example": "02:00:00"
                              },
                              "decimal": {
                                "type": "string",
                                "example": "2.00"
                              },
                              "text": {
                                "type": "string",
                                "example": "2h"
                              },
                              "ai_input_tokens": {
                                "type": "integer",
                                "format": "int64",
                                "nullable": true,
                                "example": 1200
                              },
                              "ai_output_tokens": {
                                "type": "integer",
                                "format": "int64",
                                "nullable": true,
                                "example": 350
                              },
                              "ai_model_breakdown": {
                                "type": "array",
                                "nullable": true,
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "name": {
                                      "type": "string",
                                      "example": "gpt/5.6"
                                    },
                                    "lines": {
                                      "type": "integer",
                                      "example": 18
                                    }
                                  }
                                }
                              }
                            },
                            "required": [
                              "total_seconds",
                              "hours",
                              "minutes",
                              "seconds",
                              "digital",
                              "decimal",
                              "text"
                            ]
                          },
                          "projects": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "name": {
                                  "type": "string",
                                  "example": "hackatime"
                                },
                                "total_seconds": {
                                  "type": "integer",
                                  "example": 7200
                                },
                                "percent": {
                                  "type": "number",
                                  "example": 100.0
                                },
                                "hours": {
                                  "type": "integer",
                                  "example": 2
                                },
                                "minutes": {
                                  "type": "integer",
                                  "example": 0
                                },
                                "seconds": {
                                  "type": "integer",
                                  "example": 0
                                },
                                "digital": {
                                  "type": "string",
                                  "example": "02:00:00"
                                },
                                "decimal": {
                                  "type": "string",
                                  "example": "2.00"
                                },
                                "text": {
                                  "type": "string",
                                  "example": "2h"
                                }
                              }
                            }
                          },
                          "range": {
                            "type": "object",
                            "properties": {
                              "date": {
                                "type": "string",
                                "format": "date"
                              },
                              "start": {
                                "type": "string",
                                "format": "date_time"
                              },
                              "end": {
                                "type": "string",
                                "format": "date_time"
                              },
                              "text": {
                                "type": "string",
                                "example": "Today"
                              },
                              "timezone": {
                                "type": "string",
                                "example": "America/New_York"
                              }
                            },
                            "required": [
                              "date",
                              "start",
                              "end",
                              "text",
                              "timezone"
                            ]
                          }
                        },
                        "required": [
                          "grand_total",
                          "projects",
                          "range"
                        ]
                      }
                    },
                    "cumulative_total": {
                      "type": "object",
                      "properties": {
                        "seconds": {
                          "type": "integer",
                          "example": 7200
                        },
                        "text": {
                          "type": "string",
                          "example": "2h"
                        },
                        "decimal": {
                          "type": "string",
                          "example": "2.00"
                        },
                        "digital": {
                          "type": "string",
                          "example": "02:00:00"
                        }
                      }
                    },
                    "daily_average": {
                      "type": "object",
                      "properties": {
                        "holidays": {
                          "type": "integer",
                          "example": 0
                        },
                        "days_including_holidays": {
                          "type": "integer",
                          "example": 1
                        },
                        "days_minus_holidays": {
                          "type": "integer",
                          "example": 1
                        },
                        "seconds": {
                          "type": "integer",
                          "example": 7200
                        },
                        "text": {
                          "type": "string",
                          "example": "2h"
                        }
                      }
                    },
                    "start": {
                      "type": "string",
                      "format": "date"
                    },
                    "end": {
                      "type": "string",
                      "format": "date"
                    }
                  },
                  "required": [
                    "data",
                    "cumulative_total",
                    "daily_average",
                    "start",
                    "end"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "invalid date range"
          },
          "401": {
            "description": "unauthorized"
          }
        }
      }
    },
    "/api/hackatime/v1/users/{id}/statusbar/today": {
      "get": {
        "summary": "Get status bar today",
        "tags": [
          "WakaTime Compatibility"
        ],
        "description": "Returns the total coding time for today. Used by editor plugins to display the status bar widget.",
        "security": [
          {
            "Bearer": [],
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "User ID or \"current\"",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "grand_total": {
                          "type": "object",
                          "properties": {
                            "total_seconds": {
                              "type": "number",
                              "example": 7200.0
                            },
                            "text": {
                              "type": "string",
                              "example": "2h 30m / 4h goal"
                            }
                          }
                        },
                        "goal": {
                          "type": "object",
                          "nullable": true,
                          "properties": {
                            "target_seconds": {
                              "type": "number",
                              "example": 14400
                            },
                            "tracked_seconds": {
                              "type": "number",
                              "example": 9000
                            },
                            "completion_percent": {
                              "type": "number",
                              "example": 62
                            },
                            "complete": {
                              "type": "boolean",
                              "example": false
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "unauthorized"
          }
        }
      }
    },
    "/api/hackatime/v1/users/current/stats/last_7_days": {
      "get": {
        "summary": "Get last 7 days stats",
        "tags": [
          "WakaTime Compatibility"
        ],
        "description": "Returns coding statistics for the last 7 days. Used by some WakaTime dashboards.",
        "security": [
          {
            "Bearer": [],
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "username": {
                          "type": "string",
                          "example": "U0266FRGP"
                        },
                        "user_id": {
                          "type": "string",
                          "example": "U0266FRGP"
                        },
                        "start": {
                          "type": "string",
                          "format": "date_time",
                          "example": "2024-03-13T00:00:00Z"
                        },
                        "end": {
                          "type": "string",
                          "format": "date_time",
                          "example": "2024-03-20T23:59:59Z"
                        },
                        "status": {
                          "type": "string",
                          "example": "ok"
                        },
                        "total_seconds": {
                          "type": "number",
                          "example": 25200
                        },
                        "daily_average": {
                          "type": "number",
                          "example": 3600.0
                        },
                        "days_including_holidays": {
                          "type": "integer",
                          "example": 7
                        },
                        "range": {
                          "type": "string",
                          "example": "last_7_days"
                        },
                        "human_readable_range": {
                          "type": "string",
                          "example": "Last 7 Days"
                        },
                        "human_readable_total": {
                          "type": "string",
                          "example": "7 hrs 0 mins"
                        },
                        "human_readable_daily_average": {
                          "type": "string",
                          "example": "1 hrs 0 mins"
                        },
                        "is_coding_activity_visible": {
                          "type": "boolean",
                          "example": true
                        },
                        "is_other_usage_visible": {
                          "type": "boolean",
                          "example": true
                        },
                        "editors": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": {
                                "type": "string",
                                "example": "VS Code"
                              },
                              "total_seconds": {
                                "type": "integer",
                                "example": 25200
                              },
                              "percent": {
                                "type": "number",
                                "example": 100.0
                              },
                              "digital": {
                                "type": "string",
                                "example": "7:00:00"
                              },
                              "text": {
                                "type": "string",
                                "example": "7 hrs 0 mins"
                              },
                              "hours": {
                                "type": "integer",
                                "example": 7
                              },
                              "minutes": {
                                "type": "integer",
                                "example": 0
                              },
                              "seconds": {
                                "type": "integer",
                                "example": 0
                              }
                            }
                          }
                        },
                        "languages": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": {
                                "type": "string",
                                "example": "Ruby"
                              },
                              "total_seconds": {
                                "type": "integer",
                                "example": 18000
                              },
                              "percent": {
                                "type": "number",
                                "example": 71.43
                              },
                              "digital": {
                                "type": "string",
                                "example": "5:00:00"
                              },
                              "text": {
                                "type": "string",
                                "example": "5 hrs 0 mins"
                              },
                              "hours": {
                                "type": "integer",
                                "example": 5
                              },
                              "minutes": {
                                "type": "integer",
                                "example": 0
                              },
                              "seconds": {
                                "type": "integer",
                                "example": 0
                              }
                            }
                          }
                        },
                        "machines": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": {
                                "type": "string",
                                "example": "Orpheus-MacBook-Pro"
                              },
                              "total_seconds": {
                                "type": "integer",
                                "example": 25200
                              },
                              "percent": {
                                "type": "number",
                                "example": 100.0
                              },
                              "digital": {
                                "type": "string",
                                "example": "7:00:00"
                              },
                              "text": {
                                "type": "string",
                                "example": "7 hrs 0 mins"
                              },
                              "hours": {
                                "type": "integer",
                                "example": 7
                              },
                              "minutes": {
                                "type": "integer",
                                "example": 0
                              },
                              "seconds": {
                                "type": "integer",
                                "example": 0
                              }
                            }
                          }
                        },
                        "projects": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": {
                                "type": "string",
                                "example": "hackatime"
                              },
                              "total_seconds": {
                                "type": "integer",
                                "example": 21600
                              },
                              "percent": {
                                "type": "number",
                                "example": 85.71
                              },
                              "digital": {
                                "type": "string",
                                "example": "6:00:00"
                              },
                              "text": {
                                "type": "string",
                                "example": "6 hrs 0 mins"
                              },
                              "hours": {
                                "type": "integer",
                                "example": 6
                              },
                              "minutes": {
                                "type": "integer",
                                "example": 0
                              },
                              "seconds": {
                                "type": "integer",
                                "example": 0
                              }
                            }
                          }
                        },
                        "operating_systems": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": {
                                "type": "string",
                                "example": "Mac"
                              },
                              "total_seconds": {
                                "type": "integer",
                                "example": 25200
                              },
                              "percent": {
                                "type": "number",
                                "example": 100.0
                              },
                              "digital": {
                                "type": "string",
                                "example": "7:00:00"
                              },
                              "text": {
                                "type": "string",
                                "example": "7 hrs 0 mins"
                              },
                              "hours": {
                                "type": "integer",
                                "example": 7
                              },
                              "minutes": {
                                "type": "integer",
                                "example": 0
                              },
                              "seconds": {
                                "type": "integer",
                                "example": 0
                              }
                            }
                          }
                        },
                        "categories": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": {
                                "type": "string",
                                "example": "coding"
                              },
                              "total_seconds": {
                                "type": "integer",
                                "example": 25200
                              },
                              "percent": {
                                "type": "number",
                                "example": 100.0
                              },
                              "digital": {
                                "type": "string",
                                "example": "7:00:00"
                              },
                              "text": {
                                "type": "string",
                                "example": "7 hrs 0 mins"
                              },
                              "hours": {
                                "type": "integer",
                                "example": 7
                              },
                              "minutes": {
                                "type": "integer",
                                "example": 0
                              },
                              "seconds": {
                                "type": "integer",
                                "example": 0
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "unauthorized"
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "summary": "Fetch the OpenAPI description of this API",
        "tags": [
          "Discovery"
        ],
        "description": "Returns this document. No authentication is required.\n\n`/api/openapi.json` is an alias for the same resource, and the YAML\nrepresentation is available at `/openapi.yaml` (aliased at\n`/api/openapi.yaml`).\n",
        "security": [],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "An OpenAPI 3.0 document describing the Hackatime API.",
                  "properties": {
                    "openapi": {
                      "type": "string",
                      "example": "3.0.1"
                    },
                    "info": {
                      "type": "object"
                    },
                    "paths": {
                      "type": "object"
                    },
                    "components": {
                      "type": "object"
                    },
                    "servers": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  },
                  "required": [
                    "openapi",
                    "info",
                    "paths"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/openapi.yaml": {
      "get": {
        "summary": "Fetch the OpenAPI description of this API as YAML",
        "tags": [
          "Discovery"
        ],
        "description": "The YAML representation of `/openapi.json`. No authentication is required.",
        "security": [],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/yaml": {
                "schema": {
                  "type": "string",
                  "description": "An OpenAPI 3.0 document, serialised as YAML."
                }
              }
            }
          }
        }
      }
    },
    "/api/summary": {
      "get": {
        "summary": "Get WakaTime-compatible summary",
        "tags": [
          "WakaTime Compatibility"
        ],
        "description": "Returns a summary of coding activity in a format compatible with WakaTime clients. This endpoint does NOT authenticate any API token: access is gated solely by the target user (identified by user_id/user) having allow_public_stats_lookup enabled. No caller credentials are required or verified.",
        "security": [],
        "parameters": [
          {
            "name": "start",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date (YYYY-MM-DD). Requires \"end\"/\"to\" to be set as well to form an explicit range."
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Alias for \"start\". Used when \"start\" is absent."
          },
          {
            "name": "end",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date (YYYY-MM-DD). Requires \"start\"/\"from\" to be set as well to form an explicit range."
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Alias for \"end\". Used when \"end\" is absent."
          },
          {
            "name": "interval",
            "in": "query",
            "description": "Interval keyword. One of: today, yesterday, week, 7_days, last_7_days, month, 30_days, last_30_days, 6_months, last_6_months, year, 12_months, last_12_months, last_year, any, all_time. Defaults to all_time when neither interval nor range is given; unknown values fall back to today.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "range",
            "in": "query",
            "description": "Fallback interval keyword used when \"interval\" is absent. Accepts the same values as \"interval\".",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "user_id",
            "in": "query",
            "required": true,
            "description": "User identifier (slack_uid, username, hca_id, or numeric ID)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "user",
            "in": "query",
            "description": "Deprecated: use user_id instead. Kept for backwards compatibility.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user_id": {
                      "type": "string",
                      "nullable": true,
                      "example": "U0266FRGP"
                    },
                    "from": {
                      "type": "string",
                      "format": "date_time",
                      "example": "2023-01-01T00:00:00Z"
                    },
                    "to": {
                      "type": "string",
                      "format": "date_time",
                      "example": "2023-01-31T23:59:59Z"
                    },
                    "projects": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "key": {
                            "type": "string",
                            "example": "hackatime"
                          },
                          "total": {
                            "type": "number",
                            "example": 21600.0
                          }
                        }
                      }
                    },
                    "languages": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "key": {
                            "type": "string",
                            "example": "Ruby"
                          },
                          "total": {
                            "type": "number",
                            "example": 18000.0
                          }
                        }
                      }
                    },
                    "editors": {
                      "type": "object",
                      "nullable": true
                    },
                    "operating_systems": {
                      "type": "object",
                      "nullable": true
                    },
                    "machines": {
                      "type": "object",
                      "nullable": true
                    },
                    "categories": {
                      "type": "object",
                      "nullable": true
                    },
                    "branches": {
                      "type": "object",
                      "nullable": true
                    },
                    "entities": {
                      "type": "object",
                      "nullable": true
                    },
                    "labels": {
                      "type": "object",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid date range"
          },
          "404": {
            "description": "user not found"
          },
          "403": {
            "description": "user has disabled public stats"
          }
        }
      }
    },
    "/api/v1/authenticated/me": {
      "get": {
        "summary": "Get current user info",
        "tags": [
          "OAuth2-specific"
        ],
        "description": "Returns detailed information about the currently authenticated user. Requires an OAuth2 access token with the `profile` scope in the Bearer header.",
        "security": [
          {
            "OAuth2": [
              "profile"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "integer",
                      "example": 42
                    },
                    "emails": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "example": "orpheus@hackclub.com"
                      }
                    },
                    "slack_id": {
                      "type": "string",
                      "nullable": true,
                      "example": "U0266FRGP"
                    },
                    "github_username": {
                      "type": "string",
                      "nullable": true,
                      "example": "orpheus"
                    },
                    "trust_factor": {
                      "type": "object",
                      "properties": {
                        "trust_level": {
                          "type": "string",
                          "example": "blue"
                        },
                        "trust_value": {
                          "type": "integer",
                          "example": 0
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "insufficient scope"
          },
          "401": {
            "description": "unauthorized — Returned when the OAuth access token is missing or invalid."
          }
        }
      }
    },
    "/api/v1/authenticated/hours": {
      "get": {
        "summary": "Get hours",
        "tags": [
          "OAuth2-specific"
        ],
        "description": "Returns the total coding hours for the authenticated user. Requires an OAuth2 access token with the `read` scope in the Bearer header.",
        "security": [
          {
            "OAuth2": [
              "read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "start_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date (YYYY-MM-DD)"
          },
          {
            "name": "end_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date (YYYY-MM-DD)"
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "start_date": {
                      "type": "string",
                      "format": "date",
                      "example": "2024-03-13"
                    },
                    "end_date": {
                      "type": "string",
                      "format": "date",
                      "example": "2024-03-20"
                    },
                    "total_seconds": {
                      "type": "number",
                      "example": 153000.0
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "insufficient scope"
          },
          "401": {
            "description": "unauthorized — Returned when the OAuth access token is missing or invalid (empty body), or when the authenticated user is banned (`trust_level == \"red\"`) via the `ensure_no_ban` before_action (which responds with a `{ \"error\": \"Unauthorized\" }` body)."
          }
        }
      }
    },
    "/api/v1/authenticated/streak": {
      "get": {
        "summary": "Get streak",
        "tags": [
          "OAuth2-specific"
        ],
        "description": "Returns the current streak information (days coded in a row). Requires an OAuth2 access token with the `read` scope in the Bearer header.",
        "security": [
          {
            "OAuth2": [
              "read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "streak_days": {
                      "type": "integer",
                      "example": 5
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "insufficient scope"
          },
          "401": {
            "description": "unauthorized — Returned when the OAuth access token is missing or invalid."
          }
        }
      }
    },
    "/api/v1/authenticated/projects": {
      "get": {
        "summary": "Get projects",
        "tags": [
          "OAuth2-specific"
        ],
        "description": "Returns a list of projects associated with the authenticated user. Requires an OAuth2 access token with the `read` scope in the Bearer header.",
        "security": [
          {
            "OAuth2": [
              "read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "include_archived",
            "in": "query",
            "description": "Include archived projects (true/false)",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "projects",
            "in": "query",
            "description": "Comma-separated list of project names",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "since",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            },
            "description": "Project discovery start time (ISO 8601)"
          },
          {
            "name": "until",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            },
            "description": "Project discovery end time (ISO 8601)"
          },
          {
            "name": "until_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            },
            "description": "Alias for until"
          },
          {
            "name": "start",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            },
            "description": "Stats start time (ISO 8601)"
          },
          {
            "name": "end",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            },
            "description": "Stats end time (ISO 8601)"
          },
          {
            "name": "start_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            },
            "description": "Alias for start"
          },
          {
            "name": "end_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            },
            "description": "Alias for end"
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "projects": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string",
                            "example": "hackatime"
                          },
                          "total_seconds": {
                            "type": "number",
                            "example": 3600.0
                          },
                          "most_recent_heartbeat": {
                            "type": "string",
                            "format": "date_time",
                            "nullable": true,
                            "example": "2024-03-20T15:30:00Z"
                          },
                          "languages": {
                            "type": "array",
                            "items": {
                              "type": "string",
                              "example": "Ruby"
                            }
                          },
                          "archived": {
                            "type": "boolean",
                            "example": false
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "insufficient scope"
          },
          "401": {
            "description": "unauthorized — Returned when the OAuth access token is missing or invalid."
          }
        }
      }
    },
    "/api/v1/authenticated/api_keys": {
      "get": {
        "summary": "Get API keys",
        "tags": [
          "OAuth2-specific"
        ],
        "description": "Returns the API keys for the authenticated user. Requires an OAuth2 access token (Bearer header). Warning: This returns sensitive information.",
        "security": [
          {
            "Bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "token": {
                      "type": "string",
                      "example": "550e8400-e29b-41d4-a716-446655440000"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "unauthorized — Returned when the OAuth access token is missing or invalid."
          }
        }
      }
    },
    "/api/v1/authenticated/heartbeats/latest": {
      "get": {
        "summary": "Get latest heartbeat",
        "tags": [
          "OAuth2-specific"
        ],
        "description": "Returns the absolutely latest heartbeat processed for the user. Requires an OAuth2 access token with the `read` scope in the Bearer header. When the user has no non-test heartbeat, the response is `{ \"heartbeat\": null }`.",
        "security": [
          {
            "OAuth2": [
              "read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "title": "Latest heartbeat",
                      "properties": {
                        "id": {
                          "type": "integer",
                          "example": 987654
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date_time",
                          "example": "2024-03-20T15:30:00Z"
                        },
                        "time": {
                          "type": "number",
                          "example": 1710948600.0
                        },
                        "category": {
                          "type": "string",
                          "example": "coding"
                        },
                        "project": {
                          "type": "string",
                          "example": "hackatime"
                        },
                        "language": {
                          "type": "string",
                          "example": "Ruby"
                        },
                        "editor": {
                          "type": "string",
                          "example": "VS Code"
                        },
                        "operating_system": {
                          "type": "string",
                          "example": "Mac"
                        },
                        "machine": {
                          "type": "string",
                          "example": "Orpheus-MacBook-Pro"
                        },
                        "entity": {
                          "type": "string",
                          "example": "app/models/user.rb"
                        }
                      },
                      "required": [
                        "id",
                        "time"
                      ]
                    },
                    {
                      "type": "object",
                      "title": "No heartbeats yet",
                      "description": "Returned when the user has no non-test heartbeat.",
                      "properties": {
                        "heartbeat": {
                          "type": "object",
                          "nullable": true,
                          "example": null
                        }
                      },
                      "required": [
                        "heartbeat"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "insufficient scope"
          },
          "401": {
            "description": "unauthorized — Returned when the OAuth access token is missing or invalid."
          }
        }
      }
    },
    "/api/v1/badge/{user_id}/{project}": {
      "get": {
        "summary": "Generate a shields.io coding-time badge for a project",
        "tags": [
          "Badges"
        ],
        "description": "Redirects (307) to an img.shields.io badge URL showing the total coding\ntime a user has logged on a project. The endpoint is public (no auth) but\nonly works for users who have not disabled public stats lookup.\n\n`user_id` is matched, in order, against the user's Slack UID, then\nusername, then (only when the value is all digits) the internal numeric\nID. `project` may be a raw project name (e.g. `hackatime`) or an\n`owner/repo` pair (e.g. `hackclub/hackatime`) which is resolved to a\nproject name via the user's repo mappings.\n\nAny additional query parameters not consumed below (e.g. `style`, `logo`,\n`logoColor`, `labelColor`) are passed straight through to shields.io.\n",
        "security": [],
        "parameters": [
          {
            "name": "user_id",
            "in": "path",
            "required": true,
            "description": "User identifier: Slack UID, username, or numeric internal ID.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "project",
            "in": "path",
            "required": true,
            "description": "Project name (e.g. \"hackatime\") or \"owner/repo\" (e.g. \"hackclub/hackatime\").",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "label",
            "in": "query",
            "required": false,
            "description": "Left-hand text of the badge. Default: \"hackatime\".",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "color",
            "in": "query",
            "required": false,
            "description": "Badge color passed to shields.io (any shields.io-accepted color). Default: \"blue\".",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "aliases",
            "in": "query",
            "required": false,
            "description": "Comma-separated list of additional project names whose coding time is summed into the total.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "307": {
            "description": "redirect to the shields.io badge image"
          },
          "404": {
            "description": "project not found"
          },
          "403": {
            "description": "user has disabled public stats lookup"
          },
          "400": {
            "description": "project has no countable coding time"
          }
        }
      }
    },
    "/api/v1/currently_hacking": {
      "get": {
        "summary": "List users currently hacking",
        "tags": [
          "Currently Hacking"
        ],
        "description": "Returns the set of users who have logged a direct-entry coding heartbeat\nin the last 5 minutes, along with the project each is currently working\non (if its repo mapping is not archived). The endpoint is public (no\nauthentication required) and the result is cached for 5 minutes.\n",
        "security": [],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Number of users currently hacking.",
                      "example": 1
                    },
                    "users": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "display_name": {
                            "type": "string",
                            "nullable": true,
                            "example": "Orpheus"
                          },
                          "avatar_url": {
                            "type": "string",
                            "nullable": true,
                            "example": "https://hackatime.hackclub.com/images/athena.png"
                          },
                          "country_code": {
                            "type": "string",
                            "nullable": true,
                            "example": "US"
                          },
                          "working_on": {
                            "type": "object",
                            "nullable": true,
                            "description": "The project the user is currently working on, or null.",
                            "properties": {
                              "project_name": {
                                "type": "string",
                                "example": "hackatime"
                              },
                              "repo_url": {
                                "type": "string",
                                "nullable": true,
                                "example": "https://github.com/hackclub/hackatime"
                              }
                            }
                          }
                        },
                        "required": [
                          "display_name",
                          "avatar_url",
                          "country_code",
                          "working_on"
                        ]
                      }
                    }
                  },
                  "required": [
                    "count",
                    "users"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/leaderboard/daily": {
      "get": {
        "summary": "Get daily leaderboard",
        "tags": [
          "Leaderboard"
        ],
        "description": "Returns the daily leaderboard of coding time. Public, no authentication required. The leaderboard is cached and regenerated periodically.",
        "security": [],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "period": {
                      "type": "string",
                      "example": "daily"
                    },
                    "start_date": {
                      "type": "string",
                      "format": "date",
                      "example": "2024-03-20"
                    },
                    "date_range": {
                      "type": "string",
                      "example": "Wed, Mar 20, 2024"
                    },
                    "generated_at": {
                      "type": "string",
                      "format": "date_time",
                      "example": "2024-03-20T10:00:00Z"
                    },
                    "entries": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LeaderboardEntry"
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "service unavailable — Leaderboard is being generated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/leaderboard/weekly": {
      "get": {
        "summary": "Get weekly leaderboard",
        "tags": [
          "Leaderboard"
        ],
        "description": "Returns the weekly leaderboard of coding time (last 7 days). Public, no authentication required.",
        "security": [],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "period": {
                      "type": "string",
                      "example": "last_7_days"
                    },
                    "start_date": {
                      "type": "string",
                      "format": "date",
                      "example": "2024-03-13"
                    },
                    "date_range": {
                      "type": "string",
                      "example": "Mar 13 - Mar 20, 2024"
                    },
                    "generated_at": {
                      "type": "string",
                      "format": "date_time",
                      "example": "2024-03-20T10:00:00Z"
                    },
                    "entries": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LeaderboardEntry"
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "service unavailable — Leaderboard is being generated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/my/heartbeats/most_recent": {
      "get": {
        "summary": "Get most recent heartbeat",
        "tags": [
          "My Data"
        ],
        "description": "Returns the most recent heartbeat for the authenticated user. Useful for checking if the user is currently active. Authenticate with an OAuth access token with the `read` scope or an API key as a Bearer token in the `Authorization` header (HTTP Basic auth with the API key is also accepted).",
        "security": [
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "name": "source_type",
            "in": "query",
            "description": "Filter by source type (e.g. \"direct_entry\"). If omitted, results exclude heartbeats with source_type \"test_entry\" by default.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "editor",
            "in": "query",
            "description": "Filter by editor name (e.g. \"VSCode\"). Matched case-insensitively.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "has_heartbeat": {
                      "type": "boolean",
                      "description": "Whether a matching heartbeat was found.",
                      "example": true
                    },
                    "heartbeat": {
                      "type": "object",
                      "nullable": true,
                      "description": "The most recent matching heartbeat, or null when none is found."
                    },
                    "editor": {
                      "type": "string",
                      "nullable": true,
                      "description": "Editor of the matching heartbeat, or null.",
                      "example": "VS Code"
                    },
                    "time_ago": {
                      "type": "string",
                      "nullable": true,
                      "description": "Human-readable time since the heartbeat (e.g. \"5 minutes ago\"), or null.",
                      "example": "5 minutes ago"
                    }
                  },
                  "required": [
                    "has_heartbeat",
                    "heartbeat",
                    "editor",
                    "time_ago"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "unauthorized — Returned when the Authorization header is missing, the OAuth token lacks the read scope, or the token is invalid."
          }
        }
      }
    },
    "/api/v1/my/heartbeats": {
      "get": {
        "summary": "Get heartbeats",
        "tags": [
          "My Data"
        ],
        "description": "Returns a list of heartbeats for the authenticated user within a time range. This is the raw data stream. Authenticate with an OAuth access token with the `read` scope or an API key as a Bearer token in the `Authorization` header (HTTP Basic auth with the API key is also accepted).",
        "security": [
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "name": "start_time",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            },
            "description": "Start time (ISO 8601). Defaults to the beginning of the current day when omitted."
          },
          {
            "name": "end_time",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            },
            "description": "End time (ISO 8601). Defaults to the end of the current day when omitted."
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "start_time": {
                      "type": "string",
                      "format": "date_time",
                      "description": "Effective start of the queried range.",
                      "example": "2024-03-20T00:00:00Z"
                    },
                    "end_time": {
                      "type": "string",
                      "format": "date_time",
                      "description": "Effective end of the queried range.",
                      "example": "2024-03-20T23:59:59Z"
                    },
                    "total_seconds": {
                      "type": "number",
                      "description": "Total coding duration in seconds across the returned heartbeats.",
                      "example": 3600.0
                    },
                    "heartbeats": {
                      "type": "array",
                      "description": "Heartbeats in the range, ordered by time ascending.",
                      "items": {
                        "$ref": "#/components/schemas/Heartbeat"
                      }
                    }
                  },
                  "required": [
                    "start_time",
                    "end_time",
                    "total_seconds",
                    "heartbeats"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "unauthorized — Returned when the Authorization header is missing, the OAuth token lacks the read scope, or the token is invalid."
          }
        }
      }
    },
    "/api/v1/stats": {
      "get": {
        "summary": "Get total coding time",
        "tags": [
          "Stats"
        ],
        "description": "Returns the total coding time for all users, optionally filtered by user or date range. Requires an active Admin API Key supplied via the Bearer header.",
        "security": [
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "name": "start_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date (YYYY-MM-DD), defaults to 10 years ago"
          },
          {
            "name": "end_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date (YYYY-MM-DD), defaults to today"
          },
          {
            "name": "username",
            "in": "query",
            "description": "Filter by username (optional)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "user_email",
            "in": "query",
            "description": "Filter by user email (optional)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "integer",
                  "example": 123456
                }
              }
            }
          },
          "401": {
            "description": "unauthorized — Returned when the Admin API Key is missing, revoked, or incorrect. (Auth is bypassed in the development environment.)",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "user not found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "invalid date",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/banned_users/counts": {
      "get": {
        "summary": "Get newly-banned user counts",
        "tags": [
          "Stats"
        ],
        "description": "Returns the number of distinct users whose trust level was newly set to \"red\" (banned/convicted) over the last day, week, and month.",
        "security": [],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "day": {
                      "type": "integer",
                      "example": 3
                    },
                    "week": {
                      "type": "integer",
                      "example": 12
                    },
                    "month": {
                      "type": "integer",
                      "example": 48
                    }
                  },
                  "required": [
                    "day",
                    "week",
                    "month"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/users/{username}/heartbeats/spans": {
      "get": {
        "summary": "Get user heartbeat spans",
        "tags": [
          "Stats"
        ],
        "description": "Returns heartbeat spans for a user, useful for visualizations. Accessible anonymously when the target user has public stats lookup enabled; otherwise the requester must be the user (authenticated via the User API Key).",
        "security": [
          {},
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "description": "Username, Slack ID, or User ID. The literal value \"my\" resolves the user from the Authorization Bearer token.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "start_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            },
            "description": "Start date/time (ISO 8601), defaults to 10 years ago"
          },
          {
            "name": "end_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            },
            "description": "End date/time (ISO 8601), defaults to end of today"
          },
          {
            "name": "project",
            "in": "query",
            "description": "Filter by single project",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter_by_project",
            "in": "query",
            "description": "Filter by multiple projects (comma separated). Ignored if project is present.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "spans": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "start_time": {
                            "type": "number",
                            "description": "Span start time (epoch seconds)",
                            "example": 1717689600.0
                          },
                          "end_time": {
                            "type": "number",
                            "description": "Span end time (epoch seconds)",
                            "example": 1717691820.5
                          },
                          "duration": {
                            "type": "number",
                            "description": "Span duration (seconds)",
                            "example": 2220.5
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "forbidden — The target user has disabled public stats lookup and the requester is not that user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "user not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "invalid date",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/users/{username}/trust_factor": {
      "get": {
        "summary": "Get user trust factor",
        "tags": [
          "Stats"
        ],
        "description": "Returns the (masked) trust level and value for a user. Only the public-facing levels are ever returned: blue (0, unscored), red (1, convicted), green (2, trusted). The internal \"yellow\" (suspected) level is masked to blue and never exposed.",
        "security": [],
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "description": "Username, Slack ID, or User ID",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "trust_level": {
                      "type": "string",
                      "enum": [
                        "blue",
                        "red",
                        "green"
                      ],
                      "example": "blue"
                    },
                    "trust_value": {
                      "type": "integer",
                      "enum": [
                        0,
                        1,
                        2
                      ],
                      "example": 0
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/users/{username}/projects": {
      "get": {
        "summary": "Get user project names",
        "tags": [
          "Stats"
        ],
        "description": "Returns a list of project names for a user from the last 30 days. Accessible anonymously when the target user has public stats lookup enabled.",
        "security": [
          {},
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "description": "Username, Slack ID, or User ID",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "projects": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "example": "hackatime"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "forbidden — The target user has disabled public stats lookup and the requester is not that user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/users/{username}/project/{project_name}": {
      "get": {
        "summary": "Get user project details",
        "tags": [
          "Stats"
        ],
        "description": "Returns details for a specific project. Accessible anonymously when the target user has public stats lookup enabled.",
        "security": [
          {},
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "description": "Username, Slack ID, or User ID",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "project_name",
            "in": "path",
            "description": "Project name",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "start",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            }
          },
          {
            "name": "end",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            }
          },
          {
            "name": "start_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            }
          },
          {
            "name": "end_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string",
                      "example": "hackatime"
                    },
                    "total_seconds": {
                      "type": "number",
                      "example": 14820.5
                    },
                    "languages": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "example": "Ruby"
                      },
                      "example": [
                        "Ruby",
                        "Svelte",
                        "TypeScript"
                      ]
                    },
                    "repo_url": {
                      "type": "string",
                      "nullable": true,
                      "example": "https://github.com/hackclub/hackatime"
                    },
                    "total_heartbeats": {
                      "type": "integer",
                      "example": 482
                    },
                    "first_heartbeat": {
                      "type": "string",
                      "format": "date_time",
                      "nullable": true,
                      "example": "2024-03-20T15:30:00Z"
                    },
                    "last_heartbeat": {
                      "type": "string",
                      "format": "date_time",
                      "nullable": true,
                      "example": "2024-06-06T18:45:00Z"
                    },
                    "most_recent_heartbeat": {
                      "type": "string",
                      "format": "date_time",
                      "nullable": true,
                      "example": "2024-06-06T18:45:00Z"
                    },
                    "archived": {
                      "type": "boolean",
                      "example": false
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "bad request — Returned when project_name is blank/whitespace-only.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "forbidden — The target user has disabled public stats lookup and the requester is not that user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not found — Returned when the user is not found, or no data exists for the requested project.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/users/{username}/projects/details": {
      "get": {
        "summary": "Get details for multiple projects",
        "tags": [
          "Stats"
        ],
        "description": "Returns details for multiple projects, or all projects in a time range. Accessible anonymously when the target user has public stats lookup enabled.",
        "security": [
          {},
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "description": "Username, Slack ID, or User ID",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "projects",
            "in": "query",
            "description": "Comma-separated project names",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "since",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            },
            "description": "Start time (ISO 8601) for project discovery"
          },
          {
            "name": "until",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            },
            "description": "End time (ISO 8601) for project discovery"
          },
          {
            "name": "until_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            },
            "description": "End time (ISO 8601) for project discovery"
          },
          {
            "name": "start",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            }
          },
          {
            "name": "end",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            }
          },
          {
            "name": "start_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            }
          },
          {
            "name": "end_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "projects": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string",
                            "example": "hackatime"
                          },
                          "total_seconds": {
                            "type": "number",
                            "example": 14820.5
                          },
                          "languages": {
                            "type": "array",
                            "items": {
                              "type": "string",
                              "example": "Ruby"
                            },
                            "example": [
                              "Ruby",
                              "Svelte",
                              "TypeScript"
                            ]
                          },
                          "repo_url": {
                            "type": "string",
                            "nullable": true,
                            "example": "https://github.com/hackclub/hackatime"
                          },
                          "total_heartbeats": {
                            "type": "integer",
                            "example": 482
                          },
                          "first_heartbeat": {
                            "type": "string",
                            "format": "date_time",
                            "nullable": true,
                            "example": "2024-03-20T15:30:00Z"
                          },
                          "last_heartbeat": {
                            "type": "string",
                            "format": "date_time",
                            "nullable": true,
                            "example": "2024-06-06T18:45:00Z"
                          },
                          "most_recent_heartbeat": {
                            "type": "string",
                            "format": "date_time",
                            "nullable": true,
                            "example": "2024-06-06T18:45:00Z"
                          },
                          "archived": {
                            "type": "boolean",
                            "example": false
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "forbidden — The target user has disabled public stats lookup and the requester is not that user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "user not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/users/{username}/stats": {
      "get": {
        "summary": "Get user stats",
        "tags": [
          "Stats"
        ],
        "description": "Returns detailed coding stats for a specific user, including languages, projects, and total time.\n\nAuthentication is OPTIONAL: the endpoint is publicly accessible (no token) whenever the target user has public stats lookup enabled. When a User API Key is supplied it is used to resolve the special username \"my\" and to grant access to the caller's own private stats.\n\nWhen total_seconds=true, the response shape is instead { \"total_seconds\": <number> }.",
        "security": [
          {},
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "description": "Username, Slack ID, or User ID. The literal value \"my\" resolves the current user from the Authorization Bearer token (User API Key).",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "start_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            },
            "description": "Start date/time (ISO 8601), defaults to 10 years ago"
          },
          {
            "name": "end_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date_time"
            },
            "description": "End date/time (ISO 8601), defaults to end of today"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Limit number of results",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "features",
            "in": "query",
            "description": "Comma-separated list of features to include (e.g., languages,projects). Defaults to languages.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter_by_project",
            "in": "query",
            "description": "Filter results by specific project names (comma-separated)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter_by_category",
            "in": "query",
            "description": "Filter results by category (comma-separated)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "boundary_aware",
            "in": "query",
            "description": "Use boundary aware calculation (only applied in the total_seconds branch)",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "total_seconds",
            "in": "query",
            "description": "When \"true\", returns only { total_seconds: <number> } instead of the full stats object",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "no_ai_coding",
            "in": "query",
            "description": "When \"true\", excludes the \"ai coding\" category from totals/summary. Caveat: heartbeats with no category at all (legacy data) are also excluded due to SQL NULL-comparison semantics.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "test_param",
            "in": "query",
            "description": "When \"true\", switches to test mode: forces boundary-aware + valid-timestamps-only and excludes the browsing/meeting/communicating categories (plus \"ai coding\" when no_ai_coding=true)",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/StatsSummary"
                        },
                        {
                          "type": "object",
                          "properties": {
                            "unique_total_seconds": {
                              "type": "number",
                              "description": "Only present when features includes \"projects\" AND filter_by_project is supplied.",
                              "example": 12960.0
                            }
                          }
                        }
                      ]
                    },
                    "trust_factor": {
                      "type": "object",
                      "properties": {
                        "trust_level": {
                          "type": "string",
                          "enum": [
                            "blue",
                            "red",
                            "green"
                          ],
                          "example": "blue"
                        },
                        "trust_value": {
                          "type": "integer",
                          "enum": [
                            0,
                            1,
                            2
                          ],
                          "example": 0
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "forbidden — User has disabled public stats lookup",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "user not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "invalid date",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/users/lookup_email/{email}": {
      "get": {
        "summary": "Lookup user by email",
        "tags": [
          "Users"
        ],
        "description": "Find a user ID by their email address. Useful for integrations that need to map emails to Hackatime users. Requires an active Admin API Key supplied via the Authorization Bearer header.",
        "security": [
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "name": "email",
            "in": "path",
            "description": "Email address to lookup",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user_id": {
                      "type": "integer",
                      "example": 42
                    },
                    "email": {
                      "type": "string",
                      "example": "orpheus@hackclub.com"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "unauthorized — Returned when the Admin API Key is missing, revoked, or incorrect. (Auth is bypassed in the development environment.)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "User not found"
                    },
                    "email": {
                      "type": "string",
                      "example": "unknown@example.com"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/users/lookup_slack_uid/{slack_uid}": {
      "get": {
        "summary": "Lookup user by Slack UID",
        "tags": [
          "Users"
        ],
        "description": "Find a user ID by their Slack User ID. Requires an active Admin API Key supplied via the Authorization Bearer header",
        "security": [
          {
            "Bearer": []
          }
        ],
        "parameters": [
          {
            "name": "slack_uid",
            "in": "path",
            "description": "Slack User ID (e.g. U123456)",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "successful",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user_id": {
                      "type": "integer",
                      "example": 42
                    },
                    "slack_uid": {
                      "type": "string",
                      "example": "U0266FRGP"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "unauthorized — Returned when the Admin API Key is missing, revoked, or incorrect. (Auth is bypassed in the development environment.)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "User not found"
                    },
                    "slack_uid": {
                      "type": "string",
                      "example": "U000000"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "OAuth2": {
        "type": "oauth2",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "/oauth/authorize",
            "tokenUrl": "/oauth/token",
            "scopes": {
              "profile": "Read profile information",
              "read": "Read coding activity data",
              "admin": "Access administrative operations"
            }
          }
        }
      },
      "Bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "User or Admin API Key, depending on the endpoint, prefixed with \"Bearer\""
      },
      "ApiKeyAuth": {
        "type": "apiKey",
        "name": "api_key",
        "in": "query",
        "description": "User API Key from settings"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "example": "Unauthorized"
          }
        },
        "required": [
          "error"
        ]
      },
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "example": 1
          },
          "username": {
            "type": "string",
            "example": "orpheus"
          },
          "avatar_url": {
            "type": "string",
            "example": "https://hackatime.hackclub.com/images/athena.png"
          },
          "display_name": {
            "type": "string",
            "example": "Orpheus"
          },
          "is_admin": {
            "type": "boolean",
            "example": false
          }
        }
      },
      "Heartbeat": {
        "type": "object",
        "description": "A single unit of coding activity representing a specific moment in time.",
        "properties": {
          "id": {
            "type": "integer",
            "example": 1024
          },
          "entity": {
            "type": "string",
            "nullable": true,
            "example": "/Users/orpheus/hackatime/app/services/chaos_monkey_service.rb",
            "description": "File path or app name being accessed"
          },
          "type": {
            "type": "string",
            "nullable": true,
            "example": "file",
            "enum": [
              "file",
              "app"
            ]
          },
          "category": {
            "type": "string",
            "nullable": true,
            "example": "coding",
            "enum": [
              "advising",
              "ai coding",
              "animating",
              "browsing",
              "building",
              "code reviewing",
              "coding",
              "communicating",
              "configuring",
              "debugging",
              "designing",
              "indexing",
              "learning",
              "manual testing",
              "meeting",
              "notes",
              "planning",
              "researching",
              "running tests",
              "supporting",
              "translating",
              "writing docs",
              "writing tests"
            ]
          },
          "time": {
            "type": "number",
            "format": "float",
            "example": 1709251200.0,
            "description": "Unix timestamp of the activity"
          },
          "project": {
            "type": "string",
            "nullable": true,
            "example": "hackatime"
          },
          "branch": {
            "type": "string",
            "nullable": true,
            "example": "main"
          },
          "language": {
            "type": "string",
            "nullable": true,
            "example": "Ruby"
          },
          "is_write": {
            "type": "boolean",
            "nullable": true,
            "example": true
          },
          "editor": {
            "type": "string",
            "nullable": true,
            "example": "VS Code"
          },
          "operating_system": {
            "type": "string",
            "nullable": true,
            "example": "Mac"
          },
          "machine": {
            "type": "string",
            "nullable": true,
            "example": "Orpheus-MacBook-Pro"
          },
          "cursorpos": {
            "type": "integer",
            "nullable": true,
            "example": 123
          },
          "lineno": {
            "type": "integer",
            "nullable": true,
            "example": 42
          },
          "lines": {
            "type": "integer",
            "nullable": true,
            "example": 100
          },
          "line_additions": {
            "type": "integer",
            "nullable": true,
            "example": 5
          },
          "line_deletions": {
            "type": "integer",
            "nullable": true,
            "example": 2
          }
        }
      },
      "LeaderboardEntry": {
        "type": "object",
        "properties": {
          "rank": {
            "type": "integer",
            "example": 1
          },
          "user": {
            "type": "object",
            "properties": {
              "id": {
                "type": "integer",
                "example": 42
              },
              "username": {
                "type": "string",
                "example": "goat_heidi"
              },
              "avatar_url": {
                "type": "string",
                "example": "https://..."
              }
            }
          },
          "total_seconds": {
            "type": "number",
            "example": 14500.5,
            "description": "Total coding duration in seconds for the period"
          }
        }
      },
      "StatsSummary": {
        "type": "object",
        "properties": {
          "total_seconds": {
            "type": "number",
            "example": 3600.0
          },
          "daily_average": {
            "type": "number",
            "example": 1800.0
          },
          "languages": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "example": "Ruby"
                },
                "total_seconds": {
                  "type": "number",
                  "example": 2400.0
                },
                "percent": {
                  "type": "number",
                  "example": 66.6
                }
              }
            }
          },
          "projects": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "example": "hackatime"
                },
                "total_seconds": {
                  "type": "number",
                  "example": 3600.0
                },
                "percent": {
                  "type": "number",
                  "example": 100.0
                }
              }
            }
          },
          "editors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "example": "VS Code"
                },
                "total_seconds": {
                  "type": "number",
                  "example": 3600.0
                },
                "percent": {
                  "type": "number",
                  "example": 100.0
                }
              }
            }
          },
          "streak": {
            "type": "integer",
            "example": 7,
            "description": "Number of consecutive days the user has coded"
          }
        }
      },
      "WakatimeMirror": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "example": 7
          },
          "target_url": {
            "type": "string",
            "example": "https://api.wakatime.com/api/v1/users/current/heartbeats"
          },
          "last_sync_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "status": {
            "type": "string",
            "example": "active"
          }
        }
      },
      "ProjectRepoMapping": {
        "type": "object",
        "properties": {
          "project_name": {
            "type": "string",
            "example": "hackatime"
          },
          "repository": {
            "type": "object",
            "properties": {
              "url": {
                "type": "string",
                "example": "https://github.com/hackclub/hackatime"
              },
              "homepage": {
                "type": "string",
                "example": "https://hackatime.hackclub.com"
              }
            }
          },
          "is_archived": {
            "type": "boolean",
            "example": false
          }
        }
      },
      "Extension": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "vscode"
          },
          "name": {
            "type": "string",
            "example": "VS Code"
          },
          "download_url": {
            "type": "string",
            "example": "https://marketplace.visualstudio.com/items?itemName=WakaTime.vscode-wakatime"
          },
          "version": {
            "type": "string",
            "example": "24.0.0"
          }
        }
      },
      "Summary": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "string",
            "nullable": true,
            "example": "U123456"
          },
          "from": {
            "type": "string",
            "format": "date-time",
            "example": "2023-01-01T00:00:00Z"
          },
          "to": {
            "type": "string",
            "format": "date-time",
            "example": "2023-01-31T23:59:59Z"
          },
          "projects": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string",
                  "example": "hackatime"
                },
                "total": {
                  "type": "number",
                  "example": 3600.0
                }
              }
            }
          },
          "languages": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string",
                  "example": "Ruby"
                },
                "total": {
                  "type": "number",
                  "example": 1200.0
                }
              }
            }
          },
          "editors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string",
                  "example": "VS Code"
                },
                "total": {
                  "type": "number",
                  "example": 3600.0
                }
              }
            }
          },
          "operating_systems": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string",
                  "example": "Mac"
                },
                "total": {
                  "type": "number",
                  "example": 3600.0
                }
              }
            }
          },
          "machines": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string",
                  "example": "MacBook-Pro"
                },
                "total": {
                  "type": "number",
                  "example": 3600.0
                }
              }
            }
          }
        }
      }
    }
  },
  "servers": [
    {
      "url": "https://{defaultHost}",
      "description": "Production API",
      "variables": {
        "defaultHost": {
          "default": "hackatime.hackclub.com"
        }
      }
    },
    {
      "url": "http://{localHost}",
      "description": "Local Development API",
      "variables": {
        "localHost": {
          "default": "localhost:3000"
        }
      }
    }
  ]
}
