{
  "schema_version": "1.0.0",
  "canonical": "https://approximated.app/agent-tools/catalog.json",
  "generated_from": "https://approximated.app/openapi.yaml",
  "source_openapi_version": "3.1.0",
  "source_api_version": "2026-08-05",
  "reviewed_date": "2026-08-05",
  "operation_count": 17,
  "operations": [
    {
      "operation_id": "checkDkimRecord",
      "method": "GET",
      "path": "/api/tools/dkim",
      "url": "https://cloud.approximated.app/api/tools/dkim",
      "summary": "Parse a DKIM selector record",
      "description": null,
      "parameters": [
        {
          "name": "domain",
          "in": "query",
          "required": true,
          "description": null,
          "schema": {
            "type": "string",
            "format": "hostname",
            "example": "example.com"
          },
          "source_ref": "#/components/parameters/ToolDomain"
        },
        {
          "name": "selector",
          "in": "query",
          "required": true,
          "description": null,
          "schema": {
            "type": "string",
            "minLength": 1,
            "maxLength": 63,
            "pattern": "^[A-Za-z0-9._-]+$",
            "example": "google"
          },
          "source_ref": null
        }
      ],
      "auth": false,
      "success_semantics": [
        {
          "status": "200",
          "description": "DKIM result. No record is a successful negative result.",
          "schema_ref": "#/components/schemas/ToolDkimEnvelope",
          "response_ref": null
        }
      ],
      "error_semantics": [
        {
          "status": "400",
          "description": "Required input is missing or invalid.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolInvalidInput"
        },
        {
          "status": "429",
          "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.",
          "schema_ref": "#/components/schemas/ToolRateLimitError",
          "response_ref": "#/components/responses/ToolRateLimited"
        },
        {
          "status": "502",
          "description": "An upstream DNS, RDAP, or TLS dependency failed.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolUpstreamError"
        }
      ],
      "rate_limit": {
        "applies": true,
        "policy": "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.",
        "retry_after_header": {
          "description": "Seconds until the denying bucket resets.",
          "schema": {
            "type": "integer",
            "minimum": 1
          },
          "example": 42
        }
      },
      "retry_guidance": "On HTTP 429, wait for the Retry-After number of seconds before retrying.",
      "safety_notes": [],
      "partial_result_notes": [
        "No record is a successful negative result."
      ],
      "schema_refs": [
        "#/components/schemas/ToolDkimEnvelope",
        "#/components/schemas/ToolError",
        "#/components/schemas/ToolRateLimitError"
      ]
    },
    {
      "operation_id": "checkDmarcRecord",
      "method": "GET",
      "path": "/api/tools/dmarc",
      "url": "https://cloud.approximated.app/api/tools/dmarc",
      "summary": "Parse a domain's DMARC record",
      "description": null,
      "parameters": [
        {
          "name": "domain",
          "in": "query",
          "required": true,
          "description": null,
          "schema": {
            "type": "string",
            "format": "hostname",
            "example": "example.com"
          },
          "source_ref": "#/components/parameters/ToolDomain"
        }
      ],
      "auth": false,
      "success_semantics": [
        {
          "status": "200",
          "description": "DMARC result. No record is a successful negative result.",
          "schema_ref": "#/components/schemas/ToolDmarcEnvelope",
          "response_ref": null
        }
      ],
      "error_semantics": [
        {
          "status": "400",
          "description": "Required input is missing or invalid.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolInvalidInput"
        },
        {
          "status": "429",
          "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.",
          "schema_ref": "#/components/schemas/ToolRateLimitError",
          "response_ref": "#/components/responses/ToolRateLimited"
        },
        {
          "status": "502",
          "description": "An upstream DNS, RDAP, or TLS dependency failed.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolUpstreamError"
        }
      ],
      "rate_limit": {
        "applies": true,
        "policy": "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.",
        "retry_after_header": {
          "description": "Seconds until the denying bucket resets.",
          "schema": {
            "type": "integer",
            "minimum": 1
          },
          "example": 42
        }
      },
      "retry_guidance": "On HTTP 429, wait for the Retry-After number of seconds before retrying.",
      "safety_notes": [],
      "partial_result_notes": [
        "No record is a successful negative result."
      ],
      "schema_refs": [
        "#/components/schemas/ToolDmarcEnvelope",
        "#/components/schemas/ToolError",
        "#/components/schemas/ToolRateLimitError"
      ]
    },
    {
      "operation_id": "checkDnsPropagation",
      "method": "GET",
      "path": "/api/tools/propagation",
      "url": "https://cloud.approximated.app/api/tools/propagation",
      "summary": "Compare A records across public resolvers",
      "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": [
        {
          "name": "domain",
          "in": "query",
          "required": true,
          "description": null,
          "schema": {
            "type": "string",
            "format": "hostname",
            "example": "example.com"
          },
          "source_ref": "#/components/parameters/ToolDomain"
        }
      ],
      "auth": false,
      "success_semantics": [
        {
          "status": "200",
          "description": "Resolver results.",
          "schema_ref": "#/components/schemas/ToolPropagationEnvelope",
          "response_ref": null
        }
      ],
      "error_semantics": [
        {
          "status": "400",
          "description": "Required input is missing or invalid.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolInvalidInput"
        },
        {
          "status": "429",
          "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.",
          "schema_ref": "#/components/schemas/ToolRateLimitError",
          "response_ref": "#/components/responses/ToolRateLimited"
        }
      ],
      "rate_limit": {
        "applies": true,
        "policy": "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.",
        "retry_after_header": {
          "description": "Seconds until the denying bucket resets.",
          "schema": {
            "type": "integer",
            "minimum": 1
          },
          "example": 42
        }
      },
      "retry_guidance": "On HTTP 429, wait for the Retry-After number of seconds before retrying.",
      "safety_notes": [],
      "partial_result_notes": [
        "Per-resolver failures are returned inside a successful result.",
        "consistent is true when all successful resolvers agree; zero successful resolvers currently also yields true."
      ],
      "schema_refs": [
        "#/components/schemas/ToolPropagationEnvelope",
        "#/components/schemas/ToolError",
        "#/components/schemas/ToolRateLimitError"
      ]
    },
    {
      "operation_id": "checkDomainAvailability",
      "method": "GET",
      "path": "/api/tools/availability",
      "url": "https://cloud.approximated.app/api/tools/availability",
      "summary": "Check one domain or a base label across TLDs",
      "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"
          },
          "source_ref": null
        },
        {
          "name": "tlds",
          "in": "query",
          "required": false,
          "description": "Comma-separated TLDs; at most 10.",
          "schema": {
            "type": "string",
            "example": "com,net,io"
          },
          "source_ref": null
        }
      ],
      "auth": false,
      "success_semantics": [
        {
          "status": "200",
          "description": "Single-domain or multi-TLD result.",
          "schema_ref": "#/components/schemas/ToolAvailabilityEnvelope",
          "response_ref": null
        }
      ],
      "error_semantics": [
        {
          "status": "400",
          "description": "Required input is missing or invalid.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolInvalidInput"
        },
        {
          "status": "429",
          "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.",
          "schema_ref": "#/components/schemas/ToolRateLimitError",
          "response_ref": "#/components/responses/ToolRateLimited"
        },
        {
          "status": "502",
          "description": "An upstream DNS, RDAP, or TLS dependency failed.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolUpstreamError"
        }
      ],
      "rate_limit": {
        "applies": true,
        "policy": "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.",
        "retry_after_header": {
          "description": "Seconds until the denying bucket resets.",
          "schema": {
            "type": "integer",
            "minimum": 1
          },
          "example": 42
        }
      },
      "retry_guidance": "On HTTP 429, wait for the Retry-After number of seconds before retrying.",
      "safety_notes": [],
      "partial_result_notes": [
        "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."
      ],
      "schema_refs": [
        "#/components/schemas/ToolAvailabilityEnvelope",
        "#/components/schemas/ToolError",
        "#/components/schemas/ToolRateLimitError"
      ]
    },
    {
      "operation_id": "checkSpfRecord",
      "method": "GET",
      "path": "/api/tools/spf",
      "url": "https://cloud.approximated.app/api/tools/spf",
      "summary": "Parse a domain's SPF record",
      "description": null,
      "parameters": [
        {
          "name": "domain",
          "in": "query",
          "required": true,
          "description": null,
          "schema": {
            "type": "string",
            "format": "hostname",
            "example": "example.com"
          },
          "source_ref": "#/components/parameters/ToolDomain"
        }
      ],
      "auth": false,
      "success_semantics": [
        {
          "status": "200",
          "description": "SPF result. No record is a successful negative result.",
          "schema_ref": "#/components/schemas/ToolSpfEnvelope",
          "response_ref": null
        }
      ],
      "error_semantics": [
        {
          "status": "400",
          "description": "Required input is missing or invalid.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolInvalidInput"
        },
        {
          "status": "429",
          "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.",
          "schema_ref": "#/components/schemas/ToolRateLimitError",
          "response_ref": "#/components/responses/ToolRateLimited"
        },
        {
          "status": "502",
          "description": "An upstream DNS, RDAP, or TLS dependency failed.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolUpstreamError"
        }
      ],
      "rate_limit": {
        "applies": true,
        "policy": "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.",
        "retry_after_header": {
          "description": "Seconds until the denying bucket resets.",
          "schema": {
            "type": "integer",
            "minimum": 1
          },
          "example": 42
        }
      },
      "retry_guidance": "On HTTP 429, wait for the Retry-After number of seconds before retrying.",
      "safety_notes": [],
      "partial_result_notes": [
        "No record is a successful negative result."
      ],
      "schema_refs": [
        "#/components/schemas/ToolSpfEnvelope",
        "#/components/schemas/ToolError",
        "#/components/schemas/ToolRateLimitError"
      ]
    },
    {
      "operation_id": "checkWebsiteStatus",
      "method": "GET",
      "path": "/api/tools/status",
      "url": "https://cloud.approximated.app/api/tools/status",
      "summary": "Check an HTTP URL without following redirects",
      "description": "SSRF blocks and transport failures are successful HTTP 200 responses with data.up=false and data.error set.",
      "parameters": [
        {
          "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"
            ]
          },
          "source_ref": "#/components/parameters/ToolUrl"
        }
      ],
      "auth": false,
      "success_semantics": [
        {
          "status": "200",
          "description": "HTTP status or in-band block/failure result.",
          "schema_ref": "#/components/schemas/ToolStatusEnvelope",
          "response_ref": null
        }
      ],
      "error_semantics": [
        {
          "status": "400",
          "description": "Required input is missing or invalid.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolInvalidInput"
        },
        {
          "status": "429",
          "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.",
          "schema_ref": "#/components/schemas/ToolRateLimitError",
          "response_ref": "#/components/responses/ToolRateLimited"
        }
      ],
      "rate_limit": {
        "applies": true,
        "policy": "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.",
        "retry_after_header": {
          "description": "Seconds until the denying bucket resets.",
          "schema": {
            "type": "integer",
            "minimum": 1
          },
          "example": 42
        }
      },
      "retry_guidance": "On HTTP 429, wait for the Retry-After number of seconds before retrying.",
      "safety_notes": [
        "SSRF blocks and transport failures are successful HTTP 200 responses with data.up=false and data.error set."
      ],
      "partial_result_notes": [
        "HTTP status or in-band block/failure result."
      ],
      "schema_refs": [
        "#/components/schemas/ToolStatusEnvelope",
        "#/components/schemas/ToolError",
        "#/components/schemas/ToolRateLimitError"
      ]
    },
    {
      "operation_id": "findSubdomains",
      "method": "GET",
      "path": "/api/tools/subdomains",
      "url": "https://cloud.approximated.app/api/tools/subdomains",
      "summary": "Find subdomains from certificate transparency",
      "description": "crt.sh failures degrade to a 200 response with an empty list and data.error set.",
      "parameters": [
        {
          "name": "domain",
          "in": "query",
          "required": true,
          "description": null,
          "schema": {
            "type": "string",
            "format": "hostname",
            "example": "example.com"
          },
          "source_ref": "#/components/parameters/ToolDomain"
        }
      ],
      "auth": false,
      "success_semantics": [
        {
          "status": "200",
          "description": "Subdomain result, possibly partial.",
          "schema_ref": "#/components/schemas/ToolSubdomainsEnvelope",
          "response_ref": null
        }
      ],
      "error_semantics": [
        {
          "status": "400",
          "description": "Required input is missing or invalid.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolInvalidInput"
        },
        {
          "status": "429",
          "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.",
          "schema_ref": "#/components/schemas/ToolRateLimitError",
          "response_ref": "#/components/responses/ToolRateLimited"
        }
      ],
      "rate_limit": {
        "applies": true,
        "policy": "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.",
        "retry_after_header": {
          "description": "Seconds until the denying bucket resets.",
          "schema": {
            "type": "integer",
            "minimum": 1
          },
          "example": 42
        }
      },
      "retry_guidance": "On HTTP 429, wait for the Retry-After number of seconds before retrying.",
      "safety_notes": [],
      "partial_result_notes": [
        "crt.sh failures degrade to a 200 response with an empty list and data.error set.",
        "Subdomain result, possibly partial."
      ],
      "schema_refs": [
        "#/components/schemas/ToolSubdomainsEnvelope",
        "#/components/schemas/ToolError",
        "#/components/schemas/ToolRateLimitError"
      ]
    },
    {
      "operation_id": "getDomainAge",
      "method": "GET",
      "path": "/api/tools/domain-age",
      "url": "https://cloud.approximated.app/api/tools/domain-age",
      "summary": "Calculate domain age from RDAP",
      "description": null,
      "parameters": [
        {
          "name": "domain",
          "in": "query",
          "required": true,
          "description": null,
          "schema": {
            "type": "string",
            "format": "hostname",
            "example": "example.com"
          },
          "source_ref": "#/components/parameters/ToolDomain"
        }
      ],
      "auth": false,
      "success_semantics": [
        {
          "status": "200",
          "description": "Registered, unregistered, or unsupported-TLD result.",
          "schema_ref": "#/components/schemas/ToolDomainAgeEnvelope",
          "response_ref": null
        }
      ],
      "error_semantics": [
        {
          "status": "400",
          "description": "Required input is missing or invalid.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolInvalidInput"
        },
        {
          "status": "429",
          "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.",
          "schema_ref": "#/components/schemas/ToolRateLimitError",
          "response_ref": "#/components/responses/ToolRateLimited"
        },
        {
          "status": "502",
          "description": "An upstream DNS, RDAP, or TLS dependency failed.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolUpstreamError"
        }
      ],
      "rate_limit": {
        "applies": true,
        "policy": "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.",
        "retry_after_header": {
          "description": "Seconds until the denying bucket resets.",
          "schema": {
            "type": "integer",
            "minimum": 1
          },
          "example": 42
        }
      },
      "retry_guidance": "On HTTP 429, wait for the Retry-After number of seconds before retrying.",
      "safety_notes": [],
      "partial_result_notes": [],
      "schema_refs": [
        "#/components/schemas/ToolDomainAgeEnvelope",
        "#/components/schemas/ToolError",
        "#/components/schemas/ToolRateLimitError"
      ]
    },
    {
      "operation_id": "inspectHttpHeaders",
      "method": "GET",
      "path": "/api/tools/headers",
      "url": "https://cloud.approximated.app/api/tools/headers",
      "summary": "Inspect response and security headers",
      "description": "SSRF blocks and transport failures are successful HTTP 200 responses with an empty header map and data.error set.",
      "parameters": [
        {
          "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"
            ]
          },
          "source_ref": "#/components/parameters/ToolUrl"
        }
      ],
      "auth": false,
      "success_semantics": [
        {
          "status": "200",
          "description": "HTTP headers or in-band block/failure result.",
          "schema_ref": "#/components/schemas/ToolHeadersEnvelope",
          "response_ref": null
        }
      ],
      "error_semantics": [
        {
          "status": "400",
          "description": "Required input is missing or invalid.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolInvalidInput"
        },
        {
          "status": "429",
          "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.",
          "schema_ref": "#/components/schemas/ToolRateLimitError",
          "response_ref": "#/components/responses/ToolRateLimited"
        }
      ],
      "rate_limit": {
        "applies": true,
        "policy": "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.",
        "retry_after_header": {
          "description": "Seconds until the denying bucket resets.",
          "schema": {
            "type": "integer",
            "minimum": 1
          },
          "example": 42
        }
      },
      "retry_guidance": "On HTTP 429, wait for the Retry-After number of seconds before retrying.",
      "safety_notes": [
        "SSRF blocks and transport failures are successful HTTP 200 responses with an empty header map and data.error set."
      ],
      "partial_result_notes": [
        "SSRF blocks and transport failures are successful HTTP 200 responses with an empty header map and data.error set.",
        "HTTP headers or in-band block/failure result."
      ],
      "schema_refs": [
        "#/components/schemas/ToolHeadersEnvelope",
        "#/components/schemas/ToolError",
        "#/components/schemas/ToolRateLimitError"
      ]
    },
    {
      "operation_id": "inspectRedirectChain",
      "method": "GET",
      "path": "/api/tools/redirects",
      "url": "https://cloud.approximated.app/api/tools/redirects",
      "summary": "Follow and inspect an HTTP redirect chain",
      "description": "Every hop is SSRF-checked. Blocks, loops, hop limits, and transport failures are represented in-band in a successful HTTP 200 response.",
      "parameters": [
        {
          "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"
            ]
          },
          "source_ref": "#/components/parameters/ToolUrl"
        }
      ],
      "auth": false,
      "success_semantics": [
        {
          "status": "200",
          "description": "Redirect chain or in-band stop result.",
          "schema_ref": "#/components/schemas/ToolRedirectsEnvelope",
          "response_ref": null
        }
      ],
      "error_semantics": [
        {
          "status": "400",
          "description": "Required input is missing or invalid.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolInvalidInput"
        },
        {
          "status": "429",
          "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.",
          "schema_ref": "#/components/schemas/ToolRateLimitError",
          "response_ref": "#/components/responses/ToolRateLimited"
        }
      ],
      "rate_limit": {
        "applies": true,
        "policy": "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.",
        "retry_after_header": {
          "description": "Seconds until the denying bucket resets.",
          "schema": {
            "type": "integer",
            "minimum": 1
          },
          "example": 42
        }
      },
      "retry_guidance": "On HTTP 429, wait for the Retry-After number of seconds before retrying.",
      "safety_notes": [
        "Every hop is SSRF-checked."
      ],
      "partial_result_notes": [
        "Blocks, loops, hop limits, and transport failures are represented in-band in a successful HTTP 200 response.",
        "Redirect chain or in-band stop result."
      ],
      "schema_refs": [
        "#/components/schemas/ToolRedirectsEnvelope",
        "#/components/schemas/ToolError",
        "#/components/schemas/ToolRateLimitError"
      ]
    },
    {
      "operation_id": "inspectTlsCertificate",
      "method": "GET",
      "path": "/api/tools/ssl",
      "url": "https://cloud.approximated.app/api/tools/ssl",
      "summary": "Inspect a host's leaf TLS certificate",
      "description": null,
      "parameters": [
        {
          "name": "host",
          "in": "query",
          "required": true,
          "description": null,
          "schema": {
            "type": "string",
            "format": "hostname",
            "example": "example.com"
          },
          "source_ref": null
        },
        {
          "name": "port",
          "in": "query",
          "required": false,
          "description": null,
          "schema": {
            "type": "integer",
            "minimum": 1,
            "maximum": 65535,
            "default": 443
          },
          "source_ref": null
        }
      ],
      "auth": false,
      "success_semantics": [
        {
          "status": "200",
          "description": "Certificate details.",
          "schema_ref": "#/components/schemas/ToolSslEnvelope",
          "response_ref": null
        }
      ],
      "error_semantics": [
        {
          "status": "400",
          "description": "Invalid input or private/unresolvable host.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": null
        },
        {
          "status": "429",
          "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.",
          "schema_ref": "#/components/schemas/ToolRateLimitError",
          "response_ref": "#/components/responses/ToolRateLimited"
        },
        {
          "status": "502",
          "description": "An upstream DNS, RDAP, or TLS dependency failed.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolUpstreamError"
        },
        {
          "status": "504",
          "description": "TLS connection timed out.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": null
        }
      ],
      "rate_limit": {
        "applies": true,
        "policy": "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.",
        "retry_after_header": {
          "description": "Seconds until the denying bucket resets.",
          "schema": {
            "type": "integer",
            "minimum": 1
          },
          "example": 42
        }
      },
      "retry_guidance": "On HTTP 429, wait for the Retry-After number of seconds before retrying.",
      "safety_notes": [
        "Invalid input or private/unresolvable host."
      ],
      "partial_result_notes": [],
      "schema_refs": [
        "#/components/schemas/ToolSslEnvelope",
        "#/components/schemas/ToolError",
        "#/components/schemas/ToolRateLimitError"
      ]
    },
    {
      "operation_id": "lookupCname",
      "method": "GET",
      "path": "/api/tools/cname",
      "url": "https://cloud.approximated.app/api/tools/cname",
      "summary": "Resolve a CNAME chain and optionally generate setup instructions",
      "description": null,
      "parameters": [
        {
          "name": "domain",
          "in": "query",
          "required": true,
          "description": null,
          "schema": {
            "type": "string",
            "format": "hostname",
            "example": "example.com"
          },
          "source_ref": "#/components/parameters/ToolDomain"
        },
        {
          "name": "target",
          "in": "query",
          "required": false,
          "description": "When present, adds provider detection and instructions for pointing domain to target.",
          "schema": {
            "type": "string",
            "format": "hostname",
            "example": "target.example.net"
          },
          "source_ref": null
        }
      ],
      "auth": false,
      "success_semantics": [
        {
          "status": "200",
          "description": "CNAME lookup or generator result.",
          "schema_ref": "#/components/schemas/ToolCnameEnvelope",
          "response_ref": null
        }
      ],
      "error_semantics": [
        {
          "status": "400",
          "description": "Required input is missing or invalid.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolInvalidInput"
        },
        {
          "status": "429",
          "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.",
          "schema_ref": "#/components/schemas/ToolRateLimitError",
          "response_ref": "#/components/responses/ToolRateLimited"
        },
        {
          "status": "502",
          "description": "An upstream DNS, RDAP, or TLS dependency failed.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolUpstreamError"
        }
      ],
      "rate_limit": {
        "applies": true,
        "policy": "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.",
        "retry_after_header": {
          "description": "Seconds until the denying bucket resets.",
          "schema": {
            "type": "integer",
            "minimum": 1
          },
          "example": 42
        }
      },
      "retry_guidance": "On HTTP 429, wait for the Retry-After number of seconds before retrying.",
      "safety_notes": [],
      "partial_result_notes": [],
      "schema_refs": [
        "#/components/schemas/ToolCnameEnvelope",
        "#/components/schemas/ToolError",
        "#/components/schemas/ToolRateLimitError"
      ]
    },
    {
      "operation_id": "lookupDnsRecords",
      "method": "GET",
      "path": "/api/tools/dns-records",
      "url": "https://cloud.approximated.app/api/tools/dns-records",
      "summary": "Look up multiple DNS record types",
      "description": null,
      "parameters": [
        {
          "name": "domain",
          "in": "query",
          "required": true,
          "description": null,
          "schema": {
            "type": "string",
            "format": "hostname",
            "example": "example.com"
          },
          "source_ref": "#/components/parameters/ToolDomain"
        },
        {
          "name": "types",
          "in": "query",
          "required": false,
          "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"
          },
          "source_ref": null
        }
      ],
      "auth": false,
      "success_semantics": [
        {
          "status": "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.",
          "schema_ref": "#/components/schemas/ToolDnsRecordsEnvelope",
          "response_ref": null
        }
      ],
      "error_semantics": [
        {
          "status": "400",
          "description": "Required input is missing or invalid.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolInvalidInput"
        },
        {
          "status": "429",
          "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.",
          "schema_ref": "#/components/schemas/ToolRateLimitError",
          "response_ref": "#/components/responses/ToolRateLimited"
        },
        {
          "status": "502",
          "description": "An upstream DNS, RDAP, or TLS dependency failed.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolUpstreamError"
        }
      ],
      "rate_limit": {
        "applies": true,
        "policy": "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.",
        "retry_after_header": {
          "description": "Seconds until the denying bucket resets.",
          "schema": {
            "type": "integer",
            "minimum": 1
          },
          "example": 42
        }
      },
      "retry_guidance": "On HTTP 429, wait for the Retry-After number of seconds before retrying.",
      "safety_notes": [],
      "partial_result_notes": [
        "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."
      ],
      "schema_refs": [
        "#/components/schemas/ToolDnsRecordsEnvelope",
        "#/components/schemas/ToolError",
        "#/components/schemas/ToolRateLimitError"
      ]
    },
    {
      "operation_id": "lookupDomainRegistration",
      "method": "GET",
      "path": "/api/tools/whois",
      "url": "https://cloud.approximated.app/api/tools/whois",
      "summary": "Look up domain registration using RDAP",
      "description": null,
      "parameters": [
        {
          "name": "domain",
          "in": "query",
          "required": true,
          "description": null,
          "schema": {
            "type": "string",
            "format": "hostname",
            "example": "example.com"
          },
          "source_ref": "#/components/parameters/ToolDomain"
        }
      ],
      "auth": false,
      "success_semantics": [
        {
          "status": "200",
          "description": "Registered, unregistered, or unsupported-TLD result.",
          "schema_ref": "#/components/schemas/ToolWhoisEnvelope",
          "response_ref": null
        }
      ],
      "error_semantics": [
        {
          "status": "400",
          "description": "Required input is missing or invalid.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolInvalidInput"
        },
        {
          "status": "429",
          "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.",
          "schema_ref": "#/components/schemas/ToolRateLimitError",
          "response_ref": "#/components/responses/ToolRateLimited"
        },
        {
          "status": "502",
          "description": "An upstream DNS, RDAP, or TLS dependency failed.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolUpstreamError"
        }
      ],
      "rate_limit": {
        "applies": true,
        "policy": "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.",
        "retry_after_header": {
          "description": "Seconds until the denying bucket resets.",
          "schema": {
            "type": "integer",
            "minimum": 1
          },
          "example": 42
        }
      },
      "retry_guidance": "On HTTP 429, wait for the Retry-After number of seconds before retrying.",
      "safety_notes": [],
      "partial_result_notes": [],
      "schema_refs": [
        "#/components/schemas/ToolWhoisEnvelope",
        "#/components/schemas/ToolError",
        "#/components/schemas/ToolRateLimitError"
      ]
    },
    {
      "operation_id": "lookupTxtRecords",
      "method": "GET",
      "path": "/api/tools/txt",
      "url": "https://cloud.approximated.app/api/tools/txt",
      "summary": "Look up and categorize TXT records",
      "description": null,
      "parameters": [
        {
          "name": "domain",
          "in": "query",
          "required": true,
          "description": null,
          "schema": {
            "type": "string",
            "format": "hostname",
            "example": "example.com"
          },
          "source_ref": "#/components/parameters/ToolDomain"
        }
      ],
      "auth": false,
      "success_semantics": [
        {
          "status": "200",
          "description": "TXT records.",
          "schema_ref": "#/components/schemas/ToolTxtEnvelope",
          "response_ref": null
        }
      ],
      "error_semantics": [
        {
          "status": "400",
          "description": "Required input is missing or invalid.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolInvalidInput"
        },
        {
          "status": "429",
          "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.",
          "schema_ref": "#/components/schemas/ToolRateLimitError",
          "response_ref": "#/components/responses/ToolRateLimited"
        },
        {
          "status": "502",
          "description": "An upstream DNS, RDAP, or TLS dependency failed.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolUpstreamError"
        }
      ],
      "rate_limit": {
        "applies": true,
        "policy": "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.",
        "retry_after_header": {
          "description": "Seconds until the denying bucket resets.",
          "schema": {
            "type": "integer",
            "minimum": 1
          },
          "example": 42
        }
      },
      "retry_guidance": "On HTTP 429, wait for the Retry-After number of seconds before retrying.",
      "safety_notes": [],
      "partial_result_notes": [],
      "schema_refs": [
        "#/components/schemas/ToolTxtEnvelope",
        "#/components/schemas/ToolError",
        "#/components/schemas/ToolRateLimitError"
      ]
    },
    {
      "operation_id": "pingFreeTools",
      "method": "GET",
      "path": "/api/tools/ping",
      "url": "https://cloud.approximated.app/api/tools/ping",
      "summary": "Check free-tools API availability",
      "description": "Public and intentionally not rate-limited.",
      "parameters": [],
      "auth": false,
      "success_semantics": [
        {
          "status": "200",
          "description": "Service is available.",
          "schema_ref": "#/components/schemas/ToolPingEnvelope",
          "response_ref": null
        }
      ],
      "error_semantics": [],
      "rate_limit": {
        "applies": false,
        "policy": "Public and intentionally not rate-limited.",
        "retry_after_header": null
      },
      "retry_guidance": "No retry behavior is specified by the API contract.",
      "safety_notes": [],
      "partial_result_notes": [],
      "schema_refs": [
        "#/components/schemas/ToolPingEnvelope"
      ]
    },
    {
      "operation_id": "reverseIpLookup",
      "method": "GET",
      "path": "/api/tools/reverse-ip",
      "url": "https://cloud.approximated.app/api/tools/reverse-ip",
      "summary": "Perform a PTR lookup",
      "description": null,
      "parameters": [
        {
          "name": "ip",
          "in": "query",
          "required": true,
          "description": null,
          "schema": {
            "type": "string",
            "example": "8.8.8.8"
          },
          "source_ref": null
        }
      ],
      "auth": false,
      "success_semantics": [
        {
          "status": "200",
          "description": "PTR answers.",
          "schema_ref": "#/components/schemas/ToolReverseIpEnvelope",
          "response_ref": null
        }
      ],
      "error_semantics": [
        {
          "status": "400",
          "description": "Required input is missing or invalid.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolInvalidInput"
        },
        {
          "status": "429",
          "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.",
          "schema_ref": "#/components/schemas/ToolRateLimitError",
          "response_ref": "#/components/responses/ToolRateLimited"
        },
        {
          "status": "502",
          "description": "An upstream DNS, RDAP, or TLS dependency failed.",
          "schema_ref": "#/components/schemas/ToolError",
          "response_ref": "#/components/responses/ToolUpstreamError"
        }
      ],
      "rate_limit": {
        "applies": true,
        "policy": "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.",
        "retry_after_header": {
          "description": "Seconds until the denying bucket resets.",
          "schema": {
            "type": "integer",
            "minimum": 1
          },
          "example": 42
        }
      },
      "retry_guidance": "On HTTP 429, wait for the Retry-After number of seconds before retrying.",
      "safety_notes": [],
      "partial_result_notes": [],
      "schema_refs": [
        "#/components/schemas/ToolReverseIpEnvelope",
        "#/components/schemas/ToolError",
        "#/components/schemas/ToolRateLimitError"
      ]
    }
  ]
}
