{
  "openapi": "3.1.0",
  "info": {
    "title": "Approximated Public API",
    "version": "2026-09-15",
    "summary": "Manage custom domains and inspect DNS, TLS, and request traffic.",
    "description": "Authoritative machine-readable contract for the customer-facing Approximated API. Authenticated operations use the api-key header and are scoped to the proxy cluster attached to that key. Supplying api_key in a request body is unsupported legacy behavior and is intentionally not part of this contract. The general authenticated API budget is 240 requests per minute per key. Analytics and request-log reads each have an additional independent 60 requests per minute per-key budget. Edge sequence writes have an additional independent 30 requests per minute per-key budget. Public free tools use separate per-IP limits. This contract intentionally excludes browser/dashboard routes, Stripe callbacks, self-hosted node check-in/downloads, proxy configuration distribution, trace/analytics ingestion, and other cluster-internal endpoints.",
    "contact": {
      "name": "Approximated Support",
      "url": "https://approximated.app/company/",
      "email": "support@approximated.app"
    },
    "license": {
      "name": "All rights reserved"
    },
    "x-source-of-truth": [
      "Approximated Phoenix router, controllers, views, schemas, and controller tests",
      "Approximated marketing API documentation"
    ],
    "x-intentionally-excluded-route-groups": [
      "dashboard and browser-session routes",
      "Stripe webhook receiver",
      "self-hosted node check-in and image downloads",
      "proxy config, mTLS bundle, trace-event, and analytics-ingest routes",
      "OAuth and MCP routes",
      "Caddy on-demand-TLS ask endpoint",
      "unscoped DNS widget issuance and original HTML widget APIs"
    ]
  },
  "externalDocs": {
    "description": "Human-readable Approximated documentation",
    "url": "https://approximated.app/docs/"
  },
  "servers": [
    {
      "url": "https://cloud.approximated.app",
      "description": "Production"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "tags": [
    {"name": "Virtual Hosts", "description": "Create and manage custom-domain proxy routes."},
    {"name": "DNS Checks", "description": "Compare live DNS answers with expected records."},
    {"name": "DNS Widget", "description": "Create scoped customer tokens for the embedded v2 widget and headless v2 browser API."},
    {"name": "Edge Verify", "description": "Manage browser-verification rules at virtual-host or cluster scope."},
    {"name": "L4 Rules", "description": "List, find, create, and revoke customer-visible network block rules."},
    {"name": "Edge Sequences", "description": "Cluster-scoped Caddy routing rule sequences managed via a declarative apply model. Create/update take the full desired definition (matcher groups + rules) and promote it atomically; version history and rollback are exposed."},
    {"name": "Analytics", "description": "Read request-volume and bandwidth aggregates."},
    {"name": "Request Logs", "description": "Read feature-gated recent request logs."},
    {"name": "Free Tools", "description": "Public, no-auth DNS, domain, HTTP, and TLS inspection tools."}
  ],
  "paths": {
    "/api/dns/v2/token": {
      "get": {
        "tags": [
          "DNS Widget"
        ],
        "operationId": "mintScopedDnsWidgetToken",
        "summary": "Create a scoped DNS widget customer token",
        "description": "Call from your authenticated backend with the proxy cluster API key, then pass the token to the embedded v2 widget or headless v2 client. Tokens are bound to the issuing API key and cluster. Each token lasts at most 630 seconds; renewals cannot extend the session beyond 24 hours from its original issuance. Deleting or rotating the issuing API key invalidates its tokens. Use /api/dns/v2 for token creation, instructions, verification and renewal. V2 browser operations reject unscoped tokens. Limits: 60 requests per IP and 60 per cluster per minute, plus the general 240/minute API-key budget. Limits are per 60 seconds on each Approximated application server. Keys for the same proxy cluster share its budget; renewal retains the session identity and does not reset its counters.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Scoped customer token; treat it as opaque and keep the API key on the server.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DnsWidgetTokenEnvelope"
                },
                "example": {
                  "token": "SFMyNTY.g3QAAAAB...signature"
                }
              }
            },
            "headers": {
              "Cache-Control": {
                "description": "Do not cache this response.",
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/DnsWidgetIssuanceRateLimited"
          }
        }
      }
    },
    "/api/dns/v2/token/renew": {
      "post": {
        "tags": [
          "DNS Widget"
        ],
        "operationId": "renewDnsWidgetTokenV2",
        "summary": "Renew an unexpired DNS widget token",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DnsWidgetTokenRequest"
              },
              "example": {
                "token": "SFMyNTY.g3QAAAAB...signature"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Replacement token for the same session, bounded by its original 24-hour deadline.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DnsWidgetTokenEnvelope"
                },
                "example": {
                  "token": "SFMyNTY.g3QAAAAC...signature"
                }
              }
            },
            "headers": {
              "Cache-Control": {
                "description": "Do not cache this response.",
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/DnsWidgetTokenRejected"
          },
          "429": {
            "$ref": "#/components/responses/DnsWidgetRateLimited"
          }
        },
        "description": "Renew an unexpired scoped customer token created by /api/dns/v2/token. Retains its original session start and identity; the replacement expires at the earlier of 630 seconds from renewal or the original 24-hour session deadline. A deleted or rotated API key, expired token, or expired session cannot be renewed. Obtain a new token from your authenticated backend using a current key. Limits: 120 requests per IP, 120 per cluster, and 12 per session per minute. Limits are per 60 seconds on each Approximated application server. Keys for the same proxy cluster share its budget; renewal retains the session identity and does not reset its counters."
      }
    },
    "/api/dns/v2/token/check-records-match-exactly": {
      "post": {
        "tags": [
          "DNS Widget"
        ],
        "operationId": "checkDnsWidgetRecordsMatchExactlyV2",
        "summary": "Check widget records for exact DNS answers",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DnsWidgetExactCheckRequest"
              },
              "example": {
                "token": "SFMyNTY.g3QAAAAB...signature",
                "records": [
                  {
                    "domain": "customer.example.com",
                    "host": "@",
                    "type": "cname",
                    "match_against": "proxy.example.net",
                    "value": "proxy.example.net"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Enriched widget record results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DnsWidgetExactCheckResponse"
                },
                "example": {
                  "records": [
                    {
                      "domain": "customer.example.com",
                      "host": "@",
                      "type": "cname",
                      "match_against": "proxy.example.net",
                      "value": "proxy.example.net",
                      "actual_values": [
                        "proxy.example.net"
                      ],
                      "match": true,
                      "combined_host": "customer",
                      "apex": "example",
                      "tld": "com",
                      "full": "customer.example.com",
                      "non_tld": "customer.example",
                      "subdomain": "customer"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Missing or malformed required JSON body parameters."
          },
          "403": {
            "$ref": "#/components/responses/DnsWidgetTokenRejected"
          },
          "429": {
            "$ref": "#/components/responses/DnsWidgetRateLimited"
          }
        },
        "description": "Browser API v2, authenticated by a scoped token created by /api/dns/v2/token. Limits: 240 requests per IP, 240 per cluster, and 120 per session per minute, shared with existence verification. Limits are per 60 seconds on each Approximated application server. Keys for the same proxy cluster share its budget; renewal retains the session identity and does not reset its counters."
      }
    },
    "/api/dns/v2/token/check-records-exist": {
      "post": {
        "tags": [
          "DNS Widget"
        ],
        "operationId": "checkDnsWidgetRecordsExistV2",
        "summary": "Check widget records for any matching DNS answer",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DnsWidgetExistCheckRequest"
              },
              "example": {
                "token": "SFMyNTY.g3QAAAAB...signature",
                "records": [
                  {
                    "address": "customer.example.com",
                    "type": "cname",
                    "match_against": "proxy.example.net"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Record results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DnsCheckResponse"
                },
                "example": {
                  "records": [
                    {
                      "address": "customer.example.com",
                      "type": "cname",
                      "match_against": "proxy.example.net",
                      "actual_values": false,
                      "match": false
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Missing or malformed required JSON body parameters."
          },
          "403": {
            "$ref": "#/components/responses/DnsWidgetTokenRejected"
          },
          "429": {
            "$ref": "#/components/responses/DnsWidgetRateLimited"
          }
        },
        "description": "Browser API v2, authenticated by a scoped token created by /api/dns/v2/token. Limits: 240 requests per IP, 240 per cluster, and 120 per session per minute, shared with exact-match verification. Limits are per 60 seconds on each Approximated application server. Keys for the same proxy cluster share its budget; renewal retains the session identity and does not reset its counters."
      }
    },
    "/api/dns/v2/check-records-match-exactly": {
      "post": {
        "tags": [
          "DNS Checks"
        ],
        "operationId": "checkDnsRecordsMatchExactlyV2",
        "summary": "Check that each DNS answer has exactly one expected value",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DnsCheckRequest"
              },
              "example": {
                "records": [
                  {
                    "address": "customer.example.com",
                    "type": "cname",
                    "match_against": "proxy.example.net"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "DNS comparison results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DnsCheckResponse"
                },
                "example": {
                  "records": [
                    {
                      "address": "customer.example.com",
                      "type": "cname",
                      "match_against": "proxy.example.net",
                      "actual_values": [
                        "proxy.example.net"
                      ],
                      "match": true
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/ApiRateLimited"
          }
        },
        "description": "Headless API v2. "
      }
    },
    "/api/dns/v2/check-records-exist": {
      "post": {
        "tags": [
          "DNS Checks"
        ],
        "operationId": "checkDnsRecordsExistV2",
        "summary": "Check that each expected value exists among the DNS answers",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DnsCheckRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "DNS comparison results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DnsCheckResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/ApiRateLimited"
          }
        },
        "description": "Headless API v2. "
      }
    },
    "/api/vhosts": {
      "post": {
        "tags": ["Virtual Hosts"],
        "operationId": "createVirtualHost",
        "summary": "Create a virtual host",
        "description": "Creates a custom-domain route on the API key's cluster. Supplying redirect_www=true also creates a non-billable www redirect. Rule/config propagation is asynchronous.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {"$ref": "#/components/schemas/VirtualHostCreate"},
              "example": {
                "incoming_address": "customer.example.com",
                "target_address": "origin.example.net",
                "target_ports": "443",
                "keep_host": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Virtual host created.",
            "headers": {"Location": {"schema": {"type": "string"}, "description": "Relative URL of the new virtual host."}},
            "content": {"application/json": {"schema": {"$ref": "#/components/schemas/VirtualHostEnvelope"}}}
          },
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "422": {"$ref": "#/components/responses/ValidationError"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      },
      "delete": {
        "tags": ["Virtual Hosts"],
        "operationId": "deleteVirtualHostByIncomingBody",
        "summary": "Delete a virtual host by incoming address",
        "description": "Compatibility endpoint. Prefer DELETE /api/vhosts/by/incoming/{incoming_address}.",
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncomingAddressRequest"}}}},
        "responses": {
          "200": {"$ref": "#/components/responses/DeletingVirtualHost"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "403": {"$ref": "#/components/responses/SuspendedVirtualHost"},
          "404": {"$ref": "#/components/responses/VirtualHostNotFound"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/vhosts/{id}": {
      "parameters": [{"$ref": "#/components/parameters/VirtualHostId"}],
      "get": {
        "tags": ["Virtual Hosts"],
        "operationId": "getVirtualHost",
        "summary": "Get a virtual host by ID",
        "description": "Returns the most recently stored monitoring result; it does not start a new check.",
        "responses": {
          "200": {"$ref": "#/components/responses/VirtualHost"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/VirtualHostNotFound"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      },
      "delete": {
        "tags": ["Virtual Hosts"],
        "operationId": "deleteVirtualHost",
        "summary": "Delete a virtual host by ID",
        "responses": {
          "200": {"$ref": "#/components/responses/DeletingVirtualHost"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "403": {"$ref": "#/components/responses/SuspendedVirtualHost"},
          "404": {"$ref": "#/components/responses/VirtualHostNotFound"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/vhosts/{id}/update": {
      "parameters": [{"$ref": "#/components/parameters/VirtualHostId"}],
      "post": {
        "tags": ["Virtual Hosts"],
        "operationId": "updateVirtualHost",
        "summary": "Update a virtual host by ID",
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/VirtualHostUpdate"}}}},
        "responses": {
          "200": {"$ref": "#/components/responses/VirtualHost"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "403": {"$ref": "#/components/responses/SuspendedVirtualHost"},
          "404": {"$ref": "#/components/responses/VirtualHostNotFound"},
          "422": {"$ref": "#/components/responses/ValidationError"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/vhosts/{id}/force-check": {
      "parameters": [{"$ref": "#/components/parameters/VirtualHostId"}],
      "get": {
        "tags": ["Virtual Hosts"],
        "operationId": "forceCheckVirtualHost",
        "summary": "Refresh and return a virtual host monitor result",
        "description": "At most 6 fresh checks per minute per API key. After that limit, the endpoint still returns 200 with the stored result and does not identify that a fresh check was skipped.",
        "responses": {
          "200": {"$ref": "#/components/responses/VirtualHost"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/VirtualHostNotFound"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/vhosts/offset/{offset}": {
      "get": {
        "tags": ["Virtual Hosts"],
        "operationId": "listVirtualHostsByOffset",
        "summary": "List virtual hosts using legacy offset pagination",
        "deprecated": true,
        "parameters": [{"name": "offset", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 0}}],
        "responses": {
          "200": {"description": "Virtual hosts.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/VirtualHostListEnvelope"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/cursor/vhosts/": {
      "get": {
        "tags": ["Virtual Hosts"],
        "operationId": "listVirtualHosts",
        "summary": "List the first cursor-paginated page of virtual hosts",
        "description": "Returns up to 100 virtual hosts. Pass a returned before_cursor or after_cursor to the directional cursor route.",
        "responses": {
          "200": {"description": "Cursor page.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/VirtualHostCursorEnvelope"}, "example": {"data": [{"id": 405455, "incoming_address": "customer.example.com", "target_address": "origin.example.net", "target_ports": "443", "keep_host": null, "lb_policy": "first", "lb_enabled": false, "lb_sticky": true, "rate_limit": null, "coraza_enabled": null, "mtls_client_cert": null, "upstreams": []}], "before_cursor": null, "after_cursor": "g3QAAAACZAACaWQ..."}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/cursor/vhosts/{cursor_direction}/{cursor}": {
      "get": {
        "tags": ["Virtual Hosts"],
        "operationId": "listVirtualHostsFromCursor",
        "summary": "List a directional cursor page of virtual hosts",
        "parameters": [
          {"$ref": "#/components/parameters/CursorDirection"},
          {"$ref": "#/components/parameters/Cursor"}
        ],
        "responses": {
          "200": {"description": "Cursor page.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/VirtualHostCursorEnvelope"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/vhosts/by/incoming/{incoming_address}": {
      "parameters": [{"$ref": "#/components/parameters/IncomingAddress"}],
      "get": {
        "tags": ["Virtual Hosts"],
        "operationId": "getVirtualHostByIncomingAddress",
        "summary": "Get a virtual host by incoming address",
        "description": "Use the POST alternative when the stored incoming address contains a scheme, path, or query string.",
        "responses": {
          "200": {"$ref": "#/components/responses/VirtualHost"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/VirtualHostNotFound"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      },
      "delete": {
        "tags": ["Virtual Hosts"],
        "operationId": "deleteVirtualHostByIncomingAddress",
        "summary": "Delete a virtual host by incoming address",
        "responses": {
          "200": {"$ref": "#/components/responses/DeletingVirtualHost"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "403": {"$ref": "#/components/responses/SuspendedVirtualHost"},
          "404": {"$ref": "#/components/responses/VirtualHostNotFound"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/vhosts/by/incoming/{incoming_address}/force-check": {
      "parameters": [{"$ref": "#/components/parameters/IncomingAddress"}],
      "get": {
        "tags": ["Virtual Hosts"],
        "operationId": "forceCheckVirtualHostByIncomingAddress",
        "summary": "Refresh and return monitoring by incoming address",
        "description": "At most 6 fresh checks per minute per key; when exhausted, the stored result is returned with 200.",
        "responses": {
          "200": {"$ref": "#/components/responses/VirtualHost"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/VirtualHostNotFound"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/vhosts/by/incoming": {
      "post": {
        "tags": ["Virtual Hosts"],
        "operationId": "getVirtualHostByIncomingAddressBody",
        "summary": "Get a virtual host by incoming address in JSON",
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncomingAddressRequest"}}}},
        "responses": {
          "200": {"$ref": "#/components/responses/VirtualHost"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/VirtualHostNotFound"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/vhosts/by/incoming/force-check": {
      "post": {
        "tags": ["Virtual Hosts"],
        "operationId": "forceCheckVirtualHostByIncomingAddressBody",
        "summary": "Refresh monitoring using an incoming address in JSON",
        "description": "At most 6 fresh checks per minute per key; when exhausted, the stored result is returned with 200.",
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncomingAddressRequest"}}}},
        "responses": {
          "200": {"$ref": "#/components/responses/VirtualHost"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/VirtualHostNotFound"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/vhosts/update/by/incoming": {
      "post": {
        "tags": ["Virtual Hosts"],
        "operationId": "updateVirtualHostByIncomingAddress",
        "summary": "Update a virtual host by incoming address",
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/VirtualHostUpdateByIncoming"}}}},
        "responses": {
          "200": {"$ref": "#/components/responses/VirtualHost"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "403": {"$ref": "#/components/responses/SuspendedVirtualHost"},
          "404": {"$ref": "#/components/responses/VirtualHostNotFound"},
          "422": {"$ref": "#/components/responses/ValidationError"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/vhosts/bulk/update/by/incoming": {
      "post": {
        "tags": ["Virtual Hosts"],
        "operationId": "bulkUpdateVirtualHostsByIncomingAddress",
        "summary": "Apply one update to up to 100 virtual hosts",
        "description": "Input addresses are de-duplicated and only the first 100 unique values are processed. incoming_address inside updates is ignored.",
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/VirtualHostBulkUpdate"}}}},
        "responses": {
          "200": {"description": "Per-address update results.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/VirtualHostBulkUpdateEnvelope"}}}},
          "400": {"$ref": "#/components/responses/BadRequest"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "422": {"$ref": "#/components/responses/ValidationError"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/vhosts/delete/by/incoming": {
      "post": {
        "tags": ["Virtual Hosts"],
        "operationId": "deleteVirtualHostByIncomingAddressPost",
        "summary": "Delete a virtual host by incoming address",
        "description": "Compatibility POST form of the by-incoming delete operation.",
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncomingAddressRequest"}}}},
        "responses": {
          "200": {"$ref": "#/components/responses/DeletingVirtualHost"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "403": {"$ref": "#/components/responses/SuspendedVirtualHost"},
          "404": {"$ref": "#/components/responses/VirtualHostNotFound"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/dns/v2/token/instructions": {
      "post": {
        "tags": [
          "DNS Widget"
        ],
        "operationId": "getDnsInstructionsWithToken",
        "summary": "Get provider-specific DNS setup instructions as structured JSON (browser)",
        "description": "Same structured JSON as /api/dns/v2/instructions, authenticated with a scoped customer token created by /api/dns/v2/token in the JSON body. CORS-enabled for any origin. Limits: 120 requests per IP, 120 per cluster, and 60 per session per minute. Limits are per 60 seconds on each Approximated application server. Keys for the same proxy cluster share its budget; renewal retains the session identity and does not reset its counters.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DnsInstructionsTokenRequest"
              },
              "example": {
                "token": "SFMyNTY.g3QAAAAB...signature",
                "domain": "app.customer.com",
                "records": [
                  {
                    "type": "CNAME",
                    "host": "www",
                    "value": "{domain}",
                    "ttl": 3600
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Instructions grouped by registrable domain.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DnsInstructionsResponse"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/DnsWidgetTokenRejected"
          },
          "422": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DnsInstructionsError"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/DnsWidgetRateLimited"
          }
        }
      }
    },
    "/api/dns/v2/instructions": {
      "post": {
        "tags": ["DNS Widget"],
        "operationId": "getDnsInstructions",
        "summary": "Get provider-specific DNS setup instructions as structured JSON (server-side)",
        "description": "Headless mode. Detects the DNS provider for each record's domain and returns provider-specific steps as data for you to render.",
        "security": [{"apiKey": []}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DnsInstructionsRequest"}, "example": {"domain": "app.customer.com", "records": [{"type": "CNAME", "host": "www", "value": "{domain}", "ttl": 3600}]}}}},
        "responses": {
          "200": {"description": "Instructions grouped by registrable domain.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DnsInstructionsResponse"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "422": {"description": "Invalid request.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DnsInstructionsError"}}}},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/edge-verify/rules/by/incoming": {
      "post": {
        "tags": ["Edge Verify"],
        "operationId": "listEdgeVerifyRulesByIncomingAddress",
        "summary": "List rules for one virtual host",
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/IncomingAddressRequest"}}}},
        "responses": {
          "200": {"description": "Rules.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeVerifyRuleListEnvelope"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/JsonNotFound"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/edge-verify/rules/create/by/incoming": {
      "post": {
        "tags": ["Edge Verify"],
        "operationId": "createEdgeVerifyRuleByIncomingAddress",
        "summary": "Create a rule for one virtual host",
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeVerifyVhostCreate"}, "example": {"incoming_address": "customer.example.com", "path_pattern": "/contact", "methods": ["POST"], "mode": "monitor"}}}},
        "responses": {
          "201": {"description": "Rule created.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeVerifyRuleEnvelope"}, "example": {"data": {"id": 91, "virtual_host_id": 405455, "proxy_server_id": null, "path_pattern": "/contact", "methods": ["POST"], "mode": "monitor", "inserted_at": "2026-08-05T16:30:00", "updated_at": "2026-08-05T16:30:00"}}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/JsonNotFound"},
          "422": {"$ref": "#/components/responses/ValidationError"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/edge-verify/rules/update/by/incoming": {
      "post": {
        "tags": ["Edge Verify"],
        "operationId": "updateEdgeVerifyRuleByIncomingAddress",
        "summary": "Update a rule for one virtual host",
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeVerifyVhostUpdate"}}}},
        "responses": {
          "200": {"description": "Rule updated.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeVerifyRuleEnvelope"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/JsonNotFound"},
          "422": {"$ref": "#/components/responses/ValidationError"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/edge-verify/rules/delete/by/incoming": {
      "post": {
        "tags": ["Edge Verify"],
        "operationId": "deleteEdgeVerifyRuleByIncomingAddress",
        "summary": "Delete a rule for one virtual host",
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeVerifyVhostDelete"}}}},
        "responses": {
          "204": {"description": "Rule deleted."},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/JsonNotFound"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/edge-verify/cluster-rules": {
      "get": {
        "tags": ["Edge Verify"],
        "operationId": "listClusterEdgeVerifyRules",
        "summary": "List cluster-wide rules",
        "responses": {
          "200": {"description": "Rules.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeVerifyRuleListEnvelope"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      },
      "post": {
        "tags": ["Edge Verify"],
        "operationId": "createClusterEdgeVerifyRule",
        "summary": "Create a cluster-wide rule",
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeVerifyRuleWrite"}}}},
        "responses": {
          "201": {"description": "Rule created.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeVerifyRuleEnvelope"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "422": {"$ref": "#/components/responses/ValidationError"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/edge-verify/cluster-rules/{id}/update": {
      "parameters": [{"$ref": "#/components/parameters/RuleId"}],
      "post": {
        "tags": ["Edge Verify"],
        "operationId": "updateClusterEdgeVerifyRule",
        "summary": "Update a cluster-wide rule",
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeVerifyRulePatch"}}}},
        "responses": {
          "200": {"description": "Rule updated.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeVerifyRuleEnvelope"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/JsonNotFound"},
          "422": {"$ref": "#/components/responses/ValidationError"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/edge-verify/cluster-rules/{id}": {
      "parameters": [{"$ref": "#/components/parameters/RuleId"}],
      "delete": {
        "tags": ["Edge Verify"],
        "operationId": "deleteClusterEdgeVerifyRule",
        "summary": "Delete a cluster-wide rule",
        "responses": {
          "204": {"description": "Rule deleted."},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/JsonNotFound"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/cursor/l4-rules": {
      "get": {
        "tags": ["L4 Rules"],
        "operationId": "listL4Rules",
        "summary": "List live L4 rules for the API key's cluster",
        "description": "Returns up to 100 non-revoked, non-expired rules.",
        "responses": {
          "200": {"description": "Cursor page.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/L4RuleListEnvelope"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/cursor/l4-rules/{cursor_direction}/{cursor}": {
      "get": {
        "tags": ["L4 Rules"],
        "operationId": "listL4RulesFromCursor",
        "summary": "List a directional cursor page of L4 rules",
        "parameters": [{"$ref": "#/components/parameters/CursorDirection"}, {"$ref": "#/components/parameters/Cursor"}],
        "responses": {
          "200": {"description": "Cursor page.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/L4RuleListEnvelope"}}}},
          "400": {"description": "Invalid cursor.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SimpleError"}, "example": {"error": "invalid cursor"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/l4-rules/lookup": {
      "post": {
        "tags": ["L4 Rules"],
        "operationId": "lookupL4Rule",
        "summary": "Find a live rule by match type and value",
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/L4RuleLookup"}}}},
        "responses": {
          "200": {"description": "Matching rule.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/L4RuleEnvelope"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/SimpleJsonNotFound"},
          "422": {"$ref": "#/components/responses/ValidationError"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/l4-rules": {
      "post": {
        "tags": ["L4 Rules"],
        "operationId": "createL4Rule",
        "summary": "Create a cluster-scoped block rule",
        "description": "Customer API callers may only create block rules. IP values are normalized to CIDR form.",
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/L4RuleCreate"}, "example": {"match_type": "ip", "value": "203.0.113.8", "action": "block", "reason": "abusive scraper"}}}},
        "responses": {
          "201": {"description": "Rule created.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/L4RuleEnvelope"}, "example": {"data": {"id": 314, "proxy_server_id": 42, "match_type": "ip", "value": "203.0.113.8/32", "action": "block", "reason": "abusive scraper", "source": "customer", "expires_at": null, "inserted_at": "2026-08-05T16:30:00", "updated_at": "2026-08-05T16:30:00"}}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "409": {"description": "A non-customer-revokable rule conflicts with the requested decision.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/L4Conflict"}}}},
          "422": {"$ref": "#/components/responses/ValidationError"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/l4-rules/{id}": {
      "parameters": [{"$ref": "#/components/parameters/RuleId"}],
      "delete": {
        "tags": ["L4 Rules"],
        "operationId": "deleteL4Rule",
        "summary": "Revoke a customer-revokable L4 rule",
        "responses": {
          "204": {"description": "Rule revoked."},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "403": {"description": "The rule was created by an operator and cannot be revoked by a customer.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SimpleError"}, "example": {"error": "not_revokable_by_customer"}}}},
          "404": {"$ref": "#/components/responses/SimpleJsonNotFound"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/cursor/edge-sequences": {
      "get": {
        "tags": ["Edge Sequences"],
        "operationId": "listEdgeSequences",
        "summary": "List edge sequences for the API key's cluster",
        "description": "Returns up to 100 sequences in cluster execution order, each with its live definition embedded. Any item's data object is itself a valid apply payload.",
        "security": [{"apiKey": []}],
        "responses": {
          "200": {"description": "Cursor page.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeSequenceListEnvelope"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/cursor/edge-sequences/{cursor_direction}/{cursor}": {
      "get": {
        "tags": ["Edge Sequences"],
        "operationId": "listEdgeSequencesFromCursor",
        "summary": "List a directional cursor page of edge sequences",
        "security": [{"apiKey": []}],
        "parameters": [{"$ref": "#/components/parameters/CursorDirection"}, {"$ref": "#/components/parameters/Cursor"}],
        "responses": {
          "200": {"description": "Cursor page.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeSequenceListEnvelope"}}}},
          "400": {"description": "Invalid cursor.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SimpleError"}, "example": {"error": "invalid cursor"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/edge-sequences": {
      "post": {
        "tags": ["Edge Sequences"],
        "operationId": "createEdgeSequence",
        "summary": "Create an edge sequence from a full declarative definition",
        "description": "Validates the whole definition, creates the sequence at the end of the cluster's execution order, and promotes it live atomically (version 1). active defaults to true on create. With dry_run true the definition is validated and all warnings are computed but nothing is written, returning 200 with data null. Counts against the additional 30 requests/minute per-key write budget.",
        "security": [{"apiKey": []}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"allOf": [{"$ref": "#/components/schemas/EdgeSequenceApply"}, {"required": ["name"]}], "description": "name is required on create."}, "example": {"name": "Block legacy admin panel", "description": "Deny requests to /admin on every domain", "matcher_groups": [{"matchers": [{"type": "path", "data": {"paths": ["/admin*"]}}]}], "rules": [{"type": "blocker", "name": "Deny admin", "config": {"status_code": "403", "body": "Forbidden"}}]}}}},
        "responses": {
          "200": {"description": "Dry run only: the definition validated, nothing was written.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeSequenceEnvelope"}, "example": {"data": null, "warnings": {}}}}},
          "201": {"description": "Sequence created and promoted live.", "headers": {"Location": {"description": "Path of the created sequence.", "schema": {"type": "string", "example": "/api/edge-sequences/12"}}}, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeSequenceEnvelope"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "422": {"description": "Validation failed. errors maps JSON Pointers into the payload to lists of coded problems.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeSequenceErrors"}, "example": {"errors": {"/matcher_groups/0/matchers/1/type": [{"code": "unknown_type", "message": "unknown matcher type"}], "/rules/0/config/max_events": [{"code": "required", "message": "can't be blank"}]}}}}},
          "429": {"$ref": "#/components/responses/EdgeSequenceWriteRateLimited"},
          "503": {"$ref": "#/components/responses/EdgeSequenceRegexValidationUnavailable"}
        }
      }
    },
    "/api/edge-sequences/{id}": {
      "parameters": [{"$ref": "#/components/parameters/EdgeSequenceId"}],
      "get": {
        "tags": ["Edge Sequences"],
        "operationId": "getEdgeSequence",
        "summary": "Read an edge sequence and its live definition",
        "description": "The data object round-trips: it is a valid body for the update endpoint.",
        "security": [{"apiKey": []}],
        "responses": {
          "200": {"description": "The sequence. warnings is always an empty map on reads.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeSequenceEnvelope"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/SimpleJsonNotFound"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      },
      "delete": {
        "tags": ["Edge Sequences"],
        "operationId": "deleteEdgeSequence",
        "summary": "Delete an edge sequence",
        "description": "Deletes the sequence and its whole version history. Counts against the additional 30 requests/minute per-key write budget.",
        "security": [{"apiKey": []}],
        "responses": {
          "204": {"description": "Sequence deleted."},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/SimpleJsonNotFound"},
          "429": {"$ref": "#/components/responses/EdgeSequenceWriteRateLimited"}
        }
      }
    },
    "/api/edge-sequences/{id}/update": {
      "parameters": [{"$ref": "#/components/parameters/EdgeSequenceId"}],
      "post": {
        "tags": ["Edge Sequences"],
        "operationId": "updateEdgeSequence",
        "summary": "Replace an edge sequence's definition with a new live version",
        "description": "Full replace: the payload is the complete desired definition, not a patch. The previous live version and any unpromoted dashboard draft are demoted to version history and the new definition is promoted live atomically as the next version number. name may be omitted to keep the current name; an omitted active preserves the current value. rate_limit rule counters survive updates: zone state is carried over by pairing rate_limit rules positionally with the previous live version's. With dry_run true nothing is written and data is null. Counts against the additional 30 requests/minute per-key write budget.",
        "security": [{"apiKey": []}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeSequenceApply"}}}},
        "responses": {
          "200": {"description": "New version promoted live, or dry run validated (data null).", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeSequenceEnvelope"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/SimpleJsonNotFound"},
          "422": {"description": "Validation failed. errors maps JSON Pointers into the payload to lists of coded problems; a non-boolean dry_run fails with invalid_type at /dry_run.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeSequenceErrors"}, "example": {"errors": {"/dry_run": [{"code": "invalid_type", "message": "must be a boolean"}]}}}}},
          "429": {"$ref": "#/components/responses/EdgeSequenceWriteRateLimited"},
          "503": {"$ref": "#/components/responses/EdgeSequenceRegexValidationUnavailable"}
        }
      }
    },
    "/api/edge-sequences/{id}/activate": {
      "parameters": [{"$ref": "#/components/parameters/EdgeSequenceId"}],
      "post": {
        "tags": ["Edge Sequences"],
        "operationId": "activateEdgeSequence",
        "summary": "Activate an edge sequence",
        "description": "Sets active to true without touching the definition. Activating an already-active sequence is a safe no-op. Counts against the additional 30 requests/minute per-key write budget.",
        "security": [{"apiKey": []}],
        "responses": {
          "200": {"description": "The sequence after activation.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeSequenceEnvelope"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/SimpleJsonNotFound"},
          "422": {"$ref": "#/components/responses/EdgeSequenceWriteFailed"},
          "429": {"$ref": "#/components/responses/EdgeSequenceWriteRateLimited"}
        }
      }
    },
    "/api/edge-sequences/{id}/deactivate": {
      "parameters": [{"$ref": "#/components/parameters/EdgeSequenceId"}],
      "post": {
        "tags": ["Edge Sequences"],
        "operationId": "deactivateEdgeSequence",
        "summary": "Deactivate an edge sequence",
        "description": "Sets active to false; the definition and version history are kept and the sequence stops applying to traffic. Counts against the additional 30 requests/minute per-key write budget.",
        "security": [{"apiKey": []}],
        "responses": {
          "200": {"description": "The sequence after deactivation.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeSequenceEnvelope"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/SimpleJsonNotFound"},
          "422": {"$ref": "#/components/responses/EdgeSequenceWriteFailed"},
          "429": {"$ref": "#/components/responses/EdgeSequenceWriteRateLimited"}
        }
      }
    },
    "/api/edge-sequences/{id}/reorder": {
      "parameters": [{"$ref": "#/components/parameters/EdgeSequenceId"}],
      "post": {
        "tags": ["Edge Sequences"],
        "operationId": "reorderEdgeSequence",
        "summary": "Move an edge sequence to a position in the cluster's execution order",
        "description": "position is 0-based and clamped into the valid range; other sequences shift accordingly. Counts against the additional 30 requests/minute per-key write budget.",
        "security": [{"apiKey": []}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeSequenceReorder"}, "example": {"position": 0}}}},
        "responses": {
          "200": {"description": "The sequence with its new order.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeSequenceEnvelope"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/SimpleJsonNotFound"},
          "422": {"description": "position was missing or not a JSON integer.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeSequenceErrors"}, "example": {"errors": {"/position": [{"code": "invalid_type", "message": "must be an integer"}]}}}}},
          "429": {"$ref": "#/components/responses/EdgeSequenceWriteRateLimited"}
        }
      }
    },
    "/api/edge-sequences/{id}/versions": {
      "parameters": [{"$ref": "#/components/parameters/EdgeSequenceId"}],
      "get": {
        "tags": ["Edge Sequences"],
        "operationId": "listEdgeSequenceVersions",
        "summary": "List an edge sequence's version history",
        "description": "Returns up to 10 versions, newest first. cursors.older and cursors.newer are integer cursors for the directional variant (null when there is no more in that direction); they are opaque and are not version numbers.",
        "security": [{"apiKey": []}],
        "responses": {
          "200": {"description": "Version history page.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeSequenceVersionListEnvelope"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/SimpleJsonNotFound"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/edge-sequences/{id}/versions/{direction}/{cursor}": {
      "parameters": [{"$ref": "#/components/parameters/EdgeSequenceId"}, {"$ref": "#/components/parameters/VersionDirection"}, {"$ref": "#/components/parameters/VersionCursor"}],
      "get": {
        "tags": ["Edge Sequences"],
        "operationId": "listEdgeSequenceVersionsFromCursor",
        "summary": "List a directional page of an edge sequence's version history",
        "security": [{"apiKey": []}],
        "responses": {
          "200": {"description": "Version history page.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeSequenceVersionListEnvelope"}}}},
          "400": {"description": "The cursor was not an integer.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SimpleError"}, "example": {"error": "invalid cursor"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/SimpleJsonNotFound"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/edge-sequences/{id}/versions/{version}/activate": {
      "parameters": [{"$ref": "#/components/parameters/EdgeSequenceId"}, {"$ref": "#/components/parameters/VersionNumber"}],
      "post": {
        "tags": ["Edge Sequences"],
        "operationId": "activateEdgeSequenceVersion",
        "summary": "Roll back by promoting a historical version live",
        "description": "version is the version number from the version history, not a cursor or database id. Activating the already-live version is a safe no-op. Counts against the additional 30 requests/minute per-key write budget.",
        "security": [{"apiKey": []}],
        "responses": {
          "200": {"description": "The sequence with the requested version live.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeSequenceEnvelope"}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"description": "Sequence not found or no such version number for it.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SimpleError"}, "example": {"error": "not_found"}}}},
          "429": {"$ref": "#/components/responses/EdgeSequenceWriteRateLimited"}
        }
      }
    },
    "/api/monitoring/health-check": {
      "get": {
        "tags": ["Analytics"],
        "operationId": "getLatestClusterHealthCheck",
        "summary": "Get the latest proxy cluster health check",
        "description": "Returns the most recent regional health result for the cluster attached to the API key. data is null when no health check exists yet.",
        "security": [{"apiKey": []}],
        "responses": {
          "200": {"description": "Latest health check.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HealthCheckEnvelope"}, "examples": {"available": {"value": {"data": {"id": 42, "results": {"iad": true, "lhr": false}, "human_readable_results": {"Ashburn, Virginia (US)": "Healthy", "London, United Kingdom": "Repairing"}, "utc_last_updated": "2026-08-05T16:30:00", "human_readable_last_updated": "2 minutes ago"}}}, "not_yet_checked": {"value": {"data": null}}}}}},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "429": {"$ref": "#/components/responses/ApiRateLimited"}
        }
      }
    },
    "/api/vhosts/{id}/analytics": {
      "parameters": [{"$ref": "#/components/parameters/VirtualHostId"}],
      "get": {
        "tags": ["Analytics"],
        "operationId": "getVirtualHostAnalyticsSeries",
        "summary": "Get a virtual host request series",
        "description": "Bucket granularity is selected automatically: up to 6 hours uses raw_1m, up to 30 days uses h_1h, and longer windows use d_1d.",
        "parameters": [{"$ref": "#/components/parameters/AnalyticsStart"}, {"$ref": "#/components/parameters/AnalyticsEnd"}],
        "responses": {
          "200": {"description": "Time series.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AnalyticsSeriesEnvelope"}}}},
          "400": {"$ref": "#/components/responses/AnalyticsBadRequest"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/SimpleJsonNotFound"},
          "429": {"$ref": "#/components/responses/AnalyticsRateLimited"},
          "500": {"$ref": "#/components/responses/InternalJsonError"}
        }
      }
    },
    "/api/vhosts/{id}/analytics/top": {
      "parameters": [{"$ref": "#/components/parameters/VirtualHostId"}],
      "get": {
        "tags": ["Analytics"],
        "operationId": "getVirtualHostAnalyticsTop",
        "summary": "Get top dimensions for a virtual host",
        "parameters": [{"$ref": "#/components/parameters/AnalyticsStart"}, {"$ref": "#/components/parameters/AnalyticsEnd"}, {"$ref": "#/components/parameters/AnalyticsDimension"}, {"$ref": "#/components/parameters/AnalyticsLimit"}],
        "responses": {
          "200": {"description": "Top values.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AnalyticsTopEnvelope"}}}},
          "400": {"$ref": "#/components/responses/AnalyticsBadRequest"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/SimpleJsonNotFound"},
          "429": {"$ref": "#/components/responses/AnalyticsRateLimited"},
          "500": {"$ref": "#/components/responses/InternalJsonError"}
        }
      }
    },
    "/api/proxy-servers/{id}/analytics": {
      "parameters": [{"$ref": "#/components/parameters/ProxyServerId"}],
      "get": {
        "tags": ["Analytics"],
        "operationId": "getClusterAnalyticsSeries",
        "summary": "Get a proxy cluster request series",
        "parameters": [{"$ref": "#/components/parameters/AnalyticsStart"}, {"$ref": "#/components/parameters/AnalyticsEnd"}],
        "responses": {
          "200": {"description": "Time series.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AnalyticsSeriesEnvelope"}}}},
          "400": {"$ref": "#/components/responses/AnalyticsBadRequest"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/SimpleJsonNotFound"},
          "429": {"$ref": "#/components/responses/AnalyticsRateLimited"},
          "500": {"$ref": "#/components/responses/InternalJsonError"}
        }
      }
    },
    "/api/proxy-servers/{id}/analytics/top": {
      "parameters": [{"$ref": "#/components/parameters/ProxyServerId"}],
      "get": {
        "tags": ["Analytics"],
        "operationId": "getClusterAnalyticsTop",
        "summary": "Get top dimensions for a proxy cluster",
        "parameters": [{"$ref": "#/components/parameters/AnalyticsStart"}, {"$ref": "#/components/parameters/AnalyticsEnd"}, {"$ref": "#/components/parameters/AnalyticsDimension"}, {"$ref": "#/components/parameters/AnalyticsLimit"}],
        "responses": {
          "200": {"description": "Top values.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AnalyticsTopEnvelope"}}}},
          "400": {"$ref": "#/components/responses/AnalyticsBadRequest"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/SimpleJsonNotFound"},
          "429": {"$ref": "#/components/responses/AnalyticsRateLimited"},
          "500": {"$ref": "#/components/responses/InternalJsonError"}
        }
      }
    },
    "/api/proxy-servers/{id}/logs": {
      "parameters": [{"$ref": "#/components/parameters/ProxyServerId"}],
      "get": {
        "tags": ["Request Logs"],
        "operationId": "getClusterRequestLogs",
        "summary": "Get recent request logs for a proxy cluster",
        "description": "Available only when customer-facing request logs are enabled for the cluster. A disabled cluster returns the same 404 as an unknown cluster.",
        "parameters": [{"$ref": "#/components/parameters/LogCursor"}, {"$ref": "#/components/parameters/LogLimit"}, {"$ref": "#/components/parameters/LogWindow"}, {"$ref": "#/components/parameters/LogHost"}, {"$ref": "#/components/parameters/LogStatus"}, {"$ref": "#/components/parameters/LogStatusClass"}, {"$ref": "#/components/parameters/LogMethod"}, {"$ref": "#/components/parameters/LogDisposition"}, {"$ref": "#/components/parameters/LogPathPrefix"}, {"$ref": "#/components/parameters/LogClientIp"}],
        "responses": {
          "200": {"description": "Request log page.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RequestLogEnvelope"}}}},
          "400": {"$ref": "#/components/responses/LogsBadRequest"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/SimpleJsonNotFound"},
          "429": {"$ref": "#/components/responses/LogsRateLimited"},
          "503": {"description": "Log storage is unavailable.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SimpleError"}, "example": {"error": "logs_unavailable"}}}}
        }
      }
    },
    "/api/vhosts/{id}/logs": {
      "parameters": [{"$ref": "#/components/parameters/VirtualHostId"}],
      "get": {
        "tags": ["Request Logs"],
        "operationId": "getVirtualHostRequestLogs",
        "summary": "Get recent request logs for one virtual host",
        "description": "Available only when customer-facing request logs are enabled for the owning cluster.",
        "parameters": [{"$ref": "#/components/parameters/LogCursor"}, {"$ref": "#/components/parameters/LogLimit"}, {"$ref": "#/components/parameters/LogWindow"}, {"$ref": "#/components/parameters/LogHost"}, {"$ref": "#/components/parameters/LogStatus"}, {"$ref": "#/components/parameters/LogStatusClass"}, {"$ref": "#/components/parameters/LogMethod"}, {"$ref": "#/components/parameters/LogDisposition"}, {"$ref": "#/components/parameters/LogPathPrefix"}, {"$ref": "#/components/parameters/LogClientIp"}],
        "responses": {
          "200": {"description": "Request log page.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RequestLogEnvelope"}}}},
          "400": {"$ref": "#/components/responses/LogsBadRequest"},
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "404": {"$ref": "#/components/responses/SimpleJsonNotFound"},
          "429": {"$ref": "#/components/responses/LogsRateLimited"},
          "503": {"description": "Log storage is unavailable.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SimpleError"}, "example": {"error": "logs_unavailable"}}}}
        }
      }
    },
    "/api/tools/ping": {
      "get": {
        "tags": ["Free Tools"],
        "operationId": "pingFreeTools",
        "summary": "Check free-tools API availability",
        "description": "Public and intentionally not rate-limited.",
        "security": [],
        "responses": {
          "200": {"description": "Service is available.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolPingEnvelope"}, "example": {"ok": true, "data": {"pong": true}}}}}
        }
      }
    },
    "/api/tools/dns-records": {
      "get": {
        "tags": ["Free Tools"],
        "operationId": "lookupDnsRecords",
        "summary": "Look up multiple DNS record types",
        "security": [],
        "parameters": [
          {"$ref": "#/components/parameters/ToolDomain"},
          {"name": "types", "in": "query", "description": "Comma-separated subset. Omit for A, AAAA, CNAME, MX, TXT, NS, and SOA.", "schema": {"type": "string", "example": "a,aaaa,cname,mx,txt,ns,soa"}}
        ],
        "responses": {
          "200": {"description": "Record map. Each requested type is present. A partial resolver failure degrades that type to an empty array and still returns 200; only failure of every requested type returns 502. Therefore an empty array can mean either an authoritative empty answer or a degraded per-type lookup.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolDnsRecordsEnvelope"}}}},
          "400": {"$ref": "#/components/responses/ToolInvalidInput"},
          "429": {"$ref": "#/components/responses/ToolRateLimited"},
          "502": {"$ref": "#/components/responses/ToolUpstreamError"}
        }
      }
    },
    "/api/tools/txt": {
      "get": {
        "tags": ["Free Tools"], "operationId": "lookupTxtRecords", "summary": "Look up and categorize TXT records", "security": [],
        "parameters": [{"$ref": "#/components/parameters/ToolDomain"}],
        "responses": {
          "200": {"description": "TXT records.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolTxtEnvelope"}}}},
          "400": {"$ref": "#/components/responses/ToolInvalidInput"}, "429": {"$ref": "#/components/responses/ToolRateLimited"}, "502": {"$ref": "#/components/responses/ToolUpstreamError"}
        }
      }
    },
    "/api/tools/spf": {
      "get": {
        "tags": ["Free Tools"], "operationId": "checkSpfRecord", "summary": "Parse a domain's SPF record", "security": [],
        "parameters": [{"$ref": "#/components/parameters/ToolDomain"}],
        "responses": {
          "200": {"description": "SPF result. No record is a successful negative result.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolSpfEnvelope"}}}},
          "400": {"$ref": "#/components/responses/ToolInvalidInput"}, "429": {"$ref": "#/components/responses/ToolRateLimited"}, "502": {"$ref": "#/components/responses/ToolUpstreamError"}
        }
      }
    },
    "/api/tools/dmarc": {
      "get": {
        "tags": ["Free Tools"], "operationId": "checkDmarcRecord", "summary": "Parse a domain's DMARC record", "security": [],
        "parameters": [{"$ref": "#/components/parameters/ToolDomain"}],
        "responses": {
          "200": {"description": "DMARC result. No record is a successful negative result.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolDmarcEnvelope"}}}},
          "400": {"$ref": "#/components/responses/ToolInvalidInput"}, "429": {"$ref": "#/components/responses/ToolRateLimited"}, "502": {"$ref": "#/components/responses/ToolUpstreamError"}
        }
      }
    },
    "/api/tools/dkim": {
      "get": {
        "tags": ["Free Tools"], "operationId": "checkDkimRecord", "summary": "Parse a DKIM selector record", "security": [],
        "parameters": [
          {"$ref": "#/components/parameters/ToolDomain"},
          {"name": "selector", "in": "query", "required": true, "schema": {"type": "string", "minLength": 1, "maxLength": 63, "pattern": "^[A-Za-z0-9._-]+$", "example": "google"}}
        ],
        "responses": {
          "200": {"description": "DKIM result. No record is a successful negative result.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolDkimEnvelope"}}}},
          "400": {"$ref": "#/components/responses/ToolInvalidInput"}, "429": {"$ref": "#/components/responses/ToolRateLimited"}, "502": {"$ref": "#/components/responses/ToolUpstreamError"}
        }
      }
    },
    "/api/tools/cname": {
      "get": {
        "tags": ["Free Tools"], "operationId": "lookupCname", "summary": "Resolve a CNAME chain and optionally generate setup instructions", "security": [],
        "parameters": [
          {"$ref": "#/components/parameters/ToolDomain"},
          {"name": "target", "in": "query", "description": "When present, adds provider detection and instructions for pointing domain to target.", "schema": {"type": "string", "format": "hostname", "example": "target.example.net"}}
        ],
        "responses": {
          "200": {"description": "CNAME lookup or generator result.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolCnameEnvelope"}}}},
          "400": {"$ref": "#/components/responses/ToolInvalidInput"}, "429": {"$ref": "#/components/responses/ToolRateLimited"}, "502": {"$ref": "#/components/responses/ToolUpstreamError"}
        }
      }
    },
    "/api/tools/reverse-ip": {
      "get": {
        "tags": ["Free Tools"], "operationId": "reverseIpLookup", "summary": "Perform a PTR lookup", "security": [],
        "parameters": [{"name": "ip", "in": "query", "required": true, "schema": {"type": "string", "example": "8.8.8.8"}}],
        "responses": {
          "200": {"description": "PTR answers.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolReverseIpEnvelope"}}}},
          "400": {"$ref": "#/components/responses/ToolInvalidInput"}, "429": {"$ref": "#/components/responses/ToolRateLimited"}, "502": {"$ref": "#/components/responses/ToolUpstreamError"}
        }
      }
    },
    "/api/tools/propagation": {
      "get": {
        "tags": ["Free Tools"], "operationId": "checkDnsPropagation", "summary": "Compare A records across public resolvers", "security": [],
        "description": "Per-resolver failures are returned inside a successful result. consistent is true when all successful resolvers agree; zero successful resolvers currently also yields true.",
        "parameters": [{"$ref": "#/components/parameters/ToolDomain"}],
        "responses": {
          "200": {"description": "Resolver results.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolPropagationEnvelope"}}}},
          "400": {"$ref": "#/components/responses/ToolInvalidInput"}, "429": {"$ref": "#/components/responses/ToolRateLimited"}
        }
      }
    },
    "/api/tools/status": {
      "get": {
        "tags": ["Free Tools"], "operationId": "checkWebsiteStatus", "summary": "Check an HTTP URL without following redirects", "security": [],
        "description": "SSRF blocks and transport failures are successful HTTP 200 responses with data.up=false and data.error set.",
        "parameters": [{"$ref": "#/components/parameters/ToolUrl"}],
        "responses": {
          "200": {"description": "HTTP status or in-band block/failure result.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolStatusEnvelope"}, "examples": {"reachable": {"value": {"ok": true, "data": {"url": "https://example.com/", "up": true, "status": 200, "response_time_ms": 87, "final_url": "https://example.com/", "error": null}}}, "blocked_private_host": {"value": {"ok": true, "data": {"url": "http://10.0.0.1/", "up": false, "status": null, "response_time_ms": null, "final_url": "http://10.0.0.1/", "error": "blocked_private_address"}}}}}}},
          "400": {"$ref": "#/components/responses/ToolInvalidInput"}, "429": {"$ref": "#/components/responses/ToolRateLimited"}
        }
      }
    },
    "/api/tools/headers": {
      "get": {
        "tags": ["Free Tools"], "operationId": "inspectHttpHeaders", "summary": "Inspect response and security headers", "security": [],
        "description": "SSRF blocks and transport failures are successful HTTP 200 responses with an empty header map and data.error set.",
        "parameters": [{"$ref": "#/components/parameters/ToolUrl"}],
        "responses": {
          "200": {"description": "HTTP headers or in-band block/failure result.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolHeadersEnvelope"}}}},
          "400": {"$ref": "#/components/responses/ToolInvalidInput"}, "429": {"$ref": "#/components/responses/ToolRateLimited"}
        }
      }
    },
    "/api/tools/redirects": {
      "get": {
        "tags": ["Free Tools"], "operationId": "inspectRedirectChain", "summary": "Follow and inspect an HTTP redirect chain", "security": [],
        "description": "Every hop is SSRF-checked. Blocks, loops, hop limits, and transport failures are represented in-band in a successful HTTP 200 response.",
        "parameters": [{"$ref": "#/components/parameters/ToolUrl"}],
        "responses": {
          "200": {"description": "Redirect chain or in-band stop result.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolRedirectsEnvelope"}}}},
          "400": {"$ref": "#/components/responses/ToolInvalidInput"}, "429": {"$ref": "#/components/responses/ToolRateLimited"}
        }
      }
    },
    "/api/tools/ssl": {
      "get": {
        "tags": ["Free Tools"], "operationId": "inspectTlsCertificate", "summary": "Inspect a host's leaf TLS certificate", "security": [],
        "parameters": [
          {"name": "host", "in": "query", "required": true, "schema": {"type": "string", "format": "hostname", "example": "example.com"}},
          {"name": "port", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 65535, "default": 443}}
        ],
        "responses": {
          "200": {"description": "Certificate details.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolSslEnvelope"}}}},
          "400": {"description": "Invalid input or private/unresolvable host.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolError"}}}},
          "429": {"$ref": "#/components/responses/ToolRateLimited"},
          "502": {"$ref": "#/components/responses/ToolUpstreamError"},
          "504": {"description": "TLS connection timed out.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolError"}, "example": {"ok": false, "error": "upstream_timeout", "message": "Timed out connecting to example.com:443."}}}}
        }
      }
    },
    "/api/tools/whois": {
      "get": {
        "tags": ["Free Tools"], "operationId": "lookupDomainRegistration", "summary": "Look up domain registration using RDAP", "security": [],
        "parameters": [{"$ref": "#/components/parameters/ToolDomain"}],
        "responses": {
          "200": {"description": "Registered, unregistered, or unsupported-TLD result.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolWhoisEnvelope"}}}},
          "400": {"$ref": "#/components/responses/ToolInvalidInput"}, "429": {"$ref": "#/components/responses/ToolRateLimited"}, "502": {"$ref": "#/components/responses/ToolUpstreamError"}
        }
      }
    },
    "/api/tools/subdomains": {
      "get": {
        "tags": ["Free Tools"], "operationId": "findSubdomains", "summary": "Find subdomains from certificate transparency", "security": [],
        "description": "crt.sh failures degrade to a 200 response with an empty list and data.error set.",
        "parameters": [{"$ref": "#/components/parameters/ToolDomain"}],
        "responses": {
          "200": {"description": "Subdomain result, possibly partial.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolSubdomainsEnvelope"}}}},
          "400": {"$ref": "#/components/responses/ToolInvalidInput"}, "429": {"$ref": "#/components/responses/ToolRateLimited"}
        }
      }
    },
    "/api/tools/domain-age": {
      "get": {
        "tags": ["Free Tools"], "operationId": "getDomainAge", "summary": "Calculate domain age from RDAP", "security": [],
        "parameters": [{"$ref": "#/components/parameters/ToolDomain"}],
        "responses": {
          "200": {"description": "Registered, unregistered, or unsupported-TLD result.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolDomainAgeEnvelope"}}}},
          "400": {"$ref": "#/components/responses/ToolInvalidInput"}, "429": {"$ref": "#/components/responses/ToolRateLimited"}, "502": {"$ref": "#/components/responses/ToolUpstreamError"}
        }
      }
    },
    "/api/tools/availability": {
      "get": {
        "tags": ["Free Tools"], "operationId": "checkDomainAvailability", "summary": "Check one domain or a base label across TLDs", "security": [],
        "description": "With tlds, this is a partial-result operation: available=null means either an unsupported TLD or an RDAP network failure, and the per-item cause is not distinguishable. Those items remain inside HTTP 200. The 502 response applies only to a single-domain upstream failure.",
        "parameters": [
          {"name": "domain", "in": "query", "required": true, "description": "A full domain when tlds is absent; a base label with no dot when tlds is present.", "schema": {"type": "string", "example": "example.com"}},
          {"name": "tlds", "in": "query", "description": "Comma-separated TLDs; at most 10.", "schema": {"type": "string", "example": "com,net,io"}}
        ],
        "responses": {
          "200": {"description": "Single-domain or multi-TLD result.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolAvailabilityEnvelope"}}}},
          "400": {"$ref": "#/components/responses/ToolInvalidInput"}, "429": {"$ref": "#/components/responses/ToolRateLimited"}, "502": {"$ref": "#/components/responses/ToolUpstreamError"}
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "api-key",
        "description": "Cluster-scoped Approximated API key. Header names are case-insensitive. The server's legacy request-body api_key fallback is unsupported and must not be used by clients."
      }
    },
    "parameters": {
      "VirtualHostId": {"name": "id", "in": "path", "required": true, "description": "Virtual host database ID.", "schema": {"type": "integer", "minimum": 1}},
      "ProxyServerId": {"name": "id", "in": "path", "required": true, "description": "Proxy cluster ID. Must equal the cluster attached to the API key.", "schema": {"type": "integer", "minimum": 1}},
      "RuleId": {"name": "id", "in": "path", "required": true, "description": "Rule database ID.", "schema": {"type": "integer", "minimum": 1}},
      "IncomingAddress": {"name": "incoming_address", "in": "path", "required": true, "description": "Custom domain without a scheme, path, or query string.", "schema": {"type": "string", "example": "customer.example.com"}},
      "CursorDirection": {"name": "cursor_direction", "in": "path", "required": true, "schema": {"type": "string", "enum": ["before", "after"]}},
      "Cursor": {"name": "cursor", "in": "path", "required": true, "description": "Opaque cursor returned by the corresponding list endpoint.", "schema": {"type": "string"}},
      "EdgeSequenceId": {"name": "id", "in": "path", "required": true, "description": "Edge sequence database ID. Malformed or cross-cluster ids return 404.", "schema": {"type": "integer", "minimum": 1}},
      "VersionDirection": {"name": "direction", "in": "path", "required": true, "description": "older pages toward earlier versions, newer toward later ones.", "schema": {"type": "string", "enum": ["older", "newer"]}},
      "VersionCursor": {"name": "cursor", "in": "path", "required": true, "description": "Integer cursor from a previous version-history page (cursors.older or cursors.newer). Not a version number.", "schema": {"type": "integer"}},
      "VersionNumber": {"name": "version", "in": "path", "required": true, "description": "Version number as shown in the version history.", "schema": {"type": "integer", "minimum": 1}},
      "AnalyticsStart": {"name": "start", "in": "query", "description": "Inclusive RFC 3339 start. Defaults to 24 hours before end.", "schema": {"type": "string", "format": "date-time"}},
      "AnalyticsEnd": {"name": "end", "in": "query", "description": "Exclusive RFC 3339 end. Defaults to now and must be after start.", "schema": {"type": "string", "format": "date-time"}},
      "AnalyticsDimension": {"name": "dim", "in": "query", "schema": {"type": "string", "enum": ["country", "status", "method", "origin"], "default": "country"}},
      "AnalyticsLimit": {"name": "limit", "in": "query", "description": "Requested top-item count. Non-integer input falls back to 10; storage limits the effective count.", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 10}},
      "LogCursor": {"name": "cursor", "in": "query", "description": "Opaque next_cursor from a prior page. Malformed cursors are ignored.", "schema": {"type": "string", "maxLength": 200}},
      "LogLimit": {"name": "limit", "in": "query", "description": "Page size, clamped to 1..1000.", "schema": {"type": "integer", "minimum": 1, "maximum": 1000, "default": 100}},
      "LogWindow": {"name": "window", "in": "query", "description": "Lookback seconds, clamped to cluster retention.", "schema": {"type": "integer", "minimum": 1, "default": 3600}},
      "LogHost": {"name": "host", "in": "query", "description": "Exact host filter.", "schema": {"type": "string"}},
      "LogStatus": {"name": "status", "in": "query", "description": "Exact HTTP status. Invalid values are ignored.", "schema": {"type": "integer", "minimum": 100, "maximum": 599}},
      "LogStatusClass": {"name": "status_class", "in": "query", "description": "HTTP status class. Invalid values are ignored.", "schema": {"type": "integer", "enum": [2, 3, 4, 5]}},
      "LogMethod": {"name": "method", "in": "query", "description": "Exact HTTP method.", "schema": {"type": "string"}},
      "LogDisposition": {"name": "disposition", "in": "query", "description": "Invalid values are ignored.", "schema": {"type": "string", "enum": ["served", "waf_blocked", "rate_limited", "challenge_issued", "challenge_passed", "challenge_failed", "challenge_passed_prior"]}},
      "LogPathPrefix": {"name": "path_prefix", "in": "query", "description": "Literal path-prefix filter.", "schema": {"type": "string"}},
      "LogClientIp": {"name": "client_ip", "in": "query", "description": "Exact IPv4 or IPv6 address.", "schema": {"type": "string"}},
      "ToolDomain": {"name": "domain", "in": "query", "required": true, "schema": {"type": "string", "format": "hostname", "example": "example.com"}},
      "ToolUrl": {"name": "url", "in": "query", "required": true, "description": "An HTTP or HTTPS URL, at most 2048 bytes after normalization. A scheme-less host/path is accepted and normalized to https://. Other URI schemes are rejected.", "schema": {"type": "string", "minLength": 1, "maxLength": 2048, "examples": ["https://example.com/", "example.com/path"]}}
    },
    "responses": {
      "Unauthorized": {"description": "Missing, deleted, or unknown API key.", "content": {"application/json": {"schema": {"type": "string"}, "example": "Unauthorized"}}},
      "ApiRateLimited": {"description": "General 240 requests/minute API-key budget exceeded. The response is plain text and includes a dynamic wait duration.", "content": {"text/plain": {"schema": {"type": "string"}, "example": "Too many requests: 240 requests per minute are allowed. Please wait 12.0 seconds."}}},
      "AnalyticsRateLimited": {"description": "The independent 60 requests/minute analytics budget was exceeded. A request can also be stopped earlier by the general API-key budget.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SimpleError"}, "example": {"error": "rate_limit_exceeded"}}}},
      "LogsRateLimited": {"description": "The independent 60 requests/minute request-log budget was exceeded. A request can also be stopped earlier by the general API-key budget.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SimpleError"}, "example": {"error": "rate_limit_exceeded"}}}},
      "EdgeSequenceWriteFailed": {"description": "The write could not be completed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeSequenceErrors"}, "example": {"errors": {"": [{"code": "activation_failed", "message": "could not update activation"}]}}}}},
      "EdgeSequenceRegexValidationUnavailable": {"description": "The regular-expression validator was unavailable, so a definition containing a vars_regexp matcher could not be checked. Server-side and transient: retry after the Retry-After delay. The definition was not written.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "example": 30}}}, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EdgeSequenceErrors"}, "example": {"errors": {"": [{"code": "regex_validation_unavailable", "message": "Regular expression validation is temporarily unavailable. This is a server-side issue, not a problem with your definition \u2014 please retry."}]}}}}},
      "EdgeSequenceWriteRateLimited": {"description": "The independent 30 requests/minute edge-sequence write budget was exceeded (JSON body). A request can also be stopped earlier by the general 240 requests/minute API-key budget, which answers in plain text instead.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SimpleError"}, "example": {"error": "rate_limit_exceeded"}}, "text/plain": {"schema": {"type": "string"}, "example": "Too many requests: 240 requests per minute are allowed. Please wait 12.0 seconds."}}},
      "VirtualHost": {"description": "Virtual host with stored monitor data when available.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/VirtualHostEnvelope"}}}},
      "VirtualHostNotFound": {"description": "No matching virtual host belongs to this API key.", "content": {"text/plain": {"schema": {"type": "string"}, "example": "Couldn't find a virtual host that matches for the api key used."}}},
      "DeletingVirtualHost": {"description": "Deletion accepted. The response is plain text because removal/config propagation is asynchronous.", "content": {"text/plain": {"schema": {"type": "string"}, "example": "Deleting customer.example.com"}}},
      "SuspendedVirtualHost": {"description": "The virtual host is suspended pending review.", "content": {"text/plain": {"schema": {"type": "string"}, "example": "Cannot update customer.example.com as it is suspended pending review."}}},
      "ValidationError": {"description": "Request validation failed. Keys and messages depend on invalid fields; upstream entries also carry params and a zero-based index.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationErrors"}}}},
      "BadRequest": {"description": "Malformed request.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SimpleError"}}}},
      "JsonNotFound": {"description": "Resource not found, not owned, or in the wrong scope.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ValidationErrors"}, "example": {"errors": {"base": ["not_found"]}}}}},
      "SimpleJsonNotFound": {"description": "Resource not found or not owned.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SimpleError"}, "example": {"error": "not_found"}}}},
      "AnalyticsBadRequest": {"description": "Invalid start/end window or dimension.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorWithMessage"}}}},
      "LogsBadRequest": {"description": "window was not a positive integer or limit was not an integer.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorWithMessage"}}}},
      "InternalJsonError": {"description": "Unexpected backend error.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SimpleError"}, "example": {"error": "internal_error"}}}},
      "ToolInvalidInput": {"description": "Required input is missing or invalid.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolError"}, "example": {"ok": false, "error": "invalid_input", "message": "Missing or invalid `domain`."}}}},
      "ToolRateLimited": {"description": "A per-IP free-tool bucket denied the request. Limits are 500/day across tools, 30/minute across tools, and 10/minute for this tool.", "headers": {"Retry-After": {"description": "Seconds until the denying bucket resets.", "schema": {"type": "integer", "minimum": 1}, "example": 42}}, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolRateLimitError"}, "example": {"ok": false, "error": "rate_limited", "scope": "tool", "message": "Too many requests. Try again later."}}}},
      "ToolUpstreamError": {"description": "An upstream DNS, RDAP, or TLS dependency failed.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolError"}, "example": {"ok": false, "error": "upstream_error", "message": "The upstream service is unavailable right now."}}}}
      ,
      "DnsWidgetRateLimited": {"description": "A widget IP, proxy-cluster or session limit denied the request. Wait 60 seconds before retrying. Budgets are per application server and shared across operation aliases; token renewal does not reset session counters. Browser responses expose Retry-After through CORS.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "const": 60}}, "Cache-Control": {"description": "Do not cache this response.", "schema": {"type": "string", "const": "no-store"}}}, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DnsWidgetRateLimitError"}, "example": {"error": "rate_limited", "message": "Too many requests. Try again later."}}}},
      "DnsWidgetIssuanceRateLimited": {"description": "Widget issuance limit (JSON: 60 per IP and 60 per proxy cluster per minute), or the general 240 requests/minute API-key budget (plain text). Retry-After: 60 is included for widget denials; the general API-key denial includes its dynamic wait duration in the body.", "headers": {"Retry-After": {"description": "Seconds to wait before retrying.", "schema": {"type": "integer", "const": 60}}, "Cache-Control": {"description": "Do not cache this response.", "schema": {"type": "string", "const": "no-store"}}}, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DnsWidgetRateLimitError"}, "example": {"error": "rate_limited", "message": "Too many requests. Try again later."}}, "text/plain": {"schema": {"type": "string"}, "example": "Too many requests: 240 requests per minute are allowed. Please wait 12.0 seconds."}}},
      "DnsWidgetTokenRejected": {"description": "Absent token property returns missing_token. A present null, non-string, empty, malformed, expired, or revoked token returns token_expired. This also covers the absolute session deadline and API-key deletion/rotation. These rules apply to instructions, verification, and renewal; a rate denial can take precedence.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DnsWidgetError"}, "examples": {"expired": {"value": {"error": "token_expired", "message": "Token is expired. Please generate a new token server-side."}}, "missing": {"value": {"error": "missing_token", "message": "There is no token included in your request, please include one."}}, "missingRenewal": {"value": {"error": "missing_token", "message": "There is no token included in your renewal request, please include one."}}}}}}
    },
    "schemas": {
      "NaiveDateTime": {
        "type": "string",
        "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{1,6})?$",
        "description": "Offset-less ISO 8601 timestamp serialized from an Ecto NaiveDateTime. The API currently omits a UTC offset; do not require a trailing Z."
      },
      "SimpleError": {
        "type": "object",
        "required": ["error"],
        "properties": {"error": {"type": "string"}},
        "additionalProperties": false
      },
      "ErrorWithMessage": {
        "type": "object",
        "required": ["error", "message"],
        "properties": {"error": {"type": "string"}, "message": {"type": "string"}},
        "additionalProperties": false
      },
      "ValidationErrors": {
        "type": "object",
        "required": ["errors"],
        "properties": {
          "errors": {
            "type": "object",
            "description": "Field name to error messages, with structured upstream validation entries where applicable.",
            "additionalProperties": true,
            "example": {"incoming_address": ["this incoming address has already been created on the cluster you selected"]}
          }
        },
        "additionalProperties": false
      },
      "IncomingAddressRequest": {
        "type": "object",
        "required": ["incoming_address"],
        "properties": {"incoming_address": {"type": "string", "example": "customer.example.com"}},
        "additionalProperties": false
      },
      "UpstreamWrite": {
        "type": "object",
        "required": ["host"],
        "properties": {
          "host": {"type": "string", "format": "hostname", "description": "Hostname only; no scheme, path, or port.", "example": "origin-2.example.net"},
          "port": {"type": "integer", "minimum": 1, "maximum": 65535, "default": 443, "description": "Defaults to 443 when omitted."},
          "enabled": {"type": "boolean", "default": true, "description": "Defaults to true when omitted."},
          "priority": {"type": "integer", "minimum": 0, "maximum": 999, "default": 0},
          "weight": {"type": "integer", "minimum": 0, "maximum": 999, "default": 1}
        },
        "additionalProperties": false
      },
      "Upstream": {
        "type": "object",
        "required": ["id", "host", "port", "enabled"],
        "properties": {
          "id": {"type": "integer"}, "host": {"type": "string"}, "port": {"type": "integer"}, "enabled": {"type": "boolean"}
        },
        "additionalProperties": false
      },
      "VirtualHostCreate": {
        "type": "object",
        "required": ["incoming_address", "target_address"],
        "properties": {
          "incoming_address": {"type": "string", "description": "Custom domain, optionally including a path for exact-match routing.", "example": "customer.example.com"},
          "target_address": {"type": "string", "description": "Origin hostname or URL/path. Redirect targets should include http:// or https://.", "example": "origin.example.net"},
          "target_ports": {"oneOf": [{"type": "string"}, {"type": "integer"}], "default": "443", "examples": ["443", "80", "8080"]},
          "redirect": {"type": "boolean", "default": false},
          "exact_match": {"type": "boolean", "default": false},
          "redirect_www": {"oneOf": [{"type": "boolean"}, {"type": "string", "enum": ["true", "false"]}], "default": false},
          "keep_host": {"type": ["boolean", "null"], "description": "null inherits the cluster default."},
          "lb_enabled": {"type": "boolean", "default": false},
          "lb_policy": {"type": "string", "enum": ["first", "random", "round_robin", "least_conn"], "default": "first"},
          "lb_sticky": {"type": "boolean", "default": true},
          "mtls_client_cert_id": {"type": ["string", "null"], "description": "UUID of an mTLS client certificate belonging to the cluster."},
          "rate_limit": {"type": ["integer", "null"], "minimum": 1, "maximum": 10000000, "description": "Optional per-vhost request-rate limit."},
          "upstreams": {"type": "array", "items": {"$ref": "#/components/schemas/UpstreamWrite"}, "default": []}
        },
        "additionalProperties": true,
        "description": "Unknown/admin-only keys are ignored by the backend rather than rejected."
      },
      "VirtualHostUpdate": {
        "type": "object",
        "minProperties": 1,
        "properties": {
          "incoming_address": {"type": "string"},
          "target_address": {"type": "string"},
          "target_ports": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
          "redirect": {"type": "boolean"},
          "exact_match": {"type": "boolean"},
          "keep_host": {"type": ["boolean", "null"]},
          "lb_enabled": {"type": "boolean"},
          "lb_policy": {"type": "string", "enum": ["first", "random", "round_robin", "least_conn"]},
          "lb_sticky": {"type": "boolean"},
          "mtls_client_cert_id": {"type": ["string", "null"]},
          "rate_limit": {"type": ["integer", "null"], "minimum": 1, "maximum": 10000000},
          "upstreams": {"type": "array", "description": "When present, replaces all existing additional upstreams.", "items": {"$ref": "#/components/schemas/UpstreamWrite"}}
        },
        "additionalProperties": true,
        "description": "Omitted fields are unchanged. Unknown/admin-only keys are ignored."
      },
      "VirtualHostUpdateByIncoming": {
        "allOf": [
          {"$ref": "#/components/schemas/VirtualHostUpdate"},
          {"type": "object", "required": ["current_incoming_address"], "properties": {"current_incoming_address": {"type": "string", "example": "customer.example.com"}}}
        ]
      },
      "VirtualHostBulkUpdate": {
        "type": "object",
        "required": ["incoming_addresses", "updates"],
        "properties": {
          "incoming_addresses": {"type": "array", "items": {"type": "string"}, "minItems": 1, "description": "Addresses are de-duplicated and only the first 100 unique values are processed; additional values are silently truncated."},
          "updates": {"$ref": "#/components/schemas/VirtualHostUpdate"}
        },
        "additionalProperties": false
      },
      "MtlsClientCertReference": {
        "type": "object",
        "required": ["name", "id"],
        "properties": {"name": {"type": "string"}, "id": {"type": "string"}},
        "additionalProperties": false
      },
      "CaaDetails": {
        "type": "object",
        "properties": {
          "governing_domain": {"type": ["string", "null"]},
          "records": {"type": "array", "items": {"type": "string"}},
          "allowed_cas": {"type": "array", "items": {"type": "string"}},
          "denied_cas": {"type": "array", "items": {"type": "string"}},
          "message": {"type": ["string", "null"]}
        },
        "additionalProperties": true
      },
      "VirtualHost": {
        "type": "object",
        "required": ["id", "incoming_address", "target_address", "target_ports", "keep_host", "lb_policy", "lb_enabled", "lb_sticky", "rate_limit", "coraza_enabled", "mtls_client_cert", "upstreams"],
        "properties": {
          "id": {"type": "integer"},
          "incoming_address": {"type": "string"},
          "target_address": {"type": "string"},
          "target_ports": {"type": "string"},
          "keep_host": {"type": ["boolean", "null"]},
          "lb_policy": {"type": "string", "enum": ["first", "random", "round_robin", "least_conn"]},
          "lb_enabled": {"type": "boolean"},
          "lb_sticky": {"type": "boolean"},
          "rate_limit": {"type": ["integer", "null"]},
          "coraza_enabled": {"type": ["boolean", "null"], "readOnly": true, "description": "Admin-managed WAF override; returned for visibility but ignored on customer writes."},
          "mtls_client_cert": {"oneOf": [{"$ref": "#/components/schemas/MtlsClientCertReference"}, {"type": "null"}]},
          "upstreams": {"type": "array", "items": {"$ref": "#/components/schemas/Upstream"}},
          "created_at": {"$ref": "#/components/schemas/NaiveDateTime"},
          "has_ssl": {"type": ["boolean", "null"]},
          "is_resolving": {"type": ["boolean", "null"]},
          "ssl_active_from": {"oneOf": [{"$ref": "#/components/schemas/NaiveDateTime"}, {"type": "null"}]},
          "ssl_active_until": {"oneOf": [{"$ref": "#/components/schemas/NaiveDateTime"}, {"type": "null"}]},
          "status": {"type": "string"},
          "status_message": {"type": "string"},
          "dns_pointed_at": {"type": ["string", "null"]},
          "apx_hit": {"type": ["boolean", "null"]},
          "caa_status": {"type": ["string", "null"], "enum": ["ok", "blocked", "inconclusive", null]},
          "caa_details": {"oneOf": [{"$ref": "#/components/schemas/CaaDetails"}, {"type": "null"}]},
          "last_monitored_unix": {"type": "integer"},
          "last_monitored_humanized": {"type": "string"},
          "utc_last_updated": {"$ref": "#/components/schemas/NaiveDateTime"},
          "human_readable_last_updated": {"type": "string"},
          "user_message": {"type": "string"},
          "user_dns_instructions": {"description": "Provider-aware DNS guidance generated for this virtual host."}
        },
        "additionalProperties": false
      },
      "VirtualHostEnvelope": {"type": "object", "required": ["data"], "properties": {"data": {"$ref": "#/components/schemas/VirtualHost"}}, "additionalProperties": false},
      "VirtualHostListEnvelope": {"type": "object", "required": ["data"], "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/VirtualHost"}}}, "additionalProperties": false},
      "VirtualHostCursorEnvelope": {
        "type": "object", "required": ["data", "before_cursor", "after_cursor"],
        "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/VirtualHost"}}, "before_cursor": {"type": ["string", "null"]}, "after_cursor": {"type": ["string", "null"]}},
        "additionalProperties": false
      },
      "VirtualHostBulkUpdateEnvelope": {
        "type": "object", "required": ["data"],
        "properties": {"data": {"type": "object", "required": ["summary", "successful", "failed", "not_found"], "properties": {
          "summary": {"type": "object", "required": ["total_requested", "successful", "failed", "not_found", "suspended"], "properties": {"total_requested": {"type": "integer"}, "successful": {"type": "integer"}, "failed": {"type": "integer"}, "not_found": {"type": "integer"}, "suspended": {"type": "integer"}}, "additionalProperties": false},
          "successful": {"type": "array", "items": {"type": "string"}},
          "failed": {"type": "array", "items": {"type": "object", "required": ["current_incoming_address", "errors"], "properties": {"current_incoming_address": {"type": "string"}, "errors": {"type": "object", "additionalProperties": true}}}},
          "not_found": {"type": "array", "items": {"type": "string"}}
        }, "additionalProperties": false}},
        "additionalProperties": false
      },
      "DnsCheckRecord": {
        "type": "object", "required": ["address", "type", "match_against"],
        "properties": {"address": {"type": "string", "example": "example.com"}, "type": {"type": "string", "description": "DNS record type (any case).", "example": "a"}, "match_against": {"type": "string", "example": "93.184.216.34"}},
        "additionalProperties": true
      },
      "DnsCheckRequest": {"type": "object", "required": ["records"], "properties": {"records": {"oneOf": [{"$ref": "#/components/schemas/DnsCheckRecord"}, {"type": "array", "items": {"$ref": "#/components/schemas/DnsCheckRecord"}}]}}, "additionalProperties": false},
      "DnsCheckResult": {
        "allOf": [
          {"$ref": "#/components/schemas/DnsCheckRecord"},
          {"type": "object", "required": ["actual_values", "match"], "properties": {"actual_values": {"oneOf": [{"type": "array", "items": {"type": "string"}}, {"const": false}], "description": "false when DNS resolution or the record-type lookup failed."}, "match": {"type": "boolean"}}}
        ]
      },
      "DnsCheckResponse": {"type": "object", "required": ["records"], "properties": {"records": {"type": "array", "items": {"$ref": "#/components/schemas/DnsCheckResult"}}}, "additionalProperties": false},
      "DnsWidgetTokenEnvelope": {"type": "object", "required": ["token"], "properties": {"token": {"type": "string", "description": "Scoped customer token tied to the issuing API key and proxy cluster. Valid for at most 630 seconds within a 24-hour session; deletion or rotation of its API key invalidates it. Treat as opaque."}}, "additionalProperties": false},
      "DnsWidgetTokenRequest": {"type": "object", "required": ["token"], "properties": {"token": {"type": "string", "minLength": 1, "maxLength": 4096, "description": "Scoped customer token created server-side by GET /api/dns/v2/token."}}, "additionalProperties": false},
      "DnsWidgetRateLimitError": {"type": "object", "required": ["error", "message"], "properties": {"error": {"type": "string", "const": "rate_limited"}, "message": {"type": "string"}}, "additionalProperties": false},
      "DnsWidgetError": {"type": "object", "required": ["error", "message"], "properties": {"error": {"type": "string", "enum": ["token_expired", "missing_token"]}, "message": {"type": "string"}}, "additionalProperties": false},
      "DnsInstructionsRequestRecord": {
        "type": "object", "required": ["type", "host", "value"],
        "properties": {"type": {"type": "string", "description": "A, CNAME or TXT (any case)."}, "host": {"type": "string", "description": "@ for the apex or a relative subdomain."}, "value": {"type": "string", "description": "May contain the literal {domain}, replaced by the record's domain."}, "ttl": {"oneOf": [{"type": "integer", "minimum": 1}, {"type": "string"}], "description": "Seconds; default 3600."}, "domain": {"type": "string", "description": "Overrides the top-level domain for this record."}},
        "additionalProperties": true
      },
      "DnsInstructionsRequest": {"type": "object", "required": ["records"], "properties": {"domain": {"type": "string", "description": "Default domain for records without one."}, "records": {"type": "array", "minItems": 1, "maxItems": 25, "items": {"$ref": "#/components/schemas/DnsInstructionsRequestRecord"}}}, "additionalProperties": true},
      "DnsInstructionsTokenRequest": {"type": "object", "required": ["token", "records"], "properties": {"token": {"type": "string", "minLength": 1, "maxLength": 4096, "description": "Scoped customer token created server-side by GET /api/dns/v2/token."}, "domain": {"type": "string", "description": "Default domain for records without one."}, "records": {"type": "array", "minItems": 1, "maxItems": 25, "items": {"$ref": "#/components/schemas/DnsInstructionsRequestRecord"}}}, "additionalProperties": true},
      "DnsInstructionTextStep": {
        "type": "object", "required": ["kind", "text"],
        "properties": {"kind": {"type": "string", "enum": ["text"]}, "text": {"type": "string"}},
        "additionalProperties": false
      },
      "DnsInstructionLinkStep": {
        "type": "object", "required": ["kind", "text", "url"],
        "properties": {"kind": {"type": "string", "enum": ["link"]}, "text": {"type": "string"}, "url": {"type": "string"}},
        "additionalProperties": false
      },
      "DnsInstructionFieldStep": {
        "type": "object", "required": ["kind", "text", "field", "label", "value"],
        "properties": {"kind": {"type": "string", "enum": ["field"]}, "text": {"type": "string"}, "field": {"type": "string", "enum": ["host", "value", "ttl"], "description": "Which of the record's values this step enters."}, "label": {"type": "string", "description": "The field's name in the provider UI."}, "value": {"type": "string", "description": "The display value; empty means leave the field blank."}},
        "additionalProperties": false
      },
      "DnsInstructionStep": {
        "description": "One instruction step, discriminated by kind.",
        "oneOf": [{"$ref": "#/components/schemas/DnsInstructionTextStep"}, {"$ref": "#/components/schemas/DnsInstructionLinkStep"}, {"$ref": "#/components/schemas/DnsInstructionFieldStep"}],
        "discriminator": {"propertyName": "kind", "mapping": {"text": "#/components/schemas/DnsInstructionTextStep", "link": "#/components/schemas/DnsInstructionLinkStep", "field": "#/components/schemas/DnsInstructionFieldStep"}}
      },
      "DnsInstructionsProvider": {
        "type": "object", "required": ["name", "provider_domain", "detected", "supported", "lookup_status", "nameservers", "message", "message_link", "login_url", "logo_url"],
        "properties": {"name": {"type": "string"}, "provider_domain": {"type": "string", "description": "Stable key; \"generic\" when undetected."}, "detected": {"type": "boolean"}, "supported": {"type": "boolean", "description": "True when steps are provider-specific."}, "lookup_status": {"type": "string", "enum": ["ok", "nameservers_not_found", "lookup_failed"]}, "nameservers": {"type": "array", "items": {"type": "string"}}, "message": {"type": "string"}, "message_link": {"type": ["object", "null"], "properties": {"text": {"type": "string"}, "url": {"type": "string"}}}, "login_url": {"type": ["string", "null"]}, "logo_url": {"type": ["string", "null"]}},
        "additionalProperties": false
      },
      "DnsInstructionsRecord": {
        "type": "object", "required": ["domain", "apex_domain", "subdomain", "type", "host", "combined_host", "value", "match_against", "ttl", "title", "automation", "steps"],
        "properties": {"domain": {"type": "string"}, "apex_domain": {"type": "string"}, "subdomain": {"type": ["string", "null"]}, "type": {"type": "string", "enum": ["A", "CNAME", "TXT"]}, "host": {"type": "string"}, "combined_host": {"type": "string", "description": "The host to enter at the provider, relative to the registrable domain."}, "value": {"type": "string"}, "match_against": {"type": "string", "description": "Ready to post to check-records-match-exactly."}, "ttl": {"type": "integer"}, "title": {"type": "string"}, "automation": {"type": ["object", "null"], "properties": {"kind": {"type": "string", "enum": ["domain_connect"]}, "url": {"type": "string"}}}, "steps": {"type": "array", "items": {"$ref": "#/components/schemas/DnsInstructionStep"}}},
        "additionalProperties": false
      },
      "DnsInstructionsDomain": {"type": "object", "required": ["apex_domain", "provider", "records"], "properties": {"apex_domain": {"type": "string"}, "provider": {"$ref": "#/components/schemas/DnsInstructionsProvider"}, "records": {"type": "array", "items": {"$ref": "#/components/schemas/DnsInstructionsRecord"}}}, "additionalProperties": false},
      "DnsInstructionsResponse": {"type": "object", "required": ["domains"], "properties": {"domains": {"type": "array", "items": {"$ref": "#/components/schemas/DnsInstructionsDomain"}}}, "additionalProperties": false},
      "DnsInstructionsError": {"type": "object", "required": ["error", "message", "details"], "properties": {"error": {"type": "string", "enum": ["invalid_request", "invalid_domain"]}, "message": {"type": "string"}, "details": {"type": "array", "items": {"type": "object", "required": ["index", "field", "message"], "properties": {"index": {"type": "integer"}, "field": {"type": "string"}, "message": {"type": "string"}}}}}, "additionalProperties": false},
      "DnsWidgetExactCheckRecord": {
        "type": "object", "required": ["domain", "host", "type", "match_against"],
        "properties": {"domain": {"type": "string"}, "host": {"type": "string"}, "type": {"type": "string"}, "match_against": {"type": "string"}, "value": {"type": "string"}, "apex": {"type": "string"}, "tld": {"type": "string"}},
        "additionalProperties": true
      },
      "DnsWidgetExactCheckRequest": {"type": "object", "required": ["token", "records"], "properties": {"token": {"type": "string", "minLength": 1, "maxLength": 4096, "description": "Scoped customer token created server-side by GET /api/dns/v2/token."}, "records": {"oneOf": [{"$ref": "#/components/schemas/DnsWidgetExactCheckRecord"}, {"type": "array", "items": {"$ref": "#/components/schemas/DnsWidgetExactCheckRecord"}}]}}, "additionalProperties": false},
      "DnsWidgetExactCheckResult": {
        "type": "object", "required": ["domain", "host", "type", "match_against", "actual_values", "match", "combined_host", "apex", "tld", "full", "non_tld", "subdomain"],
        "properties": {"domain": {"type": "string"}, "host": {"type": "string"}, "type": {"type": "string"}, "match_against": {"type": "string"}, "value": {"type": "string"}, "actual_values": {"oneOf": [{"type": "array", "items": {"type": "string"}}, {"const": false}]}, "match": {"type": "boolean"}, "combined_host": {"type": "string"}, "apex": {"type": "string"}, "tld": {"type": "string"}, "full": {"type": "string"}, "non_tld": {"type": "string"}, "subdomain": {"type": "string"}},
        "additionalProperties": true
      },
      "DnsWidgetExactCheckResponse": {"type": "object", "required": ["records"], "properties": {"records": {"type": "array", "items": {"$ref": "#/components/schemas/DnsWidgetExactCheckResult"}}}, "additionalProperties": false},
      "DnsWidgetExistCheckRequest": {"type": "object", "required": ["token", "records"], "properties": {"token": {"type": "string", "minLength": 1, "maxLength": 4096, "description": "Scoped customer token created server-side by GET /api/dns/v2/token."}, "records": {"oneOf": [{"$ref": "#/components/schemas/DnsCheckRecord"}, {"type": "array", "items": {"$ref": "#/components/schemas/DnsCheckRecord"}}]}}, "additionalProperties": false},
      "HealthCheck": {
        "type": "object", "required": ["id", "results", "human_readable_results", "utc_last_updated", "human_readable_last_updated"],
        "properties": {"id": {"type": "integer"}, "results": {"type": "object", "description": "Region code to healthy boolean.", "additionalProperties": {"type": "boolean"}}, "human_readable_results": {"type": "object", "description": "Region display name to Healthy or Repairing.", "additionalProperties": {"type": "string", "enum": ["Healthy", "Repairing"]}}, "utc_last_updated": {"$ref": "#/components/schemas/NaiveDateTime"}, "human_readable_last_updated": {"type": "string"}},
        "additionalProperties": false
      },
      "HealthCheckEnvelope": {"type": "object", "required": ["data"], "properties": {"data": {"oneOf": [{"$ref": "#/components/schemas/HealthCheck"}, {"type": "null"}]}}, "additionalProperties": false},
      "EdgeVerifyRuleWrite": {
        "type": "object", "required": ["path_pattern", "methods", "mode"],
        "properties": {
          "path_pattern": {"type": "string", "pattern": "^/", "description": "Matches this path and its descendants; a trailing slash is removed except for root.", "example": "/contact"},
          "methods": {"type": "array", "minItems": 1, "items": {"type": "string", "enum": ["POST", "PUT", "PATCH", "DELETE"]}, "example": ["POST"]},
          "mode": {"type": "string", "enum": ["monitor", "enforce"]}
        }, "additionalProperties": false
      },
      "EdgeVerifyRulePatch": {
        "type": "object", "minProperties": 1,
        "properties": {"path_pattern": {"type": "string", "pattern": "^/"}, "methods": {"type": "array", "minItems": 1, "items": {"type": "string", "enum": ["POST", "PUT", "PATCH", "DELETE"]}}, "mode": {"type": "string", "enum": ["monitor", "enforce"]}},
        "additionalProperties": false
      },
      "EdgeVerifyVhostCreate": {
        "type": "object", "required": ["incoming_address", "path_pattern", "methods", "mode"],
        "properties": {"incoming_address": {"type": "string"}, "path_pattern": {"type": "string", "pattern": "^/"}, "methods": {"type": "array", "minItems": 1, "items": {"type": "string", "enum": ["POST", "PUT", "PATCH", "DELETE"]}}, "mode": {"type": "string", "enum": ["monitor", "enforce"]}},
        "additionalProperties": false
      },
      "EdgeVerifyVhostUpdate": {
        "type": "object", "required": ["incoming_address", "id"], "minProperties": 3,
        "properties": {"incoming_address": {"type": "string"}, "id": {"type": "integer", "minimum": 1}, "path_pattern": {"type": "string", "pattern": "^/"}, "methods": {"type": "array", "minItems": 1, "items": {"type": "string", "enum": ["POST", "PUT", "PATCH", "DELETE"]}}, "mode": {"type": "string", "enum": ["monitor", "enforce"]}},
        "additionalProperties": false
      },
      "EdgeVerifyVhostDelete": {"type": "object", "required": ["incoming_address", "id"], "properties": {"incoming_address": {"type": "string"}, "id": {"type": "integer", "minimum": 1}}, "additionalProperties": false},
      "EdgeVerifyRule": {
        "type": "object", "required": ["id", "virtual_host_id", "proxy_server_id", "path_pattern", "methods", "mode", "inserted_at", "updated_at"],
        "properties": {"id": {"type": "integer"}, "virtual_host_id": {"type": ["integer", "null"]}, "proxy_server_id": {"type": ["integer", "null"]}, "path_pattern": {"type": "string"}, "methods": {"type": "array", "items": {"type": "string"}}, "mode": {"type": "string", "enum": ["monitor", "enforce"]}, "inserted_at": {"$ref": "#/components/schemas/NaiveDateTime"}, "updated_at": {"$ref": "#/components/schemas/NaiveDateTime"}},
        "additionalProperties": false
      },
      "EdgeVerifyRuleEnvelope": {"type": "object", "required": ["data"], "properties": {"data": {"$ref": "#/components/schemas/EdgeVerifyRule"}}, "additionalProperties": false},
      "EdgeVerifyRuleListEnvelope": {"type": "object", "required": ["data"], "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/EdgeVerifyRule"}}}, "additionalProperties": false},
      "L4RuleLookup": {"type": "object", "required": ["match_type", "value"], "properties": {"match_type": {"type": "string", "enum": ["ip", "sni", "ja3", "ja4"]}, "value": {"type": "string"}}, "additionalProperties": false},
      "L4RuleCreate": {
        "type": "object", "required": ["match_type", "value"],
        "properties": {"match_type": {"type": "string", "enum": ["ip", "sni", "ja3", "ja4"]}, "value": {"type": "string"}, "action": {"type": "string", "enum": ["block"], "default": "block"}, "reason": {"type": "string"}, "expires_at": {"type": ["string", "null"], "format": "date-time", "description": "Must be in the future when present."}},
        "additionalProperties": true,
        "description": "proxy_server_id is ignored if supplied; cluster scope always comes from the API key."
      },
      "L4Rule": {
        "type": "object", "required": ["id", "proxy_server_id", "match_type", "value", "action", "source", "expires_at", "inserted_at", "updated_at"],
        "properties": {"id": {"type": "integer"}, "proxy_server_id": {"type": "integer"}, "match_type": {"type": "string"}, "value": {"type": "string"}, "action": {"type": "string", "enum": ["block", "allow", "challenge"]}, "reason": {"type": ["string", "null"]}, "source": {"type": "string", "enum": ["worker", "admin", "customer", "system", "fleet"]}, "expires_at": {"type": ["string", "null"], "format": "date-time"}, "inserted_at": {"$ref": "#/components/schemas/NaiveDateTime"}, "updated_at": {"$ref": "#/components/schemas/NaiveDateTime"}},
        "additionalProperties": false
      },
      "L4RuleEnvelope": {"type": "object", "required": ["data"], "properties": {"data": {"$ref": "#/components/schemas/L4Rule"}}, "additionalProperties": false},
      "L4RuleListEnvelope": {"type": "object", "required": ["data", "cursors"], "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/L4Rule"}}, "cursors": {"type": "object", "required": ["before", "after"], "properties": {"before": {"type": ["string", "null"]}, "after": {"type": ["string", "null"]}}, "additionalProperties": false}}, "additionalProperties": false},
      "L4Conflict": {
        "type": "object", "required": ["error", "message", "blocker"],
        "properties": {"error": {"const": "conflict_not_revokable"}, "message": {"type": "string"}, "blocker": {"type": "object", "required": ["id", "source", "kind"], "properties": {"id": {"type": "integer"}, "source": {"type": "string"}, "kind": {"type": "string", "enum": ["auto_block_exemption", "l4_rule"]}}, "additionalProperties": false}},
        "additionalProperties": false
      },
      "EdgeSequenceProblem": {
        "type": "object", "required": ["code", "message"],
        "description": "One validation error or warning. code is stable and meant for programs; message is for people. Some codes add fields (unreachable adds blocked_by, a JSON Pointer to the rule that returns a response first).",
        "properties": {"code": {"type": "string"}, "message": {"type": "string"}},
        "additionalProperties": true
      },
      "EdgeSequenceProblems": {
        "type": "object",
        "description": "Problems keyed by JSON Pointer (RFC 6901) into the request payload, e.g. /rules/0/config/max_events or /matcher_groups/0/matchers/1/type. The empty key \"\" is the sequence as a whole. Each value is a non-empty list; the map is empty when there is nothing to report.",
        "propertyNames": {"pattern": "^(|/.*)$"},
        "additionalProperties": {"type": "array", "minItems": 1, "items": {"$ref": "#/components/schemas/EdgeSequenceProblem"}}
      },
      "EdgeSequenceErrors": {
        "type": "object", "required": ["errors"],
        "description": "422 and 503 body for edge-sequence endpoints. Error codes: required, invalid_type, empty, unknown_type, invalid_regex, out_of_range, not_allowed, length, format, invalid; and under \"\": apply_failed, activation_failed, reorder_failed, regex_validation_unavailable.",
        "properties": {"errors": {"$ref": "#/components/schemas/EdgeSequenceProblems"}},
        "additionalProperties": false
      },
      "EdgeSequenceMatcher": {
        "type": "object", "required": ["type"],
        "description": "One request condition. The data object depends on type: path -> {\"paths\": [string]} (a missing leading slash is added unless the path starts with a wildcard); host -> {\"hosts\": [string]} (incoming domains); target_host -> {\"hosts\": [string]} (virtual-host target hostnames; the cluster binding is server-derived and a client-supplied psid is ignored); header -> {\"header_keys\": [string], \"header_values\": [string]} (paired by index and all must match; keys must be unique and contain no spaces; values may contain spaces but not be blank); query -> {\"query_keys\": [string], \"query_values\": [string]} (paired by index; keys must be unique; neither keys nor values may be blank or contain spaces); protocol -> {\"protocol\": string}; client_ip -> {\"ranges\": [string]} (IPs or CIDR ranges); geolocation -> {\"allow_countries\": [string], \"deny_countries\": [string]} (at least one list must be non-empty; the GeoIP db_path is server infrastructure and ignored on input); vars_regexp -> {\"name\": string, \"pattern\": string, \"match_against\": string} (RE2 syntax; captures can be referenced by number or name; match_against is one of {http.request.uri.path}, {http.request.host}, {http.request.uri.query}, {http.request.header.<Name>}, or {http.vars.apx_verify_outcome}); all -> {} (matches every request).",
        "properties": {
          "type": {"type": "string", "enum": ["all", "path", "host", "target_host", "header", "query", "protocol", "client_ip", "geolocation", "vars_regexp"]},
          "negative": {"type": "boolean", "default": false, "description": "Invert the matcher: match requests that do NOT satisfy it. Several negative matchers in one group combine into a single exception; see EdgeSequenceMatcherGroup."},
          "data": {"type": "object", "description": "Type-specific condition data; see the schema description. Defaults to {} and may be omitted for type all."}
        }
      },
      "EdgeSequenceMatcherGroup": {
        "type": "object", "required": ["matchers"],
        "description": "A group matches when every positive matcher matches, unless every negative matcher matches too. Negative matchers form one combined exception (the group is skipped only when all of them match at once), so to exclude any of several values, list them in a single negative matcher.",
        "properties": {"matchers": {"type": "array", "minItems": 1, "items": {"$ref": "#/components/schemas/EdgeSequenceMatcher"}}}
      },
      "EdgeSequenceRule": {
        "type": "object", "required": ["type"],
        "description": "One action, executed in array order when the sequence matches. The config object depends on type: blocker -> {\"status_code\": string (default \"403\"), \"body\": string} returns a static response and stops; redirect -> {\"status_code\": string (default \"301\"), \"location\": string} returns a redirect and stops — supplying top-level location RESETS the response headers to the redirect Location plus the edge's apx-hit marker (any client-supplied headers are discarded); to send custom headers with a redirect, omit top-level location and instead supply {\"headers\": {\"location\": [url], ...}} (a location entry there is required and satisfies the location requirement); headers -> {\"request\": {\"add\"/\"set\": {name: [values]}, \"delete\": [names]}, \"response\": {same}} with at least one non-empty operation; reroute -> {\"destination\": string (required), \"port\": integer (default 443), \"host_setting\": \"destination\"|\"incoming_address\"|\"x_forwarded_host\" (default \"destination\")} reverse-proxies to a single upstream and stops; rewrite -> {\"uri\": string, \"method\": string} rewrites before later rules/the origin; rate_limit -> {\"key_mode\": \"per_ip\"|\"shared\" (default \"per_ip\"), \"max_events\": integer 1..10000000 (required), \"window\": \"10s\"|\"60s\"|\"600s\"|\"3600s\" (default \"60s\")}. The rate_limit zone_token is server-managed: it is never accepted on input nor returned, and counters survive updates (zone state carries over by rule position among rate_limit rules). Responses echo the stored config, which can include server-computed keys (e.g. handler, injected headers) alongside the fields above; the whole object is accepted back on apply.",
        "properties": {
          "type": {"type": "string", "enum": ["blocker", "redirect", "headers", "reroute", "rewrite", "rate_limit"]},
          "name": {"type": ["string", "null"]},
          "description": {"type": ["string", "null"]},
          "config": {"type": "object", "description": "Type-specific action config; see the schema description. Defaults to {}."}
        }
      },
      "EdgeSequenceApply": {
        "type": "object", "required": ["matcher_groups"],
        "description": "The full desired definition of a sequence. Matcher groups are OR'd (the sequence matches when any group matches) and matchers within a group are AND'd. Rules execute in array order. Apply replaces the whole definition and promotes it live atomically; the previous live version and any unpromoted dashboard draft are demoted to version history. A GET response's data object is a valid apply payload. Unknown keys anywhere in the payload and server-managed keys (id, order, live_version, has_draft, timestamps) are ignored rather than rejected, so read responses can be replayed as apply payloads unchanged.",
        "properties": {
          "name": {"type": "string", "minLength": 1, "description": "Required on create. On update, omitted means keep the current name."},
          "description": {"type": ["string", "null"]},
          "active": {"type": "boolean", "description": "Defaults to true on create; when omitted on update the current value is preserved."},
          "dry_run": {"type": "boolean", "default": false, "description": "Must be a JSON boolean; any other type fails with 422 {\"errors\": {\"dry_run\": [\"must be a boolean\"]}}. When true, validates and returns warnings without writing."},
          "matcher_groups": {"type": "array", "minItems": 1, "items": {"$ref": "#/components/schemas/EdgeSequenceMatcherGroup"}},
          "rules": {"type": "array", "default": [], "items": {"$ref": "#/components/schemas/EdgeSequenceRule"}, "description": "Executed in array order. An empty list is accepted but the sequence then has no effect and a warning is returned."}
        }
      },
      "EdgeSequence": {
        "type": "object", "required": ["id", "name", "description", "order", "active", "live_version", "has_draft", "matcher_groups", "rules", "created_at", "updated_at"],
        "properties": {
          "id": {"type": "integer"},
          "name": {"type": "string"},
          "description": {"type": ["string", "null"]},
          "order": {"type": "integer", "description": "0-based position in the cluster's sequence execution order."},
          "active": {"type": "boolean"},
          "live_version": {"type": ["integer", "null"], "description": "Version number currently serving traffic; null when nothing is promoted."},
          "has_draft": {"type": "boolean", "description": "True when an unpromoted dashboard draft exists. API applies demote drafts to history."},
          "matcher_groups": {"type": "array", "items": {"$ref": "#/components/schemas/EdgeSequenceMatcherGroup"}, "description": "The live version's matcher groups. Server-managed data keys (psid, db_path) are omitted."},
          "rules": {"type": "array", "items": {"$ref": "#/components/schemas/EdgeSequenceRule"}, "description": "The live version's rules in execution order. zone_token is omitted."},
          "created_at": {"$ref": "#/components/schemas/NaiveDateTime"},
          "updated_at": {"$ref": "#/components/schemas/NaiveDateTime"}
        },
        "additionalProperties": false
      },
      "EdgeSequenceEnvelope": {
        "type": "object", "required": ["data", "warnings"],
        "description": "data is null only for dry-run applies. warnings has the same shape as errors and flags definitions that saved but need attention. Codes: shadows_later_rules (/rules/i: a response-returning rule has rules after it), unreachable (/rules/j: a rule after a response-returning rule; blocked_by points at it), rate_limit_not_enforced (/rules/i: the cluster image cannot enforce it yet), no_rules (\"\"), feature_disabled (\"\"). Always empty on reads.",
        "properties": {"data": {"oneOf": [{"$ref": "#/components/schemas/EdgeSequence"}, {"type": "null"}]}, "warnings": {"allOf": [{"$ref": "#/components/schemas/EdgeSequenceProblems"}], "example": {"/rules/0": [{"code": "shadows_later_rules", "message": "redirect returns a response, so the rules after it never run"}], "/rules/1": [{"code": "unreachable", "message": "rule 0 (redirect) returns a response before it", "blocked_by": "/rules/0"}]}}},
        "additionalProperties": false
      },
      "EdgeSequenceListEnvelope": {"type": "object", "required": ["data", "cursors"], "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/EdgeSequence"}}, "cursors": {"type": "object", "required": ["before", "after"], "properties": {"before": {"type": ["string", "null"]}, "after": {"type": ["string", "null"]}}, "additionalProperties": false}}, "additionalProperties": false},
      "EdgeSequenceVersionSummary": {
        "type": "object", "required": ["version", "live", "draft", "name", "description", "matcher_group_count", "rule_count", "created_at"],
        "description": "A version's summary. The definition itself is not included; read the sequence for the live definition.",
        "properties": {"version": {"type": "integer"}, "live": {"type": "boolean", "description": "True for the version currently serving traffic."}, "draft": {"type": "boolean", "description": "True for an unpromoted dashboard draft."}, "name": {"type": ["string", "null"]}, "description": {"type": ["string", "null"]}, "matcher_group_count": {"type": "integer"}, "rule_count": {"type": "integer"}, "created_at": {"$ref": "#/components/schemas/NaiveDateTime"}},
        "additionalProperties": false
      },
      "EdgeSequenceVersionListEnvelope": {
        "type": "object", "required": ["data", "cursors"],
        "properties": {"data": {"type": "array", "maxItems": 10, "items": {"$ref": "#/components/schemas/EdgeSequenceVersionSummary"}}, "cursors": {"type": "object", "required": ["older", "newer"], "properties": {"older": {"type": ["integer", "null"]}, "newer": {"type": ["integer", "null"]}}, "additionalProperties": false}},
        "additionalProperties": false
      },
      "EdgeSequenceReorder": {"type": "object", "required": ["position"], "properties": {"position": {"type": "integer", "description": "0-based target position; values outside the valid range are clamped. Must be a JSON integer."}}},
      "AnalyticsWindow": {"type": "object", "required": ["start", "end"], "properties": {"start": {"type": "string", "format": "date-time"}, "end": {"type": "string", "format": "date-time"}}, "additionalProperties": false},
      "AnalyticsBucket": {
        "type": "object", "required": ["ts", "request_count", "bytes_in", "bytes_out", "bytes_egress", "by_origin", "by_status_class"],
        "properties": {"ts": {"type": "string", "format": "date-time"}, "request_count": {"type": "integer", "minimum": 0}, "bytes_in": {"type": "integer", "minimum": 0}, "bytes_out": {"type": "integer", "minimum": 0}, "bytes_egress": {"type": "integer", "minimum": 0}, "by_origin": {"type": "object", "additionalProperties": {"type": "integer"}}, "by_status_class": {"type": "object", "additionalProperties": {"type": "integer"}}},
        "additionalProperties": false
      },
      "AnalyticsSeriesEnvelope": {
        "type": "object", "required": ["data"], "properties": {"data": {"type": "object", "required": ["proxy_server_id", "window", "granularity", "buckets"], "properties": {"proxy_server_id": {"type": "integer"}, "vhost_id": {"type": "integer"}, "window": {"$ref": "#/components/schemas/AnalyticsWindow"}, "granularity": {"type": "string", "enum": ["raw_1m", "h_1h", "d_1d"]}, "buckets": {"type": "array", "items": {"$ref": "#/components/schemas/AnalyticsBucket"}}}, "additionalProperties": false}},
        "additionalProperties": false
      },
      "AnalyticsTopEnvelope": {
        "type": "object", "required": ["data"], "properties": {"data": {"type": "object", "required": ["proxy_server_id", "window", "granularity", "dim", "items"], "properties": {"proxy_server_id": {"type": "integer"}, "vhost_id": {"type": "integer"}, "window": {"$ref": "#/components/schemas/AnalyticsWindow"}, "granularity": {"type": "string", "enum": ["raw_1m", "h_1h", "d_1d"]}, "dim": {"type": "string", "enum": ["country", "status", "method", "origin"]}, "items": {"type": "array", "items": {"type": "object", "required": ["value", "request_count", "bytes_in", "bytes_out"], "properties": {"value": {"oneOf": [{"type": "string"}, {"type": "integer"}]}, "request_count": {"type": "integer"}, "bytes_in": {"type": "integer"}, "bytes_out": {"type": "integer"}}, "additionalProperties": false}}}, "additionalProperties": false}},
        "additionalProperties": false
      },
      "RequestLog": {
        "type": "object", "required": ["ts", "vhost_id", "host", "method", "path", "status", "http_version", "client_ip", "country", "ua", "bytes_in", "bytes_out", "duration_us", "disposition", "sample_rate"],
        "properties": {"ts": {"type": "string", "format": "date-time"}, "vhost_id": {"type": "integer"}, "host": {"type": "string"}, "method": {"type": "string"}, "path": {"type": "string"}, "status": {"type": "integer"}, "http_version": {"type": "string"}, "client_ip": {"type": ["string", "null"]}, "country": {"type": ["string", "null"]}, "ua": {"type": "string"}, "bytes_in": {"type": "integer", "minimum": 0}, "bytes_out": {"type": "integer", "minimum": 0}, "duration_us": {"type": "integer", "minimum": 0}, "disposition": {"type": "string"}, "sample_rate": {"type": "integer", "minimum": 1}},
        "additionalProperties": false
      },
      "RequestLogEnvelope": {"type": "object", "required": ["logs", "next_cursor"], "properties": {"logs": {"type": "array", "items": {"$ref": "#/components/schemas/RequestLog"}}, "next_cursor": {"type": ["string", "null"]}}, "additionalProperties": false},
      "ToolError": {
        "type": "object", "required": ["ok", "error", "message"],
        "properties": {"ok": {"const": false}, "error": {"type": "string", "enum": ["invalid_input", "blocked_host", "rate_limited", "upstream_error", "upstream_timeout"]}, "message": {"type": "string"}},
        "additionalProperties": false
      },
      "ToolRateLimitError": {
        "type": "object", "required": ["ok", "error", "message", "scope"],
        "properties": {"ok": {"const": false}, "error": {"const": "rate_limited"}, "message": {"type": "string"}, "scope": {"type": "string", "enum": ["tool", "global", "daily"]}},
        "additionalProperties": false
      },
      "ToolPingEnvelope": {
        "type": "object", "required": ["ok", "data"],
        "properties": {"ok": {"const": true}, "data": {"type": "object", "required": ["pong"], "properties": {"pong": {"const": true}}, "additionalProperties": false}},
        "additionalProperties": false
      },
      "ToolSuccess": {
        "type": "object", "required": ["ok", "data"],
        "properties": {"ok": {"const": true}, "data": {"type": "object"}},
        "additionalProperties": false
      },
      "StringList": {"type": "array", "items": {"type": "string"}},
      "ToolDnsRecordsEnvelope": {
        "type": "object", "required": ["ok", "data"],
        "properties": {"ok": {"const": true}, "data": {"type": "object", "required": ["domain", "records"], "properties": {"domain": {"type": "string"}, "records": {"type": "object", "additionalProperties": {"$ref": "#/components/schemas/StringList"}, "example": {"a": ["93.184.216.34"], "aaaa": [], "cname": []}}}, "additionalProperties": false}},
        "additionalProperties": false
      },
      "ToolTxtEnvelope": {
        "type": "object", "required": ["ok", "data"],
        "properties": {"ok": {"const": true}, "data": {"type": "object", "required": ["domain", "records", "categorized"], "properties": {"domain": {"type": "string"}, "records": {"$ref": "#/components/schemas/StringList"}, "categorized": {"type": "object", "required": ["spf", "dkim", "dmarc", "verification", "other"], "properties": {"spf": {"$ref": "#/components/schemas/StringList"}, "dkim": {"$ref": "#/components/schemas/StringList"}, "dmarc": {"$ref": "#/components/schemas/StringList"}, "verification": {"$ref": "#/components/schemas/StringList"}, "other": {"$ref": "#/components/schemas/StringList"}}, "additionalProperties": false}}, "additionalProperties": false}},
        "additionalProperties": false
      },
      "ToolSpfEnvelope": {
        "type": "object", "required": ["ok", "data"],
        "properties": {"ok": {"const": true}, "data": {"type": "object", "required": ["domain", "found", "record", "mechanisms", "all_qualifier", "dns_lookups", "warnings"], "properties": {"domain": {"type": "string"}, "found": {"type": "boolean"}, "record": {"type": ["string", "null"]}, "mechanisms": {"$ref": "#/components/schemas/StringList"}, "all_qualifier": {"type": ["string", "null"], "enum": ["+", "-", "~", "?", null]}, "dns_lookups": {"type": "integer", "minimum": 0}, "warnings": {"$ref": "#/components/schemas/StringList"}}, "additionalProperties": false}},
        "additionalProperties": false
      },
      "ToolDmarcEnvelope": {
        "type": "object", "required": ["ok", "data"],
        "properties": {"ok": {"const": true}, "data": {"type": "object", "required": ["domain", "found", "record", "policy", "subdomain_policy", "pct", "rua", "warnings"], "properties": {"domain": {"type": "string"}, "found": {"type": "boolean"}, "record": {"type": ["string", "null"]}, "policy": {"type": ["string", "null"]}, "subdomain_policy": {"type": ["string", "null"]}, "pct": {"type": ["integer", "null"]}, "rua": {"$ref": "#/components/schemas/StringList"}, "warnings": {"$ref": "#/components/schemas/StringList"}}, "additionalProperties": false}},
        "additionalProperties": false
      },
      "ToolDkimEnvelope": {
        "type": "object", "required": ["ok", "data"],
        "properties": {"ok": {"const": true}, "data": {"type": "object", "required": ["domain", "selector", "found", "record", "key_type", "public_key_present", "warnings"], "properties": {"domain": {"type": "string"}, "selector": {"type": "string"}, "found": {"type": "boolean"}, "record": {"type": ["string", "null"]}, "key_type": {"type": ["string", "null"]}, "public_key_present": {"type": "boolean"}, "warnings": {"$ref": "#/components/schemas/StringList"}}, "additionalProperties": false}},
        "additionalProperties": false
      },
      "CnameProvider": {
        "type": "object", "required": ["name", "provider_domain", "nameservers"],
        "properties": {"name": {"type": "string"}, "provider_domain": {"type": "string"}, "nameservers": {"$ref": "#/components/schemas/StringList"}},
        "additionalProperties": false
      },
      "DnsInstructionRecord": {
        "type": "object", "required": ["type", "host", "domain", "value", "ttl", "subdomain", "combined_host", "apex_domain"],
        "properties": {"type": {"type": "string"}, "host": {"type": "string"}, "domain": {"type": "string"}, "value": {"type": "string"}, "ttl": {"oneOf": [{"type": "string"}, {"type": "integer"}]}, "subdomain": {"type": "string"}, "combined_host": {"type": "string"}, "apex_domain": {"type": "string"}},
        "additionalProperties": true
      },
      "CnameInstructions": {
        "type": "object", "required": ["domain_results"],
        "properties": {"domain_results": {"type": "object", "additionalProperties": {"type": "object", "required": ["steps", "records"], "properties": {"steps": {"description": "Plain text with server-side HTML stripped.", "$ref": "#/components/schemas/StringList"}, "records": {"type": "array", "items": {"$ref": "#/components/schemas/DnsInstructionRecord"}}}, "additionalProperties": false}}},
        "additionalProperties": false
      },
      "ToolCnameEnvelope": {
        "type": "object", "required": ["ok", "data"],
        "properties": {"ok": {"const": true}, "data": {"oneOf": [
          {"type": "object", "required": ["domain", "target", "chain"], "properties": {"domain": {"type": "string"}, "target": {"type": ["string", "null"]}, "chain": {"$ref": "#/components/schemas/StringList"}}, "additionalProperties": false},
          {"type": "object", "required": ["domain", "target", "chain", "requested_target", "provider", "instructions"], "properties": {"domain": {"type": "string"}, "target": {"type": ["string", "null"]}, "chain": {"$ref": "#/components/schemas/StringList"}, "requested_target": {"type": "string"}, "provider": {"$ref": "#/components/schemas/CnameProvider"}, "instructions": {"oneOf": [{"$ref": "#/components/schemas/CnameInstructions"}, {"type": "null"}]}}, "additionalProperties": false}
        ]}},
        "additionalProperties": false
      },
      "ToolReverseIpEnvelope": {
        "type": "object", "required": ["ok", "data"],
        "properties": {"ok": {"const": true}, "data": {"type": "object", "required": ["ip", "hostnames"], "properties": {"ip": {"type": "string"}, "hostnames": {"$ref": "#/components/schemas/StringList"}}, "additionalProperties": false}},
        "additionalProperties": false
      },
      "PropagationResolverResult": {
        "type": "object", "required": ["resolver", "status", "ips", "error", "duration_ms"],
        "properties": {"resolver": {"type": "string"}, "status": {"type": "string", "enum": ["ok", "error"]}, "ips": {"$ref": "#/components/schemas/StringList"}, "error": {"type": ["string", "null"]}, "duration_ms": {"type": "integer", "minimum": 0}},
        "additionalProperties": false
      },
      "ToolPropagationEnvelope": {
        "type": "object", "required": ["ok", "data"],
        "properties": {"ok": {"const": true}, "data": {"type": "object", "required": ["domain", "consistent", "results"], "properties": {"domain": {"type": "string"}, "consistent": {"type": "boolean"}, "results": {"type": "array", "items": {"$ref": "#/components/schemas/PropagationResolverResult"}}}, "additionalProperties": false}},
        "additionalProperties": false
      },
      "ToolStatusEnvelope": {
        "type": "object", "required": ["ok", "data"],
        "properties": {"ok": {"const": true}, "data": {"type": "object", "required": ["url", "up", "status", "response_time_ms", "final_url", "error"], "properties": {"url": {"type": "string", "format": "uri"}, "up": {"type": "boolean"}, "status": {"type": ["integer", "null"]}, "response_time_ms": {"type": ["integer", "null"]}, "final_url": {"type": "string", "format": "uri"}, "error": {"type": ["string", "null"]}}, "additionalProperties": false}},
        "additionalProperties": false
      },
      "SecurityHeaderGrade": {
        "type": "object", "required": ["grade", "present", "missing"],
        "properties": {"grade": {"type": "string", "enum": ["A", "B", "C", "D", "E", "F"]}, "present": {"$ref": "#/components/schemas/StringList"}, "missing": {"$ref": "#/components/schemas/StringList"}},
        "additionalProperties": false
      },
      "ToolHeadersEnvelope": {
        "type": "object", "required": ["ok", "data"],
        "properties": {"ok": {"const": true}, "data": {"type": "object", "required": ["url", "status", "headers", "security", "error"], "properties": {"url": {"type": "string", "format": "uri"}, "status": {"type": ["integer", "null"]}, "headers": {"type": "object", "additionalProperties": {"type": "string"}}, "security": {"$ref": "#/components/schemas/SecurityHeaderGrade"}, "error": {"type": ["string", "null"]}}, "additionalProperties": false}},
        "additionalProperties": false
      },
      "RedirectHop": {"type": "object", "required": ["url", "status", "location"], "properties": {"url": {"type": "string", "format": "uri"}, "status": {"type": ["integer", "null"]}, "location": {"type": ["string", "null"]}}, "additionalProperties": false},
      "ToolRedirectsEnvelope": {
        "type": "object", "required": ["ok", "data"],
        "properties": {"ok": {"const": true}, "data": {"type": "object", "required": ["url", "hops", "final_url", "final_status", "count", "looped", "error"], "properties": {"url": {"type": "string", "format": "uri"}, "hops": {"type": "array", "items": {"$ref": "#/components/schemas/RedirectHop"}}, "final_url": {"type": "string", "format": "uri"}, "final_status": {"type": ["integer", "null"]}, "count": {"type": "integer", "minimum": 0}, "looped": {"type": "boolean"}, "error": {"type": ["string", "null"]}}, "additionalProperties": false}},
        "additionalProperties": false
      },
      "ToolSslEnvelope": {
        "type": "object", "required": ["ok", "data"],
        "properties": {"ok": {"const": true}, "data": {"type": "object", "required": ["host", "port", "subject", "issuer", "sans", "not_before", "not_after", "days_remaining", "serial", "signature_algorithm", "self_signed"], "properties": {"host": {"type": "string"}, "port": {"type": "integer"}, "subject": {"type": "string"}, "issuer": {"type": "string"}, "sans": {"$ref": "#/components/schemas/StringList"}, "not_before": {"type": "string", "format": "date-time"}, "not_after": {"type": "string", "format": "date-time"}, "days_remaining": {"type": "integer"}, "serial": {"type": "string"}, "signature_algorithm": {"type": "string"}, "self_signed": {"type": "boolean"}}, "additionalProperties": false}},
        "additionalProperties": false
      },
      "WhoisRegistered": {
        "type": "object", "required": ["domain", "registered", "registrar", "created", "updated", "expires", "nameservers", "statuses", "registrant_country"],
        "properties": {"domain": {"type": "string"}, "registered": {"const": true}, "registrar": {"type": ["string", "null"]}, "created": {"type": ["string", "null"], "format": "date-time"}, "updated": {"type": ["string", "null"], "format": "date-time"}, "expires": {"type": ["string", "null"], "format": "date-time"}, "nameservers": {"$ref": "#/components/schemas/StringList"}, "statuses": {"$ref": "#/components/schemas/StringList"}, "registrant_country": {"type": ["string", "null"]}},
        "additionalProperties": false
      },
      "RegistrationNegative": {"type": "object", "required": ["domain", "registered"], "properties": {"domain": {"type": "string"}, "registered": {"const": false}}, "additionalProperties": false},
      "RegistrationUnknown": {"type": "object", "required": ["domain", "registered", "note"], "properties": {"domain": {"type": "string"}, "registered": {"type": "null"}, "note": {"type": "string"}}, "additionalProperties": false},
      "ToolWhoisEnvelope": {
        "type": "object", "required": ["ok", "data"],
        "properties": {"ok": {"const": true}, "data": {"oneOf": [{"$ref": "#/components/schemas/WhoisRegistered"}, {"$ref": "#/components/schemas/RegistrationNegative"}, {"$ref": "#/components/schemas/RegistrationUnknown"}]}},
        "additionalProperties": false
      },
      "ToolSubdomainsEnvelope": {
        "type": "object", "required": ["ok", "data"],
        "properties": {"ok": {"const": true}, "data": {"type": "object", "required": ["domain", "subdomains", "count", "truncated", "source"], "properties": {"domain": {"type": "string"}, "subdomains": {"$ref": "#/components/schemas/StringList"}, "count": {"type": "integer", "minimum": 0, "maximum": 500}, "truncated": {"type": "boolean"}, "source": {"const": "crt.sh"}, "error": {"type": "string", "description": "Present only when crt.sh returned a partial/failure result."}}, "additionalProperties": false}},
        "additionalProperties": false
      },
      "DomainAgeRegistered": {
        "type": "object", "required": ["domain", "registered", "created", "expires", "age_days", "age_years"],
        "properties": {"domain": {"type": "string"}, "registered": {"const": true}, "created": {"type": ["string", "null"], "format": "date-time"}, "expires": {"type": ["string", "null"], "format": "date-time"}, "age_days": {"type": ["integer", "null"]}, "age_years": {"type": ["integer", "null"]}},
        "additionalProperties": false
      },
      "ToolDomainAgeEnvelope": {
        "type": "object", "required": ["ok", "data"],
        "properties": {"ok": {"const": true}, "data": {"oneOf": [{"$ref": "#/components/schemas/DomainAgeRegistered"}, {"$ref": "#/components/schemas/RegistrationNegative"}, {"$ref": "#/components/schemas/RegistrationUnknown"}]}},
        "additionalProperties": false
      },
      "AvailabilitySingle": {
        "oneOf": [
          {"type": "object", "required": ["domain", "available"], "properties": {"domain": {"type": "string"}, "available": {"const": true}}, "additionalProperties": false},
          {"type": "object", "required": ["domain", "available", "expires"], "properties": {"domain": {"type": "string"}, "available": {"const": false}, "expires": {"type": ["string", "null"], "format": "date-time"}}, "additionalProperties": false},
          {"type": "object", "required": ["domain", "available", "note"], "properties": {"domain": {"type": "string"}, "available": {"type": "null"}, "note": {"type": "string"}}, "additionalProperties": false}
        ]
      },
      "AvailabilityMulti": {
        "type": "object", "required": ["base", "results"],
        "properties": {"base": {"type": "string"}, "results": {"type": "array", "maxItems": 10, "items": {"type": "object", "required": ["domain", "available"], "properties": {"domain": {"type": "string"}, "available": {"type": ["boolean", "null"]}}, "additionalProperties": false}}},
        "additionalProperties": false
      },
      "ToolAvailabilityEnvelope": {
        "type": "object", "required": ["ok", "data"],
        "properties": {"ok": {"const": true}, "data": {"oneOf": [{"$ref": "#/components/schemas/AvailabilitySingle"}, {"$ref": "#/components/schemas/AvailabilityMulti"}]}},
        "additionalProperties": false
      }
    }
  },
  "webhooks": {}
}
