{
  "openapi": "3.0.3",
  "info": {
    "title": "HTTPS or Not — Porcelain API",
    "version": "1.0.0",
    "description": "Machine-readable HTTPS / SSL / redirect check as JSON (\"porcelain\" output). No API key. Rate limited by IP. Same payload shape as the in-app checker.\n\n**Note:** Authenticated backend routes (`/check/:domain`, `/check-bulk` on cert-backend) are used only by the httpsornot.com frontend via proxy and are not part of this public contract.",
    "contact": {
      "url": "https://httpsornot.com/support"
    }
  },
  "servers": [
    {
      "url": "https://httpsornot.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Check",
      "description": "Domain security and HTTPS checks"
    }
  ],
  "paths": {
    "/api/porcelain": {
      "get": {
        "tags": ["Check"],
        "operationId": "getPorcelainCheck",
        "summary": "Run HTTPS check for a domain",
        "description": "Returns a full check result as JSON. Rate limit: **30 requests per hour per IP** (enforced on cert-backend).",
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "description": "Hostname only (e.g. example.com). Scheme and path are stripped.",
            "schema": {
              "type": "string",
              "example": "example.com"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Check completed (may include `error` field if HTTPS failed or domain blocked).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckResult"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid `domain` parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests (per IP)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "string"
                },
                "description": "Suggested retry delay"
              },
              "RateLimit-Limit": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Remaining": {
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Reset": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "502": {
            "description": "Upstream check failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/check": {
      "get": {
        "tags": ["Check"],
        "operationId": "getPublicCheckAlias",
        "summary": "Same as /api/porcelain",
        "description": "Alias endpoint; same query parameters and response as `GET /api/porcelain`.",
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ErrorBody": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "hint": {
            "type": "string"
          },
          "domain": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "CheckResult": {
        "type": "object",
        "description": "Full check payload. Many fields are optional depending on reachability and configuration.",
        "required": ["domain", "httpRedirects", "httpsWorks", "redirectChain"],
        "properties": {
          "domain": {
            "type": "string"
          },
          "httpRedirects": {
            "type": "boolean"
          },
          "httpsWorks": {
            "type": "boolean"
          },
          "redirectChain": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "redirectChainDetails": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "type": "string"
                },
                "statusCode": {
                  "type": "integer"
                },
                "responseTime": {
                  "type": "integer"
                }
              },
              "additionalProperties": true
            }
          },
          "totalResponseTime": {
            "type": "number"
          },
          "statusCode": {
            "type": "integer"
          },
          "finalUrl": {
            "type": "string"
          },
          "checkedAt": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp when the result was produced"
          },
          "sslCertificate": {
            "type": "object",
            "additionalProperties": true
          },
          "sslGrade": {
            "type": "object",
            "additionalProperties": true
          },
          "securityHeaders": {
            "type": "object",
            "additionalProperties": true
          },
          "hstsStatus": {
            "type": "object",
            "additionalProperties": true
          },
          "tlsProtocols": {
            "type": "object",
            "additionalProperties": true
          },
          "http2": {
            "type": "object",
            "properties": {
              "supported": {
                "type": "boolean"
              },
              "alpnProtocol": {
                "type": "string"
              }
            },
            "additionalProperties": true
          },
          "http3": {
            "type": "object",
            "additionalProperties": true
          },
          "mixedContent": {
            "type": "object",
            "additionalProperties": true
          },
          "caa": {
            "type": "object",
            "additionalProperties": true
          },
          "dnssec": {
            "type": "object",
            "additionalProperties": true
          },
          "cookieFlags": {
            "type": "object",
            "additionalProperties": true
          },
          "error": {
            "type": "string",
            "description": "Human-readable error when the check could not complete normally"
          }
        },
        "additionalProperties": true
      }
    }
  }
}
