{
  "openapi": "3.1.0",
  "info": {
    "title": "Cycling Coach AI public API",
    "version": "2.0.0",
    "summary": "Read-only endpoints behind the Cycling Coach AI website.",
    "description": "Public, unauthenticated, read-only endpoints behind the Cycling Coach AI website.\nIt exposes no user accounts, workouts or activity data.\n\n## Where product information lives\n\nPricing, features, supported integrations, training use cases, supported languages, company details and\ncomparisons with competitors are published as text, not through this API:\n\n- `https://cyclingcoachai.com/llms.txt` and `https://cyclingcoachai.com/llms-full.txt`\n- every page of the site in markdown: send `Accept: text/markdown`\n\n## Errors\n\nEvery endpoint returns the same JSON envelope: `{ \"error\": { \"code\", \"message\", \"hint\", \"docs_url\" } }`.\nIt never returns HTML.",
    "contact": {
      "name": "Cycling Coach AI support",
      "email": "support@cyclingcoachai.com",
      "url": "https://cyclingcoachai.com/docs/"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://cyclingcoachai.com/tos/"
    },
    "termsOfService": "https://cyclingcoachai.com/tos/"
  },
  "servers": [
    {
      "url": "https://cyclingcoachai.com",
      "description": "Production"
    }
  ],
  "security": [],
  "externalDocs": {
    "description": "Agent integration guide",
    "url": "https://cyclingcoachai.com/agents/"
  },
  "tags": [
    {
      "name": "Discovery",
      "description": "Entry points that describe the rest of the API."
    },
    {
      "name": "Site",
      "description": "Endpoints backing the public website."
    }
  ],
  "paths": {
    "/api": {
      "get": {
        "operationId": "getApiIndex",
        "summary": "API index",
        "description": "Machine-readable index of every public endpoint and the error format. Start here if you are discovering the API without reading this document.",
        "tags": [
          "Discovery"
        ],
        "responses": {
          "200": {
            "description": "The API index.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "name",
                    "documentation",
                    "openapi",
                    "endpoints"
                  ],
                  "properties": {
                    "name": {
                      "type": "string",
                      "description": "API name."
                    },
                    "description": {
                      "type": "string",
                      "description": "What this API is for."
                    },
                    "documentation": {
                      "type": "string",
                      "format": "uri",
                      "description": "Human-readable docs."
                    },
                    "openapi": {
                      "type": "string",
                      "format": "uri",
                      "description": "This document."
                    },
                    "llms_txt": {
                      "type": "string",
                      "format": "uri",
                      "description": "llms.txt with product summary and when-to-use guidance."
                    },
                    "endpoints": {
                      "type": "array",
                      "description": "Every public endpoint with its method.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "method": {
                            "type": "string",
                            "description": "HTTP method."
                          },
                          "path": {
                            "type": "string",
                            "description": "Path."
                          },
                          "description": {
                            "type": "string",
                            "description": "What it returns."
                          }
                        }
                      }
                    },
                    "errors": {
                      "type": "object",
                      "description": "Error envelope format and the list of stable codes."
                    },
                    "contact": {
                      "type": "string",
                      "description": "Support email."
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "The client does not accept application/json.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/ab/status": {
      "get": {
        "operationId": "getAbTestStatus",
        "summary": "Current A/B test status",
        "description": "Reports whether a site-wide A/B test is running. Used by the edge middleware to decide whether to split traffic; public because it carries no user data.",
        "tags": [
          "Site"
        ],
        "responses": {
          "200": {
            "description": "The current test status.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "active",
                    "test"
                  ],
                  "properties": {
                    "active": {
                      "type": "boolean",
                      "description": "True when a test is running."
                    },
                    "test": {
                      "description": "The running test, or null when none is active.",
                      "oneOf": [
                        {
                          "type": "object",
                          "required": [
                            "id",
                            "name"
                          ],
                          "properties": {
                            "id": {
                              "type": "integer",
                              "description": "Test id."
                            },
                            "name": {
                              "type": "string",
                              "description": "Test name."
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "Only GET and HEAD are allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "The status could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/strava-live": {
      "get": {
        "operationId": "getStravaLiveActivity",
        "summary": "Latest public Strava activity",
        "description": "Proxies the public activity feed shown by the homepage widget. Cached for 60 seconds. The response shape is owned by the upstream application API and is not part of this contract.",
        "tags": [
          "Site"
        ],
        "responses": {
          "200": {
            "description": "The upstream activity payload, passed through unchanged.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Opaque upstream payload.",
                  "additionalProperties": true
                }
              }
            }
          },
          "405": {
            "description": "Only GET is allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "The upstream service is unreachable or failing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Every error in this API uses this envelope. `code` is the stable contract; `message` and `hint` are human/agent readable and may be reworded.",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "description": "The error detail. Always present on a failed request.",
            "required": [
              "code",
              "message",
              "hint",
              "docs_url"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable machine-readable error code.",
                "enum": [
                  "bad_request",
                  "invalid_json",
                  "unauthorized",
                  "not_found",
                  "method_not_allowed",
                  "not_acceptable",
                  "unprocessable_entity",
                  "rate_limited",
                  "internal_error"
                ]
              },
              "message": {
                "type": "string",
                "description": "What went wrong, in one sentence."
              },
              "hint": {
                "type": "string",
                "description": "How to fix the request and retry."
              },
              "docs_url": {
                "type": "string",
                "format": "uri",
                "description": "Documentation covering this endpoint."
              }
            }
          }
        }
      }
    }
  }
}
