{
  "openapi": "3.1.1",
  "info": {
    "title": "CDN Behaviour Explorer API",
    "version": "1.0.0",
    "summary": "Which CDN serves a URL, whether it caches it (HIT/MISS, Age, TTL) and how, from two requests.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://cdnbehaviorexplorer.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Which CDN serves a URL, whether it caches it (HIT/MISS, Age, TTL) and how, from two requests.",
        "description": "Sends two consecutive requests to a public URL (or reads two pasted header sets) and compares them: CDN detection from vendor headers (Cloudflare, CloudFront, Fastly, Akamai, Vercel, Netlify, Bunny, Azure, Google), edge cache status HIT/MISS/EXPIRED, Age progression, edge location, shared-cache TTL, Vary and compression. Only this server's vantage point is used; there is no multi-region comparison.\n\nMethodology:\n- Live mode: two GET requests in a row through the SSRF-guarded fetcher (body capped at 64 KiB each), identical request headers.\n- CDN detection from vendor headers: cf-ray/cf-cache-status (Cloudflare), x-amz-cf-id/x-amz-cf-pop (CloudFront), x-served-by cache-xxx/x-fastly-request-id (Fastly), akamai-grn/x-akamai-*/AkamaiGHost (Akamai), x-vercel-id, x-nf-request-id, BunnyCDN, x-azure-ref, Via: google.\n- Cache status from the vendor header or RFC 9211 Cache-Status (the last listed cache is closest to the client); Age (RFC 9111 §5.1) growing between requests means one stored copy answered both.\n- TTL: CDN-Cache-Control / Surrogate-Control > s-maxage > max-age > Expires − Date. Browser TTL is max-age.\n- Region comparison is not available: tools run from one server. HeaderLens has multi-region probe agents, but they are not wired into tools.",
        "tags": [
          "infrastructure"
        ],
        "x-mcp-tool": "cdn_behavior_explorer",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CdnBehaviorExplorerInput"
              },
              "examples": {
                "example1": {
                  "summary": "Cloudflare MISS then HIT (pasted)",
                  "value": {
                    "mode": "paste",
                    "headersFirst": "HTTP/2 200\ndate: Mon, 12 Oct 2026 10:00:00 GMT\ncontent-type: text/html; charset=utf-8\ncontent-encoding: br\ncache-control: public, max-age=60, s-maxage=3600\netag: W/\"abc123\"\nvary: Accept-Encoding\ncf-cache-status: MISS\nage: 0\ncf-ray: 8d2f1a2b3c4d5e6f-FRA\nserver: cloudflare\nalt-svc: h3=\":443\"; ma=86400",
                    "headersSecond": "HTTP/2 200\ndate: Mon, 12 Oct 2026 10:00:05 GMT\ncontent-type: text/html; charset=utf-8\ncontent-encoding: br\ncache-control: public, max-age=60, s-maxage=3600\netag: W/\"abc123\"\nvary: Accept-Encoding\ncf-cache-status: HIT\nage: 5\ncf-ray: 8d2f1a2c4e5f6a7b-FRA\nserver: cloudflare\nalt-svc: h3=\":443\"; ma=86400"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CdnBehaviorExplorerResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "CdnBehaviorExplorerInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "mode": {
            "title": "Mode",
            "type": "string",
            "enum": [
              "live",
              "paste"
            ],
            "default": "live"
          },
          "url": {
            "title": "URL (live mode)",
            "type": "string",
            "format": "uri"
          },
          "headersFirst": {
            "title": "Response headers of request 1 (paste mode)",
            "type": "string",
            "maxLength": 30000
          },
          "headersSecond": {
            "title": "Response headers of request 2 (paste mode)",
            "type": "string",
            "maxLength": 30000
          }
        },
        "required": []
      },
      "CdnBehaviorExplorerResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "mode",
              "url",
              "cdns",
              "requests",
              "verdict",
              "explanation",
              "ageDelta",
              "dateDelta",
              "etagStable",
              "caching",
              "regionComparison"
            ],
            "properties": {
              "mode": {
                "type": "string",
                "enum": [
                  "live",
                  "paste"
                ]
              },
              "url": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "cdns": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "cdn",
                    "confidence",
                    "evidence"
                  ],
                  "properties": {
                    "cdn": {
                      "type": "string"
                    },
                    "confidence": {
                      "type": "string",
                      "enum": [
                        "high",
                        "medium",
                        "low"
                      ]
                    },
                    "evidence": {
                      "type": "string"
                    }
                  }
                }
              },
              "requests": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "status",
                    "cacheStatus",
                    "cacheHeader",
                    "age",
                    "date",
                    "etag",
                    "pop",
                    "encoding"
                  ],
                  "properties": {
                    "status": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "cacheStatus": {
                      "type": "string"
                    },
                    "cacheHeader": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "age": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "date": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "etag": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "pop": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "encoding": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              },
              "verdict": {
                "type": "string",
                "enum": [
                  "edge-cached",
                  "warmed-on-second-request",
                  "not-cached-at-edge",
                  "bypassed",
                  "no-cdn-detected",
                  "inconclusive"
                ]
              },
              "explanation": {
                "type": "string"
              },
              "ageDelta": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "dateDelta": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "etagStable": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "caching": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "verdict",
                  "cacheControl",
                  "cdnCacheControl",
                  "surrogateControl",
                  "sharedTtl",
                  "browserTtl",
                  "vary"
                ],
                "properties": {
                  "verdict": {
                    "type": "string"
                  },
                  "cacheControl": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "cdnCacheControl": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "surrogateControl": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "sharedTtl": {
                    "type": [
                      "integer",
                      "null"
                    ]
                  },
                  "browserTtl": {
                    "type": [
                      "integer",
                      "null"
                    ]
                  },
                  "vary": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                }
              },
              "regionComparison": {
                "type": "string"
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}