{
  "openapi": "3.1.0",
  "info": {
    "title": "jshah.dev content API",
    "version": "1.0.0",
    "summary": "Read-only access to https://jshah.dev, the personal blog of Jay Shah.",
    "description": "A personal blog. Notes on engineering, work, travel, and whatever I'm thinking through as I go.\n\nThe whole API is public, read-only GET endpoints with no authentication. Beyond the endpoints listed here, every HTML page on the site has a Markdown twin: fetch `index.md` under the page URL, e.g. `/writing/index.md`. Outside `/api/`, the twin is also served by requesting the page URL with `Accept: text/markdown` (q-values are honored and responses carry `Vary: Accept`). Nonexistent pages return HTTP 404, as Markdown when requested with `Accept: text/markdown`; unknown paths under `/api/` return a structured JSON 404. A human-readable guide to all of this lives at https://jshah.dev/api/.",
    "contact": {
      "name": "Jay Shah",
      "url": "https://jshah.dev/about/"
    }
  },
  "servers": [
    {
      "url": "https://jshah.dev"
    }
  ],
  "security": [],
  "paths": {
    "/api/posts.json": {
      "get": {
        "operationId": "listPosts",
        "summary": "Every published post with URLs, dates, topics, and tags.",
        "responses": {
          "200": {
            "description": "The post index.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "site",
                    "count",
                    "posts"
                  ],
                  "properties": {
                    "site": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "url": {
                          "type": "string",
                          "format": "uri"
                        },
                        "description": {
                          "type": "string"
                        }
                      }
                    },
                    "count": {
                      "type": "integer"
                    },
                    "posts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Post"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/{resource}": {
      "get": {
        "operationId": "unknownApiResource",
        "summary": "Any other path under /api/ returns a structured JSON error.",
        "parameters": [
          {
            "name": "resource",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "404": {
            "description": "No such API resource.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "operationId": "getOpenApiSpec",
        "summary": "This document.",
        "responses": {
          "200": {
            "description": "The OpenAPI 3.1 specification.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "operationId": "getLlmsTxt",
        "summary": "Markdown index of the site (llmstxt.org convention).",
        "responses": {
          "200": {
            "description": "Annotated links to every page, feed, and API resource.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/atom.xml": {
      "get": {
        "operationId": "getAtomFeed",
        "summary": "Full-content Atom feed of all posts.",
        "responses": {
          "200": {
            "description": "Atom 1.0 feed.",
            "content": {
              "application/atom+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/sitemap-index.xml": {
      "get": {
        "operationId": "getSitemap",
        "summary": "XML sitemap index of every page.",
        "responses": {
          "200": {
            "description": "Sitemap index.",
            "content": {
              "application/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Post": {
        "type": "object",
        "required": [
          "title",
          "url",
          "markdown_url",
          "date",
          "topic",
          "tags",
          "description"
        ],
        "properties": {
          "title": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Canonical HTML URL of the post."
          },
          "markdown_url": {
            "type": "string",
            "format": "uri",
            "description": "Pre-rendered Markdown version of the same post."
          },
          "date": {
            "type": "string",
            "format": "date-time",
            "description": "Publish date."
          },
          "topic": {
            "type": "string",
            "description": "Primary topic; drives /writing/<topic>/."
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "description": {
            "type": "string",
            "description": "One-line summary of the post."
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "status",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable machine-readable error code."
              },
              "status": {
                "type": "integer",
                "description": "HTTP status of the response."
              },
              "message": {
                "type": "string",
                "description": "Human-readable explanation."
              },
              "hint": {
                "type": "string",
                "description": "What to try instead."
              },
              "resources": {
                "type": "object",
                "additionalProperties": {
                  "type": "string",
                  "format": "uri"
                },
                "description": "Links to the resources that do exist."
              }
            }
          }
        }
      }
    }
  }
}