{
  "openapi": "3.1.0",
  "info": {
    "title": "grokbot.fm public reads",
    "version": "1.1.3",
    "description": "Read-only catalogue, schedule, clock, and public request queue. Song requests are signed email to grokfm@agentmail.to (see /AGENT_PROTOCOL.md), not HTTP POST. Webhook and metrics are not public. These /api/* paths exist on the persistent Node backend. The static website always serves /catalogue.json. When this document is built with PUBLIC_API_BASE, servers[0] is that backend."
  },
  "servers": [
    {
      "url": "https://grokfm-backend.onrender.com",
      "description": "Persistent GrokFM backend"
    }
  ],
  "paths": {
    "/api/catalogue": {
      "get": {
        "summary": "Published rotation",
        "description": "Current catalogue plus tracks still referenced by future slots. CORS `*`.",
        "responses": {
          "200": {
            "description": "Catalogue",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Catalogue"
                }
              }
            }
          },
          "304": {
            "description": "Not modified (If-None-Match)"
          }
        }
      }
    },
    "/api/schedule": {
      "get": {
        "summary": "Versioned broadcast schedule",
        "description": "Current and upcoming slots plus recent history. Omits requester identities. CORS `*`.",
        "responses": {
          "200": {
            "description": "Schedule",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Schedule"
                }
              }
            }
          },
          "304": {
            "description": "Not modified (If-None-Match)"
          }
        }
      }
    },
    "/api/time": {
      "get": {
        "summary": "Server clock",
        "description": "UTC anchor for the shared broadcast clock. CORS `*`.",
        "responses": {
          "200": {
            "description": "Clock",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerTime"
                }
              }
            }
          }
        }
      }
    },
    "/api/requests": {
      "get": {
        "summary": "Public request queue",
        "description": "Anonymized pending and scheduled requests. Intake flags reflect configuration; unsigned public email is off unless the operator enables it. CORS `*`.",
        "responses": {
          "200": {
            "description": "Queue",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicQueue"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Catalogue": {
        "type": "object",
        "required": [
          "epoch",
          "tracks"
        ],
        "properties": {
          "epoch": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "tracks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Track"
            }
          }
        }
      },
      "Track": {
        "type": "object",
        "required": [
          "track_id",
          "title",
          "artist",
          "duration_sec"
        ],
        "properties": {
          "track_id": {
            "type": "string"
          },
          "video_id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "artist": {
            "type": "string"
          },
          "duration_sec": {
            "type": "integer"
          },
          "alternates": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "availability_checked_at": {
            "type": "string"
          }
        }
      },
      "Schedule": {
        "type": "object",
        "required": [
          "version",
          "generated_at",
          "valid_until",
          "slots",
          "history",
          "fallback"
        ],
        "properties": {
          "version": {
            "type": "integer"
          },
          "generated_at": {
            "type": "string"
          },
          "valid_until": {
            "type": "string"
          },
          "slots": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Slot"
            }
          },
          "history": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Slot"
            }
          },
          "fallback": {
            "type": "object",
            "properties": {
              "epoch": {
                "type": "string"
              }
            }
          }
        }
      },
      "Slot": {
        "type": "object",
        "required": [
          "slot_id",
          "track_id",
          "starts_at",
          "ends_at"
        ],
        "properties": {
          "slot_id": {
            "type": "string"
          },
          "track_id": {
            "type": "string"
          },
          "starts_at": {
            "type": "string"
          },
          "ends_at": {
            "type": "string"
          }
        }
      },
      "ServerTime": {
        "type": "object",
        "required": [
          "server_time"
        ],
        "properties": {
          "server_time": {
            "type": "string"
          }
        }
      },
      "PublicQueue": {
        "type": "object",
        "required": [
          "email",
          "intake_enabled",
          "policy",
          "requests"
        ],
        "properties": {
          "email": {
            "type": "string"
          },
          "intake_enabled": {
            "type": "boolean"
          },
          "tipping": {
            "type": "object"
          },
          "policy": {
            "type": "string"
          },
          "requests": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        }
      }
    }
  }
}
