{
  "openapi": "3.1.0",
  "info": {
    "title": "edugalbs.com API",
    "version": "1.0.0",
    "summary": "Search and read edugalbs.com, the site of Eduardo Galbiati.",
    "description": "Read-only access to the published pages of edugalbs.com: Eduardo Galbiati's profile, the \"Diário da fábrica\" (Factory diary) and his blog on technology and leadership, in Portuguese and English. No sign-in; 60 requests a minute per address (429 with Retry-After beyond that). Every error is JSON: {\"error\": {\"status\", \"code\", \"message\", \"hint\", \"docs\"}}. Every answer carries the RateLimit headers (RateLimit-Policy, RateLimit, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset). Stick to what the pages say and cite their URLs.\n\nVersioning: the major version is in the path (/api/v1/). Additions (new endpoints, parameters or fields) come within v1 and only bump info.version; anything that would break a client comes as /api/v2/, and v1 keeps working for at least 6 months after that, announced on its responses with the Deprecation (RFC 9745) and Sunset (RFC 8594) headers and a Link to the policy (rel=\"deprecation\"). /api/<endpoint>, without a version, is an alias of v1 and stays one. Policy: https://www.edugalbs.com/developers#versioning.",
    "contact": {
      "name": "Eduardo Galbiati",
      "url": "https://www.linkedin.com/in/edugalbs/"
    }
  },
  "servers": [
    {
      "url": "https://www.edugalbs.com"
    }
  ],
  "security": [],
  "externalDocs": {
    "url": "https://www.edugalbs.com/developers",
    "description": "Developer guide: quickstart, MCP, rate limits, errors, versioning"
  },
  "tags": [
    {
      "name": "site",
      "description": "The site's pages, as JSON."
    },
    {
      "name": "mcp",
      "description": "The MCP server (com.edugalbs/site)."
    }
  ],
  "paths": {
    "/api/v1": {
      "get": {
        "operationId": "apiIndex",
        "summary": "List the endpoints",
        "tags": [
          "site"
        ],
        "responses": {
          "200": {
            "description": "The API's endpoints.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: wait the seconds in Retry-After.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/search": {
      "get": {
        "operationId": "search",
        "summary": "Search the site",
        "description": "Full-text search over every published page of edugalbs.com (profile, diary chapters, blog posts, the Multiagent Orchestrator page). Returns the best sections with a snippet and the page URL. Accents and case do not matter; Portuguese and English queries both work. Read a result in full with /api/v1/pages.",
        "tags": [
          "site"
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "description": "What to look for.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "12-factor agents"
          },
          {
            "name": "section",
            "in": "query",
            "description": "Limit to the diary chapters, the blog posts or the profile.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "diary",
                "blog",
                "profile"
              ],
              "default": "all"
            }
          },
          {
            "name": "lang",
            "in": "query",
            "description": "Only pages in this language (pt or en). Default: both.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "pt",
                "en"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Results to return.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10,
              "default": 5
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResults"
                }
              }
            }
          },
          "400": {
            "description": "A parameter is missing or invalid.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: wait the seconds in Retry-After.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The site's text could not be read right now.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pages": {
      "get": {
        "operationId": "pages",
        "summary": "Read a page",
        "description": "A page of edugalbs.com as Markdown: its title, URL, summary and full text. Pass its URL or path (e.g. \"/fabrica-24x7/capitulos/o-gargalo-e-o-teste\" or \"https://www.edugalbs.com/blog/12-factor-agents\").",
        "tags": [
          "site"
        ],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "description": "The page URL or path on edugalbs.com.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "/blog/12-factor-agents"
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Character to start from, to read a long page in parts (next_offset of the previous answer).",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "max_chars",
            "in": "query",
            "description": "Characters to return.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1000,
              "maximum": 60000,
              "default": 30000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page"
                }
              }
            }
          },
          "400": {
            "description": "A parameter is missing or invalid.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No page at that address.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: wait the seconds in Retry-After.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The site's text could not be read right now.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/chapters": {
      "get": {
        "operationId": "chapters",
        "summary": "List the diary chapters",
        "description": "The published chapters of the \"Diário da fábrica\" (Factory diary), in order: number, title, date line, summary and URL.",
        "tags": [
          "site"
        ],
        "parameters": [
          {
            "name": "lang",
            "in": "query",
            "description": "pt (Portuguese, the default) or en (English).",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "pt",
                "en"
              ],
              "default": "pt"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChapterList"
                }
              }
            }
          },
          "400": {
            "description": "A parameter is missing or invalid.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: wait the seconds in Retry-After.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The site's text could not be read right now.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/posts": {
      "get": {
        "operationId": "posts",
        "summary": "List the blog posts",
        "description": "The published posts of the blog on technology and leadership, newest first: title, date line, summary and URL.",
        "tags": [
          "site"
        ],
        "parameters": [
          {
            "name": "lang",
            "in": "query",
            "description": "pt (Portuguese, the default) or en (English).",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "pt",
                "en"
              ],
              "default": "pt"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostList"
                }
              }
            }
          },
          "400": {
            "description": "A parameter is missing or invalid.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: wait the seconds in Retry-After.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The site's text could not be read right now.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/profile": {
      "get": {
        "operationId": "profile",
        "summary": "Who Eduardo Galbiati is",
        "description": "The profile Eduardo wrote for AI assistants: how he would like to be introduced, career, education, the factory, the diary, the orchestrator and how to reach him. Use it before describing him.",
        "tags": [
          "site"
        ],
        "parameters": [
          {
            "name": "lang",
            "in": "query",
            "description": "pt (Portuguese, the default) or en (English).",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "pt",
                "en"
              ],
              "default": "pt"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Page"
                }
              }
            }
          },
          "400": {
            "description": "A parameter is missing or invalid.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests: wait the seconds in Retry-After.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The site's text could not be read right now.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/mcp": {
      "post": {
        "operationId": "mcp",
        "summary": "MCP server (JSON-RPC 2.0)",
        "description": "The Model Context Protocol server, over Streamable HTTP without sessions: POST a JSON-RPC 2.0 message (initialize, tools/list, tools/call…) and get the answer as JSON. Same tools as the GET endpoints. Card: https://www.edugalbs.com/.well-known/mcp/server-card.json.",
        "tags": [
          "mcp"
        ],
        "externalDocs": {
          "url": "https://modelcontextprotocol.io/specification",
          "description": "Model Context Protocol"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "jsonrpc",
                  "method"
                ],
                "properties": {
                  "jsonrpc": {
                    "const": "2.0"
                  },
                  "id": {
                    "type": [
                      "string",
                      "integer"
                    ]
                  },
                  "method": {
                    "type": "string"
                  },
                  "params": {
                    "type": "object"
                  }
                }
              },
              "example": {
                "jsonrpc": "2.0",
                "id": 1,
                "method": "tools/call",
                "params": {
                  "name": "search_site",
                  "arguments": {
                    "query": "12-factor agents"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The JSON-RPC answer (result or error).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "202": {
            "description": "A notification was received (no answer)."
          },
          "400": {
            "description": "Not JSON, or an invalid batch (a JSON-RPC error).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests (a JSON-RPC error); wait the seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "headers": {
      "RateLimitPolicy": {
        "description": "The quota (draft-ietf-httpapi-ratelimit-headers): q requests per w seconds, per client address.",
        "schema": {
          "type": "string"
        },
        "example": "\"default\";q=60;w=60"
      },
      "RateLimit": {
        "description": "What is left of the quota: r requests in the next t seconds.",
        "schema": {
          "type": "string"
        },
        "example": "\"default\";r=59;t=60"
      },
      "RateLimitLimit": {
        "description": "Requests allowed per window (60).",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimitRemaining": {
        "description": "Requests left in the current window.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimitReset": {
        "description": "Seconds until a request is freed in the window.",
        "schema": {
          "type": "integer"
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait before the next request (RFC 9110).",
        "schema": {
          "type": "integer"
        }
      }
    },
    "schemas": {
      "PageSummary": {
        "type": "object",
        "required": [
          "title",
          "url",
          "meta",
          "summary"
        ],
        "properties": {
          "title": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "chapter": {
            "type": "integer",
            "description": "The chapter number (diary chapters only)."
          },
          "meta": {
            "type": "string",
            "description": "The line under the summary: the chapter and its date, a post's date…"
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "SearchResults": {
        "type": "object",
        "required": [
          "query",
          "results"
        ],
        "properties": {
          "query": {
            "type": "string"
          },
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "title",
                "url",
                "kind",
                "lang",
                "section",
                "snippet",
                "score"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string",
                  "format": "uri"
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "profile",
                    "diary",
                    "chapter",
                    "blog",
                    "post",
                    "product",
                    "home",
                    "page"
                  ]
                },
                "lang": {
                  "type": "string",
                  "enum": [
                    "pt",
                    "en"
                  ]
                },
                "section": {
                  "type": "string",
                  "description": "The heading of the section that matched."
                },
                "snippet": {
                  "type": "string"
                },
                "score": {
                  "type": "number"
                }
              }
            }
          }
        }
      },
      "Page": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PageSummary"
          },
          {
            "type": "object",
            "required": [
              "kind",
              "lang",
              "offset",
              "length",
              "total_length",
              "next_offset",
              "markdown"
            ],
            "properties": {
              "kind": {
                "type": "string"
              },
              "lang": {
                "type": "string",
                "enum": [
                  "pt",
                  "en"
                ]
              },
              "offset": {
                "type": "integer"
              },
              "length": {
                "type": "integer"
              },
              "total_length": {
                "type": "integer"
              },
              "next_offset": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Where the next part starts, or null at the end of the page."
              },
              "markdown": {
                "type": "string",
                "description": "The page's text as Markdown (this part of it)."
              }
            }
          }
        ]
      },
      "ChapterList": {
        "type": "object",
        "required": [
          "lang",
          "chapters"
        ],
        "properties": {
          "lang": {
            "type": "string",
            "enum": [
              "pt",
              "en"
            ]
          },
          "chapters": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PageSummary"
            }
          }
        }
      },
      "PostList": {
        "type": "object",
        "required": [
          "lang",
          "posts"
        ],
        "properties": {
          "lang": {
            "type": "string",
            "enum": [
              "pt",
              "en"
            ]
          },
          "posts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PageSummary"
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "status",
              "code",
              "message",
              "hint"
            ],
            "properties": {
              "status": {
                "type": "integer",
                "description": "The HTTP status."
              },
              "code": {
                "type": "string",
                "enum": [
                  "not_found",
                  "unsupported_version",
                  "method_not_allowed",
                  "missing_parameter",
                  "invalid_parameter",
                  "page_not_found",
                  "rate_limited",
                  "unavailable"
                ]
              },
              "message": {
                "type": "string",
                "description": "What went wrong."
              },
              "hint": {
                "type": "string",
                "description": "What to do about it."
              },
              "docs": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}