{
  "openapi": "3.0.4",
  "info": {
    "title": "Goffy user data API",
    "description": "Read-only access to your own Goffy data: profile, tours, rounds with your own scorecard lines, statistics, and a full export. Authenticate with your app session token or a personal access token.",
    "version": "1.2.0"
  },
  "servers": [
    {
      "url": "https://backend.goffy.app",
      "description": "Production"
    }
  ],
  "paths": {
    "/api/me": {
      "get": {
        "tags": [
          "Me"
        ],
        "summary": "Your profile",
        "description": "Account fields and the handicap held on your player record.",
        "operationId": "GetMe",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeProfile"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/api/me/tours": {
      "get": {
        "tags": [
          "Me"
        ],
        "summary": "Your tours",
        "description": "Every tour you are a member of, hidden and finished ones included, each with the players in it.",
        "operationId": "ListMyTours",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/MeTour"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/api/me/tours/{tourId}": {
      "get": {
        "tags": [
          "Me"
        ],
        "summary": "One of your tours",
        "description": "The tour, the players in it, and the merit standings. A tour you are not in is a 404.",
        "operationId": "GetMyTour",
        "parameters": [
          {
            "name": "tourId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeTourDetail"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/api/me/rounds": {
      "get": {
        "tags": [
          "Me"
        ],
        "summary": "Your rounds",
        "description": "Every round you have played, newest first, with your totals in each.",
        "operationId": "ListMyRounds",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/MeRoundSummary"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/api/me/rounds/{roundId}": {
      "get": {
        "tags": [
          "Me"
        ],
        "summary": "One of your rounds",
        "description": "The round as the app shows it to you: who played, every player\u0027s scorecard lines, hole events and scores, the game scores and the leaderboard. A round you did not play is a 404.",
        "operationId": "GetMyRound",
        "parameters": [
          {
            "name": "roundId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeRoundDetail"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/api/me/statistics": {
      "get": {
        "tags": [
          "Me"
        ],
        "summary": "Your statistics",
        "description": "Rounds, tours, games, trophies and scoring trends for one calendar year, or all time when no year is given.",
        "operationId": "GetMyStatistics",
        "parameters": [
          {
            "name": "year",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeStatistics"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ]
      }
    },
    "/api/me/export": {
      "get": {
        "tags": [
          "Me"
        ],
        "summary": "Download everything",
        "description": "Your profile, tours, every round with your own scorecard lines, and all-time statistics as one JSON file. Limited to two downloads per minute.",
        "operationId": "ExportMyData",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeExport"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          },
          "429": {
            "description": "Too Many Requests"
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/problem\u002Bjson": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "MeExport": {
        "type": "object",
        "properties": {
          "exportedAt": {
            "type": "string",
            "description": "When the export was produced.",
            "format": "date-time"
          },
          "profile": {
            "$ref": "#/components/schemas/MeProfile"
          },
          "tours": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MeTour"
            },
            "description": "Every tour the user is a member of, finished ones included."
          },
          "rounds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MeRoundDetail"
            },
            "description": "Every round the user has played, with their own scorecard lines."
          },
          "statistics": {
            "$ref": "#/components/schemas/MeStatistics"
          }
        },
        "additionalProperties": false,
        "description": "Everything the user data API can return, in one document."
      },
      "MeGameScore": {
        "type": "object",
        "properties": {
          "playerId": {
            "type": "string",
            "description": "The player these points belong to.",
            "format": "uuid"
          },
          "gameId": {
            "type": "string",
            "description": "Game definition id.",
            "format": "uuid"
          },
          "scorePoints": {
            "type": "integer",
            "description": "Points the game\u0027s rules awarded this player over the round.",
            "format": "int32"
          },
          "matchLead": {
            "type": "integer",
            "description": "Holes up in a match game; null for games that are not played as a match.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One player\u0027s score points in one game of a round \u2014 the rule-defined points the game awards,\nnot the placement points on the leaderboard (those are BackendForFrontend.Models.MeApi.MeGameStanding)."
      },
      "MeGameStanding": {
        "type": "object",
        "properties": {
          "gameId": {
            "type": "string",
            "description": "Game definition id.",
            "format": "uuid"
          },
          "gamePoints": {
            "type": "number",
            "description": "Game points earned for the placing in this game.",
            "format": "double"
          },
          "position": {
            "type": "integer",
            "description": "Finishing position in this game, 1 for the winner.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Where a player finished in one game of a round, and the game points that placing is worth.\nThese are the meta-points behind the leaderboard, not the game\u0027s own scoring."
      },
      "MeHoleEntry": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Entry id.",
            "format": "uuid"
          },
          "roundId": {
            "type": "string",
            "description": "Round id.",
            "format": "uuid"
          },
          "hole": {
            "type": "integer",
            "description": "Hole number, 1-18.",
            "format": "int32"
          },
          "holeIndex": {
            "type": "integer",
            "description": "Stroke index of the hole, 1-18.",
            "format": "int32"
          },
          "par": {
            "type": "integer",
            "description": "Par of the hole.",
            "format": "int32"
          },
          "lengthMeters": {
            "type": "integer",
            "description": "Length of the hole in metres, or null when nobody has measured it for us \u2014 which is the\nanswer on most holes. Only Goffy\u0027s own measurement is reported here; a length off an\nimported scorecard is never substituted, so a blank means we do not know rather than that\nthe hole has no length.",
            "format": "int32",
            "nullable": true
          },
          "playerId": {
            "type": "string",
            "description": "The caller\u0027s player id.",
            "format": "uuid"
          },
          "grossStroke": {
            "type": "integer",
            "description": "Gross strokes; null when the hole was picked up.",
            "format": "int32",
            "nullable": true
          },
          "pickup": {
            "type": "boolean",
            "description": "True when the ball was picked up without holing out."
          },
          "createdAt": {
            "type": "string",
            "description": "When the score was entered.",
            "format": "date-time"
          },
          "playingHandicap": {
            "type": "integer",
            "description": "Playing handicap stamped on the round for this player.",
            "format": "int32",
            "nullable": true
          },
          "handicapStroke": {
            "type": "integer",
            "description": "Handicap strokes received on this hole.",
            "format": "int32",
            "nullable": true
          },
          "netStroke": {
            "type": "integer",
            "description": "Net strokes after handicap strokes.",
            "format": "int32",
            "nullable": true
          },
          "greenInRegulation": {
            "type": "boolean",
            "description": "Green in regulation, when the hole\u0027s putts and score allow it to be worked out.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "The user\u0027s scorecard line for one hole of a round."
      },
      "MeHoleEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Event id.",
            "format": "uuid"
          },
          "roundId": {
            "type": "string",
            "description": "Round id.",
            "format": "uuid"
          },
          "playerId": {
            "type": "string",
            "description": "The caller\u0027s player id.",
            "format": "uuid"
          },
          "holeNumber": {
            "type": "integer",
            "description": "Hole number, 1-18.",
            "format": "int32"
          },
          "eventType": {
            "type": "string",
            "description": "Event type, e.g. \u0060water\u0060, \u0060bunker\u0060, \u0060penalty\u0060, \u0060putts\u0060, \u0060fairway\u0060."
          },
          "eventValue": {
            "type": "string",
            "description": "Event value for types that carry one, e.g. the number of putts.",
            "nullable": true
          },
          "occurredAt": {
            "type": "string",
            "description": "When the event was recorded.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Something the user recorded on a hole besides the score: water, bunker, penalty, putts,\nfairway hit, and the like."
      },
      "MeHoleScore": {
        "type": "object",
        "properties": {
          "playerId": {
            "type": "string",
            "description": "The caller\u0027s player id.",
            "format": "uuid"
          },
          "holeNumber": {
            "type": "integer",
            "description": "Hole number, 1-18.",
            "format": "int32"
          },
          "grossStrokes": {
            "type": "integer",
            "description": "Gross strokes; null when the hole was picked up.",
            "format": "int32",
            "nullable": true
          },
          "pickup": {
            "type": "boolean",
            "description": "True when the ball was picked up without holing out."
          }
        },
        "additionalProperties": false,
        "description": "The user\u0027s stored gross score for one hole of a round."
      },
      "MeHomeClub": {
        "type": "object",
        "properties": {
          "clubId": {
            "type": "string",
            "description": "Club id in the course catalogue.",
            "format": "uuid"
          },
          "clubName": {
            "type": "string",
            "description": "Club name at the time it was added."
          },
          "clubCity": {
            "type": "string",
            "description": "Club city, when known.",
            "nullable": true
          },
          "isPrimary": {
            "type": "boolean",
            "description": "True for the club the user plays most; at most one per user."
          }
        },
        "additionalProperties": false,
        "description": "A golf club the user has marked as one of their home clubs."
      },
      "MePlayer": {
        "type": "object",
        "properties": {
          "playerId": {
            "type": "string",
            "description": "Player id. Use it to pick this player out of a round\u0027s own rows.",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "description": "Display name, as the app shows it. Empty when the player has no name yet."
          },
          "isYou": {
            "type": "boolean",
            "description": "True when this is the caller\u0027s own player."
          }
        },
        "additionalProperties": false,
        "description": "A player in a tour or round the caller took part in, by id and display name \u2014 the same\npeople, under the same names, that the app shows the caller on that tour or round.\nNothing else about them is carried: no account fields, and no scores."
      },
      "MeProfile": {
        "type": "object",
        "properties": {
          "userId": {
            "type": "string",
            "description": "The account id; the same value as the token subject.",
            "format": "uuid"
          },
          "playerId": {
            "type": "string",
            "description": "The player id every round, score and statistic is keyed by. Null until a player record exists.",
            "format": "uuid",
            "nullable": true
          },
          "username": {
            "type": "string",
            "description": "Sign-in name."
          },
          "displayName": {
            "type": "string",
            "description": "Name shown to other players."
          },
          "fullName": {
            "type": "string",
            "description": "Full name as entered on the profile."
          },
          "email": {
            "type": "string",
            "description": "Contact email, when one is set.",
            "nullable": true
          },
          "golfId": {
            "type": "string",
            "description": "National golf id, normalised (no separators), when one is set.",
            "nullable": true
          },
          "distanceUnit": {
            "type": "string",
            "description": "Preferred distance unit: \u0060metric\u0060 or \u0060imperial\u0060. Stored values are always metres."
          },
          "createdAt": {
            "type": "string",
            "description": "When the account was created.",
            "format": "date-time"
          },
          "homeClubs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MeHomeClub"
            },
            "description": "Home clubs, primary first when one is marked."
          },
          "handicapIndex": {
            "type": "number",
            "description": "Current handicap index, when one is recorded.",
            "format": "double",
            "nullable": true
          },
          "handicapDate": {
            "type": "string",
            "description": "The date the handicap index was last set.",
            "format": "date",
            "nullable": true
          },
          "gender": {
            "type": "string",
            "description": "Gender as chosen on the player record, when set.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "The calling user\u0027s own profile: account fields from the user service merged with the\nhandicap held on their player record."
      },
      "MeRound": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Round id.",
            "format": "uuid"
          },
          "tourId": {
            "type": "string",
            "description": "The tour the round belongs to, when it is part of one.",
            "format": "uuid",
            "nullable": true
          },
          "courseId": {
            "type": "string",
            "description": "Course id in the course catalogue."
          },
          "courseName": {
            "type": "string",
            "description": "Course name."
          },
          "courseAddress": {
            "type": "string",
            "description": "Course address."
          },
          "name": {
            "type": "string",
            "description": "Round name, when one was given.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Round description, when one was given.",
            "nullable": true
          },
          "holesCount": {
            "type": "integer",
            "description": "Holes in the round, 9 or 18.",
            "format": "int32"
          },
          "status": {
            "type": "string",
            "description": "Round status: \u0060open\u0060, \u0060playing\u0060, \u0060finished\u0060 or \u0060cancelled\u0060."
          },
          "createdAt": {
            "type": "string",
            "description": "When the round was created.",
            "format": "date-time"
          },
          "gameDefinitionIds": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Game definitions played in the round."
          },
          "startHoleNumber": {
            "type": "integer",
            "description": "The hole the round started on; 10 for a back-nine start.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "A round the user played. Membership is checked before this is returned, so a round that is\nnot the caller\u0027s is a 404; who else played is on the round detail\u0027s \u0060players\u0060."
      },
      "MeRoundDetail": {
        "type": "object",
        "properties": {
          "round": {
            "$ref": "#/components/schemas/MeRound"
          },
          "players": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MePlayer"
            },
            "description": "Everyone who played the round, the caller included, by id and display name."
          },
          "holeEntries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MeHoleEntry"
            },
            "description": "Scorecard lines for every player, one per scored hole. Keyed by \u0060playerId\u0060."
          },
          "holeEvents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MeHoleEvent"
            },
            "description": "Hole events for every player."
          },
          "scores": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MeHoleScore"
            },
            "description": "Stored gross scores for every player."
          },
          "gameScores": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MeGameScore"
            },
            "description": "Each game\u0027s score points, per player."
          },
          "leaderboard": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MeRoundStanding"
            },
            "description": "The round leaderboard: game points per player, with the per-game breakdown."
          }
        },
        "additionalProperties": false,
        "description": "A round as the app shows it to someone who played it: who was there, every player\u0027s\nscorecard, and the leaderboard. Membership is checked before any of it is returned."
      },
      "MeRoundStanding": {
        "type": "object",
        "properties": {
          "playerId": {
            "type": "string",
            "description": "The player this line belongs to.",
            "format": "uuid"
          },
          "totalGamePoints": {
            "type": "number",
            "description": "Game points over every game in the round.",
            "format": "double"
          },
          "games": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MeGameStanding"
            },
            "description": "The per-game placings that add up to the total."
          }
        },
        "additionalProperties": false,
        "description": "One player\u0027s line on a round\u0027s leaderboard: the game points they took across the round\u0027s\ngames, and the per-game breakdown behind that total. Names are on the round\u0027s\n\u0060players\u0060 list, keyed by the same player id."
      },
      "MeRoundSummary": {
        "type": "object",
        "properties": {
          "roundId": {
            "type": "string",
            "description": "Round id; use it with the round detail route.",
            "format": "uuid"
          },
          "tourId": {
            "type": "string",
            "description": "The tour the round belongs to.",
            "format": "uuid"
          },
          "tourName": {
            "type": "string",
            "description": "Tour name."
          },
          "courseName": {
            "type": "string",
            "description": "Course name."
          },
          "status": {
            "type": "string",
            "description": "Round status: \u0060open\u0060, \u0060playing\u0060, \u0060finished\u0060 or \u0060cancelled\u0060."
          },
          "playDate": {
            "type": "string",
            "description": "Calendar date of play, when the round has one.",
            "format": "date",
            "nullable": true
          },
          "playedAtUtc": {
            "type": "string",
            "description": "When the round was played, UTC.",
            "format": "date-time"
          },
          "holesScored": {
            "type": "integer",
            "description": "Holes with a score.",
            "format": "int32"
          },
          "grossStrokes": {
            "type": "integer",
            "description": "Total gross strokes over the scored holes.",
            "format": "int32"
          },
          "toPar": {
            "type": "integer",
            "description": "Gross strokes relative to par over the scored holes.",
            "format": "int32"
          },
          "meritPoints": {
            "type": "number",
            "description": "Merit points earned in this round across its games.",
            "format": "double"
          },
          "position": {
            "type": "integer",
            "description": "Finishing position in the field; null when the round has no leaderboard yet.",
            "format": "int32",
            "nullable": true
          },
          "fieldSize": {
            "type": "integer",
            "description": "Number of players in the round.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "One round the user has played, as the \u0022my rounds\u0022 list shows it. Newest first."
      },
      "MeStatistics": {
        "type": "object",
        "properties": {
          "playerId": {
            "type": "string",
            "description": "The caller\u0027s player id.",
            "format": "uuid"
          },
          "year": {
            "type": "integer",
            "description": "Calendar year the numbers cover, or null for all time.",
            "format": "int32",
            "nullable": true
          },
          "availableYears": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32"
            },
            "description": "Years the user has rounds in, newest first."
          },
          "overview": {
            "$ref": "#/components/schemas/MeStatisticsOverview"
          },
          "activeTours": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MeStatisticsTour"
            },
            "description": "Tours the user is in that have not finished."
          },
          "trophies": {
            "$ref": "#/components/schemas/MeStatisticsTrophies"
          },
          "games": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MeStatisticsGame"
            },
            "description": "Game types played in the period, with wins."
          },
          "recentRounds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MeRoundSummary"
            },
            "description": "The most recent rounds in the period."
          },
          "scoring": {
            "$ref": "#/components/schemas/MeStatisticsScoring"
          }
        },
        "additionalProperties": false,
        "description": "Everything the personal statistics screen shows, for one period."
      },
      "MeStatisticsBestRound": {
        "type": "object",
        "properties": {
          "roundId": {
            "type": "string",
            "description": "Round id.",
            "format": "uuid"
          },
          "courseName": {
            "type": "string",
            "description": "Course name."
          },
          "playDate": {
            "type": "string",
            "description": "Calendar date of play, when the round has one.",
            "format": "date",
            "nullable": true
          },
          "grossStrokes": {
            "type": "integer",
            "description": "Gross strokes over the scored holes.",
            "format": "int32"
          },
          "toPar": {
            "type": "integer",
            "description": "Gross strokes relative to par.",
            "format": "int32"
          },
          "holesScored": {
            "type": "integer",
            "description": "Holes with a score.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "The best round of the period by score to par."
      },
      "MeStatisticsDistribution": {
        "type": "object",
        "properties": {
          "eagles": {
            "type": "integer",
            "description": "Holes scored two under par or better.",
            "format": "int32"
          },
          "birdies": {
            "type": "integer",
            "description": "Holes scored one under par.",
            "format": "int32"
          },
          "pars": {
            "type": "integer",
            "description": "Holes scored at par.",
            "format": "int32"
          },
          "bogeys": {
            "type": "integer",
            "description": "Holes scored one over par.",
            "format": "int32"
          },
          "doublePlus": {
            "type": "integer",
            "description": "Holes scored two over par or worse.",
            "format": "int32"
          },
          "pickups": {
            "type": "integer",
            "description": "Holes picked up.",
            "format": "int32"
          },
          "totalScored": {
            "type": "integer",
            "description": "Holes with a score.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Scored holes bucketed relative to par. Picked-up holes have no score and are counted separately."
      },
      "MeStatisticsFormPoint": {
        "type": "object",
        "properties": {
          "roundId": {
            "type": "string",
            "description": "Round id.",
            "format": "uuid"
          },
          "courseName": {
            "type": "string",
            "description": "Course name."
          },
          "playDate": {
            "type": "string",
            "description": "Calendar date of play, when the round has one.",
            "format": "date",
            "nullable": true
          },
          "toPar": {
            "type": "integer",
            "description": "Gross strokes relative to par.",
            "format": "int32"
          },
          "holesScored": {
            "type": "integer",
            "description": "Holes with a score.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Score to par for one round; lower is better."
      },
      "MeStatisticsGame": {
        "type": "object",
        "properties": {
          "gameId": {
            "type": "string",
            "description": "Game definition id.",
            "format": "uuid"
          },
          "roundsPlayed": {
            "type": "integer",
            "description": "Rounds in which the game was played.",
            "format": "int32"
          },
          "wins": {
            "type": "integer",
            "description": "Rounds in which the user won the game.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "One game type the user has played, with how often they won it."
      },
      "MeStatisticsHandicapPoint": {
        "type": "object",
        "properties": {
          "roundId": {
            "type": "string",
            "description": "Round id.",
            "format": "uuid"
          },
          "playDate": {
            "type": "string",
            "description": "Calendar date of play, when the round has one.",
            "format": "date",
            "nullable": true
          },
          "playedAtUtc": {
            "type": "string",
            "description": "When the round was played, UTC.",
            "format": "date-time"
          },
          "playingHandicap": {
            "type": "integer",
            "description": "Playing handicap for that round.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "The playing handicap stamped on one round. Not the handicap index: that is not versioned per\nround, so the round stamps are the only trend the data supports."
      },
      "MeStatisticsNemesisHole": {
        "type": "object",
        "properties": {
          "courseId": {
            "type": "string",
            "description": "Course id in the course catalogue."
          },
          "courseName": {
            "type": "string",
            "description": "Course name."
          },
          "holeNumber": {
            "type": "integer",
            "description": "Hole number, 1-18.",
            "format": "int32"
          },
          "averageToPar": {
            "type": "number",
            "description": "Average strokes over par on the hole.",
            "format": "double"
          },
          "plays": {
            "type": "integer",
            "description": "Times the hole was played.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "The hole the user has scored worst on across visits."
      },
      "MeStatisticsOverview": {
        "type": "object",
        "properties": {
          "roundsPlayed": {
            "type": "integer",
            "description": "Rounds played.",
            "format": "int32"
          },
          "holesScored": {
            "type": "integer",
            "description": "Holes with a score.",
            "format": "int32"
          },
          "tours": {
            "type": "integer",
            "description": "Tours the user was a member of.",
            "format": "int32"
          },
          "activeTours": {
            "type": "integer",
            "description": "Tours still in play.",
            "format": "int32"
          },
          "gamesPlayed": {
            "type": "integer",
            "description": "Games played across those rounds.",
            "format": "int32"
          },
          "meritPoints": {
            "type": "number",
            "description": "Merit points earned.",
            "format": "double"
          },
          "previousYearRoundsPlayed": {
            "type": "integer",
            "description": "Rounds played in the previous calendar year; null when the period is all time.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Headline counts for the statistics period."
      },
      "MeStatisticsParAverage": {
        "type": "object",
        "properties": {
          "par": {
            "type": "integer",
            "description": "Hole par: 3, 4 or 5.",
            "format": "int32"
          },
          "averageToPar": {
            "type": "number",
            "description": "Average strokes over par on those holes.",
            "format": "double"
          },
          "holes": {
            "type": "integer",
            "description": "Holes of that par with a score.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Average score to par on holes of one par value."
      },
      "MeStatisticsRecords": {
        "type": "object",
        "properties": {
          "mostBirdiesInRound": {
            "type": "integer",
            "description": "Most birdies in a single round.",
            "format": "int32"
          },
          "longestParOrBetterStreak": {
            "type": "integer",
            "description": "Longest run of consecutive holes at par or better.",
            "format": "int32"
          },
          "bestComeback": {
            "type": "integer",
            "description": "Best back-nine improvement over the front nine in a single 18-hole round.",
            "format": "int32",
            "nullable": true
          },
          "holeInOnes": {
            "type": "integer",
            "description": "Holes in one.",
            "format": "int32"
          },
          "nemesisHole": {
            "$ref": "#/components/schemas/MeStatisticsNemesisHole"
          }
        },
        "additionalProperties": false,
        "description": "Personal records for the statistics period."
      },
      "MeStatisticsScoring": {
        "type": "object",
        "properties": {
          "averageToPar18": {
            "type": "number",
            "description": "Average strokes over par scaled to 18 holes, so 9-hole rounds do not skew it.",
            "format": "double",
            "nullable": true
          },
          "previousYearAverageToPar18": {
            "type": "number",
            "description": "The same average for the previous calendar year; null when the period is all time.",
            "format": "double",
            "nullable": true
          },
          "bestRound": {
            "$ref": "#/components/schemas/MeStatisticsBestRound"
          },
          "handicapTrend": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MeStatisticsHandicapPoint"
            },
            "description": "Playing handicap stamped on each round, oldest first."
          },
          "form": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MeStatisticsFormPoint"
            },
            "description": "Score to par per round, oldest first."
          },
          "distribution": {
            "$ref": "#/components/schemas/MeStatisticsDistribution"
          },
          "byPar": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MeStatisticsParAverage"
            },
            "description": "Average score to par by hole par."
          },
          "frontNineToPar": {
            "type": "number",
            "description": "Average score to par on the front nine.",
            "format": "double",
            "nullable": true
          },
          "backNineToPar": {
            "type": "number",
            "description": "Average score to par on the back nine.",
            "format": "double",
            "nullable": true
          },
          "records": {
            "$ref": "#/components/schemas/MeStatisticsRecords"
          },
          "shotDetail": {
            "$ref": "#/components/schemas/MeStatisticsShotDetail"
          }
        },
        "additionalProperties": false,
        "description": "Scoring averages, trends and records for the statistics period."
      },
      "MeStatisticsShotDetail": {
        "type": "object",
        "properties": {
          "holesWithFairway": {
            "type": "integer",
            "description": "Holes where a fairway was recorded. Par 3s never count.",
            "format": "int32"
          },
          "fairwaysHit": {
            "type": "integer",
            "description": "Fairways hit.",
            "format": "int32"
          },
          "fairwayHitPercent": {
            "type": "number",
            "description": "Fairways hit as a percentage of holes with a fairway recorded.",
            "format": "double",
            "nullable": true
          },
          "holesWithPutts": {
            "type": "integer",
            "description": "Holes where putts were recorded.",
            "format": "int32"
          },
          "totalPutts": {
            "type": "integer",
            "description": "Total putts over those holes.",
            "format": "int32"
          },
          "puttsPerHole": {
            "type": "number",
            "description": "Putts per hole with putts recorded.",
            "format": "double",
            "nullable": true
          },
          "puttsPer18": {
            "type": "number",
            "description": "Putts scaled to 18 holes.",
            "format": "double",
            "nullable": true
          },
          "holesWithGreenInRegulation": {
            "type": "integer",
            "description": "Holes where green in regulation could be worked out.",
            "format": "int32"
          },
          "greensInRegulation": {
            "type": "integer",
            "description": "Greens hit in regulation.",
            "format": "int32"
          },
          "greenInRegulationPercent": {
            "type": "number",
            "description": "Greens in regulation as a percentage.",
            "format": "double",
            "nullable": true
          },
          "puttsPerGreenInRegulation": {
            "type": "number",
            "description": "Putts on greens hit in regulation.",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Fairways, putts and greens in regulation. Each metric carries its own hole count because\nshot detail is opt-in and entered by hand, so a percentage over three holes is noise."
      },
      "MeStatisticsTour": {
        "type": "object",
        "properties": {
          "tourId": {
            "type": "string",
            "description": "Tour id.",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "description": "Tour name."
          },
          "position": {
            "type": "integer",
            "description": "The user\u0027s current position on the tour leaderboard.",
            "format": "int32"
          },
          "playerCount": {
            "type": "integer",
            "description": "Players in the tour.",
            "format": "int32"
          },
          "meritPoints": {
            "type": "number",
            "description": "The user\u0027s merit points on the tour.",
            "format": "double"
          },
          "pointsBehindLeader": {
            "type": "number",
            "description": "Merits between the user and the leader; 0 when the user leads.",
            "format": "double"
          }
        },
        "additionalProperties": false,
        "description": "A tour the user is in that has not finished yet, with their standing in it."
      },
      "MeStatisticsTrophies": {
        "type": "object",
        "properties": {
          "tourWins": {
            "type": "integer",
            "description": "Tours won.",
            "format": "int32"
          },
          "tourRunnerUps": {
            "type": "integer",
            "description": "Tours finished second.",
            "format": "int32"
          },
          "tourPodiums": {
            "type": "integer",
            "description": "Tours finished in the top three.",
            "format": "int32"
          },
          "roundWins": {
            "type": "integer",
            "description": "Rounds won.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "All-time honours. Never filtered by period."
      },
      "MeTour": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Tour id.",
            "format": "uuid"
          },
          "tourName": {
            "type": "string",
            "description": "Tour name, when one was given.",
            "nullable": true
          },
          "status": {
            "type": "string",
            "description": "Tour status: \u0060active\u0060, \u0060finished\u0060 or \u0060archived\u0060."
          },
          "isHidden": {
            "type": "boolean",
            "description": "True when the user hid the tour from their own tour list."
          },
          "unfinishedRoundCount": {
            "type": "integer",
            "description": "Rounds in the tour that have not finished.",
            "format": "int32"
          },
          "createdAt": {
            "type": "string",
            "description": "When the tour was created.",
            "format": "date-time"
          },
          "playerCount": {
            "type": "integer",
            "description": "How many players are in the tour, the caller included.",
            "format": "int32"
          },
          "players": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MePlayer"
            },
            "description": "The players in the tour, the caller included, by id and display name."
          }
        },
        "additionalProperties": false,
        "description": "A tour the user is a member of, with the players in it \u2014 the same names the app shows the\ncaller on that tour. Their scores are not here; a player\u0027s own rows stay theirs."
      },
      "MeTourDetail": {
        "type": "object",
        "properties": {
          "tour": {
            "$ref": "#/components/schemas/MeTour"
          },
          "leaderboard": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MeTourStanding"
            },
            "description": "The merit standings, highest first. Empty until a round has been scored."
          }
        },
        "additionalProperties": false,
        "description": "One of the caller\u0027s tours with the players in it and the merit standings."
      },
      "MeTourStanding": {
        "type": "object",
        "properties": {
          "playerId": {
            "type": "string",
            "description": "The player this line belongs to.",
            "format": "uuid"
          },
          "meritPoints": {
            "type": "number",
            "description": "Merit points over every round of the tour so far.",
            "format": "double"
          }
        },
        "additionalProperties": false,
        "description": "One player\u0027s line on a tour\u0027s leaderboard: the merits they have taken across the tour\u0027s\nrounds. Names are on the tour\u0027s \u0060players\u0060 list, keyed by the same player id."
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          },
          "instance": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": {}
      }
    },
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "description": "Your Goffy session access token (valid 24 hours) or a personal access token minted under Profile \u2192 API access.",
        "scheme": "bearer"
      }
    }
  },
  "tags": [
    {
      "name": "Me"
    }
  ]
}
