{
  "openapi": "3.1.1",
  "info": {
    "title": "ondelva public endpoints",
    "version": "1.0.0",
    "summary": "Read-only endpoints published by ondelva.",
    "description": "ondelva is a static site. Every endpoint below is a public GET that needs no\nkey, no account, and no headers beyond the ones you choose for content negotiation.\nThere is no write API and no rate limit beyond Cloudflare's own edge protection.\n\nAny HTML page also answers `Accept: text/markdown` with Markdown, and serves the same\ndocument at its path with `.md` appended. Responses that negotiate carry\n`Vary: Accept, Accept-Encoding`.",
    "license": {
      "name": "Content is the author's; code samples are free to reuse.",
      "identifier": "MIT"
    },
    "contact": {
      "name": "egg",
      "email": "im@ondelva.com",
      "url": "https://ondelva.com/about"
    }
  },
  "servers": [
    {
      "url": "https://ondelva.com",
      "description": "Production"
    }
  ],
  "security": [],
  "externalDocs": {
    "description": "Developer resources",
    "url": "https://ondelva.com/developers"
  },
  "tags": [
    {
      "name": "pages",
      "description": "Human-facing pages, negotiable to Markdown."
    },
    {
      "name": "discovery",
      "description": "Machine-readable indexes of the site."
    },
    {
      "name": "media",
      "description": "Generated images."
    }
  ],
  "paths": {
    "/": {
      "get": {
        "tags": [
          "pages"
        ],
        "operationId": "getHomePage",
        "summary": "The front page, as HTML or Markdown.",
        "description": "Send `Accept: text/markdown` for Markdown. The same negotiation applies to every page listed in the sitemap.",
        "parameters": [
          {
            "name": "Accept",
            "in": "header",
            "required": false,
            "description": "`text/html` (default) or `text/markdown`. Quality values are honoured.",
            "schema": {
              "type": "string",
              "default": "text/html"
            },
            "example": "text/markdown"
          }
        ],
        "responses": {
          "200": {
            "description": "The page in the negotiated representation.",
            "headers": {
              "Vary": {
                "description": "Always `Accept, Accept-Encoding`.",
                "schema": {
                  "type": "string"
                }
              },
              "Content-Location": {
                "description": "The `.md` URL, when Markdown was selected.",
                "schema": {
                  "type": "string",
                  "format": "uri-reference"
                }
              }
            },
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "406": {
            "$ref": "#/components/responses/NotAcceptable"
          }
        }
      }
    },
    "/{path}.md": {
      "get": {
        "tags": [
          "pages"
        ],
        "operationId": "getPageMarkdown",
        "summary": "Any page as Markdown, without content negotiation.",
        "description": "`path` is the page path without its leading slash; the front page is `index`. Examples: `tools/hotdealsheet`, `blog/2026/08/cloudflare-free-plan-rate-limiting-daily-quota`, `blog`, `index`. Pages authored directly as HTML (`about`, `privacy`) have no Markdown variant and return 404.",
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "description": "Page path without the leading slash. `index` for the front page.",
            "schema": {
              "type": "string"
            },
            "example": "tools"
          }
        ],
        "responses": {
          "200": {
            "description": "The page as Markdown, with YAML front matter.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "tags": [
          "discovery"
        ],
        "operationId": "getLlmsTxt",
        "summary": "The whole site as one Markdown index.",
        "description": "Follows the llmstxt.org layout: an H1, a summary blockquote, then link sections.",
        "responses": {
          "200": {
            "description": "Markdown index.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "tags": [
          "discovery"
        ],
        "operationId": "getOpenApi",
        "summary": "This document.",
        "responses": {
          "200": {
            "description": "OpenAPI 3.1 document.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/sitemap.xml": {
      "get": {
        "tags": [
          "discovery"
        ],
        "operationId": "getSitemap",
        "summary": "Every indexed URL.",
        "responses": {
          "200": {
            "description": "Sitemap 0.9 XML.",
            "content": {
              "application/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/rss.xml": {
      "get": {
        "tags": [
          "discovery"
        ],
        "operationId": "getFeed",
        "summary": "Full post feed.",
        "responses": {
          "200": {
            "description": "RSS 2.0 XML.",
            "content": {
              "application/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/search-index.json": {
      "get": {
        "tags": [
          "discovery"
        ],
        "operationId": "getSearchIndex",
        "summary": "Every post and tool, with plain-text body.",
        "description": "Regenerated on each build. Cached for five minutes.",
        "responses": {
          "200": {
            "description": "Search records, tools first, then posts newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SearchItem"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/og/{route}.png": {
      "get": {
        "tags": [
          "media"
        ],
        "operationId": "getOpenGraphImage",
        "summary": "Open Graph card for a page.",
        "description": "`route` is `home`, or a page path such as `blog/2026/08/example`.",
        "parameters": [
          {
            "name": "route",
            "in": "path",
            "required": true,
            "description": "`home`, or the page path without its leading slash.",
            "schema": {
              "type": "string"
            },
            "example": "home"
          }
        ],
        "responses": {
          "200": {
            "description": "PNG card, 1200x630.",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "status",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable machine-readable identifier.",
                "enum": [
                  "not_found",
                  "not_acceptable"
                ]
              },
              "status": {
                "type": "integer",
                "description": "HTTP status code, repeated in the body."
              },
              "message": {
                "type": "string",
                "description": "What went wrong, in one sentence."
              },
              "resolution": {
                "type": "string",
                "description": "What to do next."
              },
              "supported": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Media types this URL can serve. Present on not_acceptable."
              },
              "links": {
                "type": "object",
                "additionalProperties": {
                  "type": "string",
                  "format": "uri"
                },
                "description": "Entry points worth trying instead."
              }
            }
          }
        }
      },
      "SearchItem": {
        "type": "object",
        "required": [
          "title",
          "excerpt",
          "href",
          "category",
          "date",
          "reading",
          "body"
        ],
        "properties": {
          "title": {
            "type": "string"
          },
          "excerpt": {
            "type": "string"
          },
          "href": {
            "type": "string",
            "description": "Site-relative path, no trailing slash."
          },
          "category": {
            "type": "string",
            "description": "A post category, or `Tool`."
          },
          "date": {
            "type": "string",
            "description": "Publication date for posts, status label for tools."
          },
          "reading": {
            "type": "string",
            "description": "Reading time for posts, kind label for tools."
          },
          "body": {
            "type": "string",
            "description": "Plain-text body, truncated to 1200 characters."
          }
        }
      }
    },
    "responses": {
      "NotFound": {
        "description": "Nothing is published at that path.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotAcceptable": {
        "description": "The `Accept` header rules out every representation this URL has.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}