{
  "openapi": "3.1.0",
  "info": {
    "title": "Duarte O. Carmo API",
    "version": "1.0.0",
    "description": "A public, unauthenticated, read-only API for duarteocarmo.com. No API key is needed."
  },
  "servers": [
    {
      "url": "https://duarteocarmo.com"
    }
  ],
  "security": [],
  "paths": {
    "/api": {
      "get": {
        "operationId": "getApiMetadata",
        "summary": "Get API metadata",
        "description": "Returns API metadata and access information.",
        "responses": {
          "200": {
            "description": "API metadata",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiMetadataResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/about": {
      "get": {
        "operationId": "getAbout",
        "summary": "Get about page",
        "description": "Returns the About page as Markdown. This endpoint is read-only.",
        "responses": {
          "200": {
            "description": "About page in Markdown",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/consulting": {
      "get": {
        "operationId": "getConsulting",
        "summary": "Get consulting page",
        "description": "Returns the Consulting page as Markdown. This endpoint is read-only.",
        "responses": {
          "200": {
            "description": "Consulting page in Markdown",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/contact": {
      "get": {
        "operationId": "getContact",
        "summary": "Get contact details",
        "description": "Returns public contact details. This endpoint is read-only.",
        "responses": {
          "200": {
            "description": "Public contact details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/posts": {
      "get": {
        "operationId": "listPosts",
        "summary": "List posts",
        "description": "Returns public posts. Results are read-only.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Query"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of posts",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostListResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "Query": {
        "name": "q",
        "in": "query",
        "required": false,
        "description": "Search posts by text.",
        "schema": {
          "type": "string"
        }
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "Number of posts to return.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 20
        }
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "required": false,
        "description": "Opaque cursor for the next page.",
        "schema": {
          "type": "string"
        }
      }
    },
    "responses": {
      "BadRequestError": {
        "description": "Invalid request",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "InternalServerError": {
        "description": "Internal server error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    },
    "schemas": {
      "ApiMetadata": {
        "type": "object",
        "required": [
          "name",
          "version",
          "readOnly",
          "authentication"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "readOnly": {
            "type": "boolean",
            "const": true
          },
          "authentication": {
            "type": "string",
            "const": "none"
          }
        },
        "additionalProperties": false
      },
      "Post": {
        "type": "object",
        "required": [
          "id",
          "title",
          "url",
          "publishedAt",
          "summary"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "publishedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "summary": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "Pagination": {
        "type": "object",
        "required": [
          "nextCursor"
        ],
        "properties": {
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "additionalProperties": false
      },
      "Error": {
        "type": "object",
        "required": [
          "code",
          "message"
        ],
        "properties": {
          "code": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "hint": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "ApiMetadataResponse": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/ApiMetadata"
          }
        },
        "additionalProperties": false
      },
      "ContactResponse": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "object",
            "required": [
              "email",
              "bookingUrl",
              "consultingUrl"
            ],
            "properties": {
              "email": {
                "type": "string",
                "format": "email"
              },
              "bookingUrl": {
                "type": "string",
                "format": "uri"
              },
              "consultingUrl": {
                "type": "string",
                "format": "uri"
              }
            },
            "additionalProperties": false
          }
        },
        "additionalProperties": false
      },
      "PostListResponse": {
        "type": "object",
        "required": [
          "data",
          "pagination"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Post"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        },
        "additionalProperties": false
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "$ref": "#/components/schemas/Error"
          }
        },
        "additionalProperties": false
      }
    }
  }
}
