{
  "openapi": "3.1.0",
  "info": {
    "title": "andrewmayes.com public API",
    "version": "1.0.0",
    "description": "Small public JSON API behind andrewmayes.com \u2014 live theme-park wait times plus a few health checks. No authentication required; see /auth.md.",
    "contact": {
      "name": "Andrew Mayes",
      "url": "https://www.andrewmayes.com/#contact"
    }
  },
  "servers": [
    {
      "url": "https://www.andrewmayes.com"
    }
  ],
  "paths": {
    "/api/wait-times": {
      "get": {
        "summary": "Live ride wait times for a park",
        "description": "Proxied from queue-times.com with a 5-minute KV cache. Attribute queue-times.com when displaying. Each ride carries a trend vs ~30 minutes ago and a naive half-hour forecast.",
        "parameters": [
          {
            "name": "park",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "magic-kingdom",
                "epcot",
                "hollywood-studios",
                "animal-kingdom",
                "universal-studios-florida",
                "islands-of-adventure",
                "epic-universe",
                "seaworld-orlando",
                "busch-gardens-tampa",
                "disneyland",
                "california-adventure",
                "universal-studios-hollywood",
                "disneyland-paris",
                "disney-adventure-world",
                "dollywood",
                "hersheypark",
                "volcano-bay"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Wait times",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "updatedAt": {
                      "type": "integer",
                      "description": "Unix ms of the upstream fetch"
                    },
                    "source": {
                      "type": "string",
                      "const": "queue-times.com"
                    },
                    "rides": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string"
                          },
                          "wait": {
                            "type": "integer",
                            "description": "minutes"
                          },
                          "open": {
                            "type": "boolean"
                          },
                          "trend": {
                            "type": "string",
                            "enum": [
                              "up",
                              "down",
                              "flat"
                            ]
                          },
                          "forecast": {
                            "type": [
                              "integer",
                              "null"
                            ],
                            "description": "projected wait ~30 minutes out, 5-minute steps"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Unknown park slug"
          }
        }
      }
    },
    "/api/publish-status": {
      "get": {
        "summary": "Daily publish cron health",
        "responses": {
          "200": {
            "description": "Last run + hook status"
          }
        }
      }
    },
    "/api/linkedin-status": {
      "get": {
        "summary": "LinkedIn auto-share health",
        "responses": {
          "200": {
            "description": "Token + last-share status"
          }
        }
      }
    },
    "/api/instagram": {
      "get": {
        "summary": "Cached Instagram feed",
        "responses": {
          "200": {
            "description": "Recent media (may be empty if unconfigured)"
          }
        }
      }
    },
    "/api/location": {
      "get": {
        "summary": "Travel-mode live pin",
        "responses": {
          "200": {
            "description": "Current shared location or stale marker"
          }
        }
      }
    },
    "/api/contact": {
      "post": {
        "summary": "Send a contact message",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "email",
                  "message"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "message": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sent"
          },
          "503": {
            "description": "Email unconfigured \u2014 use the mailto fallback"
          }
        }
      }
    }
  }
}
