{
  "openapi": "3.1.0",
  "info": {
    "title": "CertGuard API",
    "version": "0.2.0",
    "summary": "Live SSL/TLS certificate checks: expiry, chain trust, hostname match, TLS version, grade.",
    "description": "Free JSON API behind https://certguard.mike-tusa.workers.dev. No key needed for light use (about 10 checks/min and 200/day per IP). A free API key (POST /api/v1/keys) allows about 60/min and 1,000/day. Limits apply to cached answers too. There are no X-RateLimit-* headers; a 429 carries Retry-After. Revocation (OCSP/CRL) is never checked. AI agents can also use the remote MCP server at https://certguard.mike-tusa.workers.dev/mcp (see /llms.txt).",
    "contact": {
      "name": "CertGuard",
      "email": "digitalpromohub.support@gmail.com",
      "url": "https://certguard.mike-tusa.workers.dev/"
    }
  },
  "servers": [
    {
      "url": "https://certguard.mike-tusa.workers.dev"
    }
  ],
  "externalDocs": {
    "description": "Human-readable API docs",
    "url": "https://certguard.mike-tusa.workers.dev/docs"
  },
  "tags": [
    {
      "name": "checks"
    },
    {
      "name": "keys"
    },
    {
      "name": "meta"
    },
    {
      "name": "mcp"
    }
  ],
  "components": {
    "securitySchemes": {
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Free key (`cg_` + 32 characters). Optional on /api/v1/check and /mcp."
      },
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Same key as apiKeyHeader, as `Authorization: Bearer cg_…`. X-API-Key wins when both are sent."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "ok",
          "error"
        ],
        "properties": {
          "ok": {
            "const": false
          },
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      },
      "Issue": {
        "type": "object",
        "required": [
          "severity",
          "code",
          "message"
        ],
        "properties": {
          "severity": {
            "type": "string",
            "enum": [
              "critical",
              "warning",
              "info"
            ]
          },
          "code": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "CheckResult": {
        "type": "object",
        "required": [
          "ok",
          "status",
          "revocation_checked",
          "host",
          "port",
          "checkedAt",
          "source",
          "grade",
          "summary",
          "expiry",
          "certificate",
          "hostname",
          "tls",
          "chain",
          "issues"
        ],
        "additionalProperties": true,
        "properties": {
          "ok": {
            "const": true
          },
          "status": {
            "const": "checked"
          },
          "revocation_checked": {
            "const": false
          },
          "host": {
            "type": "string",
            "examples": [
              "example.com"
            ]
          },
          "port": {
            "type": "integer",
            "enum": [
              443,
              8443,
              465,
              993,
              995
            ]
          },
          "checkedAt": {
            "type": "string",
            "format": "date-time"
          },
          "source": {
            "type": "object",
            "properties": {
              "method": {
                "type": "string",
                "enum": [
                  "live_tls_handshake",
                  "certificate_transparency"
                ]
              },
              "live": {
                "type": "boolean"
              },
              "ip": {
                "type": "string"
              },
              "attempts": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              }
            }
          },
          "grade": {
            "type": "string",
            "enum": [
              "A",
              "B",
              "C",
              "F"
            ]
          },
          "gradeEstimated": {
            "type": "boolean"
          },
          "summary": {
            "type": "string"
          },
          "expiry": {
            "type": "object",
            "properties": {
              "notBefore": {
                "type": "string"
              },
              "notAfter": {
                "type": "string"
              },
              "daysRemaining": {
                "type": "integer"
              },
              "status": {
                "type": "string",
                "enum": [
                  "ok",
                  "warning",
                  "critical",
                  "expired",
                  "not_yet_valid"
                ]
              },
              "lifetimeDays": {
                "type": "integer"
              }
            }
          },
          "certificate": {
            "type": "object",
            "additionalProperties": true
          },
          "hostname": {
            "type": "object",
            "properties": {
              "requested": {
                "type": "string"
              },
              "matches": {
                "type": "boolean"
              },
              "matchedName": {
                "type": "string"
              }
            }
          },
          "tls": {
            "type": "object",
            "additionalProperties": true
          },
          "chain": {
            "type": "object",
            "additionalProperties": true
          },
          "issues": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Issue"
            }
          },
          "measuredLive": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "notChecked": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "cache": {
            "type": "object",
            "properties": {
              "hit": {
                "type": "boolean"
              },
              "ageSeconds": {
                "type": "integer"
              },
              "ttlSeconds": {
                "type": "integer"
              }
            }
          },
          "timingMs": {
            "type": "integer"
          }
        }
      },
      "FailedCheck": {
        "type": "object",
        "required": [
          "ok",
          "status",
          "grade",
          "host",
          "port",
          "revocation_checked",
          "error"
        ],
        "additionalProperties": true,
        "properties": {
          "ok": {
            "const": false
          },
          "status": {
            "type": "string",
            "enum": [
              "check_failed",
              "live_unavailable"
            ]
          },
          "grade": {
            "type": "null"
          },
          "host": {
            "type": "string"
          },
          "port": {
            "type": "integer"
          },
          "revocation_checked": {
            "const": false
          },
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "check_failed",
                  "live_check_unavailable"
                ]
              },
              "reason": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          },
          "summary": {
            "type": "string"
          },
          "source": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "JsonRpcMessage": {
        "type": "object",
        "required": [
          "jsonrpc"
        ],
        "properties": {
          "jsonrpc": {
            "const": "2.0"
          },
          "id": {
            "type": [
              "string",
              "integer"
            ]
          },
          "method": {
            "type": "string"
          },
          "params": {
            "type": "object"
          }
        }
      }
    }
  },
  "paths": {
    "/api/v1/check": {
      "get": {
        "tags": [
          "checks"
        ],
        "operationId": "checkCertificate",
        "summary": "Check a server's SSL/TLS certificate",
        "security": [
          {},
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "host",
            "in": "query",
            "required": true,
            "description": "Hostname, public IP or https:// URL. Private/internal/reserved targets are rejected.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 300
            },
            "example": "example.com"
          },
          {
            "name": "port",
            "in": "query",
            "required": false,
            "description": "TCP port (default 443)",
            "schema": {
              "type": "integer",
              "enum": [
                443,
                8443,
                465,
                993,
                995
              ],
              "default": 443
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Check result (live handshake, or, only when a CT fallback is enabled, an estimate from Certificate Transparency logs with gradeEstimated: true)",
            "headers": {
              "x-certguard-cache": {
                "description": "`HIT` (served from the result cache), `MISS` (fresh check, or a negative answer that will be cached) or `BYPASS` (never cached: failed checks and temporary errors)",
                "schema": {
                  "type": "string",
                  "enum": [
                    "HIT",
                    "MISS",
                    "BYPASS"
                  ]
                }
              },
              "x-certguard-plan": {
                "description": "`anonymous` or `key`",
                "schema": {
                  "type": "string",
                  "enum": [
                    "anonymous",
                    "key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckResult"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_host`, `invalid_port`, `port_not_allowed` or (POST) `invalid_json`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: a key was sent but is unknown or revoked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`blocked_target`: private, internal or reserved address or name (also when DNS resolves to one)",
            "headers": {
              "x-certguard-cache": {
                "description": "`HIT` (served from the result cache), `MISS` (fresh check, or a negative answer that will be cached) or `BYPASS` (never cached: failed checks and temporary errors)",
                "schema": {
                  "type": "string",
                  "enum": [
                    "HIT",
                    "MISS",
                    "BYPASS"
                  ]
                }
              },
              "x-certguard-plan": {
                "description": "`anonymous` or `key`",
                "schema": {
                  "type": "string",
                  "enum": [
                    "anonymous",
                    "key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "`payload_too_large`: POST body over 16 KB",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "`nxdomain` / `no_address` (error body), or `status: \"live_unavailable\"` with `error.code = \"live_check_unavailable\"` and `grade: null` (Cloudflare-network target or socket refused by the runtime)",
            "headers": {
              "x-certguard-cache": {
                "description": "`HIT` (served from the result cache), `MISS` (fresh check, or a negative answer that will be cached) or `BYPASS` (never cached: failed checks and temporary errors)",
                "schema": {
                  "type": "string",
                  "enum": [
                    "HIT",
                    "MISS",
                    "BYPASS"
                  ]
                }
              },
              "x-certguard-plan": {
                "description": "`anonymous` or `key`",
                "schema": {
                  "type": "string",
                  "enum": [
                    "anonymous",
                    "key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/FailedCheck"
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited` (per-minute), `ip_daily_quota`, `key_quota_exceeded`, `issuer_quota_exceeded` or `daily_cap_reached` (service-wide daily allowance)",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "`status: \"check_failed\"` (TLS handshake could not be completed; `grade: null`, never cached) or `dns_error`",
            "headers": {
              "x-certguard-cache": {
                "description": "`HIT` (served from the result cache), `MISS` (fresh check, or a negative answer that will be cached) or `BYPASS` (never cached: failed checks and temporary errors)",
                "schema": {
                  "type": "string",
                  "enum": [
                    "HIT",
                    "MISS",
                    "BYPASS"
                  ]
                }
              },
              "x-certguard-plan": {
                "description": "`anonymous` or `key`",
                "schema": {
                  "type": "string",
                  "enum": [
                    "anonymous",
                    "key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/FailedCheck"
                    }
                  ]
                }
              }
            }
          },
          "503": {
            "description": "`not_configured` (deployment missing a secret) or a temporary `live_unavailable` (CT fallback unavailable)",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying",
                "schema": {
                  "type": "integer"
                }
              },
              "x-certguard-cache": {
                "description": "`HIT` (served from the result cache), `MISS` (fresh check, or a negative answer that will be cached) or `BYPASS` (never cached: failed checks and temporary errors)",
                "schema": {
                  "type": "string",
                  "enum": [
                    "HIT",
                    "MISS",
                    "BYPASS"
                  ]
                }
              },
              "x-certguard-plan": {
                "description": "`anonymous` or `key`",
                "schema": {
                  "type": "string",
                  "enum": [
                    "anonymous",
                    "key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/FailedCheck"
                    }
                  ]
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "checks"
        ],
        "operationId": "checkCertificatePost",
        "summary": "Check a server's SSL/TLS certificate (JSON body)",
        "security": [
          {},
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "host"
                ],
                "properties": {
                  "host": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 300
                  },
                  "port": {
                    "type": "integer",
                    "enum": [
                      443,
                      8443,
                      465,
                      993,
                      995
                    ],
                    "default": 443
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Check result (live handshake, or, only when a CT fallback is enabled, an estimate from Certificate Transparency logs with gradeEstimated: true)",
            "headers": {
              "x-certguard-cache": {
                "description": "`HIT` (served from the result cache), `MISS` (fresh check, or a negative answer that will be cached) or `BYPASS` (never cached: failed checks and temporary errors)",
                "schema": {
                  "type": "string",
                  "enum": [
                    "HIT",
                    "MISS",
                    "BYPASS"
                  ]
                }
              },
              "x-certguard-plan": {
                "description": "`anonymous` or `key`",
                "schema": {
                  "type": "string",
                  "enum": [
                    "anonymous",
                    "key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckResult"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_host`, `invalid_port`, `port_not_allowed` or (POST) `invalid_json`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "`invalid_api_key`: a key was sent but is unknown or revoked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`blocked_target`: private, internal or reserved address or name (also when DNS resolves to one)",
            "headers": {
              "x-certguard-cache": {
                "description": "`HIT` (served from the result cache), `MISS` (fresh check, or a negative answer that will be cached) or `BYPASS` (never cached: failed checks and temporary errors)",
                "schema": {
                  "type": "string",
                  "enum": [
                    "HIT",
                    "MISS",
                    "BYPASS"
                  ]
                }
              },
              "x-certguard-plan": {
                "description": "`anonymous` or `key`",
                "schema": {
                  "type": "string",
                  "enum": [
                    "anonymous",
                    "key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "`payload_too_large`: POST body over 16 KB",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "`nxdomain` / `no_address` (error body), or `status: \"live_unavailable\"` with `error.code = \"live_check_unavailable\"` and `grade: null` (Cloudflare-network target or socket refused by the runtime)",
            "headers": {
              "x-certguard-cache": {
                "description": "`HIT` (served from the result cache), `MISS` (fresh check, or a negative answer that will be cached) or `BYPASS` (never cached: failed checks and temporary errors)",
                "schema": {
                  "type": "string",
                  "enum": [
                    "HIT",
                    "MISS",
                    "BYPASS"
                  ]
                }
              },
              "x-certguard-plan": {
                "description": "`anonymous` or `key`",
                "schema": {
                  "type": "string",
                  "enum": [
                    "anonymous",
                    "key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/FailedCheck"
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited` (per-minute), `ip_daily_quota`, `key_quota_exceeded`, `issuer_quota_exceeded` or `daily_cap_reached` (service-wide daily allowance)",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "`internal_error`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "`status: \"check_failed\"` (TLS handshake could not be completed; `grade: null`, never cached) or `dns_error`",
            "headers": {
              "x-certguard-cache": {
                "description": "`HIT` (served from the result cache), `MISS` (fresh check, or a negative answer that will be cached) or `BYPASS` (never cached: failed checks and temporary errors)",
                "schema": {
                  "type": "string",
                  "enum": [
                    "HIT",
                    "MISS",
                    "BYPASS"
                  ]
                }
              },
              "x-certguard-plan": {
                "description": "`anonymous` or `key`",
                "schema": {
                  "type": "string",
                  "enum": [
                    "anonymous",
                    "key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/FailedCheck"
                    }
                  ]
                }
              }
            }
          },
          "503": {
            "description": "`not_configured` (deployment missing a secret) or a temporary `live_unavailable` (CT fallback unavailable)",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying",
                "schema": {
                  "type": "integer"
                }
              },
              "x-certguard-cache": {
                "description": "`HIT` (served from the result cache), `MISS` (fresh check, or a negative answer that will be cached) or `BYPASS` (never cached: failed checks and temporary errors)",
                "schema": {
                  "type": "string",
                  "enum": [
                    "HIT",
                    "MISS",
                    "BYPASS"
                  ]
                }
              },
              "x-certguard-plan": {
                "description": "`anonymous` or `key`",
                "schema": {
                  "type": "string",
                  "enum": [
                    "anonymous",
                    "key"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/FailedCheck"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/keys": {
      "post": {
        "tags": [
          "keys"
        ],
        "operationId": "createKey",
        "summary": "Get a free API key (shown once; JSON only; no CORS)",
        "security": [
          {}
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "maxLength": 254,
                    "description": "Optional, unverified contact info"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Key created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "apiKey",
                    "keyId"
                  ],
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "apiKey": {
                      "type": "string",
                      "pattern": "^cg_[A-Za-z0-9]{32}$"
                    },
                    "keyId": {
                      "type": "string"
                    },
                    "plan": {
                      "const": "free"
                    },
                    "dailyQuota": {
                      "type": "integer"
                    },
                    "perMinute": {
                      "type": "integer"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`invalid_json` or `invalid_email`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`cross_origin_forbidden`: requests from other websites are refused",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "`payload_too_large`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "`unsupported_media_type`: send application/json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`, `key_issue_limit` (at most 3 keys per IP per day) or `daily_cap_reached`",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "`not_configured` or `unavailable`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/usage": {
      "get": {
        "tags": [
          "keys"
        ],
        "operationId": "usage",
        "summary": "Today's usage for your key",
        "security": [
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Usage (approximate, batched counters)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "keyId": {
                      "type": "string"
                    },
                    "plan": {
                      "type": "string"
                    },
                    "dailyQuota": {
                      "type": "integer"
                    },
                    "usedToday": {
                      "type": "integer"
                    },
                    "remainingToday": {
                      "type": "integer"
                    },
                    "perMinute": {
                      "type": "integer"
                    },
                    "resetsAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`missing_api_key` or `invalid_api_key`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/health": {
      "get": {
        "tags": [
          "meta"
        ],
        "operationId": "health",
        "summary": "Service status and deployed version",
        "security": [
          {}
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "service",
                    "version"
                  ],
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "service": {
                      "const": "certguard"
                    },
                    "version": {
                      "type": "string",
                      "examples": [
                        "0.2.0"
                      ]
                    },
                    "environment": {
                      "type": "string"
                    },
                    "time": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed`",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/mcp": {
      "post": {
        "tags": [
          "mcp"
        ],
        "operationId": "mcp",
        "summary": "Remote MCP server (Streamable HTTP, JSON-RPC 2.0)",
        "description": "Model Context Protocol endpoint. Stateless, JSON responses only (no SSE, no Mcp-Session-Id). Supported protocol versions: 2026-07-28, 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05. Modern (2026-07-28) requests carry params._meta and the MCP-Protocol-Version, Mcp-Method and Mcp-Name headers; legacy clients use initialize. Tool: check_certificate. Same keys and limits as /api/v1/check; each tools/call counts as one check. Body max 65536 bytes; legacy batches max 10 messages with at most one tools/call.",
        "security": [
          {},
          {
            "apiKeyHeader": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "2026-07-28",
                "2025-11-25",
                "2025-06-18",
                "2025-03-26",
                "2024-11-05"
              ]
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "description": "Required for 2026-07-28; must equal the body method",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "description": "Required for 2026-07-28 tools/call; must equal params.name",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/JsonRpcMessage"
                  },
                  {
                    "type": "array",
                    "maxItems": 10,
                    "items": {
                      "$ref": "#/components/schemas/JsonRpcMessage"
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response (or batch of responses). Tool failures, including rate limits, are results with isError: true.",
            "content": {
              "application/json": {
                "schema": {
                  "type": [
                    "object",
                    "array"
                  ]
                }
              }
            }
          },
          "202": {
            "description": "Notification(s) accepted; no body"
          },
          "400": {
            "description": "Parse error (-32700), invalid request (-32600), header mismatch (-32020), unsupported protocol version (-32022) or missing _meta (-32602)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key (JSON-RPC error, data.code = invalid_api_key)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "403": {
            "description": "Origin header present but not allowed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "Unknown method in a 2026-07-28 request (-32601)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "413": {
            "description": "Body larger than the cap",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "429": {
            "description": "Too many non-check MCP messages from this IP",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected internal error (`internal_error`); per-message failures are JSON-RPC -32603 inside a 200 response instead",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Deployment missing its HASH_PEPPER secret (`not_configured`)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "mcp"
        ],
        "operationId": "mcp_get_not_allowed",
        "summary": "Not supported (stateless server: no SSE stream, no sessions)",
        "responses": {
          "405": {
            "description": "Always 405 with `Allow: POST, OPTIONS` and a JSON-RPC error body",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string",
                  "const": "POST, OPTIONS"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "mcp"
        ],
        "operationId": "mcp_delete_not_allowed",
        "summary": "Not supported (stateless server: no SSE stream, no sessions)",
        "responses": {
          "405": {
            "description": "Always 405 with `Allow: POST, OPTIONS` and a JSON-RPC error body",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string",
                  "const": "POST, OPTIONS"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  }
}